date and time created 82/10/21 23:58:06 by mckusick
[unix-history] / usr / src / usr.bin / indent / indent.c
CommitLineData
c6468b47
KM
1static char sccsid[] = "@(#)indent.c 4.1 (Berkeley) %G%";
2
3/*
4
5 Copyright (C) 1976
6 by the
7 Board of Trustees
8 of the
9 University of Illinois
10
11 All rights reserved
12
13
14NAME:
15 indent main program
16
17FUNCTION:
18 This is the main program of the indent program. Indent will take a C
19 program source and reformat it into a semi-reasonable form.
20
21ALGORITHM:
22 The routine lexi scans tokens and passes them back one at a time to the
23 main routine. The subroutine parse takes care of much of the work of
24 figuring indentation level.
25
26 1) Call lexi
27 2) Enter a monster switch statement on the code returned by lexi. If
28 the indentation level for the line yet to be printed should be
29 changed, set the variable ind_level. If the indentation level for
30 the following line should be changed, set the variable i_l_follow.
31
32PARAMETERS:
33 None
34
35RETURNS:
36 Nothing
37
38GLOBALS:
39 be_save =
40 break_comma
41 bp_save =
42 btype_2 =
43 code_lines
44 com_ind =
45 com_lines
46 dec_nest =
47 decl_com_ind =
48 decl_on_line =
49 i_l_follow =
50 in_decl =
51 ind_level =
52 ind_size =
53 ind_stmt =
54 last_u_d =
55 leave_comma =
56 line_no =
57 ljust_decl =
58 max_col =
59 out_coms
60 out_lines
61 p_l_follow =
62 paren_level =
63 pcase =
64 sc_end =
65 unindent_displace =
66 use_ff =
67 verbose =
68
69CALLS:
70 atoi (lib)
71 cmp
72 creat (lib)
73 dump_line
74 eqin
75 fill_buffer
76 lexi
77 open (lib)
78 parse
79 pr_comment
80 printf (lib)
81 seek (lib)
82 time (lib)
83
84CALLED BY:
85 No one (main routine)
86
87HISTORY:
88 November 1976 D A Willcox of CAC Initial coding
89 12/9/76 D A Willcox of CAC Fixed defaults for decl_com_ind
90 to be 8 less than com_ind if
91 left justifying declarations
92 12/9/76 D A Willcox of CAC Fixed processing of nested
93 <c>?<s>:<s> constructs
94 1/7/77 D A Willcox of CAC Added check for overwrite of
95 input file
96 Added code to handle -br and -bl
97 parameters
98\f*/
99#include "indent_globs.h";
100#include "indent_codes.h";
101
102/* #define dolog 1 /* if this define is removed, then the code to
103 produce a log file will be removed */
104
105struct templ { /* this is a template for the list of
106 command line args */
107 char *str; /* pointer to string which is a valid
108 command line arg */
109 int code; /* code to be used in switch for processing
110 this arg */
111};
112
113
114struct templ options[] =
115{ /* warning - because of the way that this
116 table is scanned, if one entry is an
117 initial substring of another, then the
118 longer entry should occur first */
119 "-cd", 4,
120 "-c", 2,
121 "-l", 1,
122 "-i", 3,
123 "-v", 5,
124 "-nv", 6,
125 "-dj", 7,
126 "-d", 13, /* unindented comment placement */
127 "-ndj", 8,
128 "-bc", 10, /* break after command in decl */
129 "-nbc", 9, /* don't break after comma */
130 "-br", 14, /* put brace on right of stmt */
131 "-bl", 15, /* put brace on left by itself */
132 "-st", 16, /* use the standard input and output
133 files */
134 0, 0
135};
136
137
138char *in_name = "Standard Input";
139 /* will always point to name of input file
140 */
141char *out_name = "Standard Output";
142 /* will always point to name of output file
143 */
144char bakfile[32] = "";
145\f
146main (argc, argv)
147int argc;
148char **argv;
149{
150
151 int dec_ind; /* current indentation for declarations */
152 int di_stack[20]; /* a stack of structure indentation levels
153 */
154 int flushed_nl; /* used when buffering up comments to
155 remember that a newline was passed over
156 */
157 int force_nl; /* when true, code must be broken */
158 int hd_type; /* used to store type of stmt for if (...),
159 for (...), etc */
160 register int i; /* local loop counter */
161 int in_or_st; /* Will be true iff there has been a
162 declarator (e.g. int or char) and no
163 left paren since the last semicolon.
164 When true, a { is starting a structure
165 definition or an initialization list */
166 register int j; /* local loop counter */
167 int scase; /* set to true when we see a case, so we
168 will know what to do with the following
169 colon */
170 int sp_sw; /* when true, we are in the expressin of
171 if(...), while(...), etc. */
172 int squest; /* when this is positive, we have seen a ?
173 without the matching : in a <c>?<s>:<s>
174 construct */
175 register char *t_ptr; /* used for copying tokens */
176 int type_code; /* the type of token, returned by lexi */
177 int want_blank; /* set to true when the following token
178 should be prefixed by a blank. (Said
179 prefixing is ignored in some cases.) */
180
181#ifdef dolog /* include declarations needed for log */
182 int log_fid; /* fid of log file */
183
184 struct logtmpl { /* structure of a log entry */
185 int tvec[2]; /* time of execution */
186 char inp; /* input fid */
187 char outp; /* output fid */
188 int nout; /* # output lines */
189 int ncom; /* # comments */
190 int wcom; /* # lines w/ comments */
191 int wcode; /* # lines w/code */
192 char mc; /* max line size */
193 char ci; /* comment indentation */
194 char inds; /* indent size */
195 char dci; /* decl comment indentation */
196 char verb; /* verbose */
197 char ljus; /* left just */
198 char lvcom; /* leave commas */
199 char unin; /* unindented comment indentation */
200 char uid; /* the user id */
201 char bropt; /* btype_2 */
202 int reserved[2];
203 };
204
205 struct logtmpl logent;
206#endif
207\f
208/*-----------------------------------------------*\
209| INITIALIZATION
210\*-----------------------------------------------*/
211
212
213 combuf[0] = codebuf[0] = labbuf[0] = ' ';
214 /* set up code, label, and comment buffers */
215 combuf[1] = codebuf[1] = labbuf[1] = '\0';
216 s_lab = e_lab = labbuf + 1;
217 s_code = e_code = codebuf + 1;
218 s_com = e_com = combuf + 1;
219
220 buf_ptr = buf_end = in_buffer;
221 line_no = 1;
222 had_eof = in_decl = decl_on_line = break_comma = false;
223 sp_sw = force_nl = false;
224 in_or_st = false;
225 bl_line = true;
226 dec_ind = 0;
227 di_stack[dec_nest = 0] = 0;
228 want_blank = in_stmt = ind_stmt = false;
229
230
231 scase = pcase = false;
232 squest = 0;
233 sc_end = 0;
234 bp_save = 0;
235 be_save = 0;
236
237 input = -1;
238 output = -1;
239 ljust_decl = d_ljust;
240
241
242
243/*--------------------------------------------------*\
244| COMMAND LINE SCAN
245\*--------------------------------------------------*/
246
247 max_col = d_max_col; /* set up some default values */
248 com_ind = d_com_ind;
249 ind_size = d_ind_size;
250 verbose = d_verbose;
251 decl_com_ind = 0; /* if this is not set to some positive
252 value by an arg, we will set this equal
253 to com_ind */
254 btype_2 = d_btype_2;
255 unindent_displace = d_unindent;
256 leave_comma = d_leave_comma;
257
258 set_profile ();
259
260 for (i = 1; i < argc; ++i) {
261 /* look thru args (if any) for changes to defaults */
262 if (argv[i][0] != '-') {/* no flag on parameter */
263 if (input < 0) { /* we must have the input file */
264 in_name = argv[i]; /* remember name of input
265 file */
266 input = open (in_name, 0);
267 if (input < 0) { /* check for open error */
268 printf ("Can't open %s\n", argv[i]);
269 exit ();
270 }
271 continue;
272 }
273 else
274 if (output < 0) { /* we have the output file */
275 out_name = argv[i]; /* remember name of output file */
276 if (cmp (in_name, out_name) == 0) { /* attempt to
277 overwright the file */
278 printf ("Input and output files must be different\n");
279 exit ();
280 }
281 output = creat (out_name, 0644);
282 if (output < 0) { /* check for create error */
283 printf ("Can't create %s\n", argv[i]);
284 exit ();
285 }
286 continue;
287 }
288
289 printf ("Unknown parameter: %s\n", argv[i]);
290 exit ();
291 }
292 else
293 set_option (argv[i]);
294
295 } /* end of for */
296
297 if (input < 0) {
298 printf ("Usage: indent file [ outfile ] [ options ]\n");
299 exit ();
300 }
301 if (output < 0) {
302 out_name = in_name;
303 bakcopy ();
304 }
305
306 if (com_ind <= 1)
307 com_ind = 2; /* don't put normal comments before column
308 2 */
309
310 if (decl_com_ind <= 0) /* if not specified by user, set this */
311 decl_com_ind = ljust_decl ? (com_ind <= 10 ? 2 : com_ind - 8) : com_ind;
312
313 fill_buffer (); /* get first batch of stuff into input
314 buffer */
315
316 parse (semicolon);
317\f/*-----------------------------------------------------
318| START OF MAIN LOOP
319\*----------------------------------------------------*/
320
321 while (1) { /* this is the main loop. it will go until
322 we reach eof */
323 type_code = lexi (); /* lexi reads one token. The actual
324 characters read are stored in "token".
325 lexi returns a code indicating the type
326 of token */
327
328 /*
329 * The following code moves everything following an if (), while (),
330 * else, etc. up to the start of the following stmt to a buffer. This
331 * allows proper handling of both kinds of brace placement.
332 */
333
334 flushed_nl = false;
335 while (search_brace) { /* if we scanned an if(), while(), etc., we
336 might need to copy stuff into a buffer
337 *//* we must loop, copying stuff into save_com, until we find the
338 start of the stmt which follows the if, or whatever */
339 switch (type_code) {
340 case newline:
341 ++line_no;
342 flushed_nl = true;
343 case form_feed:
344 break; /* form feeds and newlines found here will
345 be ignored */
346
347 case lbrace: /* this is a brace that starts the compound
348 stmt */
349 if (sc_end == 0) {
350 /* ignore buffering if a comment wasn't stored up */
351 search_brace = false;
352 goto check_type;
353 }
354
355 if (btype_2) {
356 save_com[0] = '{';
357 /* we either want to put the brace right after the if
358 */
359 goto sw_buffer;
360 /* go to common code to get out of this loop */
361 }
362
363 default: /* it is the start of a normal statment */
364 if (flushed_nl)
365 /* if we flushed a newline, make sure it is
366 put back */
367 force_nl = true;
368
369 if (sc_end == 0) {
370 /* ignore buffering if comment wasn't saved up */
371 search_brace = false;
372 goto check_type;
373 }
374
375 if (force_nl) {
376 /* if we should insert a nl here, put it into the
377 buffer */
378 force_nl = false;
379 --line_no;
380 /* this will be re-increased when the nl is read from
381 the buffer */
382 *sc_end++ = '\n';
383 *sc_end++ = ' ';
384 if (verbose && !flushed_nl)
385 /* print error msg if the line was not
386 already broken */
387 printf ("%d: Line broken\n", line_no);
388 flushed_nl = false;
389 }
390
391 for (t_ptr = token; *t_ptr; ++t_ptr)
392 *sc_end++ = *t_ptr;
393 /* copy token into temp buffer */
394
395 sw_buffer:
396 search_brace = false;
397 /* stop looking for start of stmt */
398 bp_save = buf_ptr;
399 /* save current input buffer */
400 be_save = buf_end;
401 buf_ptr = save_com;
402 /* fix so that subsequent calls to lexi will take tokens
403 out of save_com */
404 *sc_end++ = ' ';
405 /* add trailing blank, just in case */
406 buf_end = sc_end;
407 sc_end = 0;
408 break;
409
410 case comment: /* we have a comment, so we must copy it
411 into the buffer */
412 if (sc_end == 0) {
413 /* if this is the first comment, we must set up the
414 buffer */
415 save_com[0] = save_com[1] = ' ';
416 sc_end = &(save_com[2]);
417 }
418 else {
419 *sc_end++ = '\n';
420 /* add newline between comments */
421 *sc_end++ = ' ';
422 --line_no;
423 }
424
425 *sc_end++ = '/';
426 /* copy in start of comment */
427 *sc_end++ = '*';
428
429 for (;;) { /* loop until we get to the end of the
430 comment */
431 *sc_end = *buf_ptr++;
432 if (buf_ptr >= buf_end)
433 fill_buffer ();
434
435 if (*sc_end++ == '*' && *buf_ptr == '/')
436 break;
437 /* we are at end of comment */
438
439 if (sc_end >= &(save_com[sc_size])) {
440 /* check for temp buffer overflow */
441 printf ("%d: Internal buffer overflow.\n",
442 line_no);
443 printf ("Move big comment from right after if,\
444 while, or whatever.\n");
445 exit ();
446 }
447 }
448
449 *sc_end++ = '/';
450 /* add ending slash */
451 if (++buf_ptr >= buf_end)/* get past / in buffer */
452 fill_buffer ();
453 break;
454 } /* end of switch */
455
456 if (type_code != 0)/* we must make this check, just in case
457 there was an unexpected EOF */
458 type_code = lexi ();
459 /* read another token */
460 } /* end of while (serach_brace) */
461check_type:
462\f
463 if (type_code == 0) { /* we got eof */
464 if (s_lab != e_lab || s_code != e_code
465 || s_com != e_com)/* must dump end of line */
466 dump_line ();
467 if (i_l_follow != 0)/* check for balanced braces */
468 printf ("%d too few }'s\n", i_l_follow);
469
470#ifdef dolog /* only include this stuff if we want to
471 keep a log */
472 log_fid = open ("/mnt/net/willcox/indent/indent_log", 1);
473 /* open the log file */
474 if (log_fid >= 0) {
475 seek (log_fid, 0, 2);
476 /* point to end of log */
477 time (logent.tvec);
478 /* get current time */
479 logent.inp = input;
480 /* set up the log entry */
481 logent.outp = output;
482 logent.nout = out_lines;
483 logent.ncom = out_coms;
484 logent.wcom = com_lines;
485 logent.wcode = code_lines;
486 logent.mc = max_col;
487 logent.ci = com_ind;
488 logent.inds = ind_size;
489 logent.dci = decl_com_ind;
490 logent.verb = verbose;
491 logent.ljus = ljust_decl;
492 logent.lvcom = leave_comma;
493 logent.unin = unindent_displace;
494 logent.uid = getuid ();
495 logent.bropt = btype_2;
496 write (log_fid, &logent, sizeof logent);
497 }
498#endif
499 if (verbose) {
500 printf ("There were %d output lines and %d comments\n",
501 out_lines, out_coms);
502 printf ("(Lines with comments)/(Lines with code): %6.3f\n",
503 (1.0 * com_lines) / code_lines);
504 }
505
506 exit ();
507 }
508
509 if (
510 (type_code != comment) &&
511 (type_code != newline) &&
512 (type_code != preesc) &&
513 (type_code != form_feed)) {
514 if (
515 force_nl
516 &&
517 (type_code != semicolon) &&
518 (
519 type_code != lbrace
520 ||
521 !btype_2
522 )) { /* we should force a broken line here */
523 if (verbose && !flushed_nl)
524 printf ("%d: Line broken\n", line_no);
525 flushed_nl = false;
526 dump_line ();
527 want_blank = false;
528 /* don't insert blank at line start */
529 force_nl = false;
530 }
531
532 in_stmt = true; /* turn on flag which causes an extra level
533 of indentation. this is turned off by a
534 ; or } */
535 if (s_com != e_com) {
536 /* the turkey has embedded a comment in a line. fix it */
537 *e_code++ = ' ';
538 for (t_ptr = s_com; *t_ptr; ++t_ptr)
539 *e_code++ = *t_ptr;
540 *e_code++ = ' ';
541 *e_code = '\0';/* null terminate code sect */
542 want_blank = false;
543 e_com = s_com;
544 }
545 }
546 else
547 if (type_code != comment)
548 /* preserve force_nl thru a comment */
549 force_nl = false;
550 /* cancel forced newline after newline, form feed, etc */
551
552
553
554 /*----------------------------------------------------*\
555 | do switch on type of token scanned
556 \*----------------------------------------------------*/
557 switch (type_code) { /* now, decide what to do with the token */
558
559 case form_feed: /* found a form feed in line */
560 use_ff = true; /* a form feed is treated much like a
561 newline */
562 dump_line ();
563 want_blank = false;
564 break;
565
566 case newline:
567 dump_line ();
568 ++line_no; /* keep track of input line number */
569 want_blank = false;
570 break;
571
572 case lparen: /* got a ( or [ */
573 ++p_l_follow; /* count parens to make Healy happy */
574 if (want_blank && *token != '[')
575 /* don't put space in front of square
576 bracket */
577 *e_code++ = ' ';
578
579 if (in_decl)
580 while ((e_code - s_code) < dec_ind)
581 *e_code++ = ' ';
582
583 *e_code++ = token[0];
584 want_blank = false;
585 if (in_or_st && *token == '(') {
586 /* this is a kluge to make sure that declarations will be
587 aaigned right if proc decl has an explicit type on it,
588 i.e. "int a(x) {..." */
589 parse (semicolon);
590 /* I said this was a kluge... */
591 in_or_st = false;
592 /* turn off flag for structure decl or initialization */
593 }
594
595 break;
596
597 case rparen: /* got a ) or ] */
598 if (--p_l_follow < 0) {
599 p_l_follow = 0;
600 printf ("%d: Extra %c\n", line_no, *token);
601 }
602
603 if (e_code == s_code)/* if the paren starts the line */
604 paren_level = p_l_follow;
605 /* then indent it */
606
607 *e_code++ = token[0];
608 want_blank = true;
609
610 if (sp_sw && (p_l_follow == 0)) {
611 /* check for end of if (...), or some such */
612 sp_sw = false;
613 force_nl = true;
614 /* must force newline after if */
615 last_u_d = true;
616 /* inform lexi that a following operator is unary */
617 in_stmt = false;
618 /* don't use stmt continuation indentation */
619
620 parse (hd_type);
621 /* let parser worry about if, or whatever */
622 }
623
624 search_brace = btype_2;
625 /* this should insure that constructs such as main(){... and
626 int[]{... have their braces put in the right place */
627 break;
628
629 case unary_op: /* this could be any unary operation */
630 if (want_blank)
631 *e_code++ = ' ';
632
633 if (in_decl) { /* if this is a unary op in a *//*
634 declaration, we should indent this token
635 */
636 for (i = 0; token[i]; ++i);
637 /* find length of token */
638 while ((e_code - s_code) < (dec_ind - i))
639 *e_code++ = ' ';
640 /* pad it */
641 }
642
643 for (t_ptr = token; *t_ptr; ++t_ptr)
644 *e_code++ = *t_ptr;
645 /* move the token to buffer */
646 want_blank = false;
647 break;
648
649 case binary_op: /* any binary operation */
650 do_binary:
651 if (want_blank)
652 *e_code++ = ' ';
653 for (t_ptr = token; *t_ptr; ++t_ptr)
654 *e_code++ = *t_ptr;
655 /* move the operator */
656 want_blank = true;
657 break;
658
659 case postop: /* got a trailing ++ or -- */
660 *e_code++ = token[0];
661 *e_code++ = token[1];
662 want_blank = true;
663 break;
664
665 case question: /* got a ? */
666 squest++; /* this will be used when a later colon
667 appears so we can distinguish the
668 <c>?<n>:<n> construct */
669 if (want_blank)
670 *e_code++ = ' ';
671 *e_code++ = '?';
672 want_blank = true;
673 break;
674
675 case casestmt: /* got word 'case' or 'default' */
676 scase = true; /* so we can process the later colon
677 properly */
678 if (want_blank)
679 *e_code++ = ' ';
680 for (t_ptr = token; *t_ptr; ++t_ptr)
681 *e_code++ = *t_ptr;
682 want_blank = true;
683 break;
684
685 case colon: /* got a ':' */
686 if (squest > 0) {
687 /* it is part of the <c>?<n>: <n> construct */
688 --squest;
689 if (want_blank)
690 *e_code++ = ' ';
691 *e_code++ = ':';
692 want_blank = true;
693 break;
694 }
695
696 in_stmt = false;
697 /* seeing a label does not imply we are in a stmt */
698 for (t_ptr = s_code; *t_ptr; ++t_ptr)
699 *e_lab++ = *t_ptr;
700 /* turn everything so far into a label */
701 e_code = s_code;
702 *e_lab++ = ':';
703 *e_lab++ = ' ';
704 *e_lab = '\0';
705
706 force_nl = pcase = scase;
707 /* pcase will be used by dump_line to decide how to indent the
708 label. force_nl will force a case n: to be on a line by
709 itself */
710 scase = false;
711 want_blank = false;
712 break;
713
714 case semicolon: /* got a ';' */
715 in_or_st = false;
716 /* we are not in an initialization or structure declaration */
717 scase = false; /* these will only need resetting in a
718 error */
719 squest = 0;
720
721 if (in_decl && s_code == e_code)
722 /* align this in a declaration */
723 while ((e_code - s_code) < (dec_ind - 1))
724 *e_code++ = ' ';
725
726 in_decl = (dec_nest > 0);
727 /* if we were in a first level structure declaration, we
728 aren't any more */
729
730 if ((!sp_sw || hd_type != forstmt) && p_l_follow > 0) {
731 /* This should be true iff there were unbalanced parens in
732 the stmt. It is a bit complicated, because the
733 semicolon might be in a for stmt */
734 printf ("%d: Unbalanced parens\n", line_no);
735 p_l_follow = 0;
736 if (sp_sw) {
737 /* this is a check for a if, while, etc. with
738 unbalanced parens */
739 sp_sw = false;
740 parse (hd_type);
741 /* don't lose the if, or whatever */
742 }
743 }
744
745 *e_code++ = ';';
746 want_blank = true;
747 in_stmt = (p_l_follow > 0);
748 /* we are no longer in the middle of a stmt */
749
750 if (!sp_sw) { /* if not if for (;;) */
751 parse (semicolon);
752 /* let parser know about end of stmt */
753 force_nl = true;
754 /* force newline after a end of stmt */
755 }
756
757 break;
758
759 case lbrace: /* got a { */
760 in_stmt = false;
761 /* don't indent the { */
762 force_nl = true;
763 /* force other stuff on same line as { onto new line */
764
765 if (s_code != e_code && !btype_2) {
766 /* bracket is not alone on line */
767 if (verbose)
768 printf ("%d: Line broken\n", line_no);
769 dump_line ();
770 want_blank = false;
771 }
772
773 if (p_l_follow > 0) {
774 /* check for preceeding unbalanced parens */
775 printf ("%d: Unbalanced parens\n", line_no);
776 p_l_follow = 0;
777 if (sp_sw) {
778 /* check for unclosed if, for, etc. */
779 sp_sw = false;
780 parse (hd_type);
781 ind_level = i_l_follow;
782 }
783 }
784
785 if (s_code == e_code)
786 ind_stmt = false;
787 /* don't put extra indentation on line with '{' */
788 if (in_decl && in_or_st) {
789 /* this is either a structure declaration or an init */
790 di_stack[dec_nest++] = dec_ind;
791 dec_ind = 0;
792 }
793 else
794 decl_on_line = false;
795 /* we can't be in the middle of a declaration, so don't do
796 special indentation of comments */
797
798 parse (lbrace);/* let parser know about this */
799 if (want_blank)/* put a blank before { if { is not at
800 start of line */
801 *e_code++ = ' ';
802 want_blank = false;
803 *e_code++ = '{';
804 break;
805
806 case rbrace: /* got a } */
807 if (p_l_follow) {
808 /* check for unclosed if, for, else. */
809 printf ("%d: Unbalanced parens\n", line_no);
810 p_l_follow = 0;
811 sp_sw = false;
812 }
813
814 if (s_code != e_code) {
815 /* } must be first on line */
816 if (verbose)
817 printf ("%d: Line broken\n", line_no);
818 dump_line ();
819 }
820
821 *e_code++ = '}';
822 want_blank = true;
823 in_stmt = ind_stmt = false;
824
825 if (dec_nest > 0) {
826 /* we are in multi-level structure declaration */
827 dec_ind = di_stack[--dec_nest];
828 in_decl = true;
829 }
830
831 parse (rbrace);/* let parser know about this */
832 break;
833
834 case swstmt: /* got keyword "switch" */
835 sp_sw = true;
836 hd_type = swstmt;
837 /* keep this for when we have seen the expression */
838 goto copy_id; /* go move the token into buffer */
839
840 case sp_paren: /* token is if, while, for */
841 sp_sw = true; /* the interesting stuff is done after the
842 expression is scanned */
843 hd_type = (*token == 'i' ? ifstmt :
844 (*token == 'w' ? whilestmt : forstmt));
845 /* remember the type of header for later use by parser */
846 goto copy_id; /* copy the token into line */
847
848 case sp_nparen: /* got else, do */
849 in_stmt = false;
850 if (e_code != s_code) {
851 /* make sure this starts a line */
852 if (verbose)
853 printf ("%d: Line broken\n", line_no);
854 dump_line ();
855 want_blank = false;
856 }
857
858 force_nl = true;
859 /* also, following stuff must go onto new line */
860 parse (*token == 'e' ? elselit : dolit);
861 /* pass token on to parser */
862 goto copy_id; /* move the token into line */
863
864 case decl: /* we have a declaration type (int,
865 register, etc.) */
866 parse (decl); /* let parser worry about indentation */
867 in_or_st = true;
868 /* this might be a structure or initialization declaration */
869 in_decl = decl_on_line = true;
870 for (i = 0; token[i++];);
871 /* get length of token */
872
873 if (i <= 3)
874 i = 4;
875
876 dec_ind = ((e_code - s_code + i) / ind_size + 1) * ind_size;
877 /* this will tell us how far to indent subsequent identifiers
878 */
879 goto copy_id;
880
881 case ident: /* got an identifier or constant */
882 if (in_decl) { /* if we are in a declaration, we must
883 indent identifier */
884 if (want_blank)
885 *e_code++ = ' ';
886 want_blank = false;
887
888 while ((e_code - s_code) < dec_ind)
889 *e_code++ = ' ';
890 }
891 else
892 if (sp_sw && p_l_follow == 0) {
893 /* check for if expr w/o parens *//* this will make
894 JRM's obsurd "for ever" statements work */
895 sp_sw = false;
896 force_nl = true;
897 last_u_d = true;
898 in_stmt = false;
899 parse (hd_type);
900 }
901
902 copy_id:
903 if (want_blank)
904 *e_code++ = ' ';
905 for (t_ptr = token; *t_ptr; ++t_ptr)
906 *e_code++ = *t_ptr;
907 want_blank = true;
908 break;
909
910 case period: /* treat a period kind of like a binary
911 operation */
912 *e_code++ = '.';
913 /* move the period into line */
914 want_blank = false;
915 /* don't put a blank after a period */
916 break;
917
918 case comma:
919 want_blank = (s_code != e_code);
920 /* only put blank after comma if comma does not start the line
921 */
922 if (in_decl) /* align these in a declaration */
923 while ((e_code - s_code) < (dec_ind - 1))
924 *e_code++ = ' ';
925
926 *e_code++ = ',';
927
928 if (break_comma && p_l_follow == 0 && !leave_comma)
929 force_nl = true;
930
931 break;
932
933 case preesc: /* got the character '#' */
934 if (
935 (s_com != e_com) ||
936 (s_lab != e_lab) ||
937 (s_code != e_code)) {
938 /* true iff the '#' was not at start of the line */
939 printf ("%d: What is this # doing here?\n", line_no);
940 goto do_binary;
941 /* treat it as a binary operator */
942 }
943
944 *e_lab++ = '#';/* move whole line to 'label' buffer */
945 while (*buf_ptr != '\n') {
946 *e_lab = *buf_ptr++;
947 if (buf_ptr >= buf_end)
948 fill_buffer ();
949
950 if (*e_lab++ == '/' && *buf_ptr == '*') {
951 /* check for comment on preprocessor line */
952 e_lab - = 2;
953 /* skip back over slash */
954 while (*e_lab == '\t' || *e_lab == ' ')
955 --e_lab;
956 /* strip off trailing blanks and tabs */
957 *(++e_lab) = '\0';
958 /* null terminate the line */
959 if (++buf_ptr >= buf_end)
960 /* space past start of comment */
961 fill_buffer ();
962 col_1 = false;
963 /* don't let pr_comment think that this comment starts
964 in column 1 */
965 decl_on_line = true;
966 /* treat this as a declaration for comment placement
967 purposes */
968 goto proc_comment;
969 /* go process the comment */
970 }
971 }
972
973 *e_lab = '\0'; /* null terminate line */
974 pcase = false;
975 break; /* subsequent processing of the newline
976 character will cause the line to be
977 printed */
978
979 case comment: /* we have gotten a /* this is a biggie */
980 proc_comment:
981 pr_comment ();
982 break;
983 } /* end of big switch stmt */
984
985 *e_code = '\0'; /* make sure code section is null
986 terminated */
987
988 } /* end of main while (1) loop */
989};
990
991/*
992 * copy input file to backup file
993 * if in_name is /blah/blah/blah/file, then backup file
994 * will be ".Bfile"
995 * then make the backup file the input and original
996 * input file the output
997 */
998bakcopy () {
999 int n,
1000 bakchn;
1001 char buff[512];
1002 register char *p;
1003
1004 /* construct file name .Bfile */
1005 for (p = in_name; *p; p++);/* skip to end of string */
1006 while (p > in_name && *p != '/')/* find last '/' */
1007 p--;
1008 if (*p == '/')
1009 p++;
1010 sprintf (bakfile, ".B%s", p);
1011
1012 /* copy in_name to backup file */
1013 bakchn = creat (bakfile, 0600);
1014 if (bakchn < 0) {
1015 printf ("can't create backup file \"%s\"\n", bakfile);
1016 exit ();
1017 }
1018 while (n = read (input, buff, 512))
1019 write (bakchn, buff, n);
1020 close (bakchn);
1021 close (input);
1022
1023 /* re-open backup file as the input file */
1024 input = open (bakfile, 0);
1025 if (input < 0) {
1026 printf ("can't re-open backup file\n");
1027 exit ();
1028 }
1029
1030 /* now the original input file will be the output */
1031 output = creat (in_name, 0644);
1032 if (output < 0) {
1033 printf ("can't create %s\n", in_name);
1034 unlink (bakfile);
1035 exit ();
1036 }
1037}
1038
1039
1040set_option (arg)
1041char *arg;
1042{
1043 register j;
1044 for (j = 0; options[j].str != 0; ++j) {
1045 /* look thru list of possible options */
1046 if (eqin (options[j].str, arg)) {
1047 set_var (j, arg);
1048 break; /* get out of for loop */
1049 }
1050 }
1051
1052 if (options[j].str == 0) { /* illegal arg given */
1053 printf ("Unknown parameter: %s\n", arg);
1054 exit ();
1055 }
1056}
1057
1058
1059set_var (j, arg)
1060char *arg;
1061{
1062 switch (options[j].code) {
1063 case 1: /* have -lnnn */
1064 max_col = atoi (&arg[2]);
1065 break;
1066 case 2: /* have -cnnn */
1067 com_ind = atoi (&arg[2]);
1068 break;
1069 case 3: /* have -innn */
1070 ind_size = atoi (&arg[2]);
1071 break;
1072 case 4: /* have -cdnnn */
1073 decl_com_ind = atoi (&arg[3]);
1074 break;
1075 case 5: /* have -v */
1076 verbose = true;
1077 break;
1078 case 6: /* have -nv */
1079 verbose = false;
1080 break;
1081 case 7: /* have -dj */
1082 ljust_decl = true;
1083 break;
1084 case 8: /* have -ndj */
1085 ljust_decl = false;
1086 break;
1087 case 9: /* -nbc */
1088 leave_comma = true;
1089 break;
1090 case 10: /* -bc */
1091 leave_comma = false;
1092 break;
1093 case 13: /* -dnnn */
1094 unindent_displace = atoi (&arg[2]);
1095 break;
1096 case 14: /* -br */
1097 btype_2 = true;
1098 break;
1099 case 15: /* -bl */
1100 btype_2 = false;
1101 break;
1102 case 16:
1103 if(input<0) input = 0;
1104 if(output<0) output = 1;
1105 break;
1106 }
1107}
1108
1109
1110/*
1111 * GETPRO - get profile file
1112 * profile file is max 127 characters
1113 */
1114getpro (name, buf)
1115char *name, /* profile file name, as in '.indent.pro'
1116 */
1117 *buf; /* will receive contents of .pro file */
1118{
1119 register chn,
1120 n;
1121 char file[32];
1122
1123 file[0] = 0;
1124 strcat (file, getenv ("HOME"));
1125 strcat (file, "/");
1126 strcat (file, name);
1127 chn = open (file, 0);
1128 if (chn < 0)
1129 return (-1);
1130 n = read (chn, buf, 127);
1131 if (n < 0)
1132 return (-1);
1133 buf[n--] = 0; /* null terminate line */
1134 if (buf[n] == '\n')
1135 buf[n] = 0;
1136 close (chn);
1137 return (0);
1138}
1139
1140
1141/*
1142 * strip off arguments in a string:
1143 * p is address of a character pointer
1144 * nextchr returns pointer to front of first arg
1145 * arg is null terminated.
1146 * p is reset to after arg for subsequent calls
1147 */
1148char *nxtarg (p)
1149char **p;
1150{
1151 register char *f,
1152 *b;
1153 f = b = *p;
1154 while (*f && (*f == ' ' || *f == '\t'))
1155 f++;
1156 while (*b && (*b != ' ' && *b != '\t'))
1157 b++;
1158 if (*b != 0)
1159 *b++ = 0;
1160 *p = b;
1161 return (f);
1162}
1163
1164
1165set_profile () {
1166 char line[128],
1167 *b;
1168 register char *f;
1169 extern char *nxtarg ();
1170
1171 if (getpro (".indent.pro", line) < 0)
1172 return;
1173 b = line;
1174 if(verbose) printf ("profile: %s\n", b);
1175 while (*(f = nxtarg (&b)))
1176 set_option (f);
1177}