Commit | Line | Data |
---|---|---|
c6468b47 KM |
1 | static 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 | ||
14 | NAME: | |
15 | indent main program | |
16 | ||
17 | FUNCTION: | |
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 | ||
21 | ALGORITHM: | |
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 | ||
32 | PARAMETERS: | |
33 | None | |
34 | ||
35 | RETURNS: | |
36 | Nothing | |
37 | ||
38 | GLOBALS: | |
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 | ||
69 | CALLS: | |
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 | ||
84 | CALLED BY: | |
85 | No one (main routine) | |
86 | ||
87 | HISTORY: | |
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 | ||
105 | struct 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 | ||
114 | struct 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 | ||
138 | char *in_name = "Standard Input"; | |
139 | /* will always point to name of input file | |
140 | */ | |
141 | char *out_name = "Standard Output"; | |
142 | /* will always point to name of output file | |
143 | */ | |
144 | char bakfile[32] = ""; | |
145 | \f | |
146 | main (argc, argv) | |
147 | int argc; | |
148 | char **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) */ | |
461 | check_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 | */ | |
998 | bakcopy () { | |
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 | ||
1040 | set_option (arg) | |
1041 | char *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 | ||
1059 | set_var (j, arg) | |
1060 | char *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 | */ | |
1114 | getpro (name, buf) | |
1115 | char *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 | */ | |
1148 | char *nxtarg (p) | |
1149 | char **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 | ||
1165 | set_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 | } |