1 /*
2 * Copyright (c) 1985 Sun Microsystems, Inc.
3 * Copyright (c) 1980 The Regents of the University of California.
4 * Copyright (c) 1976 Board of Trustees of the University of Illinois.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by the University of California, Berkeley, the University of Illinois,
13 * Urbana, and Sun Microsystems, Inc. The name of either University
14 * or Sun Microsystems may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 */
20
21 #ifndef lint
22 static char sccsid[] = "@(#)io.c 5.10 (Berkeley) 9/15/88";
23 #endif /* not lint */
24
25 #include "indent_globs.h"
26 #include <ctype.h>
27 /* POSIX says that fcntl.h should exist. Linking either sys/fcntl.h
28 or sys/file.h to fcntl.h should work fine if you don't have fcntl.h */
29 #include <fcntl.h>
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33
34 int suppress_blanklines = 0;
35 int comment_open;
36
37 int paren_target;
38
39 /* true if INDENT OFF is in effect */
40 static int inhibit_formatting;
41
dump_line()42 dump_line()
43 { /* dump_line is the routine that actually
44 * effects the printing of the new source. It
45 * prints the label section, followed by the
46 * code section with the appropriate nesting
47 * level, followed by any comments */
48 register int cur_col,
49 target_col;
50 static not_first_line;
51
52 if (parser_state_tos->procname[0]) {
53 if (troff) {
54 if (comment_open) {
55 comment_open = 0;
56 fprintf(output, ".*/\n");
57 }
58 fprintf(output, ".Pr \"%.*s\"\n", parser_state_tos->procname_end - parser_state_tos->procname,
59 parser_state_tos->procname);
60 }
61 parser_state_tos->ind_level = 0;
62 parser_state_tos->procname = "\0";
63 }
64 if (s_code == e_code && s_lab == e_lab && s_com == e_com) {
65 /* If we have a formfeed on a blank line, we should just output it,
66 rather than treat it as a normal blank line. */
67 if (parser_state_tos->use_ff)
68 {
69 putc('\014',output);
70 parser_state_tos->use_ff = false;
71 }
72 else
73 {
74 if (suppress_blanklines > 0)
75 suppress_blanklines--;
76 else {
77 parser_state_tos->bl_line = true;
78 n_real_blanklines++;
79 }
80 }
81 }
82 else if (!inhibit_formatting) {
83 suppress_blanklines = 0;
84 parser_state_tos->bl_line = false;
85 if (prefix_blankline_requested && not_first_line)
86 if (swallow_optional_blanklines) {
87 if (n_real_blanklines == 1)
88 n_real_blanklines = 0;
89 }
90 else {
91 if (n_real_blanklines == 0)
92 n_real_blanklines = 1;
93 }
94 while (--n_real_blanklines >= 0)
95 putc('\n', output);
96 n_real_blanklines = 0;
97 if (parser_state_tos->ind_level == 0)
98 parser_state_tos->ind_stmt = 0; /* this is a class A kludge. dont do
99 * additional statement indentation if we are
100 * at bracket level 0 */
101
102 if (e_lab != s_lab || e_code != s_code)
103 ++code_lines; /* keep count of lines with code */
104
105
106 if (e_lab != s_lab) { /* print lab, if any */
107 if (comment_open) {
108 comment_open = 0;
109 fprintf(output, ".*/\n");
110 }
111 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
112 e_lab--;
113 cur_col = pad_output(1, compute_label_target());
114 fprintf(output, "%.*s", e_lab - s_lab, s_lab);
115 cur_col = count_spaces(cur_col, s_lab);
116 }
117 else
118 cur_col = 1; /* there is no label section */
119
120 parser_state_tos->pcase = false;
121
122 if (s_code != e_code) { /* print code section, if any */
123 register char *p;
124
125 if (comment_open) {
126 comment_open = 0;
127 fprintf(output, ".*/\n");
128 }
129 target_col = compute_code_target();
130 /* If a line ends in an lparen character, the following
131 line should not line up with the parenthesis, but
132 should be indented by the usual amount. */
133 if (parser_state_tos->last_token == lparen)
134 {
135 parser_state_tos->paren_indents[parser_state_tos->p_l_follow-1]
136 += ind_size - 1;
137 }
138 {
139 register i;
140
141 for (i = 0; i < parser_state_tos->p_l_follow; i++)
142 if (parser_state_tos->paren_indents[i] >= 0)
143 parser_state_tos->paren_indents[i] = -(parser_state_tos->paren_indents[i] + target_col);
144 }
145 cur_col = pad_output(cur_col, target_col);
146 for (p = s_code; p < e_code; p++)
147 if (*p == (char) 0200)
148 fprintf(output, "%d", target_col * 7);
149 else
150 putc(*p, output);
151 cur_col = count_spaces(cur_col, s_code);
152 }
153 if (s_com != e_com)
154 {
155 if (troff) {
156 int all_here = 0;
157 register char *p;
158
159 if (e_com[-1] == '/' && e_com[-2] == '*')
160 e_com -= 2, all_here++;
161 while (e_com > s_com && e_com[-1] == ' ')
162 e_com--;
163 *e_com = 0;
164 p = s_com;
165 while (*p == ' ')
166 p++;
167 if (p[0] == '/' && p[1] == '*')
168 p += 2, all_here++;
169 else if (p[0] == '*')
170 p += p[1] == '/' ? 2 : 1;
171 while (*p == ' ')
172 p++;
173 if (*p == 0)
174 goto inhibit_newline;
175 if (comment_open < 2 && parser_state_tos->box_com) {
176 comment_open = 0;
177 fprintf(output, ".*/\n");
178 }
179 if (comment_open == 0) {
180 if ('a' <= *p && *p <= 'z')
181 *p = *p + 'A' - 'a';
182 if (e_com - p < 50 && all_here == 2) {
183 register char *follow = p;
184 fprintf(output, "\n.nr C! \\w\1");
185 while (follow < e_com) {
186 switch (*follow) {
187 case '\n':
188 putc(' ', output);
189 case 1:
190 break;
191 case '\\':
192 putc('\\', output);
193 default:
194 putc(*follow, output);
195 }
196 follow++;
197 }
198 putc(1, output);
199 }
200 fprintf(output, "\n./* %dp %d %dp\n",
201 parser_state_tos->com_col * 7,
202 (s_code != e_code || s_lab != e_lab) - parser_state_tos->box_com,
203 target_col * 7);
204 }
205 comment_open = 1 + parser_state_tos->box_com;
206 while (*p) {
207 if (*p == BACKSLASH)
208 putc(BACKSLASH, output);
209 putc(*p++, output);
210 }
211 }
212 else { /* print comment, if any */
213 register target = parser_state_tos->com_col;
214 register char *com_st = s_com;
215
216 target += parser_state_tos->comment_delta;
217 while (*com_st == '\t')
218 com_st++, target += 8; /* ? */
219 while (target <= 0)
220 if (*com_st == ' ')
221 target++, com_st++;
222 else if (*com_st == '\t')
223 target = ((target - 1) & ~7) + 9, com_st++;
224 else
225 target = 1;
226 if (cur_col > target) { /* if comment cant fit on this line,
227 * put it on next line */
228 putc('\n', output);
229 cur_col = 1;
230 ++parser_state_tos->out_lines;
231 }
232 while (e_com > com_st && isspace(e_com[-1]))
233 e_com--;
234 cur_col = pad_output(cur_col, target);
235 if (!parser_state_tos->box_com) {
236 if (star_comment_cont && (com_st[1] != '*' || e_com <= com_st + 1))
237 if (com_st[1] == ' ' && com_st[0] == ' ' && e_com > com_st + 1)
238 com_st[1] = '*';
239 else
240 fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output);
241 }
242 fwrite(com_st, e_com - com_st, 1, output);
243 parser_state_tos->comment_delta = parser_state_tos->n_comment_delta;
244 cur_col = count_spaces(cur_col, com_st);
245 ++parser_state_tos->com_lines; /* count lines with comments */
246 }
247 }
248 if (parser_state_tos->use_ff)
249 {
250 putc('\014', output);
251 parser_state_tos->use_ff = false;
252 }
253 else
254 putc('\n', output);
255 inhibit_newline:
256 ++parser_state_tos->out_lines;
257 if (parser_state_tos->just_saw_decl == 1 && blanklines_after_declarations) {
258 prefix_blankline_requested = 1;
259 parser_state_tos->just_saw_decl = 0;
260 }
261 else
262 prefix_blankline_requested = postfix_blankline_requested;
263 postfix_blankline_requested = 0;
264 }
265 parser_state_tos->decl_on_line = parser_state_tos->in_decl; /* if we are in the middle of a
266 * declaration, remember that fact for
267 * proper comment indentation */
268 parser_state_tos->ind_stmt = parser_state_tos->in_stmt & ~parser_state_tos->in_decl; /* next line should be
269 * indented if we have not
270 * completed this stmt and if
271 * we are not in the middle of
272 * a declaration */
273 parser_state_tos->dumped_decl_indent = 0;
274 *(e_lab = s_lab) = '\0'; /* reset buffers */
275 *(e_code = s_code) = '\0';
276 *(e_com = s_com) = '\0';
277 parser_state_tos->ind_level = parser_state_tos->i_l_follow;
278 parser_state_tos->paren_level = parser_state_tos->p_l_follow;
279 paren_target = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 1];
280 not_first_line = 1;
281 return;
282 }
283
284 /* Figure out where we should put the code in codebuf.
285 Return the column number in spaces. */
286 int
compute_code_target()287 compute_code_target()
288 {
289 register target_col = parser_state_tos->ind_level + 1;
290
291 if (parser_state_tos->paren_level)
292 if (!lineup_to_parens)
293 target_col += continuation_indent * parser_state_tos->paren_level;
294 else {
295 register w;
296 register t = paren_target;
297
298 if ((w = count_spaces(t, s_code) - max_col) > 0
299 && count_spaces(target_col, s_code) <= max_col) {
300 t -= w + 1;
301 if (t > target_col)
302 target_col = t;
303 }
304 else
305 target_col = t;
306 }
307 else if (parser_state_tos->ind_stmt)
308 target_col += continuation_indent;
309 return target_col;
310 }
311
312 int
compute_label_target()313 compute_label_target()
314 {
315 return
316 parser_state_tos->pcase ? case_ind + 1
317 : *s_lab == '#' ? 1
318 : parser_state_tos->ind_level - label_offset + 1;
319 }
320
321 /* Allocate space for FILENAME, read in the file, and set in_prog and
322 in_prog_pos to point to the buffer. If any errors occur, report an
323 error message and abort. */
324 void
read_file(filename)325 read_file(filename)
326 char *filename;
327 {
328 /* File descriptor for the input file */
329 int in_fd;
330
331 /* File status for the input file */
332 struct stat in_stat;
333
334 /* buffer used for error messages */
335 char *errbuf;
336
337 errbuf = (char *)xmalloc (strlen (filename) + 80);
338 sprintf(errbuf,"indent: %s",filename);
339
340 in_fd = open(filename,O_RDONLY,0777);
341 if (in_fd < 0)
342 {
343 perror(errbuf);
344 exit(1);
345 }
346
347 if (fstat(in_fd,&in_stat) < 0)
348 {
349 perror(errbuf);
350 exit(1);
351 }
352 in_prog_size = in_stat.st_size;
353 in_prog = xmalloc(in_prog_size + 3); /* 3 for ' ','\n','\0' */
354
355 if (read(in_fd,in_prog,in_prog_size) < 0)
356 {
357 perror(errbuf);
358 exit(1);
359 }
360
361 if (close(in_fd) < 0)
362 {
363 perror(errbuf);
364 exit(1);
365 }
366
367 in_prog[in_prog_size] = ' ';
368 in_prog[in_prog_size+1] = '\n';
369 in_prog[in_prog_size+2] = 0;
370 in_prog_pos = in_prog;
371
372 free (errbuf);
373 }
374
375 /* Like read_file but read from stdin. */
376 void
read_stdin()377 read_stdin()
378 {
379 unsigned int alloc_size = 10000;
380 char ch;
381 unsigned int pos;
382 unsigned i;
383
384 in_prog_pos = in_prog = xmalloc(alloc_size);
385 in_prog_size = 0;
386 do
387 {
388 /* Copy up until 3 bytes before the end of the buffer,
389 (the 3 is for ' \n\0')... */
390 for (; in_prog_size < alloc_size - 3; in_prog_size++)
391 {
392 ch = getc(stdin);
393 if (ch == EOF)
394 break;
395 in_prog[in_prog_size] = ch;
396 }
397 /* ...and if that's not enough allocate more. */
398 if (ch != EOF) {
399 alloc_size *= 2;
400 in_prog = xrealloc(in_prog,alloc_size);
401 }
402 }
403 while (ch != EOF);
404
405 in_prog[in_prog_size] = ' ';
406 in_prog[in_prog_size+1] = '\n';
407 in_prog[in_prog_size+2] = 0;
408 in_prog_pos = in_prog;
409 }
410
411 /* Advance buf_ptr so that it points to the next line of input. Skip
412 over indent errors (comments beginning with *INDENT**), ignoring
413 them. Process INDENT ON and INDENT OFF. (Note: the name of this
414 function is a historical artifact from before the time that indent
415 kept the whole source file in memory). */
416
fill_buffer()417 fill_buffer()
418 {
419 /* Point various places in the buffer. */
420 char *p;
421
422 /* Have we found INDENT ON or INDENT OFF ? */
423 enum {None,Indent_on,Indent_off} com;
424
425 if (bp_save != 0)
426 { /* there is a partly filled input buffer left */
427 buf_ptr = bp_save; /* dont read anything, just switch buffers */
428 buf_end = be_save;
429 bp_save = be_save = 0;
430 if (buf_ptr < buf_end)
431 return; /* only return if there is really something in
432 * this buffer */
433 }
434
435 fill_it:
436
437 cur_line = in_prog_pos;
438 buf_ptr = in_prog_pos;
439 for (p = buf_ptr; *p && *p++ != '\n';)
440 ;
441
442 buf_end = p;
443 if (!*p)
444 had_eof = true;
445
446 p = buf_ptr;
447 in_prog_pos = buf_end;
448
449 while (*p == ' ' || *p == '\t')
450 p++;
451 if (*p == '/' && p[1] == '*')
452 {
453 p += 2;
454 if (p[1] == 'I' && strncmp(p,"*INDENT**",9) == 0)
455 goto fill_it;
456 while (*p == ' ' || *p == '\t')
457 p++;
458 com = None;
459 if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
460 && p[4] == 'N' && p[5] == 'T') {
461 p += 6;
462 while (*p == ' ' || *p == '\t')
463 p++;
464 if (*p == '*')
465 com = 1;
466 else if (*p == 'O')
467 if (*++p == 'N')
468 p++, com = Indent_on;
469 else if (*p == 'F' && *++p == 'F')
470 p++, com = Indent_off;
471 while (*p == ' ' || *p == '\t')
472 p++;
473 if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) {
474 if (s_com != e_com || s_lab != e_lab || s_code != e_code)
475 dump_line();
476 if (!(inhibit_formatting = com - 1)) {
477 n_real_blanklines = 0;
478 postfix_blankline_requested = 0;
479 prefix_blankline_requested = 0;
480 suppress_blanklines = 1;
481 }
482 }
483 }
484 }
485 if (inhibit_formatting)
486 {
487 p = buf_ptr;
488 do
489 putc(*p,output);
490 while (*p++ != '\n');
491 }
492
493 }
494
495
496
497 /*
498 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
499 *
500 * All rights reserved
501 *
502 *
503 * NAME: pad_output
504 *
505 * FUNCTION: Writes tabs and spaces to move the current column up to the desired
506 * position.
507 *
508 * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
509 *
510 * PARAMETERS: current integer The current column target
511 * nteger The desired column
512 *
513 * RETURNS: Integer value of the new column. (If current >= target, no action is
514 * taken, and current is returned.
515 *
516 * GLOBALS: None
517 *
518 * CALLS: write (sys)
519 *
520 * CALLED BY: dump_line
521 *
522 * HISTORY: initial coding November 1976 D A Willcox of CAC
523 *
524 */
pad_output(current,target)525 pad_output(current, target) /* writes tabs and blanks (if necessary) to
526 * get the current output position up to the
527 * target column */
528 int current; /* the current column value */
529 int target; /* position we want it at */
530 {
531 register int curr; /* internal column pointer */
532 register int tcur;
533
534 if (troff)
535 fprintf(output, "\\h'|%dp'", (target - 1) * 7);
536 else {
537 if (current >= target)
538 return (current); /* line is already long enough */
539 curr = current;
540 while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) {
541 putc('\t', output);
542 curr = tcur;
543 }
544 while (curr++ < target)
545 putc(' ', output); /* pad with final blanks */
546 }
547 return (target);
548 }
549
550 /*
551 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
552 *
553 * All rights reserved
554 *
555 *
556 * NAME: count_spaces
557 *
558 * FUNCTION: Find out where printing of a given string will leave the current
559 * character position on output.
560 *
561 * ALGORITHM: Run thru input string and add appropriate values to current
562 * position.
563 *
564 * RETURNS: Integer value of position after printing "buffer" starting in column
565 * "current".
566 *
567 * HISTORY: initial coding November 1976 D A Willcox of CAC
568 *
569 */
570 int
count_spaces(current,buffer)571 count_spaces(current, buffer)
572 /*
573 * this routine figures out where the character position will be after
574 * printing the text in buffer starting at column "current"
575 */
576 int current;
577 char *buffer;
578 {
579 register char *buf; /* used to look thru buffer */
580 register int cur; /* current character counter */
581
582 cur = current;
583
584 for (buf = buffer; *buf != '\0'; ++buf) {
585 switch (*buf) {
586
587 case '\n':
588 case 014: /* form feed */
589 cur = 1;
590 break;
591
592 case '\t':
593 cur = ((cur - 1) & tabmask) + tabsize + 1;
594 break;
595
596 case '': /* this is a backspace */
597 --cur;
598 break;
599
600 default:
601 ++cur;
602 break;
603 } /* end of switch */
604 } /* end of for loop */
605 return (cur);
606 }
607
608 /* Nonzero if we have found an error (not a warning). */
609 int found_err;
610
611 /* Signal an error. LEVEL is nonzero if it is an error (as opposed to
612 a warning. MSG is a printf-style format string. Additional
613 arguments are additional arguments for printf. */
diag(level,msg,a,b)614 diag(level, msg, a, b)
615 {
616 if (level)
617 found_err = 1;
618 if (output == stdout) {
619 fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
620 fprintf(stdout, (char *)msg, a, b);
621 fprintf(stdout, " */\n");
622 }
623 else {
624 fprintf(stderr, "%s: %d: ", in_name, line_no);
625 fprintf(stderr, (char *)msg, a, b);
626 fprintf(stderr, "\n");
627 }
628 }
629
writefdef(f,nm)630 writefdef(f, nm)
631 register struct fstate *f;
632 {
633 fprintf(output, ".ds f%c %s\n.nr s%c %d\n",
634 nm, f->font, nm, f->size);
635 }
636
637 /* Write characters starting at S to change the font from OF to NF. Return
638 a pointer to the character after the last character written.
639 For troff mode only. */
640 char *
chfont(of,nf,s)641 chfont(of, nf, s)
642 register struct fstate *of,
643 *nf;
644 char *s;
645 {
646 if (of->font[0] != nf->font[0]
647 || of->font[1] != nf->font[1]) {
648 *s++ = '\\';
649 *s++ = 'f';
650 if (nf->font[1]) {
651 *s++ = '(';
652 *s++ = nf->font[0];
653 *s++ = nf->font[1];
654 }
655 else
656 *s++ = nf->font[0];
657 }
658 if (nf->size != of->size) {
659 *s++ = '\\';
660 *s++ = 's';
661 if (nf->size < of->size) {
662 *s++ = '-';
663 *s++ = '0' + of->size - nf->size;
664 }
665 else {
666 *s++ = '+';
667 *s++ = '0' + nf->size - of->size;
668 }
669 }
670 return s;
671 }
672
673
parsefont(f,s0)674 parsefont(f, s0)
675 register struct fstate *f;
676 char *s0;
677 {
678 register char *s = s0;
679 int sizedelta = 0;
680 int i;
681
682 f->size = 0;
683 f->allcaps = 1;
684 for (i = 0; i < 4; i++)
685 f->font[i] = 0;
686
687 while (*s) {
688 if (isdigit(*s))
689 f->size = f->size * 10 + *s - '0';
690 else if (isupper(*s))
691 if (f->font[0])
692 f->font[1] = *s;
693 else
694 f->font[0] = *s;
695 else if (*s == 'c')
696 f->allcaps = 1;
697 else if (*s == '+')
698 sizedelta++;
699 else if (*s == '-')
700 sizedelta--;
701 else {
702 fprintf(stderr, "indent: bad font specification: %s\n", s0);
703 exit(1);
704 }
705 s++;
706 }
707 if (f->font[0] == 0)
708 f->font[0] = 'R';
709 if (bodyf.size == 0)
710 bodyf.size = 11;
711 if (f->size == 0)
712 f->size = bodyf.size + sizedelta;
713 else if (sizedelta > 0)
714 f->size += bodyf.size;
715 else
716 f->size = bodyf.size - f->size;
717 }
718