GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/indent/indent.c Lines: 0 640 0.0 %
Date: 2017-11-13 Branches: 0 561 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: indent.c,v 1.30 2015/11/11 01:12:09 deraadt Exp $	*/
2
3
/*
4
 * Copyright (c) 1980, 1993
5
 *	The Regents of the University of California.
6
 * Copyright (c) 1976 Board of Trustees of the University of Illinois.
7
 * Copyright (c) 1985 Sun Microsystems, Inc.
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of the University nor the names of its contributors
19
 *    may be used to endorse or promote products derived from this software
20
 *    without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 */
34
35
#include <fcntl.h>
36
#include <unistd.h>
37
#include <limits.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include "indent_globs.h"
42
#include "indent_codes.h"
43
#include <ctype.h>
44
#include <errno.h>
45
#include <err.h>
46
47
char       *in_name = "Standard Input";	/* will always point to name of input
48
					 * file */
49
char       *out_name = "Standard Output";	/* will always point to name
50
						 * of output file */
51
char        bakfile[PATH_MAX] = "";
52
53
void bakcopy(void);
54
55
int
56
main(int argc, char **argv)
57
{
58
59
    extern int  found_err;	/* flag set in diag() on error */
60
    int         dec_ind;	/* current indentation for declarations */
61
    int         di_stack[20];	/* a stack of structure indentation levels */
62
    int         flushed_nl;	/* used when buffering up comments to remember
63
				 * that a newline was passed over */
64
    int         force_nl;	/* when true, code must be broken */
65
    int         hd_type;	/* used to store type of stmt for if (...),
66
				 * for (...), etc */
67
    int 	i;		/* local loop counter */
68
    int         scase;		/* set to true when we see a case, so we will
69
				 * know what to do with the following colon */
70
    int         sp_sw;		/* when true, we are in the expressin of
71
				 * if(...), while(...), etc. */
72
    int         squest;		/* when this is positive, we have seen a ?
73
				 * without the matching : in a <c>?<s>:<s>
74
				 * construct */
75
    char 	*t_ptr;		/* used for copying tokens */
76
    int         tabs_to_var;	/* true if using tabs to indent to var name */
77
    int         type_code;	/* the type of token, returned by lexi */
78
79
    int         last_else = 0;	/* true iff last keyword was an else */
80
81
    if (pledge("stdio rpath wpath cpath flock", NULL) == -1)
82
	err(1, "pledge");
83
84
    /*-----------------------------------------------*\
85
    |		      INITIALIZATION		      |
86
    \*-----------------------------------------------*/
87
88
89
    hd_type = 0;
90
    ps.p_stack[0] = stmt;	/* this is the parser's stack */
91
    ps.last_nl = true;		/* this is true if the last thing scanned was
92
				 * a newline */
93
    ps.last_token = semicolon;
94
    combuf = malloc(bufsize);
95
    labbuf = malloc(bufsize);
96
    codebuf = malloc(bufsize);
97
    tokenbuf = malloc(bufsize);
98
    if (combuf == NULL || labbuf == NULL || codebuf == NULL ||
99
        tokenbuf == NULL)
100
	    err(1, NULL);
101
    l_com = combuf + bufsize - 5;
102
    l_lab = labbuf + bufsize - 5;
103
    l_code = codebuf + bufsize - 5;
104
    l_token = tokenbuf + bufsize - 5;
105
    combuf[0] = codebuf[0] = labbuf[0] = ' ';	/* set up code, label, and
106
						 * comment buffers */
107
    combuf[1] = codebuf[1] = labbuf[1] = '\0';
108
    ps.else_if = 1;		/* Default else-if special processing to on */
109
    s_lab = e_lab = labbuf + 1;
110
    s_code = e_code = codebuf + 1;
111
    s_com = e_com = combuf + 1;
112
    s_token = e_token = tokenbuf + 1;
113
114
    in_buffer = malloc(10);
115
    if (in_buffer == NULL)
116
	    err(1, NULL);
117
    in_buffer_limit = in_buffer + 8;
118
    buf_ptr = buf_end = in_buffer;
119
    line_no = 1;
120
    had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
121
    sp_sw = force_nl = false;
122
    ps.in_or_st = false;
123
    ps.bl_line = true;
124
    dec_ind = 0;
125
    di_stack[ps.dec_nest = 0] = 0;
126
    ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
127
128
129
    scase = ps.pcase = false;
130
    squest = 0;
131
    sc_end = 0;
132
    bp_save = 0;
133
    be_save = 0;
134
135
    output = 0;
136
137
138
139
    /*--------------------------------------------------*\
140
    |   		COMMAND LINE SCAN		 |
141
    \*--------------------------------------------------*/
142
143
#ifdef undef
144
    max_col = 78;		/* -l78 */
145
    lineup_to_parens = 1;	/* -lp */
146
    ps.ljust_decl = 0;		/* -ndj */
147
    ps.com_ind = 33;		/* -c33 */
148
    star_comment_cont = 1;	/* -sc */
149
    ps.ind_size = 8;		/* -i8 */
150
    verbose = 0;
151
    ps.decl_indent = 16;	/* -di16 */
152
    ps.indent_parameters = 1;	/* -ip */
153
    ps.decl_com_ind = 0;	/* if this is not set to some positive value
154
				 * by an arg, we will set this equal to
155
				 * ps.com_ind */
156
    btype_2 = 1;		/* -br */
157
    cuddle_else = 1;		/* -ce */
158
    ps.unindent_displace = 0;	/* -d0 */
159
    ps.case_indent = 0;		/* -cli0 */
160
    format_col1_comments = 1;	/* -fc1 */
161
    procnames_start_line = 1;	/* -psl */
162
    proc_calls_space = 0;	/* -npcs */
163
    comment_delimiter_on_blankline = 1;	/* -cdb */
164
    ps.leave_comma = 1;		/* -nbc */
165
#endif
166
167
    for (i = 1; i < argc; ++i)
168
	if (strcmp(argv[i], "-npro") == 0)
169
	    break;
170
    set_defaults();
171
    if (i >= argc)
172
	set_profile();
173
174
    for (i = 1; i < argc; ++i) {
175
176
	/*
177
	 * look thru args (if any) for changes to defaults
178
	 */
179
	if (argv[i][0] != '-') {/* no flag on parameter */
180
	    if (input == 0) {	/* we must have the input file */
181
		in_name = argv[i];	/* remember name of input file */
182
		input = fopen(in_name, "r");
183
		if (input == NULL)		/* check for open error */
184
			err(1, "%s", in_name);
185
		continue;
186
	    }
187
	    else if (output == 0) {	/* we have the output file */
188
		out_name = argv[i];	/* remember name of output file */
189
		if (strcmp(in_name, out_name) == 0)	/* attempt to overwrite
190
							 * the file */
191
			errx(1, "input and output files must be different");
192
		output = fopen(out_name, "w");
193
		if (output == NULL)	/* check for create error */
194
			err(1, "%s", out_name);
195
		continue;
196
	    }
197
	    errx(1, "unknown parameter: %s", argv[i]);
198
	}
199
	else
200
	    set_option(argv[i]);
201
    }				/* end of for */
202
    if (input == NULL) {
203
	input = stdin;
204
    }
205
    if (output == NULL) {
206
	if (troff || input == stdin)
207
	    output = stdout;
208
	else {
209
	    out_name = in_name;
210
	    bakcopy();
211
	}
212
    }
213
    if (ps.com_ind <= 1)
214
	ps.com_ind = 2;		/* dont put normal comments before column 2 */
215
    if (troff) {
216
	if (bodyf.font[0] == 0)
217
	    parsefont(&bodyf, "R");
218
	if (scomf.font[0] == 0)
219
	    parsefont(&scomf, "I");
220
	if (blkcomf.font[0] == 0)
221
	    blkcomf = scomf, blkcomf.size += 2;
222
	if (boxcomf.font[0] == 0)
223
	    boxcomf = blkcomf;
224
	if (stringf.font[0] == 0)
225
	    parsefont(&stringf, "L");
226
	if (keywordf.font[0] == 0)
227
	    parsefont(&keywordf, "B");
228
	writefdef(&bodyf, 'B');
229
	writefdef(&scomf, 'C');
230
	writefdef(&blkcomf, 'L');
231
	writefdef(&boxcomf, 'X');
232
	writefdef(&stringf, 'S');
233
	writefdef(&keywordf, 'K');
234
    }
235
    if (block_comment_max_col <= 0)
236
	block_comment_max_col = max_col;
237
    if (ps.decl_com_ind <= 0)	/* if not specified by user, set this */
238
	ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
239
    if (continuation_indent == 0)
240
	continuation_indent = ps.ind_size;
241
    fill_buffer();	/* get first batch of stuff into input buffer */
242
243
    parse(semicolon);
244
    {
245
	char *p = buf_ptr;
246
	int   col = 1;
247
248
	while (1) {
249
	    if (*p == ' ')
250
		col++;
251
	    else if (*p == '\t')
252
		col = ((col - 1) & ~7) + 9;
253
	    else
254
		break;
255
	    p++;
256
	}
257
	if (col > ps.ind_size)
258
	    ps.ind_level = ps.i_l_follow = col / ps.ind_size;
259
    }
260
    if (troff) {
261
	char *p = in_name,
262
	           *beg = in_name;
263
264
	while (*p)
265
	    if (*p++ == '/')
266
		beg = p;
267
	fprintf(output, ".Fn \"%s\"\n", beg);
268
    }
269
    /*
270
     * START OF MAIN LOOP
271
     */
272
273
    while (1) {			/* this is the main loop.  it will go until we
274
				 * reach eof */
275
	int         is_procname;
276
277
	type_code = lexi();	/* lexi reads one token.  The actual
278
				 * characters read are stored in "token". lexi
279
				 * returns a code indicating the type of token */
280
	is_procname = ps.procname[0];
281
282
	/*
283
	 * The following code moves everything following an if (), while (),
284
	 * else, etc. up to the start of the following stmt to a buffer. This
285
	 * allows proper handling of both kinds of brace placement.
286
	 */
287
288
	flushed_nl = false;
289
	while (ps.search_brace) {	/* if we scanned an if(), while(),
290
					 * etc., we might need to copy stuff
291
					 * into a buffer we must loop, copying
292
					 * stuff into save_com, until we find
293
					 * the start of the stmt which follows
294
					 * the if, or whatever */
295
	    switch (type_code) {
296
	    case newline:
297
		++line_no;
298
		flushed_nl = true;
299
	    case form_feed:
300
		break;		/* form feeds and newlines found here will be
301
				 * ignored */
302
303
	    case lbrace:	/* this is a brace that starts the compound
304
				 * stmt */
305
		if (sc_end == 0) {	/* ignore buffering if a comment wasnt
306
					 * stored up */
307
		    ps.search_brace = false;
308
		    goto check_type;
309
		}
310
		if (btype_2) {
311
		    save_com[0] = '{';	/* we either want to put the brace
312
					 * right after the if */
313
		    goto sw_buffer;	/* go to common code to get out of
314
					 * this loop */
315
		}
316
	    case comment:	/* we have a comment, so we must copy it into
317
				 * the buffer */
318
		if (!flushed_nl || sc_end != 0) {
319
		    if (sc_end == 0) {	/* if this is the first comment, we
320
					 * must set up the buffer */
321
			save_com[0] = save_com[1] = ' ';
322
			sc_end = &(save_com[2]);
323
		    }
324
		    else {
325
			*sc_end++ = '\n';	/* add newline between
326
						 * comments */
327
			*sc_end++ = ' ';
328
			--line_no;
329
		    }
330
		    *sc_end++ = '/';	/* copy in start of comment */
331
		    *sc_end++ = '*';
332
333
		    for (;;) {	/* loop until we get to the end of the comment */
334
			*sc_end = *buf_ptr++;
335
			if (buf_ptr >= buf_end)
336
			    fill_buffer();
337
338
			if (*sc_end++ == '*' && *buf_ptr == '/')
339
			    break;	/* we are at end of comment */
340
341
			if (sc_end >= &(save_com[sc_size])) {	/* check for temp buffer
342
								 * overflow */
343
			    diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
344
			    fflush(output);
345
			    exit(1);
346
			}
347
		    }
348
		    *sc_end++ = '/';	/* add ending slash */
349
		    if (++buf_ptr >= buf_end)	/* get past / in buffer */
350
			fill_buffer();
351
		    break;
352
		}
353
	    default:		/* it is the start of a normal statment */
354
		if (flushed_nl)	/* if we flushed a newline, make sure it is
355
				 * put back */
356
		    force_nl = true;
357
		if ((type_code == sp_paren && *token == 'i'
358
		     && last_else && ps.else_if) ||
359
		    (type_code == sp_nparen && *token == 'e'
360
		     && e_code != s_code && e_code[-1] == '}'))
361
			force_nl = false;
362
363
		if (sc_end == 0) {	/* ignore buffering if comment wasnt
364
					 * saved up */
365
		    ps.search_brace = false;
366
		    goto check_type;
367
		}
368
		if (force_nl) {	/* if we should insert a nl here, put it into
369
				 * the buffer */
370
		    force_nl = false;
371
		    --line_no;	/* this will be re-increased when the nl is
372
				 * read from the buffer */
373
		    *sc_end++ = '\n';
374
		    *sc_end++ = ' ';
375
		    if (verbose && !flushed_nl)	/* print error msg if the line
376
						 * was not already broken */
377
			diag(0, "Line broken");
378
		    flushed_nl = false;
379
		}
380
		for (t_ptr = token; *t_ptr; ++t_ptr)
381
		    *sc_end++ = *t_ptr;	/* copy token into temp buffer */
382
		ps.procname[0] = 0;
383
384
	sw_buffer:
385
		ps.search_brace = false;	/* stop looking for start of
386
						 * stmt */
387
		bp_save = buf_ptr;	/* save current input buffer */
388
		be_save = buf_end;
389
		buf_ptr = save_com;	/* fix so that subsequent calls to
390
					 * lexi will take tokens out of
391
					 * save_com */
392
		*sc_end++ = ' ';/* add trailing blank, just in case */
393
		buf_end = sc_end;
394
		sc_end = 0;
395
		break;
396
	    }			/* end of switch */
397
	    if (type_code != 0)	/* we must make this check, just in case there
398
				 * was an unexpected EOF */
399
		type_code = lexi();	/* read another token */
400
	    /* if (ps.search_brace) ps.procname[0] = 0; */
401
	    if ((is_procname = ps.procname[0]) && flushed_nl
402
		    && !procnames_start_line && ps.in_decl
403
		    && type_code == ident)
404
		flushed_nl = 0;
405
	}			/* end of while (search_brace) */
406
	last_else = 0;
407
check_type:
408
	if (type_code == 0) {	/* we got eof */
409
	    if (s_lab != e_lab || s_code != e_code
410
		    || s_com != e_com)	/* must dump end of line */
411
		dump_line();
412
	    if (ps.tos > 1)	/* check for balanced braces */
413
		diag(1, "Missing braces at end of file.");
414
415
	    if (verbose) {
416
		printf("There were %d output lines and %d comments\n",
417
		       ps.out_lines, ps.out_coms);
418
		printf("(Lines with comments)/(Lines with code): %6.3f\n",
419
		       (1.0 * ps.com_lines) / code_lines);
420
	    }
421
	    fflush(output);
422
	    exit(found_err);
423
	}
424
	if (
425
		(type_code != comment) &&
426
		(type_code != newline) &&
427
		(type_code != preesc) &&
428
		(type_code != form_feed)) {
429
	    if (force_nl &&
430
		    (type_code != semicolon) &&
431
		    (type_code != lbrace || !btype_2)) {
432
		/* we should force a broken line here */
433
		if (verbose && !flushed_nl)
434
		    diag(0, "Line broken");
435
		flushed_nl = false;
436
		dump_line();
437
		ps.want_blank = false;	/* dont insert blank at line start */
438
		force_nl = false;
439
	    }
440
	    ps.in_stmt = true;	/* turn on flag which causes an extra level of
441
				 * indentation. this is turned off by a ; or
442
				 * '}' */
443
	    if (s_com != e_com) {	/* the turkey has embedded a comment
444
					 * in a line. fix it */
445
		*e_code++ = ' ';
446
		for (t_ptr = s_com; *t_ptr; ++t_ptr) {
447
		    CHECK_SIZE_CODE;
448
		    *e_code++ = *t_ptr;
449
		}
450
		*e_code++ = ' ';
451
		*e_code = '\0';	/* null terminate code sect */
452
		ps.want_blank = false;
453
		e_com = s_com;
454
	    }
455
	}
456
	else if (type_code != comment)	/* preserve force_nl thru a comment */
457
	    force_nl = false;	/* cancel forced newline after newline, form
458
				 * feed, etc */
459
460
461
462
	/*-----------------------------------------------------*\
463
	|	   do switch on type of token scanned		|
464
	\*-----------------------------------------------------*/
465
	CHECK_SIZE_CODE;
466
	switch (type_code) {	/* now, decide what to do with the token */
467
468
	case form_feed:	/* found a form feed in line */
469
	    ps.use_ff = true;	/* a form feed is treated much like a newline */
470
	    dump_line();
471
	    ps.want_blank = false;
472
	    break;
473
474
	case newline:
475
	    if (ps.last_token != comma || ps.p_l_follow > 0
476
		    || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com) {
477
		dump_line();
478
		ps.want_blank = false;
479
	    }
480
	    ++line_no;		/* keep track of input line number */
481
	    break;
482
483
	case lparen:		/* got a '(' or '[' */
484
	    ++ps.p_l_follow;	/* count parens to make Healy happy */
485
	    if (ps.want_blank && *token != '[' &&
486
		    (ps.last_token != ident || proc_calls_space
487
	      || (ps.its_a_keyword && (!ps.sizeof_keyword || Bill_Shannon))))
488
		*e_code++ = ' ';
489
	    if (ps.in_decl && !ps.block_init)
490
		if (troff && !ps.dumped_decl_indent && !is_procname && ps.last_token == decl) {
491
		    ps.dumped_decl_indent = 1;
492
		    snprintf(e_code, (l_code - e_code) + 5,
493
			"\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
494
		    e_code += strlen(e_code);
495
		    CHECK_SIZE_CODE;
496
		}
497
		else {
498
		    while ((e_code - s_code) < dec_ind) {
499
			CHECK_SIZE_CODE;
500
			*e_code++ = ' ';
501
		    }
502
		    *e_code++ = token[0];
503
		}
504
	    else
505
		*e_code++ = token[0];
506
	    ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code;
507
	    if (sp_sw && ps.p_l_follow == 1 && extra_expression_indent
508
		    && ps.paren_indents[0] < 2 * ps.ind_size)
509
		ps.paren_indents[0] = 2 * ps.ind_size;
510
	    ps.want_blank = false;
511
	    if (ps.in_or_st && *token == '(' && ps.tos <= 2) {
512
		/*
513
		 * this is a kluge to make sure that declarations will be
514
		 * aligned right if proc decl has an explicit type on it, i.e.
515
		 * "int a(x) {..."
516
		 */
517
		parse(semicolon);	/* I said this was a kluge... */
518
		ps.in_or_st = false;	/* turn off flag for structure decl or
519
					 * initialization */
520
	    }
521
	    if (ps.sizeof_keyword)
522
		ps.sizeof_mask |= 1 << ps.p_l_follow;
523
	    break;
524
525
	case rparen:		/* got a ')' or ']' */
526
	    rparen_count--;
527
	    if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask) {
528
		ps.last_u_d = true;
529
		ps.cast_mask &= (1 << ps.p_l_follow) - 1;
530
	    }
531
	    ps.sizeof_mask &= (1 << ps.p_l_follow) - 1;
532
	    if (--ps.p_l_follow < 0) {
533
		ps.p_l_follow = 0;
534
		diag(0, "Extra %c", *token);
535
	    }
536
	    if (e_code == s_code)	/* if the paren starts the line */
537
		ps.paren_level = ps.p_l_follow;	/* then indent it */
538
539
	    *e_code++ = token[0];
540
	    ps.want_blank = true;
541
542
	    if (sp_sw && (ps.p_l_follow == 0)) {	/* check for end of if
543
							 * (...), or some such */
544
		sp_sw = false;
545
		force_nl = true;/* must force newline after if */
546
		ps.last_u_d = true;	/* inform lexi that a following
547
					 * operator is unary */
548
		ps.in_stmt = false;	/* dont use stmt continuation
549
					 * indentation */
550
551
		parse(hd_type);	/* let parser worry about if, or whatever */
552
	    }
553
	    ps.search_brace = btype_2;	/* this should insure that constructs
554
					 * such as main(){...} and int[]{...}
555
					 * have their braces put in the right
556
					 * place */
557
	    break;
558
559
	case unary_op:		/* this could be any unary operation */
560
	    if (ps.want_blank)
561
		*e_code++ = ' ';
562
563
	    if (troff && !ps.dumped_decl_indent && ps.in_decl && !is_procname) {
564
		snprintf(e_code, (l_code - e_code) + 5,
565
		    "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
566
		ps.dumped_decl_indent = 1;
567
		e_code += strlen(e_code);
568
		CHECK_SIZE_CODE;
569
	    }
570
	    else {
571
		char       *res = token;
572
573
		if (ps.in_decl && !ps.block_init) {	/* if this is a unary op
574
							 * in a declaration, we
575
							 * should indent this
576
							 * token */
577
		    for (i = 0; token[i]; ++i);	/* find length of token */
578
		    while ((e_code - s_code) < (dec_ind - i)) {
579
			CHECK_SIZE_CODE;
580
			*e_code++ = ' ';	/* pad it */
581
		    }
582
		}
583
		if (troff && token[0] == '-' && token[1] == '>')
584
		    res = "\\(->";
585
		for (t_ptr = res; *t_ptr; ++t_ptr) {
586
		    CHECK_SIZE_CODE;
587
		    *e_code++ = *t_ptr;
588
		}
589
	    }
590
	    ps.want_blank = false;
591
	    break;
592
593
	case binary_op:	/* any binary operation */
594
	    if (ps.want_blank)
595
		*e_code++ = ' ';
596
	    {
597
		char       *res = token;
598
599
		if (troff)
600
		    switch (token[0]) {
601
		    case '<':
602
			if (token[1] == '=')
603
			    res = "\\(<=";
604
			break;
605
		    case '>':
606
			if (token[1] == '=')
607
			    res = "\\(>=";
608
			break;
609
		    case '!':
610
			if (token[1] == '=')
611
			    res = "\\(!=";
612
			break;
613
		    case '|':
614
			if (token[1] == '|')
615
			    res = "\\(br\\(br";
616
			else if (token[1] == 0)
617
			    res = "\\(br";
618
			break;
619
		    }
620
		for (t_ptr = res; *t_ptr; ++t_ptr) {
621
		    CHECK_SIZE_CODE;
622
		    *e_code++ = *t_ptr;	/* move the operator */
623
		}
624
	    }
625
	    ps.want_blank = true;
626
	    break;
627
628
	case postop:		/* got a trailing ++ or -- */
629
	    *e_code++ = token[0];
630
	    *e_code++ = token[1];
631
	    ps.want_blank = true;
632
	    break;
633
634
	case question:		/* got a ? */
635
	    squest++;		/* this will be used when a later colon
636
				 * appears so we can distinguish the
637
				 * <c>?<n>:<n> construct */
638
	    if (ps.want_blank)
639
		*e_code++ = ' ';
640
	    *e_code++ = '?';
641
	    ps.want_blank = true;
642
	    break;
643
644
	case casestmt:		/* got word 'case' or 'default' */
645
	    scase = true;	/* so we can process the later colon properly */
646
	    goto copy_id;
647
648
	case colon:		/* got a ':' */
649
	    if (squest > 0) {	/* it is part of the <c>?<n>: <n> construct */
650
		--squest;
651
		if (ps.want_blank)
652
		    *e_code++ = ' ';
653
		*e_code++ = ':';
654
		ps.want_blank = true;
655
		break;
656
	    }
657
	    if (ps.in_decl) {
658
		*e_code++ = ':';
659
		ps.want_blank = false;
660
		break;
661
	    }
662
	    ps.in_stmt = false;	/* seeing a label does not imply we are in a
663
				 * stmt */
664
	    for (t_ptr = s_code; *t_ptr; ++t_ptr)
665
		*e_lab++ = *t_ptr;	/* turn everything so far into a label */
666
	    e_code = s_code;
667
	    *e_lab++ = ':';
668
	    *e_lab++ = ' ';
669
	    *e_lab = '\0';
670
671
	    force_nl = ps.pcase = scase;	/* ps.pcase will be used by
672
						 * dump_line to decide how to
673
						 * indent the label. force_nl
674
						 * will force a case n: to be
675
						 * on a line by itself */
676
	    scase = false;
677
	    ps.want_blank = false;
678
	    break;
679
680
	case semicolon:	/* got a ';' */
681
	    ps.in_or_st = false;/* we are not in an initialization or
682
				 * structure declaration */
683
	    scase = false;	/* these will only need resetting in a error */
684
	    squest = 0;
685
	    if (ps.last_token == rparen && rparen_count == 0)
686
		ps.in_parameter_declaration = 0;
687
	    ps.cast_mask = 0;
688
	    ps.sizeof_mask = 0;
689
	    ps.block_init = 0;
690
	    ps.block_init_level = 0;
691
	    ps.just_saw_decl--;
692
693
	    if (ps.in_decl && s_code == e_code && !ps.block_init)
694
		while ((e_code - s_code) < (dec_ind - 1)) {
695
		    CHECK_SIZE_CODE;
696
		    *e_code++ = ' ';
697
		}
698
699
	    ps.in_decl = (ps.dec_nest > 0);	/* if we were in a first level
700
						 * structure declaration, we
701
						 * arent any more */
702
703
	    if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
704
705
		/*
706
		 * This should be true iff there were unbalanced parens in the
707
		 * stmt.  It is a bit complicated, because the semicolon might
708
		 * be in a for stmt
709
		 */
710
		diag(1, "Unbalanced parens");
711
		ps.p_l_follow = 0;
712
		if (sp_sw) {	/* this is a check for a if, while, etc. with
713
				 * unbalanced parens */
714
		    sp_sw = false;
715
		    parse(hd_type);	/* dont lose the if, or whatever */
716
		}
717
	    }
718
	    *e_code++ = ';';
719
	    ps.want_blank = true;
720
	    ps.in_stmt = (ps.p_l_follow > 0);	/* we are no longer in the
721
						 * middle of a stmt */
722
723
	    if (!sp_sw) {	/* if not if for (;;) */
724
		parse(semicolon);	/* let parser know about end of stmt */
725
		force_nl = true;/* force newline after a end of stmt */
726
	    }
727
	    break;
728
729
	case lbrace:		/* got a '{' */
730
	    ps.in_stmt = false;	/* dont indent the {} */
731
	    if (!ps.block_init)
732
		force_nl = true;/* force other stuff on same line as '{' onto
733
				 * new line */
734
	    else if (ps.block_init_level <= 0)
735
		ps.block_init_level = 1;
736
	    else
737
		ps.block_init_level++;
738
739
	    if (s_code != e_code && !ps.block_init) {
740
		if (!btype_2) {
741
		    dump_line();
742
		    ps.want_blank = false;
743
		}
744
		else if (ps.in_parameter_declaration && !ps.in_or_st) {
745
		    ps.i_l_follow = 0;
746
		    dump_line();
747
		    ps.want_blank = false;
748
		}
749
	    }
750
	    if (ps.in_parameter_declaration)
751
		prefix_blankline_requested = 0;
752
753
	    if (ps.p_l_follow > 0) {	/* check for preceding unbalanced
754
					 * parens */
755
		diag(1, "Unbalanced parens");
756
		ps.p_l_follow = 0;
757
		if (sp_sw) {	/* check for unclosed if, for, etc. */
758
		    sp_sw = false;
759
		    parse(hd_type);
760
		    ps.ind_level = ps.i_l_follow;
761
		}
762
	    }
763
	    if (s_code == e_code)
764
		ps.ind_stmt = false;	/* dont put extra indentation on line
765
					 * with '{' */
766
	    if (ps.in_decl && ps.in_or_st) {	/* this is either a structure
767
						 * declaration or an init */
768
		di_stack[ps.dec_nest++] = dec_ind;
769
		/* ?		dec_ind = 0; */
770
	    }
771
	    else {
772
		ps.decl_on_line = false;
773
		/* we can't be in the middle of a declaration, so don't do
774
		 * special indentation of comments */
775
		if (blanklines_after_declarations_at_proctop
776
			&& ps.in_parameter_declaration)
777
		    postfix_blankline_requested = 1;
778
		ps.in_parameter_declaration = 0;
779
	    }
780
	    dec_ind = 0;
781
	    parse(lbrace);	/* let parser know about this */
782
	    if (ps.want_blank)	/* put a blank before '{' if '{' is not at
783
				 * start of line */
784
		*e_code++ = ' ';
785
	    ps.want_blank = false;
786
	    *e_code++ = '{';
787
	    ps.just_saw_decl = 0;
788
	    break;
789
790
	case rbrace:		/* got a '}' */
791
	    if (ps.p_stack[ps.tos] == decl && !ps.block_init)	/* semicolons can be
792
								 * omitted in
793
								 * declarations */
794
		parse(semicolon);
795
	    if (ps.p_l_follow) {/* check for unclosed if, for, else. */
796
		diag(1, "Unbalanced parens");
797
		ps.p_l_follow = 0;
798
		sp_sw = false;
799
	    }
800
	    ps.just_saw_decl = 0;
801
	    ps.block_init_level--;
802
	    if (s_code != e_code && !ps.block_init) {	/* '}' must be first on
803
							 * line */
804
		if (verbose)
805
		    diag(0, "Line broken");
806
		dump_line();
807
	    }
808
	    *e_code++ = '}';
809
	    ps.want_blank = true;
810
	    ps.in_stmt = ps.ind_stmt = false;
811
	    if (ps.dec_nest > 0) {	/* we are in multi-level structure
812
					 * declaration */
813
		dec_ind = di_stack[--ps.dec_nest];
814
		if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
815
		    ps.just_saw_decl = 2;
816
		ps.in_decl = true;
817
	    }
818
	    prefix_blankline_requested = 0;
819
	    parse(rbrace);	/* let parser know about this */
820
	    ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead
821
		&& ps.il[ps.tos] >= ps.ind_level;
822
	    if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0)
823
		postfix_blankline_requested = 1;
824
	    break;
825
826
	case swstmt:		/* got keyword "switch" */
827
	    sp_sw = true;
828
	    hd_type = swstmt;	/* keep this for when we have seen the
829
				 * expression */
830
	    goto copy_id;	/* go move the token into buffer */
831
832
	case sp_paren:		/* token is if, while, for */
833
	    sp_sw = true;	/* the interesting stuff is done after the
834
				 * expression is scanned */
835
	    hd_type = (*token == 'i' ? ifstmt :
836
		       (*token == 'w' ? whilestmt : forstmt));
837
838
	    /*
839
	     * remember the type of header for later use by parser
840
	     */
841
	    goto copy_id;	/* copy the token into line */
842
843
	case sp_nparen:	/* got else, do */
844
	    ps.in_stmt = false;
845
	    if (*token == 'e') {
846
		if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) {
847
		    if (verbose)
848
			diag(0, "Line broken");
849
		    dump_line();/* make sure this starts a line */
850
		    ps.want_blank = false;
851
		}
852
		force_nl = true;/* also, following stuff must go onto new line */
853
		last_else = 1;
854
		parse(elselit);
855
	    }
856
	    else {
857
		if (e_code != s_code) {	/* make sure this starts a line */
858
		    if (verbose)
859
			diag(0, "Line broken");
860
		    dump_line();
861
		    ps.want_blank = false;
862
		}
863
		force_nl = true;/* also, following stuff must go onto new line */
864
		last_else = 0;
865
		parse(dolit);
866
	    }
867
	    goto copy_id;	/* move the token into line */
868
869
	case decl:		/* we have a declaration type (int, register,
870
				 * etc.) */
871
	    parse(decl);	/* let parser worry about indentation */
872
	    if (ps.last_token == rparen && ps.tos <= 1) {
873
		ps.in_parameter_declaration = 1;
874
		if (s_code != e_code) {
875
		    dump_line();
876
		    ps.want_blank = 0;
877
		}
878
	    }
879
	    if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) {
880
		ps.ind_level = ps.i_l_follow = 1;
881
		ps.ind_stmt = 0;
882
	    }
883
	    ps.in_or_st = true;	/* this might be a structure or initialization
884
				 * declaration */
885
	    ps.in_decl = ps.decl_on_line = true;
886
	    if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
887
		ps.just_saw_decl = 2;
888
	    prefix_blankline_requested = 0;
889
	    for (i = 0; token[i++];);	/* get length of token */
890
891
	    /*
892
	     * dec_ind = e_code - s_code + (ps.decl_indent>i ? ps.decl_indent
893
	     * : i);
894
	     */
895
	    dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
896
	    tabs_to_var = (use_tabs ? ps.decl_indent > 0 : 0);
897
	    goto copy_id;
898
899
	case ident:		/* got an identifier or constant */
900
	    if (ps.in_decl) {	/* if we are in a declaration, we must indent
901
				 * identifier */
902
		if (ps.want_blank)
903
		    *e_code++ = ' ';
904
		ps.want_blank = false;
905
		if (is_procname == 0 || !procnames_start_line) {
906
		    if (!ps.block_init) {
907
			if (troff && !ps.dumped_decl_indent) {
908
			    snprintf(e_code, (l_code - e_code) + 5,
909
				"\n.De %dp+\200p\n", dec_ind * 7);
910
			    ps.dumped_decl_indent = 1;
911
			    e_code += strlen(e_code);
912
			    CHECK_SIZE_CODE;
913
			} else {
914
			    int cur_dec_ind;
915
			    int pos, startpos;
916
917
			    /*
918
			     * in order to get the tab math right for
919
			     * indentations that are not multiples of 8 we
920
			     * need to modify both startpos and dec_ind
921
			     * (cur_dec_ind) here by eight minus the
922
			     * remainder of the current starting column
923
			     * divided by eight. This seems to be a
924
			     * properly working fix
925
			     */
926
			    startpos = e_code - s_code;
927
			    cur_dec_ind = dec_ind;
928
			    pos = startpos;
929
			    if ((ps.ind_level * ps.ind_size) % 8 != 0) {
930
				pos += (ps.ind_level * ps.ind_size) % 8;
931
				cur_dec_ind += (ps.ind_level * ps.ind_size) % 8;
932
			    }
933
934
			    if (tabs_to_var) {
935
				while ((pos & ~7) + 8 <= cur_dec_ind) {
936
				    CHECK_SIZE_CODE;
937
				    *e_code++ = '\t';
938
				    pos = (pos & ~7) + 8;
939
				}
940
			    }
941
			    while (pos < cur_dec_ind) {
942
				CHECK_SIZE_CODE;
943
				*e_code++ = ' ';
944
				pos++;
945
			    }
946
			    if (ps.want_blank && e_code - s_code == startpos)
947
				*e_code++ = ' ';
948
			    ps.want_blank = false;
949
			}
950
		    }
951
		}
952
		else {
953
		    if (dec_ind && s_code != e_code)
954
			dump_line();
955
		    dec_ind = 0;
956
		    ps.want_blank = false;
957
		}
958
	    }
959
	    else if (sp_sw && ps.p_l_follow == 0) {
960
		sp_sw = false;
961
		force_nl = true;
962
		ps.last_u_d = true;
963
		ps.in_stmt = false;
964
		parse(hd_type);
965
	    }
966
    copy_id:
967
	    if (ps.want_blank)
968
		*e_code++ = ' ';
969
	    if (troff && ps.its_a_keyword) {
970
		e_code = chfont(&bodyf, &keywordf, e_code);
971
		for (t_ptr = token; *t_ptr; ++t_ptr) {
972
		    CHECK_SIZE_CODE;
973
		    *e_code++ = keywordf.allcaps &&
974
		      islower((unsigned char)*t_ptr) ?
975
		      toupper((unsigned char)*t_ptr) : *t_ptr;
976
		}
977
		e_code = chfont(&keywordf, &bodyf, e_code);
978
	    }
979
	    else
980
		for (t_ptr = token; *t_ptr; ++t_ptr) {
981
		    CHECK_SIZE_CODE;
982
		    *e_code++ = *t_ptr;
983
		}
984
	    ps.want_blank = true;
985
	    break;
986
987
	case period:		/* treat a period kind of like a binary
988
				 * operation */
989
	    *e_code++ = '.';	/* move the period into line */
990
	    ps.want_blank = false;	/* dont put a blank after a period */
991
	    break;
992
993
	case comma:
994
	    ps.want_blank = (s_code != e_code);	/* only put blank after comma
995
						 * if comma does not start the
996
						 * line */
997
	    if (ps.in_decl && is_procname == 0 && !ps.block_init)
998
		while ((e_code - s_code) < (dec_ind - 1)) {
999
		    CHECK_SIZE_CODE;
1000
		    *e_code++ = ' ';
1001
		}
1002
1003
	    *e_code++ = ',';
1004
	    if (ps.p_l_follow == 0) {
1005
		if (ps.block_init_level <= 0)
1006
		    ps.block_init = 0;
1007
		if (break_comma && (!ps.leave_comma || compute_code_target() + (e_code - s_code) > max_col - 8))
1008
		    force_nl = true;
1009
	    }
1010
	    break;
1011
1012
	case preesc:		/* got the character '#' */
1013
	    if ((s_com != e_com) ||
1014
		    (s_lab != e_lab) ||
1015
		    (s_code != e_code))
1016
		dump_line();
1017
	    *e_lab++ = '#';	/* move whole line to 'label' buffer */
1018
	    {
1019
		int         in_comment = 0;
1020
		int         com_start = 0;
1021
		char        quote = 0;
1022
		int         com_end = 0;
1023
1024
		while (*buf_ptr == ' ' || *buf_ptr == '\t') {
1025
		    buf_ptr++;
1026
		    if (buf_ptr >= buf_end)
1027
			fill_buffer();
1028
		}
1029
		while (*buf_ptr != '\n' || (in_comment && !had_eof)) {
1030
		    CHECK_SIZE_LAB;
1031
		    *e_lab = *buf_ptr++;
1032
		    if (buf_ptr >= buf_end)
1033
			fill_buffer();
1034
		    switch (*e_lab++) {
1035
		    case BACKSLASH:
1036
			if (troff)
1037
			    *e_lab++ = BACKSLASH;
1038
			if (!in_comment) {
1039
			    *e_lab++ = *buf_ptr++;
1040
			    if (buf_ptr >= buf_end)
1041
				fill_buffer();
1042
			}
1043
			break;
1044
		    case '/':
1045
			if (*buf_ptr == '*' && !in_comment && !quote) {
1046
			    in_comment = 1;
1047
			    *e_lab++ = *buf_ptr++;
1048
			    com_start = e_lab - s_lab - 2;
1049
			}
1050
			break;
1051
		    case '"':
1052
			if (quote == '"')
1053
			    quote = 0;
1054
			break;
1055
		    case '\'':
1056
			if (quote == '\'')
1057
			    quote = 0;
1058
			break;
1059
		    case '*':
1060
			if (*buf_ptr == '/' && in_comment) {
1061
			    in_comment = 0;
1062
			    *e_lab++ = *buf_ptr++;
1063
			    com_end = e_lab - s_lab;
1064
			}
1065
			break;
1066
		    }
1067
		}
1068
1069
		while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1070
		    e_lab--;
1071
		if (e_lab - s_lab == com_end && bp_save == 0) {	/* comment on
1072
								 * preprocessor line */
1073
		    if (sc_end == 0)	/* if this is the first comment, we
1074
					 * must set up the buffer */
1075
			sc_end = &(save_com[0]);
1076
		    else {
1077
			*sc_end++ = '\n';	/* add newline between
1078
						 * comments */
1079
			*sc_end++ = ' ';
1080
			--line_no;
1081
		    }
1082
		    bcopy(s_lab + com_start, sc_end, com_end - com_start);
1083
		    sc_end += com_end - com_start;
1084
		    if (sc_end >= &save_com[sc_size])
1085
			abort();
1086
		    e_lab = s_lab + com_start;
1087
		    while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1088
			e_lab--;
1089
		    bp_save = buf_ptr;	/* save current input buffer */
1090
		    be_save = buf_end;
1091
		    buf_ptr = save_com;	/* fix so that subsequent calls to
1092
					 * lexi will take tokens out of
1093
					 * save_com */
1094
		    *sc_end++ = ' ';	/* add trailing blank, just in case */
1095
		    buf_end = sc_end;
1096
		    sc_end = 0;
1097
		}
1098
		*e_lab = '\0';	/* null terminate line */
1099
		ps.pcase = false;
1100
	    }
1101
1102
	    if (strncmp(s_lab, "#if", 3) == 0) {
1103
		if (blanklines_around_conditional_compilation) {
1104
		    int    c;
1105
		    prefix_blankline_requested++;
1106
		    while ((c = getc(input)) == '\n');
1107
		    ungetc(c, input);
1108
		}
1109
		if (ifdef_level < sizeof state_stack / sizeof state_stack[0]) {
1110
		    match_state[ifdef_level].tos = -1;
1111
		    state_stack[ifdef_level++] = ps;
1112
		}
1113
		else
1114
		    diag(1, "#if stack overflow");
1115
	    }
1116
	    else if (strncmp(s_lab, "#else", 5) == 0)
1117
		if (ifdef_level <= 0)
1118
		    diag(1, "Unmatched #else");
1119
		else {
1120
		    match_state[ifdef_level - 1] = ps;
1121
		    ps = state_stack[ifdef_level - 1];
1122
		}
1123
	    else if (strncmp(s_lab, "#endif", 6) == 0) {
1124
		if (ifdef_level <= 0)
1125
		    diag(1, "Unmatched #endif");
1126
		else {
1127
		    ifdef_level--;
1128
1129
#ifdef undef
1130
		    /*
1131
		     * This match needs to be more intelligent before the
1132
		     * message is useful
1133
		     */
1134
		    if (match_state[ifdef_level].tos >= 0
1135
			  && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
1136
			diag(0, "Syntactically inconsistent #ifdef alternatives.");
1137
#endif
1138
		}
1139
		if (blanklines_around_conditional_compilation) {
1140
		    postfix_blankline_requested++;
1141
		    n_real_blanklines = 0;
1142
		}
1143
	    }
1144
	    break;		/* subsequent processing of the newline
1145
				 * character will cause the line to be printed */
1146
1147
	case comment:		/* we have gotten a comment this is a biggie */
1148
	    if (flushed_nl) {	/* we should force a broken line here */
1149
		flushed_nl = false;
1150
		dump_line();
1151
		ps.want_blank = false;	/* dont insert blank at line start */
1152
		force_nl = false;
1153
	    }
1154
	    pr_comment();
1155
	    break;
1156
	}			/* end of big switch stmt */
1157
1158
	*e_code = '\0';		/* make sure code section is null terminated */
1159
	if (type_code != comment && type_code != newline && type_code != preesc)
1160
	    ps.last_token = type_code;
1161
    }				/* end of main while (1) loop */
1162
}
1163
1164
/*
1165
 * copy input file to backup file if in_name is /blah/blah/blah/file, then
1166
 * backup file will be ".Bfile" then make the backup file the input and
1167
 * original input file the output
1168
 */
1169
void
1170
bakcopy(void)
1171
{
1172
    int         n,
1173
                bakchn;
1174
    char        buff[8 * 1024];
1175
    char       *p;
1176
1177
    /* construct file name .Bfile */
1178
    for (p = in_name; *p; p++);	/* skip to end of string */
1179
    while (p > in_name && *p != '/')	/* find last '/' */
1180
	p--;
1181
    if (*p == '/')
1182
	p++;
1183
    if (snprintf(bakfile, PATH_MAX, "%s.BAK", p) >= PATH_MAX)
1184
	    errc(1, ENAMETOOLONG, "%s.BAK", p);
1185
1186
    /* copy in_name to backup file */
1187
    bakchn = open(bakfile, O_CREAT | O_TRUNC | O_WRONLY, 0600);
1188
    if (bakchn < 0)
1189
	err(1, "%s", bakfile);
1190
    while ((n = read(fileno(input), buff, sizeof buff)) > 0)
1191
	if (write(bakchn, buff, n) != n)
1192
	    err(1, "%s", bakfile);
1193
    if (n < 0)
1194
	err(1, "%s", in_name);
1195
    close(bakchn);
1196
    fclose(input);
1197
1198
    /* re-open backup file as the input file */
1199
    input = fopen(bakfile, "r");
1200
    if (input == NULL)
1201
	err(1, "%s", bakfile);
1202
    /* now the original input file will be the output */
1203
    output = fopen(in_name, "w");
1204
    if (output == NULL) {
1205
	int saved_errno = errno;
1206
	unlink(bakfile);
1207
	errc(1, saved_errno, "%s", in_name);
1208
    }
1209
}