| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: io.c,v 1.213 2023/06/10 08:17:04 rillig Exp $ */ | | 1 | /* $NetBSD: io.c,v 1.214 2023/06/10 11:01:58 rillig Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * SPDX-License-Identifier: BSD-4-Clause | | 4 | * SPDX-License-Identifier: BSD-4-Clause |
5 | * | | 5 | * |
6 | * Copyright (c) 1985 Sun Microsystems, Inc. | | 6 | * Copyright (c) 1985 Sun Microsystems, Inc. |
7 | * Copyright (c) 1980, 1993 | | 7 | * Copyright (c) 1980, 1993 |
8 | * The Regents of the University of California. All rights reserved. | | 8 | * The Regents of the University of California. All rights reserved. |
9 | * All rights reserved. | | 9 | * All rights reserved. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
| @@ -28,42 +28,43 @@ | | | @@ -28,42 +28,43 @@ |
28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
30 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 30 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 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 | | 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 | | 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 | | 36 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
37 | * SUCH DAMAGE. | | 37 | * SUCH DAMAGE. |
38 | */ | | 38 | */ |
39 | | | 39 | |
40 | #include <sys/cdefs.h> | | 40 | #include <sys/cdefs.h> |
41 | __RCSID("$NetBSD: io.c,v 1.213 2023/06/10 08:17:04 rillig Exp $"); | | 41 | __RCSID("$NetBSD: io.c,v 1.214 2023/06/10 11:01:58 rillig Exp $"); |
42 | | | 42 | |
43 | #include <stdio.h> | | 43 | #include <stdio.h> |
44 | | | 44 | |
45 | #include "indent.h" | | 45 | #include "indent.h" |
46 | | | 46 | |
47 | struct buffer inp; | | 47 | struct buffer inp; |
48 | const char *inp_p; | | 48 | const char *inp_p; |
49 | | | 49 | |
50 | struct output_state out; | | 50 | struct output_state out; |
51 | enum indent_enabled indent_enabled; | | 51 | enum indent_enabled indent_enabled; |
52 | static int out_ind; /* width of the line that is being written */ | | 52 | static int out_ind; /* width of the line that is being written */ |
53 | static unsigned wrote_newlines = 2; /* 0 in the middle of a line, 1 after a | | 53 | static unsigned newlines = 2; /* the total of written and buffered newlines; |
54 | * single '\n', > 1 means there were (n | | 54 | * 0 in the middle of a line, 1 after a single |
55 | * - 1) blank lines above */ | | 55 | * finished line, anything > 1 are trailing |
56 | static unsigned buffered_blank_lines; | | 56 | * blank lines */ |
| | | 57 | static unsigned buffered_newlines; /* not yet written */ |
57 | static int paren_indent; | | 58 | static int paren_indent; |
58 | | | 59 | |
59 | | | 60 | |
60 | static void | | 61 | static void |
61 | inp_read_next_line(FILE *f) | | 62 | inp_read_next_line(FILE *f) |
62 | { | | 63 | { |
63 | inp.len = 0; | | 64 | inp.len = 0; |
64 | | | 65 | |
65 | for (;;) { | | 66 | for (;;) { |
66 | int ch = getc(f); | | 67 | int ch = getc(f); |
67 | if (ch == EOF) { | | 68 | if (ch == EOF) { |
68 | if (indent_enabled == indent_on) { | | 69 | if (indent_enabled == indent_on) { |
69 | buf_add_char(&inp, ' '); | | 70 | buf_add_char(&inp, ' '); |
| @@ -98,76 +99,76 @@ inp_skip(void) | | | @@ -98,76 +99,76 @@ inp_skip(void) |
98 | inp_read_line(); | | 99 | inp_read_line(); |
99 | } | | 100 | } |
100 | | | 101 | |
101 | char | | 102 | char |
102 | inp_next(void) | | 103 | inp_next(void) |
103 | { | | 104 | { |
104 | char ch = inp_p[0]; | | 105 | char ch = inp_p[0]; |
105 | inp_skip(); | | 106 | inp_skip(); |
106 | return ch; | | 107 | return ch; |
107 | } | | 108 | } |
108 | | | 109 | |
109 | | | 110 | |
110 | static void | | 111 | static void |
111 | write_newline(void) | | 112 | buffer_newline(void) |
112 | { | | 113 | { |
113 | buffered_blank_lines++; | | 114 | buffered_newlines++; |
114 | wrote_newlines++; | | 115 | newlines++; |
115 | out_ind = 0; | | 116 | out_ind = 0; |
116 | } | | 117 | } |
117 | | | 118 | |
118 | static void | | 119 | static void |
119 | write_buffered_blank_lines(void) | | 120 | write_buffered_newlines(void) |
120 | { | | 121 | { |
121 | for (; buffered_blank_lines > 0; buffered_blank_lines--) { | | 122 | for (; buffered_newlines > 0; buffered_newlines--) { |
122 | fputc('\n', output); | | 123 | fputc('\n', output); |
123 | debug_println("output_newline"); | | 124 | debug_println("write_newline"); |
124 | } | | 125 | } |
125 | } | | 126 | } |
126 | | | 127 | |
127 | static void | | 128 | static void |
128 | write_range(const char *s, size_t len) | | 129 | write_range(const char *s, size_t len) |
129 | { | | 130 | { |
130 | write_buffered_blank_lines(); | | 131 | write_buffered_newlines(); |
131 | fwrite(s, 1, len, output); | | 132 | fwrite(s, 1, len, output); |
132 | debug_vis_range("output_range \"", s, len, "\"\n"); | | 133 | debug_vis_range("write_range \"", s, len, "\"\n"); |
133 | for (size_t i = 0; i < len; i++) | | 134 | for (size_t i = 0; i < len; i++) |
134 | wrote_newlines = s[i] == '\n' ? wrote_newlines + 1 : 0; | | 135 | newlines = s[i] == '\n' ? newlines + 1 : 0; |
135 | out_ind = ind_add(out_ind, s, len); | | 136 | out_ind = ind_add(out_ind, s, len); |
136 | } | | 137 | } |
137 | | | 138 | |
138 | static void | | 139 | static void |
139 | write_indent(int new_ind) | | 140 | write_indent(int new_ind) |
140 | { | | 141 | { |
141 | write_buffered_blank_lines(); | | 142 | write_buffered_newlines(); |
142 | | | 143 | |
143 | int ind = out_ind; | | 144 | int ind = out_ind; |
144 | | | 145 | |
145 | if (opt.use_tabs) { | | 146 | if (opt.use_tabs) { |
146 | int n = new_ind / opt.tabsize - ind / opt.tabsize; | | 147 | int n = new_ind / opt.tabsize - ind / opt.tabsize; |
147 | if (n > 0) { | | 148 | if (n > 0) { |
148 | ind = ind - ind % opt.tabsize + n * opt.tabsize; | | 149 | ind = ind - ind % opt.tabsize + n * opt.tabsize; |
149 | while (n-- > 0) | | 150 | while (n-- > 0) |
150 | fputc('\t', output); | | 151 | fputc('\t', output); |
151 | wrote_newlines = 0; | | 152 | newlines = 0; |
152 | } | | 153 | } |
153 | } | | 154 | } |
154 | | | 155 | |
155 | for (; ind < new_ind; ind++) { | | 156 | for (; ind < new_ind; ind++) { |
156 | fputc(' ', output); | | 157 | fputc(' ', output); |
157 | wrote_newlines = 0; | | 158 | newlines = 0; |
158 | } | | 159 | } |
159 | | | 160 | |
160 | debug_println("output_indent %d", ind); | | 161 | debug_println("write_indent %d", ind); |
161 | out_ind = ind; | | 162 | out_ind = ind; |
162 | } | | 163 | } |
163 | | | 164 | |
164 | static bool | | 165 | static bool |
165 | want_blank_line(void) | | 166 | want_blank_line(void) |
166 | { | | 167 | { |
167 | debug_println("%s: %s -> %s", __func__, | | 168 | debug_println("%s: %s -> %s", __func__, |
168 | line_kind_name[out.prev_line_kind], line_kind_name[out.line_kind]); | | 169 | line_kind_name[out.prev_line_kind], line_kind_name[out.line_kind]); |
169 | | | 170 | |
170 | if (ps.blank_line_after_decl && ps.declaration == decl_no) { | | 171 | if (ps.blank_line_after_decl && ps.declaration == decl_no) { |
171 | ps.blank_line_after_decl = false; | | 172 | ps.blank_line_after_decl = false; |
172 | return true; | | 173 | return true; |
173 | } | | 174 | } |
| @@ -181,30 +182,30 @@ want_blank_line(void) | | | @@ -181,30 +182,30 @@ want_blank_line(void) |
181 | if (opt.blanklines_after_procs && out.prev_line_kind == lk_func_end | | 182 | if (opt.blanklines_after_procs && out.prev_line_kind == lk_func_end |
182 | && out.line_kind != lk_endif) | | 183 | && out.line_kind != lk_endif) |
183 | return true; | | 184 | return true; |
184 | if (opt.blanklines_before_block_comments | | 185 | if (opt.blanklines_before_block_comments |
185 | && out.line_kind == lk_block_comment) | | 186 | && out.line_kind == lk_block_comment) |
186 | return true; | | 187 | return true; |
187 | return false; | | 188 | return false; |
188 | } | | 189 | } |
189 | | | 190 | |
190 | static bool | | 191 | static bool |
191 | is_blank_line_optional(void) | | 192 | is_blank_line_optional(void) |
192 | { | | 193 | { |
193 | if (out.prev_line_kind == lk_stmt_head) | | 194 | if (out.prev_line_kind == lk_stmt_head) |
194 | return wrote_newlines >= 1; | | 195 | return newlines >= 1; |
195 | if (ps.psyms.top >= 2) | | 196 | if (ps.psyms.top >= 2) |
196 | return wrote_newlines >= 2; | | 197 | return newlines >= 2; |
197 | return wrote_newlines >= 3; | | 198 | return newlines >= 3; |
198 | } | | 199 | } |
199 | | | 200 | |
200 | static int | | 201 | static int |
201 | compute_case_label_indent(void) | | 202 | compute_case_label_indent(void) |
202 | { | | 203 | { |
203 | int i = ps.psyms.top; | | 204 | int i = ps.psyms.top; |
204 | while (i > 0 && ps.psyms.sym[i] != psym_switch_expr) | | 205 | while (i > 0 && ps.psyms.sym[i] != psym_switch_expr) |
205 | i--; | | 206 | i--; |
206 | float case_ind = (float)ps.psyms.ind_level[i] + opt.case_indent; | | 207 | float case_ind = (float)ps.psyms.ind_level[i] + opt.case_indent; |
207 | return (int)(case_ind * (float)opt.indent_size); | | 208 | return (int)(case_ind * (float)opt.indent_size); |
208 | } | | 209 | } |
209 | | | 210 | |
210 | int | | 211 | int |
| @@ -301,70 +302,72 @@ output_line_comment(void) | | | @@ -301,70 +302,72 @@ output_line_comment(void) |
301 | | | 302 | |
302 | for (; target_ind < 0; p++) { | | 303 | for (; target_ind < 0; p++) { |
303 | if (*p == ' ') | | 304 | if (*p == ' ') |
304 | target_ind++; | | 305 | target_ind++; |
305 | else if (*p == '\t') | | 306 | else if (*p == '\t') |
306 | target_ind = next_tab(target_ind); | | 307 | target_ind = next_tab(target_ind); |
307 | else { | | 308 | else { |
308 | target_ind = 0; | | 309 | target_ind = 0; |
309 | break; | | 310 | break; |
310 | } | | 311 | } |
311 | } | | 312 | } |
312 | | | 313 | |
313 | if (out_ind > target_ind) | | 314 | if (out_ind > target_ind) |
314 | write_newline(); | | 315 | buffer_newline(); |
315 | | | 316 | |
316 | while (com.s + com.len > p && ch_isspace(com.s[com.len - 1])) | | 317 | while (com.s + com.len > p && ch_isspace(com.s[com.len - 1])) |
317 | com.len--; | | 318 | com.len--; |
318 | | | 319 | |
319 | write_indent(target_ind); | | 320 | write_indent(target_ind); |
320 | write_range(p, com.len - (size_t)(p - com.s)); | | 321 | write_range(p, com.len - (size_t)(p - com.s)); |
321 | | | 322 | |
322 | ps.comment_delta = ps.n_comment_delta; | | 323 | ps.comment_delta = ps.n_comment_delta; |
323 | } | | 324 | } |
324 | | | 325 | |
325 | static void | | 326 | static void |
326 | output_line_indented(void) | | 327 | output_line_indented(void) |
327 | { | | 328 | { |
328 | if (lab.len == 0 && code.len == 0 && com.len == 0) | | 329 | if (lab.len == 0 && code.len == 0 && com.len == 0) |
329 | out.line_kind = lk_blank; | | 330 | out.line_kind = lk_blank; |
330 | | | 331 | |
331 | if (want_blank_line() && wrote_newlines < 2 | | 332 | if (want_blank_line() && newlines < 2 |
332 | && out.line_kind != lk_blank) | | 333 | && out.line_kind != lk_blank) |
333 | write_newline(); | | 334 | buffer_newline(); |
334 | | | 335 | |
335 | /* This kludge aligns function definitions correctly. */ | | 336 | /* This kludge aligns function definitions correctly. */ |
336 | if (ps.ind_level == 0) | | 337 | if (ps.ind_level == 0) |
337 | ps.in_stmt_cont = false; | | 338 | ps.in_stmt_cont = false; |
338 | | | 339 | |
339 | if (opt.blank_line_after_decl && ps.declaration == decl_end | | 340 | if (opt.blank_line_after_decl && ps.declaration == decl_end |
340 | && ps.psyms.top > 1) { | | 341 | && ps.psyms.top > 1) { |
341 | ps.declaration = decl_no; | | 342 | ps.declaration = decl_no; |
342 | ps.blank_line_after_decl = true; | | 343 | ps.blank_line_after_decl = true; |
343 | } | | 344 | } |
344 | | | 345 | |
345 | if (opt.swallow_optional_blanklines | | 346 | if (opt.swallow_optional_blanklines |
346 | && out.line_kind == lk_blank | | 347 | && out.line_kind == lk_blank |
347 | && is_blank_line_optional()) | | 348 | && is_blank_line_optional()) |
348 | return; | | 349 | return; |
349 | | | 350 | |
350 | if (lab.len > 0) | | 351 | if (lab.len > 0) |
351 | output_line_label(); | | 352 | output_line_label(); |
352 | if (code.len > 0) | | 353 | if (code.len > 0) |
353 | output_line_code(); | | 354 | output_line_code(); |
354 | if (com.len > 0) | | 355 | if (com.len > 0) |
355 | output_line_comment(); | | 356 | output_line_comment(); |
| | | 357 | buffer_newline(); |
| | | 358 | if (out.line_kind != lk_blank) |
| | | 359 | write_buffered_newlines(); |
356 | | | 360 | |
357 | write_newline(); | | | |
358 | out.prev_line_kind = out.line_kind; | | 361 | out.prev_line_kind = out.line_kind; |
359 | } | | 362 | } |
360 | | | 363 | |
361 | /* | | 364 | /* |
362 | * Write a line of formatted source to the output file. The line consists of | | 365 | * Write a line of formatted source to the output file. The line consists of |
363 | * the label, the code and the comment. | | 366 | * the label, the code and the comment. |
364 | */ | | 367 | */ |
365 | void | | 368 | void |
366 | output_line(void) | | 369 | output_line(void) |
367 | { | | 370 | { |
368 | debug_blank_line(); | | 371 | debug_blank_line(); |
369 | debug_printf("%s", __func__); | | 372 | debug_printf("%s", __func__); |
370 | debug_buffers(); | | 373 | debug_buffers(); |
| @@ -397,25 +400,20 @@ output_line(void) | | | @@ -397,25 +400,20 @@ output_line(void) |
397 | | | 400 | |
398 | if (ps.nparen > 0) { | | 401 | if (ps.nparen > 0) { |
399 | /* TODO: explain what negative indentation means */ | | 402 | /* TODO: explain what negative indentation means */ |
400 | paren_indent = -1 - ps.paren[ps.nparen - 1].indent; | | 403 | paren_indent = -1 - ps.paren[ps.nparen - 1].indent; |
401 | debug_println("paren_indent is now %d", paren_indent); | | 404 | debug_println("paren_indent is now %d", paren_indent); |
402 | } | | 405 | } |
403 | | | 406 | |
404 | out.line_kind = lk_other; | | 407 | out.line_kind = lk_other; |
405 | } | | 408 | } |
406 | | | 409 | |
407 | void | | 410 | void |
408 | output_finish(void) | | 411 | output_finish(void) |
409 | { | | 412 | { |
410 | if (lab.len > 0 || code.len > 0 || com.len > 0) | | 413 | output_line(); |
411 | output_line(); | | 414 | if (indent_enabled != indent_on) { |
412 | if (indent_enabled == indent_on) { | | | |
413 | if (buffered_blank_lines > 1) | | | |
414 | buffered_blank_lines = 1; | | | |
415 | write_buffered_blank_lines(); | | | |
416 | } else { | | | |
417 | indent_enabled = indent_last_off_line; | | 415 | indent_enabled = indent_last_off_line; |
418 | output_line(); | | 416 | output_line(); |
419 | } | | 417 | } |
420 | fflush(output); | | 418 | fflush(output); |
421 | } | | 419 | } |