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