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