Annotation of src/usr.bin/indent/io.c, Revision 1.64
1.64 ! rillig 1: /* $NetBSD: io.c,v 1.63 2021/09/25 20:23:42 rillig Exp $ */
1.3 tls 2:
1.19 kamil 3: /*-
4: * SPDX-License-Identifier: BSD-4-Clause
5: *
6: * Copyright (c) 1985 Sun Microsystems, Inc.
1.4 mrg 7: * Copyright (c) 1980, 1993
8: * The Regents of the University of California. All rights reserved.
1.1 cgd 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:
1.19 kamil 40: #if 0
41: static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 6/6/93";
42: #endif
43:
1.5 lukem 44: #include <sys/cdefs.h>
1.19 kamil 45: #if defined(__NetBSD__)
1.64 ! rillig 46: __RCSID("$NetBSD: io.c,v 1.63 2021/09/25 20:23:42 rillig Exp $");
1.19 kamil 47: #elif defined(__FreeBSD__)
48: __FBSDID("$FreeBSD: head/usr.bin/indent/io.c 334927 2018-06-10 16:44:18Z pstef $");
49: #endif
1.1 cgd 50:
1.5 lukem 51: #include <ctype.h>
52: #include <err.h>
1.1 cgd 53: #include <stdio.h>
54: #include <stdlib.h>
55: #include <string.h>
1.20 christos 56: #include <stdarg.h>
1.22 rillig 57:
1.19 kamil 58: #include "indent.h"
1.1 cgd 59:
1.62 rillig 60: bool comment_open;
1.31 rillig 61: static int paren_indent;
1.1 cgd 62:
1.28 rillig 63: static void
64: output_char(char ch)
65: {
66: fputc(ch, output);
1.36 rillig 67: debug_vis_range("output_char '", &ch, &ch + 1, "'\n");
1.28 rillig 68: }
69:
70: static void
71: output_range(const char *s, const char *e)
72: {
73: fwrite(s, 1, (size_t)(e - s), output);
1.36 rillig 74: debug_vis_range("output_range \"", s, e, "\"\n");
1.28 rillig 75: }
76:
1.29 rillig 77: static inline void
1.28 rillig 78: output_string(const char *s)
79: {
80: output_range(s, s + strlen(s));
81: }
82:
1.34 rillig 83: static int
84: output_indent(int old_ind, int new_ind)
85: {
86: int ind = old_ind;
87:
88: if (opt.use_tabs) {
89: int tabsize = opt.tabsize;
90: int n = new_ind / tabsize - ind / tabsize;
91: if (n > 0)
92: ind -= ind % tabsize;
93: for (int i = 0; i < n; i++) {
1.36 rillig 94: fputc('\t', output);
1.34 rillig 95: ind += tabsize;
96: }
97: }
98:
99: for (; ind < new_ind; ind++)
1.36 rillig 100: fputc(' ', output);
1.34 rillig 101:
1.36 rillig 102: debug_println("output_indent %d", ind);
1.34 rillig 103: return ind;
104: }
105:
1.26 rillig 106: /*
107: * dump_line is the routine that actually effects the printing of the new
108: * source. It prints the label section, followed by the code section with
109: * the appropriate nesting level, followed by any comments.
110: */
1.5 lukem 111: void
1.11 wiz 112: dump_line(void)
1.26 rillig 113: {
1.44 rillig 114: int cur_col;
1.62 rillig 115: static bool not_first_line;
1.19 kamil 116:
1.60 rillig 117: if (ps.procname[0] != '\0') {
1.19 kamil 118: ps.ind_level = 0;
1.60 rillig 119: ps.procname[0] = '\0';
1.19 kamil 120: }
1.30 rillig 121:
1.55 rillig 122: if (code.s == code.e && lab.s == lab.e && com.s == com.e) {
1.19 kamil 123: if (suppress_blanklines > 0)
124: suppress_blanklines--;
1.63 rillig 125: else
1.19 kamil 126: n_real_blanklines++;
1.30 rillig 127: } else if (!inhibit_formatting) {
1.19 kamil 128: suppress_blanklines = 0;
129: if (prefix_blankline_requested && not_first_line) {
130: if (opt.swallow_optional_blanklines) {
131: if (n_real_blanklines == 1)
132: n_real_blanklines = 0;
1.30 rillig 133: } else {
1.19 kamil 134: if (n_real_blanklines == 0)
135: n_real_blanklines = 1;
136: }
137: }
138: while (--n_real_blanklines >= 0)
1.28 rillig 139: output_char('\n');
1.19 kamil 140: n_real_blanklines = 0;
141: if (ps.ind_level == 0)
1.60 rillig 142: ps.ind_stmt = false;/* this is a class A kludge. don't do
1.19 kamil 143: * additional statement indentation if we are
144: * at bracket level 0 */
145:
1.55 rillig 146: if (lab.e != lab.s || code.e != code.s)
1.58 rillig 147: ps.stats.code_lines++;
1.19 kamil 148:
149:
1.54 rillig 150: if (lab.e != lab.s) { /* print lab, if any */
1.19 kamil 151: if (comment_open) {
1.60 rillig 152: comment_open = false;
1.28 rillig 153: output_string(".*/\n");
1.19 kamil 154: }
1.54 rillig 155: while (lab.e > lab.s && (lab.e[-1] == ' ' || lab.e[-1] == '\t'))
156: lab.e--;
157: *lab.e = '\0';
1.38 rillig 158: cur_col = 1 + output_indent(0, compute_label_indent());
1.54 rillig 159: if (lab.s[0] == '#' && (strncmp(lab.s, "#else", 5) == 0
160: || strncmp(lab.s, "#endif", 6) == 0)) {
161: char *s = lab.s;
162: if (lab.e[-1] == '\n') lab.e--;
1.25 rillig 163: do {
1.28 rillig 164: output_char(*s++);
1.54 rillig 165: } while (s < lab.e && 'a' <= *s && *s <= 'z');
166: while ((*s == ' ' || *s == '\t') && s < lab.e)
1.19 kamil 167: s++;
1.54 rillig 168: if (s < lab.e) {
1.28 rillig 169: if (s[0] == '/' && s[1] == '*') {
170: output_char('\t');
1.54 rillig 171: output_range(s, lab.e);
1.28 rillig 172: } else {
173: output_string("\t/* ");
1.54 rillig 174: output_range(s, lab.e);
1.28 rillig 175: output_string(" */");
176: }
177: }
178: } else
1.54 rillig 179: output_range(lab.s, lab.e);
180: cur_col = 1 + indentation_after(cur_col - 1, lab.s);
1.30 rillig 181: } else
1.19 kamil 182: cur_col = 1; /* there is no label section */
183:
184: ps.pcase = false;
185:
1.55 rillig 186: if (code.s != code.e) { /* print code section, if any */
1.19 kamil 187: if (comment_open) {
1.60 rillig 188: comment_open = false;
1.28 rillig 189: output_string(".*/\n");
1.19 kamil 190: }
1.44 rillig 191: int target_col = 1 + compute_code_indent();
1.19 kamil 192: {
193: int i;
194:
1.36 rillig 195: for (i = 0; i < ps.p_l_follow; i++) {
196: if (ps.paren_indents[i] >= 0) {
197: int ind = ps.paren_indents[i];
198: /*
199: * XXX: this mix of 'indent' and 'column' smells like
200: * an off-by-one error.
201: */
202: ps.paren_indents[i] = -(ind + target_col);
203: debug_println(
204: "setting pi[%d] from %d to %d for column %d",
205: i, ind, ps.paren_indents[i], target_col);
206: }
207: }
1.19 kamil 208: }
1.34 rillig 209: cur_col = 1 + output_indent(cur_col - 1, target_col - 1);
1.55 rillig 210: output_range(code.s, code.e);
211: cur_col = 1 + indentation_after(cur_col - 1, code.s);
1.19 kamil 212: }
1.52 rillig 213: if (com.s != com.e) { /* print comment, if any */
1.45 rillig 214: int target_col = ps.com_col;
1.52 rillig 215: char *com_st = com.s;
1.19 kamil 216:
1.45 rillig 217: target_col += ps.comment_delta;
1.19 kamil 218: while (*com_st == '\t') /* consider original indentation in
1.46 rillig 219: * case this is a box comment */
1.45 rillig 220: com_st++, target_col += opt.tabsize;
221: while (target_col <= 0)
1.19 kamil 222: if (*com_st == ' ')
1.45 rillig 223: target_col++, com_st++;
1.19 kamil 224: else if (*com_st == '\t') {
1.45 rillig 225: target_col = opt.tabsize * (1 + (target_col - 1) / opt.tabsize) + 1;
1.19 kamil 226: com_st++;
1.30 rillig 227: } else
1.45 rillig 228: target_col = 1;
229: if (cur_col > target_col) { /* if comment can't fit on this line,
1.46 rillig 230: * put it on next line */
1.28 rillig 231: output_char('\n');
1.19 kamil 232: cur_col = 1;
1.58 rillig 233: ps.stats.lines++;
1.19 kamil 234: }
1.52 rillig 235: while (com.e > com_st && isspace((unsigned char)com.e[-1]))
236: com.e--;
1.45 rillig 237: (void)output_indent(cur_col - 1, target_col - 1);
1.52 rillig 238: output_range(com_st, com.e);
1.19 kamil 239: ps.comment_delta = ps.n_comment_delta;
1.58 rillig 240: ps.stats.comment_lines++;
1.19 kamil 241: }
242: if (ps.use_ff)
1.28 rillig 243: output_char('\014');
1.19 kamil 244: else
1.28 rillig 245: output_char('\n');
1.58 rillig 246: ps.stats.lines++;
1.19 kamil 247: if (ps.just_saw_decl == 1 && opt.blanklines_after_declarations) {
1.60 rillig 248: prefix_blankline_requested = true;
1.19 kamil 249: ps.just_saw_decl = 0;
1.30 rillig 250: } else
1.19 kamil 251: prefix_blankline_requested = postfix_blankline_requested;
1.60 rillig 252: postfix_blankline_requested = false;
1.19 kamil 253: }
1.24 rillig 254:
255: /* keep blank lines after '//' comments */
1.52 rillig 256: if (com.e - com.s > 1 && com.s[1] == '/'
1.56 rillig 257: && token.s < token.e && isspace((unsigned char)token.s[0]))
258: output_range(token.s, token.e);
1.24 rillig 259:
1.46 rillig 260: ps.decl_on_line = ps.in_decl; /* if we are in the middle of a declaration,
261: * remember that fact for proper comment
262: * indentation */
1.60 rillig 263: ps.ind_stmt = ps.in_stmt && !ps.in_decl; /* next line should be indented if
264: * we have not completed this stmt and if we
265: * are not in the middle of a declaration */
1.19 kamil 266: ps.use_ff = false;
1.60 rillig 267: ps.dumped_decl_indent = false;
1.54 rillig 268: *(lab.e = lab.s) = '\0'; /* reset buffers */
1.55 rillig 269: *(code.e = code.s) = '\0';
1.52 rillig 270: *(com.e = com.s = com.buf + 1) = '\0';
1.64 ! rillig 271: ps.ind_level = ps.ind_level_follow;
1.19 kamil 272: ps.paren_level = ps.p_l_follow;
1.36 rillig 273: if (ps.paren_level > 0) {
274: /* TODO: explain what negative indentation means */
1.31 rillig 275: paren_indent = -ps.paren_indents[ps.paren_level - 1];
1.36 rillig 276: debug_println("paren_indent is now %d", paren_indent);
277: }
1.60 rillig 278: not_first_line = true;
1.1 cgd 279: }
280:
1.5 lukem 281: int
1.39 rillig 282: compute_code_indent(void)
1.1 cgd 283: {
1.43 rillig 284: int target_ind = opt.indent_size * ps.ind_level;
1.19 kamil 285:
1.39 rillig 286: if (ps.paren_level != 0) {
1.19 kamil 287: if (!opt.lineup_to_parens)
1.49 rillig 288: if (2 * opt.continuation_indent == opt.indent_size)
289: target_ind += opt.continuation_indent;
290: else
291: target_ind += opt.continuation_indent * ps.paren_level;
1.19 kamil 292: else if (opt.lineup_to_parens_always)
1.39 rillig 293: /*
294: * XXX: where does this '- 1' come from? It looks strange but is
295: * nevertheless needed for proper indentation, as demonstrated in
296: * the test opt-lpl.0.
297: */
298: target_ind = paren_indent - 1;
1.19 kamil 299: else {
300: int w;
1.31 rillig 301: int t = paren_indent;
1.1 cgd 302:
1.55 rillig 303: if ((w = 1 + indentation_after(t - 1, code.s) - opt.max_line_length) > 0
304: && 1 + indentation_after(target_ind, code.s) <= opt.max_line_length) {
1.19 kamil 305: t -= w + 1;
1.39 rillig 306: if (t > target_ind + 1)
307: target_ind = t - 1;
1.30 rillig 308: } else
1.39 rillig 309: target_ind = t - 1;
1.19 kamil 310: }
1.30 rillig 311: } else if (ps.ind_stmt)
1.39 rillig 312: target_ind += opt.continuation_indent;
313: return target_ind;
1.1 cgd 314: }
315:
1.5 lukem 316: int
1.38 rillig 317: compute_label_indent(void)
1.1 cgd 318: {
1.38 rillig 319: if (ps.pcase)
1.43 rillig 320: return (int) (case_ind * opt.indent_size);
1.54 rillig 321: if (lab.s[0] == '#')
1.38 rillig 322: return 0;
1.43 rillig 323: return opt.indent_size * (ps.ind_level - label_offset);
1.1 cgd 324: }
325:
1.53 rillig 326: static void
327: skip_hspace(const char **pp)
328: {
329: while (**pp == ' ' || **pp == '\t')
330: (*pp)++;
331: }
332:
333: static void
334: parse_indent_comment(void)
335: {
336: int on_off = 0; /* 0 = keep, 1 = ON, 2 = OFF */
337:
338: const char *p = in_buffer;
339:
340: skip_hspace(&p);
341:
342: if (!(*p == '/' && p[1] == '*'))
343: return;
344: p += 2;
345:
346: skip_hspace(&p);
347:
348: if (!(p[0] == 'I' && p[1] == 'N' && p[2] == 'D'
349: && p[3] == 'E' && p[4] == 'N' && p[5] == 'T'))
350: return;
351: p += 6;
352:
353: skip_hspace(&p);
354:
355: if (*p == '*')
356: on_off = 1;
357: else if (*p == 'O') {
358: if (*++p == 'N')
359: p++, on_off = 1;
360: else if (*p == 'F' && *++p == 'F')
361: p++, on_off = 2;
362: }
363: if (on_off == 0)
364: return;
365:
366: skip_hspace(&p);
367:
368: if (!(p[0] == '*' && p[1] == '/' && p[2] == '\n'))
369: return;
370:
1.55 rillig 371: if (com.s != com.e || lab.s != lab.e || code.s != code.e)
1.53 rillig 372: dump_line();
373:
1.62 rillig 374: if (!(inhibit_formatting = (on_off == 2))) {
1.53 rillig 375: n_real_blanklines = 0;
1.60 rillig 376: postfix_blankline_requested = false;
377: prefix_blankline_requested = false;
1.53 rillig 378: suppress_blanklines = 1;
379: }
380: }
1.1 cgd 381:
382: /*
383: * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
1.5 lukem 384: *
1.1 cgd 385: * All rights reserved
1.5 lukem 386: *
1.33 rillig 387: * FUNCTION: Reads one block of input into the input buffer
1.1 cgd 388: */
1.5 lukem 389: void
1.11 wiz 390: fill_buffer(void)
1.1 cgd 391: { /* this routine reads stuff from the input */
1.19 kamil 392: char *p;
393: int i;
394: FILE *f = input;
395:
396: if (bp_save != NULL) { /* there is a partly filled input buffer left */
397: buf_ptr = bp_save; /* do not read anything, just switch buffers */
398: buf_end = be_save;
399: bp_save = be_save = NULL;
1.47 rillig 400: debug_println("switched buf_ptr back to bp_save");
1.19 kamil 401: if (buf_ptr < buf_end)
402: return; /* only return if there is really something in
1.1 cgd 403: * this buffer */
1.19 kamil 404: }
405: for (p = in_buffer;;) {
406: if (p >= in_buffer_limit) {
1.48 rillig 407: size_t size = (in_buffer_limit - in_buffer) * 2 + 10;
408: size_t offset = p - in_buffer;
1.57 rillig 409: in_buffer = xrealloc(in_buffer, size);
1.19 kamil 410: p = in_buffer + offset;
411: in_buffer_limit = in_buffer + size - 2;
412: }
413: if ((i = getc(f)) == EOF) {
1.37 rillig 414: *p++ = ' ';
415: *p++ = '\n';
416: had_eof = true;
417: break;
1.1 cgd 418: }
1.19 kamil 419: if (i != '\0')
420: *p++ = i;
421: if (i == '\n')
1.37 rillig 422: break;
1.19 kamil 423: }
424: buf_ptr = in_buffer;
425: buf_end = p;
426: if (p - in_buffer > 2 && p[-2] == '/' && p[-3] == '*') {
427: if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0)
428: fill_buffer(); /* flush indent error message */
1.53 rillig 429: else
430: parse_indent_comment();
1.19 kamil 431: }
432: if (inhibit_formatting) {
433: p = in_buffer;
1.25 rillig 434: do {
1.28 rillig 435: output_char(*p);
1.25 rillig 436: } while (*p++ != '\n');
1.19 kamil 437: }
1.1 cgd 438: }
1.19 kamil 439:
1.1 cgd 440: int
1.40 rillig 441: indentation_after_range(int ind, const char *start, const char *end)
1.1 cgd 442: {
1.40 rillig 443: for (const char *p = start; *p != '\0' && p != end; ++p) {
444: if (*p == '\n' || *p == '\f')
445: ind = 0;
446: else if (*p == '\t')
447: ind = opt.tabsize * (ind / opt.tabsize + 1);
448: else if (*p == '\b')
449: --ind;
450: else
451: ++ind;
452: }
453: return ind;
454: }
1.1 cgd 455:
1.40 rillig 456: int
457: indentation_after(int ind, const char *s)
458: {
459: return indentation_after_range(ind, s, NULL);
460: }
1.19 kamil 461:
1.5 lukem 462: void
1.20 christos 463: diag(int level, const char *msg, ...)
1.1 cgd 464: {
1.20 christos 465: va_list ap;
466: const char *s, *e;
467:
1.60 rillig 468: if (level != 0)
1.19 kamil 469: found_err = 1;
1.1 cgd 470:
1.19 kamil 471: if (output == stdout) {
1.20 christos 472: s = "/**INDENT** ";
473: e = " */";
474: } else {
475: s = e = "";
1.19 kamil 476: }
1.1 cgd 477:
1.20 christos 478: va_start(ap, msg);
479: fprintf(stderr, "%s%s@%d: ", s, level == 0 ? "Warning" : "Error", line_no);
480: vfprintf(stderr, msg, ap);
481: fprintf(stderr, "%s\n", e);
482: va_end(ap);
1.1 cgd 483: }
CVSweb <webmaster@jp.NetBSD.org>