Sat Jun 10 11:01:58 2023 UTC ()
indent: distinguish blank lines from newline characters


(rillig)
diff -r1.47 -r1.48 src/usr.bin/indent/debug.c
diff -r1.213 -r1.214 src/usr.bin/indent/io.c

cvs diff -r1.47 -r1.48 src/usr.bin/indent/debug.c (switch to unified diff)

--- src/usr.bin/indent/debug.c 2023/06/10 09:31:41 1.47
+++ src/usr.bin/indent/debug.c 2023/06/10 11:01:58 1.48
@@ -1,400 +1,400 @@ @@ -1,400 +1,400 @@
1/* $NetBSD: debug.c,v 1.47 2023/06/10 09:31:41 rillig Exp $ */ 1/* $NetBSD: debug.c,v 1.48 2023/06/10 11:01:58 rillig Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2023 The NetBSD Foundation, Inc. 4 * Copyright (c) 2023 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Roland Illig <rillig@NetBSD.org>. 8 * by Roland Illig <rillig@NetBSD.org>.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33__RCSID("$NetBSD: debug.c,v 1.47 2023/06/10 09:31:41 rillig Exp $"); 33__RCSID("$NetBSD: debug.c,v 1.48 2023/06/10 11:01:58 rillig Exp $");
34 34
35#include <stdarg.h> 35#include <stdarg.h>
36#include <string.h> 36#include <string.h>
37 37
38#include "indent.h" 38#include "indent.h"
39 39
40#ifdef debug 40#ifdef debug
41 41
42static struct { 42static struct {
43 /*- 43 /*-
44 * false show only the changes to the parser state 44 * false show only the changes to the parser state
45 * true show unchanged parts of the parser state as well 45 * true show unchanged parts of the parser state as well
46 */ 46 */
47 bool full_parser_state; 47 bool full_parser_state;
48} config = { 48} config = {
49 .full_parser_state = false, 49 .full_parser_state = false,
50}; 50};
51 51
52const char *const lsym_name[] = { 52const char *const lsym_name[] = {
53 "eof", 53 "eof",
54 "preprocessing", 54 "preprocessing",
55 "newline", 55 "newline",
56 "comment", 56 "comment",
57 "lparen", 57 "lparen",
58 "rparen", 58 "rparen",
59 "lbracket", 59 "lbracket",
60 "rbracket", 60 "rbracket",
61 "lbrace", 61 "lbrace",
62 "rbrace", 62 "rbrace",
63 "period", 63 "period",
64 "unary_op", 64 "unary_op",
65 "sizeof", 65 "sizeof",
66 "offsetof", 66 "offsetof",
67 "postfix_op", 67 "postfix_op",
68 "binary_op", 68 "binary_op",
69 "question", 69 "question",
70 "question_colon", 70 "question_colon",
71 "comma", 71 "comma",
72 "typedef", 72 "typedef",
73 "modifier", 73 "modifier",
74 "tag", 74 "tag",
75 "type_outside_parentheses", 75 "type_outside_parentheses",
76 "type_in_parentheses", 76 "type_in_parentheses",
77 "word", 77 "word",
78 "funcname", 78 "funcname",
79 "label_colon", 79 "label_colon",
80 "other_colon", 80 "other_colon",
81 "semicolon", 81 "semicolon",
82 "case", 82 "case",
83 "default", 83 "default",
84 "do", 84 "do",
85 "else", 85 "else",
86 "for", 86 "for",
87 "if", 87 "if",
88 "switch", 88 "switch",
89 "while", 89 "while",
90 "return", 90 "return",
91}; 91};
92 92
93const char *const psym_name[] = { 93const char *const psym_name[] = {
94 "-", 94 "-",
95 "{block", 95 "{block",
96 "{struct", 96 "{struct",
97 "{union", 97 "{union",
98 "{enum", 98 "{enum",
99 "}", 99 "}",
100 "decl", 100 "decl",
101 "stmt", 101 "stmt",
102 "stmt_list", 102 "stmt_list",
103 "for_exprs", 103 "for_exprs",
104 "if_expr", 104 "if_expr",
105 "if_expr_stmt", 105 "if_expr_stmt",
106 "if_expr_stmt_else", 106 "if_expr_stmt_else",
107 "else", 107 "else",
108 "switch_expr", 108 "switch_expr",
109 "do", 109 "do",
110 "do_stmt", 110 "do_stmt",
111 "while_expr", 111 "while_expr",
112}; 112};
113 113
114static const char *const declaration_name[] = { 114static const char *const declaration_name[] = {
115 "no", 115 "no",
116 "begin", 116 "begin",
117 "end", 117 "end",
118}; 118};
119 119
120const char *const paren_level_cast_name[] = { 120const char *const paren_level_cast_name[] = {
121 "(unknown cast)", 121 "(unknown cast)",
122 "(maybe cast)", 122 "(maybe cast)",
123 "(no cast)", 123 "(no cast)",
124}; 124};
125 125
126const char *const line_kind_name[] = { 126const char *const line_kind_name[] = {
127 "other", 127 "other",
128 "blank", 128 "blank",
129 "#if", 129 "#if",
130 "#endif", 130 "#endif",
131 "stmt head", 131 "stmt head",
132 "}", 132 "}",
133 "block comment", 133 "block comment",
134 "case/default", 134 "case/default",
135}; 135};
136 136
137static const char *const extra_expr_indent_name[] = { 137static const char *const extra_expr_indent_name[] = {
138 "no", 138 "no",
139 "maybe", 139 "maybe",
140 "last", 140 "last",
141}; 141};
142 142
143static struct { 143static struct {
144 struct parser_state prev_ps; 144 struct parser_state prev_ps;
145 bool ps_first; 145 bool ps_first;
146 const char *heading; 146 const char *heading;
147 unsigned wrote_newlines; 147 unsigned wrote_newlines;
148} state = { 148} state = {
149 .ps_first = true, 149 .ps_first = true,
150 .wrote_newlines = 1, 150 .wrote_newlines = 1,
151}; 151};
152 152
153void 153void
154debug_printf(const char *fmt, ...) 154debug_printf(const char *fmt, ...)
155{ 155{
156 FILE *f = output == stdout ? stderr : stdout; 156 FILE *f = output == stdout ? stderr : stdout;
157 va_list ap; 157 va_list ap;
158 158
159 if (state.heading != NULL) { 159 if (state.heading != NULL) {
160 fprintf(f, "%s\n", state.heading); 160 fprintf(f, "%s\n", state.heading);
161 state.heading = NULL; 161 state.heading = NULL;
162 } 162 }
163 va_start(ap, fmt); 163 va_start(ap, fmt);
164 vfprintf(f, fmt, ap); 164 vfprintf(f, fmt, ap);
165 va_end(ap); 165 va_end(ap);
166 state.wrote_newlines = 0; 166 state.wrote_newlines = 0;
167} 167}
168 168
169void 169void
170debug_println(const char *fmt, ...) 170debug_println(const char *fmt, ...)
171{ 171{
172 FILE *f = output == stdout ? stderr : stdout; 172 FILE *f = output == stdout ? stderr : stdout;
173 va_list ap; 173 va_list ap;
174 174
175 if (state.heading != NULL) { 175 if (state.heading != NULL) {
176 fprintf(f, "%s\n", state.heading); 176 fprintf(f, "%s\n", state.heading);
177 state.heading = NULL; 177 state.heading = NULL;
178 state.wrote_newlines = 1; 178 state.wrote_newlines = 1;
179 } 179 }
180 va_start(ap, fmt); 180 va_start(ap, fmt);
181 vfprintf(f, fmt, ap); 181 vfprintf(f, fmt, ap);
182 va_end(ap); 182 va_end(ap);
183 fprintf(f, "\n"); 183 fprintf(f, "\n");
184 state.wrote_newlines = fmt[0] == '\0' ? state.wrote_newlines + 1 : 1; 184 state.wrote_newlines = fmt[0] == '\0' ? state.wrote_newlines + 1 : 1;
185} 185}
186 186
187void 187void
188debug_blank_line(void) 188debug_blank_line(void)
189{ 189{
190 while (state.wrote_newlines < 2) 190 while (state.wrote_newlines < 2)
191 debug_println(""); 191 debug_println("");
192} 192}
193 193
194void 194void
195debug_vis_range(const char *prefix, const char *s, size_t len, 195debug_vis_range(const char *prefix, const char *s, size_t len,
196 const char *suffix) 196 const char *suffix)
197{ 197{
198 debug_printf("%s", prefix); 198 debug_printf("%s", prefix);
199 for (size_t i = 0; i < len; i++) { 199 for (size_t i = 0; i < len; i++) {
200 const char *p = s + i; 200 const char *p = s + i;
201 if (*p == '\\' || *p == '"') 201 if (*p == '\\' || *p == '"')
202 debug_printf("\\%c", *p); 202 debug_printf("\\%c", *p);
203 else if (isprint((unsigned char)*p)) 203 else if (isprint((unsigned char)*p))
204 debug_printf("%c", *p); 204 debug_printf("%c", *p);
205 else if (*p == '\n') 205 else if (*p == '\n')
206 debug_printf("\\n"); 206 debug_printf("\\n");
207 else if (*p == '\t') 207 else if (*p == '\t')
208 debug_printf("\\t"); 208 debug_printf("\\t");
209 else 209 else
210 debug_printf("\\x%02x", (unsigned char)*p); 210 debug_printf("\\x%02x", (unsigned char)*p);
211 } 211 }
212 debug_printf("%s", suffix); 212 debug_printf("%s", suffix);
213} 213}
214 214
215void 215void
216debug_print_buf(const char *name, const struct buffer *buf) 216debug_print_buf(const char *name, const struct buffer *buf)
217{ 217{
218 if (buf->len > 0) { 218 if (buf->len > 0) {
219 debug_printf(" %s ", name); 219 debug_printf(" %s ", name);
220 debug_vis_range("\"", buf->s, buf->len, "\""); 220 debug_vis_range("\"", buf->s, buf->len, "\"");
221 } 221 }
222} 222}
223 223
224void 224void
225debug_buffers(void) 225debug_buffers(void)
226{ 226{
227 debug_print_buf("label", &lab); 227 debug_print_buf("label", &lab);
228 debug_print_buf("code", &code); 228 debug_print_buf("code", &code);
229 debug_print_buf("comment", &com); 229 debug_print_buf("comment", &com);
230 debug_println(""); 230 debug_blank_line();
231} 231}
232 232
233static void 233static void
234write_ps_bool(const char *name, bool prev, bool curr) 234write_ps_bool(const char *name, bool prev, bool curr)
235{ 235{
236 if (curr != prev) { 236 if (curr != prev) {
237 char diff = " -+x"[(prev ? 1 : 0) + (curr ? 2 : 0)]; 237 char diff = " -+x"[(prev ? 1 : 0) + (curr ? 2 : 0)];
238 debug_println(" [%c] ps.%s", diff, name); 238 debug_println(" [%c] ps.%s", diff, name);
239 } else if (config.full_parser_state || state.ps_first) 239 } else if (config.full_parser_state || state.ps_first)
240 debug_println(" [%c] ps.%s", curr ? 'x' : ' ', name); 240 debug_println(" [%c] ps.%s", curr ? 'x' : ' ', name);
241} 241}
242 242
243static void 243static void
244write_ps_int(const char *name, int prev, int curr) 244write_ps_int(const char *name, int prev, int curr)
245{ 245{
246 if (curr != prev) 246 if (curr != prev)
247 debug_println(" %3d -> %3d ps.%s", prev, curr, name); 247 debug_println(" %3d -> %3d ps.%s", prev, curr, name);
248 else if (config.full_parser_state || state.ps_first) 248 else if (config.full_parser_state || state.ps_first)
249 debug_println(" %3d ps.%s", curr, name); 249 debug_println(" %3d ps.%s", curr, name);
250} 250}
251 251
252static void 252static void
253write_ps_enum(const char *name, const char *prev, const char *curr) 253write_ps_enum(const char *name, const char *prev, const char *curr)
254{ 254{
255 if (strcmp(prev, curr) != 0) 255 if (strcmp(prev, curr) != 0)
256 debug_println(" %3s -> %3s ps.%s", prev, curr, name); 256 debug_println(" %3s -> %3s ps.%s", prev, curr, name);
257 else if (config.full_parser_state || state.ps_first) 257 else if (config.full_parser_state || state.ps_first)
258 debug_println(" %10s ps.%s", curr, name); 258 debug_println(" %10s ps.%s", curr, name);
259} 259}
260 260
261static bool 261static bool
262ps_paren_has_changed(void) 262ps_paren_has_changed(void)
263{ 263{
264 if (state.prev_ps.nparen != ps.nparen) 264 if (state.prev_ps.nparen != ps.nparen)
265 return true; 265 return true;
266 266
267 const paren_level_props *prev = state.prev_ps.paren, *curr = ps.paren; 267 const paren_level_props *prev = state.prev_ps.paren, *curr = ps.paren;
268 for (int i = 0; i < ps.nparen; i++) 268 for (int i = 0; i < ps.nparen; i++)
269 if (curr[i].indent != prev[i].indent 269 if (curr[i].indent != prev[i].indent
270 || curr[i].cast != prev[i].cast) 270 || curr[i].cast != prev[i].cast)
271 return true; 271 return true;
272 return false; 272 return false;
273} 273}
274 274
275static void 275static void
276debug_ps_paren(void) 276debug_ps_paren(void)
277{ 277{
278 if (!config.full_parser_state && !ps_paren_has_changed() 278 if (!config.full_parser_state && !ps_paren_has_changed()
279 && !state.ps_first) 279 && !state.ps_first)
280 return; 280 return;
281 281
282 debug_printf(" ps.paren:"); 282 debug_printf(" ps.paren:");
283 for (int i = 0; i < ps.nparen; i++) { 283 for (int i = 0; i < ps.nparen; i++) {
284 debug_printf(" %s%d", 284 debug_printf(" %s%d",
285 paren_level_cast_name[ps.paren[i].cast], 285 paren_level_cast_name[ps.paren[i].cast],
286 ps.paren[i].indent); 286 ps.paren[i].indent);
287 } 287 }
288 if (ps.nparen == 0) 288 if (ps.nparen == 0)
289 debug_printf(" none"); 289 debug_printf(" none");
290 debug_println(""); 290 debug_blank_line();
291} 291}
292 292
293static bool 293static bool
294ps_di_stack_has_changed(void) 294ps_di_stack_has_changed(void)
295{ 295{
296 if (state.prev_ps.decl_level != ps.decl_level) 296 if (state.prev_ps.decl_level != ps.decl_level)
297 return true; 297 return true;
298 for (int i = 0; i < ps.decl_level; i++) 298 for (int i = 0; i < ps.decl_level; i++)
299 if (state.prev_ps.di_stack[i] != ps.di_stack[i]) 299 if (state.prev_ps.di_stack[i] != ps.di_stack[i])
300 return true; 300 return true;
301 return false; 301 return false;
302} 302}
303 303
304static void 304static void
305debug_ps_di_stack(void) 305debug_ps_di_stack(void)
306{ 306{
307 bool changed = ps_di_stack_has_changed(); 307 bool changed = ps_di_stack_has_changed();
308 if (!config.full_parser_state && !changed && !state.ps_first) 308 if (!config.full_parser_state && !changed && !state.ps_first)
309 return; 309 return;
310 310
311 debug_printf(" %s ps.di_stack:", changed ? "->" : " "); 311 debug_printf(" %s ps.di_stack:", changed ? "->" : " ");
312 for (int i = 0; i < ps.decl_level; i++) 312 for (int i = 0; i < ps.decl_level; i++)
313 debug_printf(" %d", ps.di_stack[i]); 313 debug_printf(" %d", ps.di_stack[i]);
314 if (ps.decl_level == 0) 314 if (ps.decl_level == 0)
315 debug_printf(" none"); 315 debug_printf(" none");
316 debug_println(""); 316 debug_blank_line();
317} 317}
318 318
319#define debug_ps_bool(name) \ 319#define debug_ps_bool(name) \
320 write_ps_bool(#name, state.prev_ps.name, ps.name) 320 write_ps_bool(#name, state.prev_ps.name, ps.name)
321#define debug_ps_int(name) \ 321#define debug_ps_int(name) \
322 write_ps_int(#name, state.prev_ps.name, ps.name) 322 write_ps_int(#name, state.prev_ps.name, ps.name)
323#define debug_ps_enum(name, names) \ 323#define debug_ps_enum(name, names) \
324 write_ps_enum(#name, (names)[state.prev_ps.name], (names)[ps.name]) 324 write_ps_enum(#name, (names)[state.prev_ps.name], (names)[ps.name])
325 325
326void 326void
327debug_parser_state(void) 327debug_parser_state(void)
328{ 328{
329 debug_blank_line(); 329 debug_blank_line();
330 debug_println(" ps.prev_lsym = %s", 330 debug_println(" ps.prev_lsym = %s",
331 lsym_name[ps.prev_lsym]); 331 lsym_name[ps.prev_lsym]);
332 332
333 state.heading = "token classification"; 333 state.heading = "token classification";
334 debug_ps_bool(in_stmt_or_decl); 334 debug_ps_bool(in_stmt_or_decl);
335 debug_ps_bool(in_decl); 335 debug_ps_bool(in_decl);
336 debug_ps_bool(in_var_decl); 336 debug_ps_bool(in_var_decl);
337 debug_ps_bool(in_init); 337 debug_ps_bool(in_init);
338 debug_ps_int(init_level); 338 debug_ps_int(init_level);
339 debug_ps_bool(line_has_func_def); 339 debug_ps_bool(line_has_func_def);
340 debug_ps_bool(in_func_def_params); 340 debug_ps_bool(in_func_def_params);
341 debug_ps_bool(line_has_decl); 341 debug_ps_bool(line_has_decl);
342 debug_ps_enum(lbrace_kind, psym_name); 342 debug_ps_enum(lbrace_kind, psym_name);
343 debug_ps_enum(spaced_expr_psym, psym_name); 343 debug_ps_enum(spaced_expr_psym, psym_name);
344 debug_ps_bool(seen_case); 344 debug_ps_bool(seen_case);
345 debug_ps_bool(prev_paren_was_cast); 345 debug_ps_bool(prev_paren_was_cast);
346 debug_ps_int(quest_level); 346 debug_ps_int(quest_level);
347 347
348 state.heading = "indentation of statements and declarations"; 348 state.heading = "indentation of statements and declarations";
349 debug_ps_int(ind_level); 349 debug_ps_int(ind_level);
350 debug_ps_int(ind_level_follow); 350 debug_ps_int(ind_level_follow);
351 debug_ps_bool(in_stmt_cont); 351 debug_ps_bool(in_stmt_cont);
352 debug_ps_int(decl_level); 352 debug_ps_int(decl_level);
353 debug_ps_di_stack(); 353 debug_ps_di_stack();
354 debug_ps_bool(decl_indent_done); 354 debug_ps_bool(decl_indent_done);
355 debug_ps_int(decl_ind); 355 debug_ps_int(decl_ind);
356 debug_ps_bool(tabs_to_var); 356 debug_ps_bool(tabs_to_var);
357 debug_ps_enum(extra_expr_indent, extra_expr_indent_name); 357 debug_ps_enum(extra_expr_indent, extra_expr_indent_name);
358 358
359 // The parser symbol stack is printed in debug_parse_stack instead. 359 // The parser symbol stack is printed in debug_parse_stack instead.
360 360
361 state.heading = "spacing inside a statement or declaration"; 361 state.heading = "spacing inside a statement or declaration";
362 debug_ps_bool(next_unary); 362 debug_ps_bool(next_unary);
363 debug_ps_bool(want_blank); 363 debug_ps_bool(want_blank);
364 debug_ps_int(line_start_nparen); 364 debug_ps_int(line_start_nparen);
365 debug_ps_int(nparen); 365 debug_ps_int(nparen);
366 debug_ps_paren(); 366 debug_ps_paren();
367 367
368 state.heading = "horizontal spacing for comments"; 368 state.heading = "horizontal spacing for comments";
369 debug_ps_int(comment_delta); 369 debug_ps_int(comment_delta);
370 debug_ps_int(n_comment_delta); 370 debug_ps_int(n_comment_delta);
371 debug_ps_int(com_ind); 371 debug_ps_int(com_ind);
372 372
373 state.heading = "vertical spacing"; 373 state.heading = "vertical spacing";
374 debug_ps_bool(break_after_comma); 374 debug_ps_bool(break_after_comma);
375 debug_ps_bool(force_nl); 375 debug_ps_bool(force_nl);
376 debug_ps_enum(declaration, declaration_name); 376 debug_ps_enum(declaration, declaration_name);
377 debug_ps_bool(blank_line_after_decl); 377 debug_ps_bool(blank_line_after_decl);
378 378
379 state.heading = "comments"; 379 state.heading = "comments";
380 debug_ps_bool(curr_col_1); 380 debug_ps_bool(curr_col_1);
381 debug_ps_bool(next_col_1); 381 debug_ps_bool(next_col_1);
382 382
383 state.heading = NULL; 383 state.heading = NULL;
384 debug_blank_line(); 384 debug_blank_line();
385 385
386 state.prev_ps = ps; 386 state.prev_ps = ps;
387 state.ps_first = false; 387 state.ps_first = false;
388} 388}
389 389
390void 390void
391debug_parse_stack(const char *situation) 391debug_parse_stack(const char *situation)
392{ 392{
393 debug_printf("parse stack %s:", situation); 393 debug_printf("parse stack %s:", situation);
394 const struct psym_stack *psyms = &ps.psyms; 394 const struct psym_stack *psyms = &ps.psyms;
395 for (int i = 0; i <= psyms->top; ++i) 395 for (int i = 0; i <= psyms->top; ++i)
396 debug_printf(" %d %s", 396 debug_printf(" %d %s",
397 psyms->ind_level[i], psym_name[psyms->sym[i]]); 397 psyms->ind_level[i], psym_name[psyms->sym[i]]);
398 debug_println(""); 398 debug_blank_line();
399} 399}
400#endif 400#endif

cvs diff -r1.213 -r1.214 src/usr.bin/indent/io.c (switch to unified diff)

--- src/usr.bin/indent/io.c 2023/06/10 08:17:04 1.213
+++ src/usr.bin/indent/io.c 2023/06/10 11:01:58 1.214
@@ -1,421 +1,419 @@ @@ -1,421 +1,419 @@
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
15 * notice, this list of conditions and the following disclaimer. 15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright 16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the 17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution. 18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software 19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement: 20 * must display the following acknowledgement:
21 * This product includes software developed by the University of 21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors. 22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of 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 24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission. 25 * without specific prior written permission.
26 * 26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 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 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
47struct buffer inp; 47struct buffer inp;
48const char *inp_p; 48const char *inp_p;
49 49
50struct output_state out; 50struct output_state out;
51enum indent_enabled indent_enabled; 51enum indent_enabled indent_enabled;
52static int out_ind; /* width of the line that is being written */ 52static int out_ind; /* width of the line that is being written */
53static unsigned wrote_newlines = 2; /* 0 in the middle of a line, 1 after a 53static 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
56static unsigned buffered_blank_lines; 56 * blank lines */
 57static unsigned buffered_newlines; /* not yet written */
57static int paren_indent; 58static int paren_indent;
58 59
59 60
60static void 61static void
61inp_read_next_line(FILE *f) 62inp_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, ' ');
70 buf_add_char(&inp, '\n'); 71 buf_add_char(&inp, '\n');
71 } 72 }
72 had_eof = true; 73 had_eof = true;
73 break; 74 break;
74 } 75 }
75 76
76 if (ch != '\0') 77 if (ch != '\0')
77 buf_add_char(&inp, (char)ch); 78 buf_add_char(&inp, (char)ch);
78 if (ch == '\n') 79 if (ch == '\n')
79 break; 80 break;
80 } 81 }
81 inp_p = inp.s; 82 inp_p = inp.s;
82} 83}
83 84
84void 85void
85inp_read_line(void) 86inp_read_line(void)
86{ 87{
87 if (indent_enabled == indent_on) 88 if (indent_enabled == indent_on)
88 out.indent_off_text.len = 0; 89 out.indent_off_text.len = 0;
89 buf_add_chars(&out.indent_off_text, inp.s, inp.len); 90 buf_add_chars(&out.indent_off_text, inp.s, inp.len);
90 inp_read_next_line(input); 91 inp_read_next_line(input);
91} 92}
92 93
93void 94void
94inp_skip(void) 95inp_skip(void)
95{ 96{
96 inp_p++; 97 inp_p++;
97 if ((size_t)(inp_p - inp.s) >= inp.len) 98 if ((size_t)(inp_p - inp.s) >= inp.len)
98 inp_read_line(); 99 inp_read_line();
99} 100}
100 101
101char 102char
102inp_next(void) 103inp_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
110static void 111static void
111write_newline(void) 112buffer_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
118static void 119static void
119write_buffered_blank_lines(void) 120write_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
127static void 128static void
128write_range(const char *s, size_t len) 129write_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
138static void 139static void
139write_indent(int new_ind) 140write_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
164static bool 165static bool
165want_blank_line(void) 166want_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 }
174 if (opt.blanklines_around_conditional_compilation) { 175 if (opt.blanklines_around_conditional_compilation) {
175 if (out.prev_line_kind != lk_if && out.line_kind == lk_if) 176 if (out.prev_line_kind != lk_if && out.line_kind == lk_if)
176 return true; 177 return true;
177 if (out.prev_line_kind == lk_endif 178 if (out.prev_line_kind == lk_endif
178 && out.line_kind != lk_endif) 179 && out.line_kind != lk_endif)
179 return true; 180 return true;
180 } 181 }
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
190static bool 191static bool
191is_blank_line_optional(void) 192is_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
200static int 201static int
201compute_case_label_indent(void) 202compute_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
210int 211int
211compute_label_indent(void) 212compute_label_indent(void)
212{ 213{
213 if (out.line_kind == lk_case_or_default) 214 if (out.line_kind == lk_case_or_default)
214 return compute_case_label_indent(); 215 return compute_case_label_indent();
215 if (lab.s[0] == '#') 216 if (lab.s[0] == '#')
216 return 0; 217 return 0;
217 return opt.indent_size * (ps.ind_level - 2); 218 return opt.indent_size * (ps.ind_level - 2);
218} 219}
219 220
220static void 221static void
221output_line_label(void) 222output_line_label(void)
222{ 223{
223 write_indent(compute_label_indent()); 224 write_indent(compute_label_indent());
224 write_range(lab.s, lab.len); 225 write_range(lab.s, lab.len);
225} 226}
226 227
227static int 228static int
228compute_code_indent_lineup(int base_ind) 229compute_code_indent_lineup(int base_ind)
229{ 230{
230 int ind = paren_indent; 231 int ind = paren_indent;
231 int overflow = ind_add(ind, code.s, code.len) - opt.max_line_length; 232 int overflow = ind_add(ind, code.s, code.len) - opt.max_line_length;
232 if (overflow >= 0 233 if (overflow >= 0
233 && ind_add(base_ind, code.s, code.len) < opt.max_line_length) { 234 && ind_add(base_ind, code.s, code.len) < opt.max_line_length) {
234 ind -= overflow + 2; 235 ind -= overflow + 2;
235 if (ind < base_ind) 236 if (ind < base_ind)
236 ind = base_ind; 237 ind = base_ind;
237 } 238 }
238 239
239 if (ps.extra_expr_indent != eei_no 240 if (ps.extra_expr_indent != eei_no
240 && ind == base_ind + opt.indent_size) 241 && ind == base_ind + opt.indent_size)
241 ind += opt.continuation_indent; 242 ind += opt.continuation_indent;
242 return ind; 243 return ind;
243} 244}
244 245
245int 246int
246compute_code_indent(void) 247compute_code_indent(void)
247{ 248{
248 int base_ind = ps.ind_level * opt.indent_size; 249 int base_ind = ps.ind_level * opt.indent_size;
249 250
250 if (ps.line_start_nparen == 0) { 251 if (ps.line_start_nparen == 0) {
251 if (ps.psyms.top >= 1 252 if (ps.psyms.top >= 1
252 && ps.psyms.sym[ps.psyms.top - 1] == psym_lbrace_enum) 253 && ps.psyms.sym[ps.psyms.top - 1] == psym_lbrace_enum)
253 return base_ind; 254 return base_ind;
254 if (ps.in_stmt_cont) 255 if (ps.in_stmt_cont)
255 return base_ind + opt.continuation_indent; 256 return base_ind + opt.continuation_indent;
256 return base_ind; 257 return base_ind;
257 } 258 }
258 259
259 if (opt.lineup_to_parens) { 260 if (opt.lineup_to_parens) {
260 if (opt.lineup_to_parens_always) 261 if (opt.lineup_to_parens_always)
261 return paren_indent; 262 return paren_indent;
262 return compute_code_indent_lineup(base_ind); 263 return compute_code_indent_lineup(base_ind);
263 } 264 }
264 265
265 int rel_ind = opt.continuation_indent * ps.line_start_nparen; 266 int rel_ind = opt.continuation_indent * ps.line_start_nparen;
266 if (ps.extra_expr_indent != eei_no && rel_ind == opt.indent_size) 267 if (ps.extra_expr_indent != eei_no && rel_ind == opt.indent_size)
267 rel_ind += opt.continuation_indent; 268 rel_ind += opt.continuation_indent;
268 return base_ind + rel_ind; 269 return base_ind + rel_ind;
269} 270}
270 271
271static void 272static void
272output_line_code(void) 273output_line_code(void)
273{ 274{
274 int target_ind = compute_code_indent(); 275 int target_ind = compute_code_indent();
275 for (int i = 0; i < ps.nparen; i++) { 276 for (int i = 0; i < ps.nparen; i++) {
276 int paren_ind = ps.paren[i].indent; 277 int paren_ind = ps.paren[i].indent;
277 if (paren_ind >= 0) { 278 if (paren_ind >= 0) {
278 ps.paren[i].indent = -1 - (paren_ind + target_ind); 279 ps.paren[i].indent = -1 - (paren_ind + target_ind);
279 debug_println( 280 debug_println(
280 "setting paren_indents[%d] from %d to %d " 281 "setting paren_indents[%d] from %d to %d "
281 "for column %d", 282 "for column %d",
282 i, paren_ind, ps.paren[i].indent, target_ind + 1); 283 i, paren_ind, ps.paren[i].indent, target_ind + 1);
283 } 284 }
284 } 285 }
285 286
286 if (lab.len > 0 && target_ind <= out_ind) 287 if (lab.len > 0 && target_ind <= out_ind)
287 write_range(" ", 1); 288 write_range(" ", 1);
288 write_indent(target_ind); 289 write_indent(target_ind);
289 write_range(code.s, code.len); 290 write_range(code.s, code.len);
290} 291}
291 292
292static void 293static void
293output_line_comment(void) 294output_line_comment(void)
294{ 295{
295 int target_ind = ps.com_ind + ps.comment_delta; 296 int target_ind = ps.com_ind + ps.comment_delta;
296 const char *p; 297 const char *p;
297 298
298 /* consider original indentation in case this is a box comment */ 299 /* consider original indentation in case this is a box comment */
299 for (p = com.s; *p == '\t'; p++) 300 for (p = com.s; *p == '\t'; p++)
300 target_ind += opt.tabsize; 301 target_ind += opt.tabsize;
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
325static void 326static void
326output_line_indented(void) 327output_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 */
365void 368void
366output_line(void) 369output_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();
371 374
372 if (indent_enabled == indent_on) 375 if (indent_enabled == indent_on)
373 output_line_indented(); 376 output_line_indented();
374 else if (indent_enabled == indent_last_off_line) { 377 else if (indent_enabled == indent_last_off_line) {
375 indent_enabled = indent_on; 378 indent_enabled = indent_on;
376 write_range(out.indent_off_text.s, out.indent_off_text.len); 379 write_range(out.indent_off_text.s, out.indent_off_text.len);
377 out.indent_off_text.len = 0; 380 out.indent_off_text.len = 0;
378 } 381 }
379 382
380 lab.len = 0; 383 lab.len = 0;
381 code.len = 0; 384 code.len = 0;
382 com.len = 0; 385 com.len = 0;
383 386
384 ps.line_has_decl = ps.in_decl; 387 ps.line_has_decl = ps.in_decl;
385 ps.line_has_func_def = false; 388 ps.line_has_func_def = false;
386 ps.in_stmt_cont = ps.in_stmt_or_decl 389 ps.in_stmt_cont = ps.in_stmt_or_decl
387 && (!ps.in_decl || ps.in_init) 390 && (!ps.in_decl || ps.in_init)
388 && ps.init_level == 0; 391 && ps.init_level == 0;
389 ps.decl_indent_done = false; 392 ps.decl_indent_done = false;
390 if (ps.extra_expr_indent == eei_last) 393 if (ps.extra_expr_indent == eei_last)
391 ps.extra_expr_indent = eei_no; 394 ps.extra_expr_indent = eei_no;
392 if (!(ps.psyms.sym[ps.psyms.top] == psym_if_expr_stmt_else 395 if (!(ps.psyms.sym[ps.psyms.top] == psym_if_expr_stmt_else
393 && ps.nparen > 0)) 396 && ps.nparen > 0))
394 ps.ind_level = ps.ind_level_follow; 397 ps.ind_level = ps.ind_level_follow;
395 ps.line_start_nparen = ps.nparen; 398 ps.line_start_nparen = ps.nparen;
396 ps.want_blank = false; 399 ps.want_blank = false;
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
407void 410void
408output_finish(void) 411output_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}