| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: io.c,v 1.210 2023/06/10 07:42:41 rillig Exp $ */ | | 1 | /* $NetBSD: io.c,v 1.211 2023/06/10 07:48:55 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,27 +28,27 @@ | | | @@ -28,27 +28,27 @@ |
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.210 2023/06/10 07:42:41 rillig Exp $"); | | 41 | __RCSID("$NetBSD: io.c,v 1.211 2023/06/10 07:48:55 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 wrote_newlines = 2; /* 0 in the middle of a line, 1 after a |
54 | * single '\n', > 1 means there were (n | | 54 | * single '\n', > 1 means there were (n |
| @@ -98,95 +98,79 @@ inp_skip(void) | | | @@ -98,95 +98,79 @@ inp_skip(void) |
98 | inp_read_line(); | | 98 | inp_read_line(); |
99 | } | | 99 | } |
100 | | | 100 | |
101 | char | | 101 | char |
102 | inp_next(void) | | 102 | inp_next(void) |
103 | { | | 103 | { |
104 | char ch = inp_p[0]; | | 104 | char ch = inp_p[0]; |
105 | inp_skip(); | | 105 | inp_skip(); |
106 | return ch; | | 106 | return ch; |
107 | } | | 107 | } |
108 | | | 108 | |
109 | | | 109 | |
110 | static void | | 110 | static void |
111 | output_newline(void) | | 111 | write_newline(void) |
112 | { | | 112 | { |
113 | buffered_blank_lines++; | | 113 | buffered_blank_lines++; |
114 | wrote_newlines++; | | 114 | wrote_newlines++; |
115 | out_ind = 0; | | 115 | out_ind = 0; |
116 | } | | 116 | } |
117 | | | 117 | |
118 | static void | | 118 | static void |
119 | write_buffered_blank_lines(void) | | 119 | write_buffered_blank_lines(void) |
120 | { | | 120 | { |
121 | for (; buffered_blank_lines > 0; buffered_blank_lines--) { | | 121 | for (; buffered_blank_lines > 0; buffered_blank_lines--) { |
122 | fputc('\n', output); | | 122 | fputc('\n', output); |
123 | debug_println("output_newline"); | | 123 | debug_println("output_newline"); |
124 | } | | 124 | } |
125 | } | | 125 | } |
126 | | | 126 | |
127 | static void | | 127 | static void |
128 | output_range(const char *s, size_t len) | | 128 | write_range(const char *s, size_t len) |
129 | { | | 129 | { |
130 | write_buffered_blank_lines(); | | 130 | write_buffered_blank_lines(); |
131 | fwrite(s, 1, len, output); | | 131 | fwrite(s, 1, len, output); |
132 | debug_vis_range("output_range \"", s, len, "\"\n"); | | 132 | debug_vis_range("output_range \"", s, len, "\"\n"); |
133 | for (size_t i = 0; i < len; i++) | | 133 | for (size_t i = 0; i < len; i++) |
134 | wrote_newlines = s[i] == '\n' ? wrote_newlines + 1 : 0; | | 134 | wrote_newlines = s[i] == '\n' ? wrote_newlines + 1 : 0; |
135 | out_ind = ind_add(out_ind, s, len); | | 135 | out_ind = ind_add(out_ind, s, len); |
136 | } | | 136 | } |
137 | | | 137 | |
138 | static void | | 138 | static void |
139 | output_indent(int new_ind) | | 139 | write_indent(int new_ind) |
140 | { | | 140 | { |
141 | write_buffered_blank_lines(); | | 141 | write_buffered_blank_lines(); |
142 | | | 142 | |
143 | int ind = out_ind; | | 143 | int ind = out_ind; |
144 | | | 144 | |
145 | if (opt.use_tabs) { | | 145 | if (opt.use_tabs) { |
146 | int n = new_ind / opt.tabsize - ind / opt.tabsize; | | 146 | int n = new_ind / opt.tabsize - ind / opt.tabsize; |
147 | if (n > 0) { | | 147 | if (n > 0) { |
148 | ind = ind - ind % opt.tabsize + n * opt.tabsize; | | 148 | ind = ind - ind % opt.tabsize + n * opt.tabsize; |
149 | while (n-- > 0) | | 149 | while (n-- > 0) |
150 | fputc('\t', output); | | 150 | fputc('\t', output); |
151 | wrote_newlines = 0; | | 151 | wrote_newlines = 0; |
152 | } | | 152 | } |
153 | } | | 153 | } |
154 | | | 154 | |
155 | for (; ind < new_ind; ind++) { | | 155 | for (; ind < new_ind; ind++) { |
156 | fputc(' ', output); | | 156 | fputc(' ', output); |
157 | wrote_newlines = 0; | | 157 | wrote_newlines = 0; |
158 | } | | 158 | } |
159 | | | 159 | |
160 | debug_println("output_indent %d", ind); | | 160 | debug_println("output_indent %d", ind); |
161 | out_ind = ind; | | 161 | out_ind = ind; |
162 | } | | 162 | } |
163 | | | 163 | |
164 | void | | | |
165 | output_finish(void) | | | |
166 | { | | | |
167 | if (lab.len > 0 || code.len > 0 || com.len > 0) | | | |
168 | output_line(); | | | |
169 | if (indent_enabled == indent_on) { | | | |
170 | if (buffered_blank_lines > 1) | | | |
171 | buffered_blank_lines = 1; | | | |
172 | write_buffered_blank_lines(); | | | |
173 | } else { | | | |
174 | indent_enabled = indent_last_off_line; | | | |
175 | output_line(); | | | |
176 | } | | | |
177 | fflush(output); | | | |
178 | } | | | |
179 | | | | |
180 | static bool | | 164 | static bool |
181 | want_blank_line(void) | | 165 | want_blank_line(void) |
182 | { | | 166 | { |
183 | debug_println("%s: %s -> %s", __func__, | | 167 | debug_println("%s: %s -> %s", __func__, |
184 | line_kind_name[out.prev_line_kind], line_kind_name[out.line_kind]); | | 168 | line_kind_name[out.prev_line_kind], line_kind_name[out.line_kind]); |
185 | | | 169 | |
186 | if (ps.blank_line_after_decl && ps.declaration == decl_no) { | | 170 | if (ps.blank_line_after_decl && ps.declaration == decl_no) { |
187 | ps.blank_line_after_decl = false; | | 171 | ps.blank_line_after_decl = false; |
188 | return true; | | 172 | return true; |
189 | } | | 173 | } |
190 | if (opt.blanklines_around_conditional_compilation) { | | 174 | if (opt.blanklines_around_conditional_compilation) { |
191 | if (out.prev_line_kind != lk_if && out.line_kind == lk_if) | | 175 | if (out.prev_line_kind != lk_if && out.line_kind == lk_if) |
192 | return true; | | 176 | return true; |
| @@ -226,28 +210,28 @@ compute_case_label_indent(void) | | | @@ -226,28 +210,28 @@ compute_case_label_indent(void) |
226 | int | | 210 | int |
227 | compute_label_indent(void) | | 211 | compute_label_indent(void) |
228 | { | | 212 | { |
229 | if (out.line_kind == lk_case_or_default) | | 213 | if (out.line_kind == lk_case_or_default) |
230 | return compute_case_label_indent(); | | 214 | return compute_case_label_indent(); |
231 | if (lab.s[0] == '#') | | 215 | if (lab.s[0] == '#') |
232 | return 0; | | 216 | return 0; |
233 | return opt.indent_size * (ps.ind_level - 2); | | 217 | return opt.indent_size * (ps.ind_level - 2); |
234 | } | | 218 | } |
235 | | | 219 | |
236 | static void | | 220 | static void |
237 | output_line_label(void) | | 221 | output_line_label(void) |
238 | { | | 222 | { |
239 | output_indent(compute_label_indent()); | | 223 | write_indent(compute_label_indent()); |
240 | output_range(lab.s, lab.len); | | 224 | write_range(lab.s, lab.len); |
241 | } | | 225 | } |
242 | | | 226 | |
243 | static int | | 227 | static int |
244 | compute_code_indent_lineup(int base_ind) | | 228 | compute_code_indent_lineup(int base_ind) |
245 | { | | 229 | { |
246 | int ind = paren_indent; | | 230 | int ind = paren_indent; |
247 | int overflow = ind_add(ind, code.s, code.len) - opt.max_line_length; | | 231 | int overflow = ind_add(ind, code.s, code.len) - opt.max_line_length; |
248 | if (overflow >= 0 | | 232 | if (overflow >= 0 |
249 | && ind_add(base_ind, code.s, code.len) < opt.max_line_length) { | | 233 | && ind_add(base_ind, code.s, code.len) < opt.max_line_length) { |
250 | ind -= overflow + 2; | | 234 | ind -= overflow + 2; |
251 | if (ind < base_ind) | | 235 | if (ind < base_ind) |
252 | ind = base_ind; | | 236 | ind = base_ind; |
253 | } | | 237 | } |
| @@ -290,112 +274,112 @@ output_line_code(void) | | | @@ -290,112 +274,112 @@ output_line_code(void) |
290 | int target_ind = compute_code_indent(); | | 274 | int target_ind = compute_code_indent(); |
291 | for (int i = 0; i < ps.nparen; i++) { | | 275 | for (int i = 0; i < ps.nparen; i++) { |
292 | int paren_ind = ps.paren[i].indent; | | 276 | int paren_ind = ps.paren[i].indent; |
293 | if (paren_ind >= 0) { | | 277 | if (paren_ind >= 0) { |
294 | ps.paren[i].indent = -1 - (paren_ind + target_ind); | | 278 | ps.paren[i].indent = -1 - (paren_ind + target_ind); |
295 | debug_println( | | 279 | debug_println( |
296 | "setting paren_indents[%d] from %d to %d " | | 280 | "setting paren_indents[%d] from %d to %d " |
297 | "for column %d", | | 281 | "for column %d", |
298 | i, paren_ind, ps.paren[i].indent, target_ind + 1); | | 282 | i, paren_ind, ps.paren[i].indent, target_ind + 1); |
299 | } | | 283 | } |
300 | } | | 284 | } |
301 | | | 285 | |
302 | if (lab.len > 0 && target_ind <= out_ind) | | 286 | if (lab.len > 0 && target_ind <= out_ind) |
303 | output_range(" ", 1); | | 287 | write_range(" ", 1); |
304 | output_indent(target_ind); | | 288 | write_indent(target_ind); |
305 | output_range(code.s, code.len); | | 289 | write_range(code.s, code.len); |
306 | } | | 290 | } |
307 | | | 291 | |
308 | static void | | 292 | static void |
309 | output_line_comment(void) | | 293 | output_line_comment(void) |
310 | { | | 294 | { |
311 | int target_ind = ps.com_ind + ps.comment_delta; | | 295 | int target_ind = ps.com_ind + ps.comment_delta; |
312 | const char *p; | | 296 | const char *p; |
313 | | | 297 | |
314 | /* consider original indentation in case this is a box comment */ | | 298 | /* consider original indentation in case this is a box comment */ |
315 | for (p = com.s; *p == '\t'; p++) | | 299 | for (p = com.s; *p == '\t'; p++) |
316 | target_ind += opt.tabsize; | | 300 | target_ind += opt.tabsize; |
317 | | | 301 | |
318 | for (; target_ind < 0; p++) { | | 302 | for (; target_ind < 0; p++) { |
319 | if (*p == ' ') | | 303 | if (*p == ' ') |
320 | target_ind++; | | 304 | target_ind++; |
321 | else if (*p == '\t') | | 305 | else if (*p == '\t') |
322 | target_ind = next_tab(target_ind); | | 306 | target_ind = next_tab(target_ind); |
323 | else { | | 307 | else { |
324 | target_ind = 0; | | 308 | target_ind = 0; |
325 | break; | | 309 | break; |
326 | } | | 310 | } |
327 | } | | 311 | } |
328 | | | 312 | |
329 | if (out_ind > target_ind) | | 313 | if (out_ind > target_ind) |
330 | output_newline(); | | 314 | write_newline(); |
331 | | | 315 | |
332 | while (com.s + com.len > p && ch_isspace(com.s[com.len - 1])) | | 316 | while (com.s + com.len > p && ch_isspace(com.s[com.len - 1])) |
333 | com.len--; | | 317 | com.len--; |
334 | | | 318 | |
335 | output_indent(target_ind); | | 319 | write_indent(target_ind); |
336 | output_range(p, com.len - (size_t)(p - com.s)); | | 320 | write_range(p, com.len - (size_t)(p - com.s)); |
337 | | | 321 | |
338 | ps.comment_delta = ps.n_comment_delta; | | 322 | ps.comment_delta = ps.n_comment_delta; |
339 | } | | 323 | } |
340 | | | 324 | |
341 | /* | | 325 | /* |
342 | * Write a line of formatted source to the output file. The line consists of | | 326 | * Write a line of formatted source to the output file. The line consists of |
343 | * the label, the code and the comment. | | 327 | * the label, the code and the comment. |
344 | */ | | 328 | */ |
345 | void | | 329 | void |
346 | output_line(void) | | 330 | output_line(void) |
347 | { | | 331 | { |
348 | debug_blank_line(); | | 332 | debug_blank_line(); |
349 | debug_printf("%s", __func__); | | 333 | debug_printf("%s", __func__); |
350 | debug_buffers(); | | 334 | debug_buffers(); |
351 | | | 335 | |
352 | if (indent_enabled == indent_on) { | | 336 | if (indent_enabled == indent_on) { |
353 | if (lab.len == 0 && code.len == 0 && com.len == 0) | | 337 | if (lab.len == 0 && code.len == 0 && com.len == 0) |
354 | out.line_kind = lk_blank; | | 338 | out.line_kind = lk_blank; |
355 | | | 339 | |
356 | if (want_blank_line() && wrote_newlines < 2 | | 340 | if (want_blank_line() && wrote_newlines < 2 |
357 | && out.line_kind != lk_blank) | | 341 | && out.line_kind != lk_blank) |
358 | output_newline(); | | 342 | write_newline(); |
359 | | | 343 | |
360 | /* This kludge aligns function definitions correctly. */ | | 344 | /* This kludge aligns function definitions correctly. */ |
361 | if (ps.ind_level == 0) | | 345 | if (ps.ind_level == 0) |
362 | ps.in_stmt_cont = false; | | 346 | ps.in_stmt_cont = false; |
363 | | | 347 | |
364 | if (opt.blank_line_after_decl && ps.declaration == decl_end | | 348 | if (opt.blank_line_after_decl && ps.declaration == decl_end |
365 | && ps.psyms.top > 1) { | | 349 | && ps.psyms.top > 1) { |
366 | ps.declaration = decl_no; | | 350 | ps.declaration = decl_no; |
367 | ps.blank_line_after_decl = true; | | 351 | ps.blank_line_after_decl = true; |
368 | } | | 352 | } |
369 | | | 353 | |
370 | if (opt.swallow_optional_blanklines | | 354 | if (opt.swallow_optional_blanklines |
371 | && out.line_kind == lk_blank | | 355 | && out.line_kind == lk_blank |
372 | && is_blank_line_optional()) | | 356 | && is_blank_line_optional()) |
373 | goto prepare_next_line; | | 357 | goto prepare_next_line; |
374 | | | 358 | |
375 | if (lab.len > 0) | | 359 | if (lab.len > 0) |
376 | output_line_label(); | | 360 | output_line_label(); |
377 | if (code.len > 0) | | 361 | if (code.len > 0) |
378 | output_line_code(); | | 362 | output_line_code(); |
379 | if (com.len > 0) | | 363 | if (com.len > 0) |
380 | output_line_comment(); | | 364 | output_line_comment(); |
381 | | | 365 | |
382 | output_newline(); | | 366 | write_newline(); |
383 | out.prev_line_kind = out.line_kind; | | 367 | out.prev_line_kind = out.line_kind; |
384 | } | | 368 | } |
385 | | | 369 | |
386 | if (indent_enabled == indent_last_off_line) { | | 370 | if (indent_enabled == indent_last_off_line) { |
387 | indent_enabled = indent_on; | | 371 | indent_enabled = indent_on; |
388 | output_range(out.indent_off_text.s, out.indent_off_text.len); | | 372 | write_range(out.indent_off_text.s, out.indent_off_text.len); |
389 | out.indent_off_text.len = 0; | | 373 | out.indent_off_text.len = 0; |
390 | } | | 374 | } |
391 | | | 375 | |
392 | prepare_next_line: | | 376 | prepare_next_line: |
393 | lab.len = 0; | | 377 | lab.len = 0; |
394 | code.len = 0; | | 378 | code.len = 0; |
395 | com.len = 0; | | 379 | com.len = 0; |
396 | | | 380 | |
397 | ps.line_has_decl = ps.in_decl; | | 381 | ps.line_has_decl = ps.in_decl; |
398 | ps.line_has_func_def = false; | | 382 | ps.line_has_func_def = false; |
399 | // XXX: don't reset in_stmt_cont here; see process_colon_question. | | 383 | // XXX: don't reset in_stmt_cont here; see process_colon_question. |
400 | ps.in_stmt_cont = ps.in_stmt_or_decl | | 384 | ps.in_stmt_cont = ps.in_stmt_or_decl |
401 | && !ps.in_decl && ps.init_level == 0; | | 385 | && !ps.in_decl && ps.init_level == 0; |
| @@ -406,13 +390,29 @@ prepare_next_line: | | | @@ -406,13 +390,29 @@ prepare_next_line: |
406 | && ps.nparen > 0)) | | 390 | && ps.nparen > 0)) |
407 | ps.ind_level = ps.ind_level_follow; | | 391 | ps.ind_level = ps.ind_level_follow; |
408 | ps.line_start_nparen = ps.nparen; | | 392 | ps.line_start_nparen = ps.nparen; |
409 | ps.want_blank = false; | | 393 | ps.want_blank = false; |
410 | | | 394 | |
411 | if (ps.nparen > 0) { | | 395 | if (ps.nparen > 0) { |
412 | /* TODO: explain what negative indentation means */ | | 396 | /* TODO: explain what negative indentation means */ |
413 | paren_indent = -1 - ps.paren[ps.nparen - 1].indent; | | 397 | paren_indent = -1 - ps.paren[ps.nparen - 1].indent; |
414 | debug_println("paren_indent is now %d", paren_indent); | | 398 | debug_println("paren_indent is now %d", paren_indent); |
415 | } | | 399 | } |
416 | | | 400 | |
417 | out.line_kind = lk_other; | | 401 | out.line_kind = lk_other; |
418 | } | | 402 | } |
| | | 403 | |
| | | 404 | void |
| | | 405 | output_finish(void) |
| | | 406 | { |
| | | 407 | if (lab.len > 0 || code.len > 0 || com.len > 0) |
| | | 408 | output_line(); |
| | | 409 | if (indent_enabled == indent_on) { |
| | | 410 | if (buffered_blank_lines > 1) |
| | | 411 | buffered_blank_lines = 1; |
| | | 412 | write_buffered_blank_lines(); |
| | | 413 | } else { |
| | | 414 | indent_enabled = indent_last_off_line; |
| | | 415 | output_line(); |
| | | 416 | } |
| | | 417 | fflush(output); |
| | | 418 | } |