xref: /original-bsd/usr.bin/indent/io.c (revision 00986467)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted
7  * provided that the above copyright notice and this paragraph are
8  * duplicated in all such forms and that any documentation,
9  * advertising materials, and other materials related to such
10  * distribution and use acknowledge that the software was developed
11  * by the University of California, Berkeley and the University
12  * of Illinois, Urbana.  The name of either
13  * University may not be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19 
20 #ifndef lint
21 static char sccsid[] = "@(#)io.c	5.7 (Berkeley) 06/29/88";
22 #endif /* not lint */
23 
24 /*
25  * FILE NAME:
26  *	io.c
27  * PURPOSE:
28  *	Contains routines to handle i/o related stuff for indent.
29  * GLOBALS:
30  *	None
31  * FUNCTIONS:
32  *	dump_line
33  *	fill_buffer
34  *	pad_output
35  *	count_spaces
36  *	eqin
37  *	cmp
38  *
39  */
40 /*-
41  *
42  *			  Copyright (C) 1976
43  *				by the
44  *			  Board of Trustees
45  *				of the
46  *			University of Illinois
47  *
48  *			 All rights reserved
49  *
50  *
51  * NAME:
52  *	dump_line
53  *
54  * FUNCTION:
55  *	Does the actual printing of the stored up line
56  *
57  * ALGORITHM:
58  *	For each of the label, code, and comment sections which are used on
59  *	this line:
60  *
61  *	1) Use pad_output to get the section aligned properly.
62  *	2) write the section
63  *
64  *	The indentation level used for the code is set by ps.ind_level.  After
65  *	printing, ps.ind_level is set to ps.i_l_follow.
66  *
67  *	An extra level of indentation is added if ps.ind_stmt is 1.  After
68  *	printing, ps.ind_stmt is set to 1 iff the line just printed has an
69  *	unterminated, non-declaration statement.
70  *
71  * HISTORY:
72  *	initial coding 	November 1976	D A Willcox of CAC
73  *
74  */
75 #include "indent_globs.h"
76 
77 
78 
79 int         ff = 014;		/* used to write a form feed */
80 int         comment_open;
81 static      paren_target;
82 
83 dump_line()
84 {				/* dump_line is the routine that actually
85 				 * effects the printing of the new source.
86 				 * It prints the label section, followed
87 				 * by the code section with the
88 				 * appropriate nesting level, followed by
89 				 * any comments */
90     register int cur_col,
91                 temp_col,
92                 target_col;
93 
94     if (ps.procname[0]) {
95 	if (troff)
96 	    fprintf(output, ".Pr \"%s\"\n", ps.procname);
97 	ps.ind_level = 0;
98 	ps.procname[0] = 0;
99     }
100     if (s_code == e_code && s_lab == e_lab && s_com == e_com) {
101 	if (suppress_blanklines>0) suppress_blanklines--;
102 	else {
103 	ps.bl_line = true;
104 	n_real_blanklines++;
105 	}
106     }
107     else if (!inhibit_formatting) {
108 	suppress_blanklines = 0;
109 	ps.bl_line = false;
110 	if (prefix_blankline_requested)
111 	    if (swallow_optional_blanklines) {
112 		if (n_real_blanklines == 1)
113 		    n_real_blanklines = 0;
114 	    }
115 	    else {
116 		if (n_real_blanklines == 0)
117 		    n_real_blanklines = 1;
118 	    }
119 	while (--n_real_blanklines >= 0)
120 	    putc('\n', output);
121 	n_real_blanklines = 0;
122 	if (ps.ind_level == 0)
123 	    ps.ind_stmt = 0;	/* this is a class A kludge. dont do
124 				 * additional statement indentation if we
125 				 * are at bracket level 0 */
126 
127 	if (e_lab != s_lab || e_code != s_code)
128 	    ++code_lines;	/* keep count of lines with code */
129 
130 
131 	if (e_lab != s_lab) {	/* print lab, if any */
132 	    if (comment_open) {
133 		comment_open = 0;
134 		fprintf(output, ".*/\n");
135 	    }
136 	    while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
137 		e_lab--;
138 	    cur_col = pad_output(1, compute_label_target());
139 	    fprintf(output, "%.*s", e_lab - s_lab, s_lab);
140 	    cur_col = count_spaces(cur_col, s_lab);
141 	}
142 	else
143 	    cur_col = 1;	/* there is no label section */
144 
145 	ps.pcase = false;
146 
147 	if (s_code != e_code) {	/* print code section, if any */
148 	    register char *p;
149 
150 	    if (comment_open) {
151 		comment_open = 0;
152 		fprintf(output, ".*/\n");
153 	    }
154 	    target_col = compute_code_target();
155 	    {
156 		register    i;
157 
158 		for (i = 0; i < ps.p_l_follow; i++)
159 		    if (ps.paren_indents[i] >= 0)
160 			ps.paren_indents[i] = -(ps.paren_indents[i] + target_col);
161 	    }
162 	    cur_col = pad_output(cur_col, target_col);
163 	    for (p = s_code; p < e_code; p++)
164 		if (*p == (char)0200)
165 		    fprintf(output, "%d", target_col * 7);
166 		else
167 		    putc(*p, output);
168 	    cur_col = count_spaces(cur_col, s_code);
169 	}
170 	if (s_com != e_com)
171 	    if (troff) {
172 		register char *p;
173 
174 		if (e_com[-1] == '/' && e_com[-2] == '*')
175 		    e_com -= 2;
176 		while (e_com > s_com && e_com[-1] == ' ')
177 		    e_com--;
178 		*e_com = 0;
179 		p = s_com;
180 		while (*p == ' ')
181 		    p++;
182 		if (p[0] == '/' && p[1] == '*')
183 		    p += 2;
184 		else if (p[0] == '*')
185 		    p += p[1] == '/' ? 2 : 1;
186 		while (*p == ' ')
187 		    p++;
188 		if (*p == 0)
189 		    goto inhibit_newline;
190 		if (!comment_open) {
191 		    if ('a' <= *p && *p <= 'z')
192 			*p = *p + 'A' - 'a';
193 		    if (s_code != e_code || s_lab != e_lab) {
194 			fprintf(output, "\\c\n./* %dp 1 %dp\n",
195 				ps.com_col * 7, target_col * 7);
196 		    }
197 		    else
198 			fprintf(output, "./* %dp 0 %dp\n",
199 				ps.com_col * 7, target_col * 7);
200 		}
201 		comment_open = 1;
202 		while (*p) {
203 		    if (*p == BACKSLASH)
204 			putc(BACKSLASH, output);
205 		    putc(*p++, output);
206 		}
207 	    }
208 	    else {		/* print comment, if any */
209 		register    target = ps.com_col;
210 		register char *com_st = s_com;
211 
212 		target += ps.comment_delta;
213 		while (target <= 0)
214 		    if (*s_com == ' ')
215 			target++, s_com++;
216 		    else if (*s_com == '\t')
217 			target = ((target - 1) & ~7) + 9, s_com++;
218 		    else
219 			target = 1;
220 		if (cur_col > target) {	/* if comment cant fit on this
221 					 * line, put it on next line */
222 		    putc('\n', output);
223 		    cur_col = 1;
224 		    ++ps.out_lines;
225 		}
226 		cur_col = pad_output(cur_col, target);
227 		if (!ps.box_com) {
228 		    if (star_comment_cont && com_st[1] != '*')
229 			if (com_st[1] == ' ' && com_st[0] == ' ')
230 			    com_st[1] = '*';
231 			else
232 			    fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output);
233 		}
234 		fwrite(com_st, e_com - com_st, 1, output);
235 		ps.comment_delta = ps.n_comment_delta;
236 		cur_col = count_spaces(cur_col, com_st);
237 		++ps.com_lines;	/* count lines with comments */
238 	    }
239 	if (ps.use_ff)
240 	    putc('\014', output);
241 	else
242 	    putc('\n', output);
243 inhibit_newline:
244 	++ps.out_lines;
245 	if (ps.just_saw_decl == 1 && blanklines_after_declarations) {
246 	    prefix_blankline_requested = 1;
247 	    ps.just_saw_decl = 0;
248 	}
249 	else
250 	    prefix_blankline_requested = postfix_blankline_requested;
251 	postfix_blankline_requested = 0;
252     }
253     ps.decl_on_line = ps.in_decl;	/* if we are in the middle of a
254 					 * declaration, remember that fact
255 					 * for proper comment indentation */
256     ps.ind_stmt = ps.in_stmt & ~ps.in_decl;	/* next line should be
257 						 * indented if we have not
258 						 * completed this stmt and
259 						 * if we are not in the
260 						 * middle of a declaration */
261     ps.use_ff = false;
262     ps.dumped_decl_indent = 0;
263     *(e_lab = s_lab) = '\0';	/* reset buffers */
264     *(e_code = s_code) = '\0';
265     *(e_com = s_com) = '\0';
266     ps.ind_level = ps.i_l_follow;
267     ps.paren_level = ps.p_l_follow;
268     paren_target = -ps.paren_indents[ps.paren_level - 1];
269     return;
270 };
271 
272 compute_code_target() {
273     register    target_col = ps.ind_size * ps.ind_level + 1;
274 
275     if (ps.paren_level)
276 	if (!lineup_to_parens)
277 	    target_col += continuation_indent * ps.paren_level;
278 	else {
279 	    register    w;
280 	    register    t = paren_target;
281 
282 	    if ((w = count_spaces(t, s_code) - max_col) > 0
283 		&& count_spaces(target_col, s_code) <= max_col) {
284 		t -= w + 1;
285 		if (t > target_col)
286 		    target_col = t;
287 	    }
288 	    else
289 		target_col = t;
290 	}
291     else if (ps.ind_stmt)
292 	target_col += continuation_indent;
293     return target_col;
294 }
295 
296 compute_label_target()
297 {
298     return
299 	ps.pcase ? (int) (case_ind * ps.ind_size) +1
300 	: *s_lab == '#' ? 1
301 	: ps.ind_size * (ps.ind_level - label_offset) +1;
302 }
303 
304 
305 /*
306  * Copyright (C) 1976 by the Board of Trustees of the University of
307  * Illinois
308  *
309  * All rights reserved
310  *
311  *
312  * NAME: fill_buffer
313  *
314  * FUNCTION: Reads one block of input into input_buffer
315  *
316  * HISTORY: initial coding 	November 1976	D A Willcox of CAC 1/7/77
317  * A Willcox of CAC	Added check for switch back to partly full input
318  * buffer from temporary buffer
319  *
320  */
321 int
322 fill_buffer()
323 {				/* this routine reads stuff from the input */
324     int         count;
325     register char *p;
326     register int i;
327     register FILE *f = input;
328 
329     if (bp_save != 0) {		/* there is a partly filled input buffer
330 				 * left */
331 	buf_ptr = bp_save;	/* dont read anything, just switch buffers */
332 	buf_end = be_save;
333 	bp_save = be_save = 0;
334 	if (buf_ptr < buf_end)
335 	    return;		/* only return if there is really
336 				 * something in this buffer */
337     }
338     p = in_buffer;
339     buf_ptr = p;
340     while ((*p++ = i = getc(f)) != EOF && i != '\n');
341     if (i == EOF) {
342 	p[-1] = ' ';
343 	*p++ = '\n';
344 	had_eof = true;
345     }
346     buf_end = p;
347     if (p[-2] == '/' && p[-3] == '*') {
348 	if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0)
349 	    fill_buffer();	/* flush indent error message */
350 	else {
351 	    int         com = 0;
352 
353 	    p = in_buffer;
354 	    while (*p == ' ' || *p == '\t')
355 		p++;
356 	    if (*p == '/' && p[1] == '*') {
357 		p += 2;
358 		while (*p == ' ' || *p == '\t')
359 		    p++;
360 		if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
361 		    && p[4] == 'N' && p[5] == 'T') {
362 		    p += 6;
363 		    while (*p == ' ' || *p == '\t')
364 			p++;
365 		    if (*p == '*')
366 			com = 1;
367 		    else if (*p == 'O')
368 			if (*++p == 'N')
369 			    p++, com = 1;
370 			else if (*p == 'F' && *++p == 'F')
371 			    p++, com = 2;
372 		    while (*p == ' ' || *p == '\t')
373 			p++;
374 		    if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) {
375 			if (s_com != e_com || s_lab != e_lab || s_code != e_code)
376 			    dump_line();
377 			if (!(inhibit_formatting = com - 1)) {
378 			    n_real_blanklines = 0;
379 			    postfix_blankline_requested = 0;
380 			    prefix_blankline_requested = 0;
381 			    suppress_blanklines = 1;
382 			}
383 		    }
384 		}
385 	    }
386 	}
387     }
388     if (inhibit_formatting) {
389 	p = in_buffer;
390 	do
391 	    putc(*p, output);
392 	while (*p++ != '\n');
393     }
394     return;
395 };
396 
397 /*
398  * Copyright (C) 1976 by the Board of Trustees of the University of
399  * Illinois
400  *
401  * All rights reserved
402  *
403  *
404  * NAME: pad_output
405  *
406  * FUNCTION: Writes tabs and spaces to move the current column up to the
407  * desired position.
408  *
409  * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
410  *
411  * PARAMETERS: current		integer		The current column target
412  * nteger		The desired column
413  *
414  * RETURNS: Integer value of the new column.  (If current >= target, no
415  * action is taken, and current is returned.
416  *
417  * GLOBALS: None
418  *
419  * CALLS: write (sys)
420  *
421  * CALLED BY: dump_line
422  *
423  * HISTORY: initial coding 	November 1976	D A Willcox of CAC
424  *
425  */
426 pad_output(current, target)	/* writes tabs and blanks (if necessary)
427 				 * to get the current output position up
428 				 * to the target column */
429     int         current;	/* the current column value */
430     int         target;		/* position we want it at */
431 {
432     register int curr;		/* internal column pointer */
433     register int tcur;
434 
435     if (troff)
436 	fprintf(output, "\\h'|%dp'", (target - 1) * 7);
437     else {
438 	if (current >= target)
439 	    return (current);	/* line is already long enough */
440 	curr = current;
441 	while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) {
442 	    putc('\t', output);
443 	    curr = tcur;
444 	}
445 	while (curr++ < target)
446 	    putc(' ', output);	/* pad with final blanks */
447     }
448     return (target);
449 };
450 
451 /*
452  * Copyright (C) 1976 by the Board of Trustees of the University of
453  * Illinois
454  *
455  * All rights reserved
456  *
457  *
458  * NAME: count_spaces
459  *
460  * FUNCTION: Find out where printing of a given string will leave the current
461  * character position on output.
462  *
463  * ALGORITHM: Run thru input string and add appropriate values to current
464  * position.
465  *
466  * RETURNS: Integer value of position after printing "buffer" starting in
467  * column "current".
468  *
469  * HISTORY: initial coding 	November 1976	D A Willcox of CAC
470  *
471  */
472 int
473 count_spaces(current, buffer)
474 
475 /*
476  * this routine figures out where the character position will be after
477  * printing the text in buffer starting at column "current"
478  */
479     int         current;
480     char       *buffer;
481 {
482     register char *buf;		/* used to look thru buffer */
483     register int cur;		/* current character counter */
484 
485     cur = current;
486 
487     for (buf = buffer; *buf != '\0'; ++buf) {
488 	switch (*buf) {
489 
490 	    case '\n':
491 	    case 014:		/* form feed */
492 		cur = 1;
493 		break;
494 
495 	    case '\t':
496 		cur = ((cur - 1) & tabmask) + tabsize + 1;
497 		break;
498 
499 	    case '':		/* this is a backspace */
500 		--cur;
501 		break;
502 
503 	    default:
504 		++cur;
505 		break;
506 	}			/* end of switch */
507     }				/* end of for loop */
508     return (cur);
509 };
510 
511 int	found_err;
512 diag(level, msg, a, b)
513 {
514     if (level)
515 	found_err = 1;
516     if (output == stdout) {
517 	fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
518 	fprintf(stdout, msg, a, b);
519 	fprintf(stdout, " */\n");
520     }
521     else {
522 	fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
523 	fprintf(stderr, msg, a, b);
524 	fprintf(stderr, "\n");
525     }
526 }
527