xref: /freebsd/usr.bin/indent/io.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
1 /*
2  * Copyright (c) 1985 Sun Microsystems, Inc.
3  * Copyright (c) 1980, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #ifndef lint
37 static char sccsid[] = "@(#)io.c	8.1 (Berkeley) 6/6/93";
38 #endif /* not lint */
39 
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include "indent_globs.h"
45 
46 
47 int         comment_open;
48 static      paren_target;
49 
50 dump_line()
51 {				/* dump_line is the routine that actually
52 				 * effects the printing of the new source. It
53 				 * prints the label section, followed by the
54 				 * code section with the appropriate nesting
55 				 * level, followed by any comments */
56     register int cur_col,
57                 target_col;
58     static      not_first_line;
59 
60     if (ps.procname[0]) {
61 	if (troff) {
62 	    if (comment_open) {
63 		comment_open = 0;
64 		fprintf(output, ".*/\n");
65 	    }
66 	    fprintf(output, ".Pr \"%s\"\n", ps.procname);
67 	}
68 	ps.ind_level = 0;
69 	ps.procname[0] = 0;
70     }
71     if (s_code == e_code && s_lab == e_lab && s_com == e_com) {
72 	if (suppress_blanklines > 0)
73 	    suppress_blanklines--;
74 	else {
75 	    ps.bl_line = true;
76 	    n_real_blanklines++;
77 	}
78     }
79     else if (!inhibit_formatting) {
80 	suppress_blanklines = 0;
81 	ps.bl_line = false;
82 	if (prefix_blankline_requested && not_first_line)
83 	    if (swallow_optional_blanklines) {
84 		if (n_real_blanklines == 1)
85 		    n_real_blanklines = 0;
86 	    }
87 	    else {
88 		if (n_real_blanklines == 0)
89 		    n_real_blanklines = 1;
90 	    }
91 	while (--n_real_blanklines >= 0)
92 	    putc('\n', output);
93 	n_real_blanklines = 0;
94 	if (ps.ind_level == 0)
95 	    ps.ind_stmt = 0;	/* this is a class A kludge. dont do
96 				 * additional statement indentation if we are
97 				 * at bracket level 0 */
98 
99 	if (e_lab != s_lab || e_code != s_code)
100 	    ++code_lines;	/* keep count of lines with code */
101 
102 
103 	if (e_lab != s_lab) {	/* print lab, if any */
104 	    if (comment_open) {
105 		comment_open = 0;
106 		fprintf(output, ".*/\n");
107 	    }
108 	    while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
109 		e_lab--;
110 	    cur_col = pad_output(1, compute_label_target());
111 	    if (s_lab[0] == '#' && (strncmp(s_lab, "#else", 5) == 0
112 				    || strncmp(s_lab, "#endif", 6) == 0)) {
113 		register char *s = s_lab;
114 		if (e_lab[-1] == '\n') e_lab--;
115 		do putc(*s++, output);
116 		while (s < e_lab && 'a' <= *s && *s<='z');
117 		while ((*s == ' ' || *s == '\t') && s < e_lab)
118 		    s++;
119 		if (s < e_lab)
120 		    fprintf(output, s[0]=='/' && s[1]=='*' ? "\t%.*s" : "\t/* %.*s */",
121 			    e_lab - s, s);
122 	    }
123 	    else fprintf(output, "%.*s", e_lab - s_lab, s_lab);
124 	    cur_col = count_spaces(cur_col, s_lab);
125 	}
126 	else
127 	    cur_col = 1;	/* there is no label section */
128 
129 	ps.pcase = false;
130 
131 	if (s_code != e_code) {	/* print code section, if any */
132 	    register char *p;
133 
134 	    if (comment_open) {
135 		comment_open = 0;
136 		fprintf(output, ".*/\n");
137 	    }
138 	    target_col = compute_code_target();
139 	    {
140 		register    i;
141 
142 		for (i = 0; i < ps.p_l_follow; i++)
143 		    if (ps.paren_indents[i] >= 0)
144 			ps.paren_indents[i] = -(ps.paren_indents[i] + target_col);
145 	    }
146 	    cur_col = pad_output(cur_col, target_col);
147 	    for (p = s_code; p < e_code; p++)
148 		if (*p == (char) 0200)
149 		    fprintf(output, "%d", target_col * 7);
150 		else
151 		    putc(*p, output);
152 	    cur_col = count_spaces(cur_col, s_code);
153 	}
154 	if (s_com != e_com)
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 && ps.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 			    ps.com_col * 7,
202 			    (s_code != e_code || s_lab != e_lab) - ps.box_com,
203 			    target_col * 7);
204 		}
205 		comment_open = 1 + ps.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 = ps.com_col;
214 		register char *com_st = s_com;
215 
216 		target += ps.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 		    ++ps.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 (!ps.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 		ps.comment_delta = ps.n_comment_delta;
244 		cur_col = count_spaces(cur_col, com_st);
245 		++ps.com_lines;	/* count lines with comments */
246 	    }
247 	if (ps.use_ff)
248 	    putc('\014', output);
249 	else
250 	    putc('\n', output);
251 inhibit_newline:
252 	++ps.out_lines;
253 	if (ps.just_saw_decl == 1 && blanklines_after_declarations) {
254 	    prefix_blankline_requested = 1;
255 	    ps.just_saw_decl = 0;
256 	}
257 	else
258 	    prefix_blankline_requested = postfix_blankline_requested;
259 	postfix_blankline_requested = 0;
260     }
261     ps.decl_on_line = ps.in_decl;	/* if we are in the middle of a
262 					 * declaration, remember that fact for
263 					 * proper comment indentation */
264     ps.ind_stmt = ps.in_stmt & ~ps.in_decl;	/* next line should be
265 						 * indented if we have not
266 						 * completed this stmt and if
267 						 * we are not in the middle of
268 						 * a declaration */
269     ps.use_ff = false;
270     ps.dumped_decl_indent = 0;
271     *(e_lab = s_lab) = '\0';	/* reset buffers */
272     *(e_code = s_code) = '\0';
273     *(e_com = s_com) = '\0';
274     ps.ind_level = ps.i_l_follow;
275     ps.paren_level = ps.p_l_follow;
276     paren_target = -ps.paren_indents[ps.paren_level - 1];
277     not_first_line = 1;
278     return;
279 }
280 
281 compute_code_target()
282 {
283     register    target_col = ps.ind_size * ps.ind_level + 1;
284 
285     if (ps.paren_level)
286 	if (!lineup_to_parens)
287 	    target_col += continuation_indent * ps.paren_level;
288 	else {
289 	    register    w;
290 	    register    t = paren_target;
291 
292 	    if ((w = count_spaces(t, s_code) - max_col) > 0
293 		    && count_spaces(target_col, s_code) <= max_col) {
294 		t -= w + 1;
295 		if (t > target_col)
296 		    target_col = t;
297 	    }
298 	    else
299 		target_col = t;
300 	}
301     else if (ps.ind_stmt)
302 	target_col += continuation_indent;
303     return target_col;
304 }
305 
306 compute_label_target()
307 {
308     return
309 	ps.pcase ? (int) (case_ind * ps.ind_size) + 1
310 	: *s_lab == '#' ? 1
311 	: ps.ind_size * (ps.ind_level - label_offset) + 1;
312 }
313 
314 
315 /*
316  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
317  *
318  * All rights reserved
319  *
320  *
321  * NAME: fill_buffer
322  *
323  * FUNCTION: Reads one block of input into input_buffer
324  *
325  * HISTORY: initial coding 	November 1976	D A Willcox of CAC 1/7/77 A
326  * Willcox of CAC	Added check for switch back to partly full input
327  * buffer from temporary buffer
328  *
329  */
330 int
331 fill_buffer()
332 {				/* this routine reads stuff from the input */
333     register char *p;
334     register int i;
335     register FILE *f = input;
336 
337     if (bp_save != 0) {		/* there is a partly filled input buffer left */
338 	buf_ptr = bp_save;	/* dont read anything, just switch buffers */
339 	buf_end = be_save;
340 	bp_save = be_save = 0;
341 	if (buf_ptr < buf_end)
342 	    return;		/* only return if there is really something in
343 				 * this buffer */
344     }
345     for (p = in_buffer;;) {
346 	if (p >= in_buffer_limit) {
347 	    register size = (in_buffer_limit - in_buffer) * 2 + 10;
348 	    register offset = p - in_buffer;
349 	    in_buffer = (char *) realloc(in_buffer, size);
350 	    if (in_buffer == 0)
351 		err("input line too long");
352 	    p = in_buffer + offset;
353 	    in_buffer_limit = in_buffer + size - 2;
354 	}
355 	if ((i = getc(f)) == EOF) {
356 		*p++ = ' ';
357 		*p++ = '\n';
358 		had_eof = true;
359 		break;
360 	}
361 	*p++ = i;
362 	if (i == '\n')
363 		break;
364     }
365     buf_ptr = in_buffer;
366     buf_end = p;
367     if (p[-2] == '/' && p[-3] == '*') {
368 	if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0)
369 	    fill_buffer();	/* flush indent error message */
370 	else {
371 	    int         com = 0;
372 
373 	    p = in_buffer;
374 	    while (*p == ' ' || *p == '\t')
375 		p++;
376 	    if (*p == '/' && p[1] == '*') {
377 		p += 2;
378 		while (*p == ' ' || *p == '\t')
379 		    p++;
380 		if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
381 			&& p[4] == 'N' && p[5] == 'T') {
382 		    p += 6;
383 		    while (*p == ' ' || *p == '\t')
384 			p++;
385 		    if (*p == '*')
386 			com = 1;
387 		    else if (*p == 'O')
388 			if (*++p == 'N')
389 			    p++, com = 1;
390 			else if (*p == 'F' && *++p == 'F')
391 			    p++, com = 2;
392 		    while (*p == ' ' || *p == '\t')
393 			p++;
394 		    if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) {
395 			if (s_com != e_com || s_lab != e_lab || s_code != e_code)
396 			    dump_line();
397 			if (!(inhibit_formatting = com - 1)) {
398 			    n_real_blanklines = 0;
399 			    postfix_blankline_requested = 0;
400 			    prefix_blankline_requested = 0;
401 			    suppress_blanklines = 1;
402 			}
403 		    }
404 		}
405 	    }
406 	}
407     }
408     if (inhibit_formatting) {
409 	p = in_buffer;
410 	do
411 	    putc(*p, output);
412 	while (*p++ != '\n');
413     }
414     return;
415 }
416 
417 /*
418  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
419  *
420  * All rights reserved
421  *
422  *
423  * NAME: pad_output
424  *
425  * FUNCTION: Writes tabs and spaces to move the current column up to the desired
426  * position.
427  *
428  * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
429  *
430  * PARAMETERS: current		integer		The current column target
431  * nteger		The desired column
432  *
433  * RETURNS: Integer value of the new column.  (If current >= target, no action is
434  * taken, and current is returned.
435  *
436  * GLOBALS: None
437  *
438  * CALLS: write (sys)
439  *
440  * CALLED BY: dump_line
441  *
442  * HISTORY: initial coding 	November 1976	D A Willcox of CAC
443  *
444  */
445 pad_output(current, target)	/* writes tabs and blanks (if necessary) to
446 				 * get the current output position up to the
447 				 * target column */
448     int         current;	/* the current column value */
449     int         target;		/* position we want it at */
450 {
451     register int curr;		/* internal column pointer */
452     register int tcur;
453 
454     if (troff)
455 	fprintf(output, "\\h'|%dp'", (target - 1) * 7);
456     else {
457 	if (current >= target)
458 	    return (current);	/* line is already long enough */
459 	curr = current;
460 	while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) {
461 	    putc('\t', output);
462 	    curr = tcur;
463 	}
464 	while (curr++ < target)
465 	    putc(' ', output);	/* pad with final blanks */
466     }
467     return (target);
468 }
469 
470 /*
471  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
472  *
473  * All rights reserved
474  *
475  *
476  * NAME: count_spaces
477  *
478  * FUNCTION: Find out where printing of a given string will leave the current
479  * character position on output.
480  *
481  * ALGORITHM: Run thru input string and add appropriate values to current
482  * position.
483  *
484  * RETURNS: Integer value of position after printing "buffer" starting in column
485  * "current".
486  *
487  * HISTORY: initial coding 	November 1976	D A Willcox of CAC
488  *
489  */
490 int
491 count_spaces(current, buffer)
492 /*
493  * this routine figures out where the character position will be after
494  * printing the text in buffer starting at column "current"
495  */
496     int         current;
497     char       *buffer;
498 {
499     register char *buf;		/* used to look thru buffer */
500     register int cur;		/* current character counter */
501 
502     cur = current;
503 
504     for (buf = buffer; *buf != '\0'; ++buf) {
505 	switch (*buf) {
506 
507 	case '\n':
508 	case 014:		/* form feed */
509 	    cur = 1;
510 	    break;
511 
512 	case '\t':
513 	    cur = ((cur - 1) & tabmask) + tabsize + 1;
514 	    break;
515 
516 	case 010:		/* backspace */
517 	    --cur;
518 	    break;
519 
520 	default:
521 	    ++cur;
522 	    break;
523 	}			/* end of switch */
524     }				/* end of for loop */
525     return (cur);
526 }
527 
528 int	found_err;
529 /* VARARGS2 */
530 diag(level, msg, a, b)
531 	char *msg;
532 {
533     if (level)
534 	found_err = 1;
535     if (output == stdout) {
536 	fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
537 	fprintf(stdout, msg, a, b);
538 	fprintf(stdout, " */\n");
539     }
540     else {
541 	fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
542 	fprintf(stderr, msg, a, b);
543 	fprintf(stderr, "\n");
544     }
545 }
546 
547 writefdef(f, nm)
548     register struct fstate *f;
549 {
550     fprintf(output, ".ds f%c %s\n.nr s%c %d\n",
551 	    nm, f->font, nm, f->size);
552 }
553 
554 char       *
555 chfont(of, nf, s)
556     register struct fstate *of,
557                *nf;
558     char       *s;
559 {
560     if (of->font[0] != nf->font[0]
561 	    || of->font[1] != nf->font[1]) {
562 	*s++ = '\\';
563 	*s++ = 'f';
564 	if (nf->font[1]) {
565 	    *s++ = '(';
566 	    *s++ = nf->font[0];
567 	    *s++ = nf->font[1];
568 	}
569 	else
570 	    *s++ = nf->font[0];
571     }
572     if (nf->size != of->size) {
573 	*s++ = '\\';
574 	*s++ = 's';
575 	if (nf->size < of->size) {
576 	    *s++ = '-';
577 	    *s++ = '0' + of->size - nf->size;
578 	}
579 	else {
580 	    *s++ = '+';
581 	    *s++ = '0' + nf->size - of->size;
582 	}
583     }
584     return s;
585 }
586 
587 
588 parsefont(f, s0)
589     register struct fstate *f;
590     char       *s0;
591 {
592     register char *s = s0;
593     int         sizedelta = 0;
594     bzero(f, sizeof *f);
595     while (*s) {
596 	if (isdigit(*s))
597 	    f->size = f->size * 10 + *s - '0';
598 	else if (isupper(*s))
599 	    if (f->font[0])
600 		f->font[1] = *s;
601 	    else
602 		f->font[0] = *s;
603 	else if (*s == 'c')
604 	    f->allcaps = 1;
605 	else if (*s == '+')
606 	    sizedelta++;
607 	else if (*s == '-')
608 	    sizedelta--;
609 	else {
610 	    fprintf(stderr, "indent: bad font specification: %s\n", s0);
611 	    exit(1);
612 	}
613 	s++;
614     }
615     if (f->font[0] == 0)
616 	f->font[0] = 'R';
617     if (bodyf.size == 0)
618 	bodyf.size = 11;
619     if (f->size == 0)
620 	f->size = bodyf.size + sizedelta;
621     else if (sizedelta > 0)
622 	f->size += bodyf.size;
623     else
624 	f->size = bodyf.size - f->size;
625 }
626