Sat Jun 17 22:28:49 2023 UTC ()
indent: miscellaneous cleanups

No binary change.


(rillig)
diff -r1.66 -r1.67 src/usr.bin/indent/debug.c
diff -r1.379 -r1.380 src/usr.bin/indent/indent.c
diff -r1.227 -r1.228 src/usr.bin/indent/io.c
diff -r1.230 -r1.231 src/usr.bin/indent/lexi.c
diff -r1.77 -r1.78 src/usr.bin/indent/parse.c
diff -r1.166 -r1.167 src/usr.bin/indent/pr_comment.c

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

--- src/usr.bin/indent/debug.c 2023/06/16 23:51:32 1.66
+++ src/usr.bin/indent/debug.c 2023/06/17 22:28:49 1.67
@@ -1,392 +1,392 @@ @@ -1,392 +1,392 @@
1/* $NetBSD: debug.c,v 1.66 2023/06/16 23:51:32 rillig Exp $ */ 1/* $NetBSD: debug.c,v 1.67 2023/06/17 22:28:49 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.66 2023/06/16 23:51:32 rillig Exp $"); 33__RCSID("$NetBSD: debug.c,v 1.67 2023/06/17 22:28:49 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 // false show only the changes to the parser state 43 // false show only the changes to the parser state
44 // true show unchanged parts of the parser state as well 44 // true show unchanged parts of the parser state as well
45 bool full_parser_state; 45 bool full_parser_state;
46} config = { 46} config = {
47 .full_parser_state = false, 47 .full_parser_state = false,
48}; 48};
49 49
50const char *const lsym_name[] = { 50const char *const lsym_name[] = {
51 "eof", 51 "eof",
52 "preprocessing", 52 "preprocessing",
53 "newline", 53 "newline",
54 "comment", 54 "comment",
55 "lparen", 55 "lparen",
56 "rparen", 56 "rparen",
57 "lbracket", 57 "lbracket",
58 "rbracket", 58 "rbracket",
59 "lbrace", 59 "lbrace",
60 "rbrace", 60 "rbrace",
61 "period", 61 "period",
62 "unary_op", 62 "unary_op",
63 "sizeof", 63 "sizeof",
64 "offsetof", 64 "offsetof",
65 "postfix_op", 65 "postfix_op",
66 "binary_op", 66 "binary_op",
67 "question", 67 "question",
68 "question_colon", 68 "question_colon",
69 "comma", 69 "comma",
70 "typedef", 70 "typedef",
71 "modifier", 71 "modifier",
72 "tag", 72 "tag",
73 "type", 73 "type",
74 "word", 74 "word",
75 "funcname", 75 "funcname",
76 "label_colon", 76 "label_colon",
77 "other_colon", 77 "other_colon",
78 "semicolon", 78 "semicolon",
79 "case", 79 "case",
80 "default", 80 "default",
81 "do", 81 "do",
82 "else", 82 "else",
83 "for", 83 "for",
84 "if", 84 "if",
85 "switch", 85 "switch",
86 "while", 86 "while",
87 "return", 87 "return",
88}; 88};
89 89
90const char *const psym_name[] = { 90const char *const psym_name[] = {
91 "-", 91 "-",
92 "{block", 92 "{block",
93 "{struct", 93 "{struct",
94 "{union", 94 "{union",
95 "{enum", 95 "{enum",
96 "}", 96 "}",
97 "decl", 97 "decl",
98 "stmt", 98 "stmt",
99 "for_exprs", 99 "for_exprs",
100 "if_expr", 100 "if_expr",
101 "if_expr_stmt", 101 "if_expr_stmt",
102 "if_expr_stmt_else", 102 "if_expr_stmt_else",
103 "else", 103 "else",
104 "switch_expr", 104 "switch_expr",
105 "do", 105 "do",
106 "do_stmt", 106 "do_stmt",
107 "while_expr", 107 "while_expr",
108}; 108};
109 109
110static const char *const declaration_name[] = { 110static const char *const declaration_name[] = {
111 "no", 111 "no",
112 "begin", 112 "begin",
113 "end", 113 "end",
114}; 114};
115 115
116const char *const paren_level_cast_name[] = { 116const char *const paren_level_cast_name[] = {
117 "(unknown cast)", 117 "(unknown cast)",
118 "(maybe cast)", 118 "(maybe cast)",
119 "(no cast)", 119 "(no cast)",
120}; 120};
121 121
122const char *const line_kind_name[] = { 122const char *const line_kind_name[] = {
123 "other", 123 "other",
124 "blank", 124 "blank",
125 "#if", 125 "#if",
126 "#endif", 126 "#endif",
127 "#other", 127 "#other",
128 "stmt head", 128 "stmt head",
129 "}", 129 "}",
130 "block comment", 130 "block comment",
131 "case/default", 131 "case/default",
132}; 132};
133 133
134static const char *const extra_expr_indent_name[] = { 134static const char *const extra_expr_indent_name[] = {
135 "no", 135 "no",
136 "maybe", 136 "maybe",
137 "last", 137 "last",
138}; 138};
139 139
140static struct { 140static struct {
141 struct parser_state prev_ps; 141 struct parser_state prev_ps;
142 bool ps_first; 142 bool ps_first;
143 const char *heading; 143 const char *heading;
144 unsigned wrote_newlines; 144 unsigned wrote_newlines;
145} state = { 145} state = {
146 .ps_first = true, 146 .ps_first = true,
147 .wrote_newlines = 1, 147 .wrote_newlines = 1,
148}; 148};
149 149
150void 150void
151debug_printf(const char *fmt, ...) 151debug_printf(const char *fmt, ...)
152{ 152{
153 FILE *f = output == stdout ? stderr : stdout; 153 FILE *f = output == stdout ? stderr : stdout;
154 va_list ap; 154 va_list ap;
155 155
156 if (state.heading != NULL) { 156 if (state.heading != NULL) {
157 fprintf(f, "%s\n", state.heading); 157 fprintf(f, "%s\n", state.heading);
158 state.heading = NULL; 158 state.heading = NULL;
159 } 159 }
160 va_start(ap, fmt); 160 va_start(ap, fmt);
161 vfprintf(f, fmt, ap); 161 vfprintf(f, fmt, ap);
162 va_end(ap); 162 va_end(ap);
163 state.wrote_newlines = 0; 163 state.wrote_newlines = 0;
164} 164}
165 165
166void 166void
167debug_println(const char *fmt, ...) 167debug_println(const char *fmt, ...)
168{ 168{
169 FILE *f = output == stdout ? stderr : stdout; 169 FILE *f = output == stdout ? stderr : stdout;
170 va_list ap; 170 va_list ap;
171 171
172 if (state.heading != NULL) { 172 if (state.heading != NULL) {
173 fprintf(f, "%s\n", state.heading); 173 fprintf(f, "%s\n", state.heading);
174 state.heading = NULL; 174 state.heading = NULL;
175 state.wrote_newlines = 1; 175 state.wrote_newlines = 1;
176 } 176 }
177 va_start(ap, fmt); 177 va_start(ap, fmt);
178 vfprintf(f, fmt, ap); 178 vfprintf(f, fmt, ap);
179 va_end(ap); 179 va_end(ap);
180 fprintf(f, "\n"); 180 fprintf(f, "\n");
181 state.wrote_newlines = fmt[0] == '\0' ? state.wrote_newlines + 1 : 1; 181 state.wrote_newlines = fmt[0] == '\0' ? state.wrote_newlines + 1 : 1;
182} 182}
183 183
184void 184void
185debug_blank_line(void) 185debug_blank_line(void)
186{ 186{
187 while (state.wrote_newlines < 2) 187 while (state.wrote_newlines < 2)
188 debug_println(""); 188 debug_println("");
189} 189}
190 190
191void 191void
192debug_vis_range(const char *s, size_t len) 192debug_vis_range(const char *s, size_t len)
193{ 193{
194 debug_printf("\""); 194 debug_printf("\"");
195 for (size_t i = 0; i < len; i++) { 195 for (size_t i = 0; i < len; i++) {
196 const char *p = s + i; 196 const char *p = s + i;
197 if (*p == '\\' || *p == '"') 197 if (*p == '\\' || *p == '"')
198 debug_printf("\\%c", *p); 198 debug_printf("\\%c", *p);
199 else if (isprint((unsigned char)*p)) 199 else if (isprint((unsigned char)*p))
200 debug_printf("%c", *p); 200 debug_printf("%c", *p);
201 else if (*p == '\n') 201 else if (*p == '\n')
202 debug_printf("\\n"); 202 debug_printf("\\n");
203 else if (*p == '\t') 203 else if (*p == '\t')
204 debug_printf("\\t"); 204 debug_printf("\\t");
205 else 205 else
206 debug_printf("\\x%02x", (unsigned char)*p); 206 debug_printf("\\x%02x", (unsigned char)*p);
207 } 207 }
208 debug_printf("\""); 208 debug_printf("\"");
209} 209}
210 210
211void 211void
212debug_print_buf(const char *name, const struct buffer *buf) 212debug_print_buf(const char *name, const struct buffer *buf)
213{ 213{
214 if (buf->len > 0) { 214 if (buf->len > 0) {
215 debug_printf(" %s ", name); 215 debug_printf(" %s ", name);
216 debug_vis_range(buf->s, buf->len); 216 debug_vis_range(buf->s, buf->len);
217 } 217 }
218} 218}
219 219
220void 220void
221debug_buffers(void) 221debug_buffers(void)
222{ 222{
223 debug_print_buf("label", &lab); 223 debug_print_buf("label", &lab);
224 debug_print_buf("code", &code); 224 debug_print_buf("code", &code);
225 debug_print_buf("comment", &com); 225 debug_print_buf("comment", &com);
226 debug_blank_line(); 226 debug_blank_line();
227} 227}
228 228
229static void 229static void
230debug_ps_bool_member(const char *name, bool prev, bool curr) 230debug_ps_bool_member(const char *name, bool prev, bool curr)
231{ 231{
232 if (!state.ps_first && curr != prev) { 232 if (!state.ps_first && curr != prev) {
233 char diff = " -+x"[(prev ? 1 : 0) + (curr ? 2 : 0)]; 233 char diff = " -+x"[(prev ? 1 : 0) + (curr ? 2 : 0)];
234 debug_println(" [%c] ps.%s", diff, name); 234 debug_println(" [%c] ps.%s", diff, name);
235 } else if (config.full_parser_state || state.ps_first) 235 } else if (config.full_parser_state || state.ps_first)
236 debug_println(" [%c] ps.%s", curr ? 'x' : ' ', name); 236 debug_println(" [%c] ps.%s", curr ? 'x' : ' ', name);
237} 237}
238 238
239static void 239static void
240debug_ps_int_member(const char *name, int prev, int curr) 240debug_ps_int_member(const char *name, int prev, int curr)
241{ 241{
242 if (!state.ps_first && curr != prev) 242 if (!state.ps_first && curr != prev)
243 debug_println(" %3d -> %3d ps.%s", prev, curr, name); 243 debug_println(" %3d -> %3d ps.%s", prev, curr, name);
244 else if (config.full_parser_state || state.ps_first) 244 else if (config.full_parser_state || state.ps_first)
245 debug_println(" %3d ps.%s", curr, name); 245 debug_println(" %3d ps.%s", curr, name);
246} 246}
247 247
248static void 248static void
249debug_ps_enum_member(const char *name, const char *prev, const char *curr) 249debug_ps_enum_member(const char *name, const char *prev, const char *curr)
250{ 250{
251 if (!state.ps_first && strcmp(prev, curr) != 0) 251 if (!state.ps_first && strcmp(prev, curr) != 0)
252 debug_println(" %3s -> %3s ps.%s", prev, curr, name); 252 debug_println(" %3s -> %3s ps.%s", prev, curr, name);
253 else if (config.full_parser_state || state.ps_first) 253 else if (config.full_parser_state || state.ps_first)
254 debug_println(" %10s ps.%s", curr, name); 254 debug_println(" %10s ps.%s", curr, name);
255} 255}
256 256
257static bool 257static bool
258paren_stack_equal(const struct paren_stack *a, const struct paren_stack *b) 258paren_stack_equal(const struct paren_stack *a, const struct paren_stack *b)
259{ 259{
260 if (a->len != b->len) 260 if (a->len != b->len)
261 return false; 261 return false;
262 262
263 for (size_t i = 0, n = a->len; i < n; i++) 263 for (size_t i = 0, n = a->len; i < n; i++)
264 if (a->item[i].indent != b->item[i].indent 264 if (a->item[i].indent != b->item[i].indent
265 || a->item[i].cast != b->item[i].cast) 265 || a->item[i].cast != b->item[i].cast)
266 return true; 266 return true;
267 return false; 267 return false;
268} 268}
269 269
270static void 270static void
271debug_ps_paren(void) 271debug_ps_paren(void)
272{ 272{
273 if (!config.full_parser_state 273 if (!config.full_parser_state
274 && paren_stack_equal(&state.prev_ps.paren, &ps.paren) 274 && paren_stack_equal(&state.prev_ps.paren, &ps.paren)
275 && !state.ps_first) 275 && !state.ps_first)
276 return; 276 return;
277 277
278 debug_printf(" ps.paren:"); 278 debug_printf(" ps.paren:");
279 for (size_t i = 0; i < ps.paren.len; i++) { 279 for (size_t i = 0; i < ps.paren.len; i++) {
280 debug_printf(" %s%d", 280 debug_printf(" %s%d",
281 paren_level_cast_name[ps.paren.item[i].cast], 281 paren_level_cast_name[ps.paren.item[i].cast],
282 ps.paren.item[i].indent); 282 ps.paren.item[i].indent);
283 } 283 }
284 if (ps.paren.len == 0) 284 if (ps.paren.len == 0)
285 debug_printf(" none"); 285 debug_printf(" none");
286 debug_println(""); 286 debug_println("");
287} 287}
288 288
289static bool 289static bool
290ps_di_stack_has_changed(void) 290ps_di_stack_has_changed(void)
291{ 291{
292 if (state.prev_ps.decl_level != ps.decl_level) 292 if (state.prev_ps.decl_level != ps.decl_level)
293 return true; 293 return true;
294 for (int i = 0; i < ps.decl_level; i++) 294 for (int i = 0; i < ps.decl_level; i++)
295 if (state.prev_ps.di_stack[i] != ps.di_stack[i]) 295 if (state.prev_ps.di_stack[i] != ps.di_stack[i])
296 return true; 296 return true;
297 return false; 297 return false;
298} 298}
299 299
300static void 300static void
301debug_ps_di_stack(void) 301debug_ps_di_stack(void)
302{ 302{
303 bool changed = ps_di_stack_has_changed(); 303 bool changed = ps_di_stack_has_changed();
304 if (!config.full_parser_state && !changed && !state.ps_first) 304 if (!config.full_parser_state && !changed && !state.ps_first)
305 return; 305 return;
306 306
307 debug_printf(" %s ps.di_stack:", changed ? "->" : " "); 307 debug_printf(" %s ps.di_stack:", changed ? "->" : " ");
308 for (int i = 0; i < ps.decl_level; i++) 308 for (int i = 0; i < ps.decl_level; i++)
309 debug_printf(" %d", ps.di_stack[i]); 309 debug_printf(" %d", ps.di_stack[i]);
310 if (ps.decl_level == 0) 310 if (ps.decl_level == 0)
311 debug_printf(" none"); 311 debug_printf(" none");
312 debug_println(""); 312 debug_println("");
313} 313}
314 314
315#define debug_ps_bool(name) \ 315#define debug_ps_bool(name) \
316 debug_ps_bool_member(#name, state.prev_ps.name, ps.name) 316 debug_ps_bool_member(#name, state.prev_ps.name, ps.name)
317#define debug_ps_int(name) \ 317#define debug_ps_int(name) \
318 debug_ps_int_member(#name, state.prev_ps.name, ps.name) 318 debug_ps_int_member(#name, state.prev_ps.name, ps.name)
319#define debug_ps_enum(name, names) \ 319#define debug_ps_enum(name, names) \
320 debug_ps_enum_member(#name, (names)[state.prev_ps.name], \ 320 debug_ps_enum_member(#name, (names)[state.prev_ps.name], \
321 (names)[ps.name]) 321 (names)[ps.name])
322 322
323void 323void
324debug_parser_state(void) 324debug_parser_state(void)
325{ 325{
326 debug_blank_line(); 326 debug_blank_line();
327 327
328 state.heading = "token classification"; 328 state.heading = "token classification";
329 debug_ps_enum(prev_lsym, lsym_name); 329 debug_ps_enum(prev_lsym, lsym_name);
330 debug_ps_bool(in_stmt_or_decl); 330 debug_ps_bool(in_stmt_or_decl);
331 debug_ps_bool(in_decl); 331 debug_ps_bool(in_decl);
332 debug_ps_bool(in_typedef_decl); 332 debug_ps_bool(in_typedef_decl);
333 debug_ps_bool(in_var_decl); 333 debug_ps_bool(in_var_decl);
334 debug_ps_bool(in_init); 334 debug_ps_bool(in_init);
335 debug_ps_int(init_level); 335 debug_ps_int(init_level);
336 debug_ps_bool(line_has_func_def); 336 debug_ps_bool(line_has_func_def);
337 debug_ps_bool(in_func_def_params); 337 debug_ps_bool(in_func_def_params);
338 debug_ps_bool(line_has_decl); 338 debug_ps_bool(line_has_decl);
339 debug_ps_enum(lbrace_kind, psym_name); 339 debug_ps_enum(lbrace_kind, psym_name);
340 debug_ps_enum(spaced_expr_psym, psym_name); 340 debug_ps_enum(spaced_expr_psym, psym_name);
341 debug_ps_bool(seen_case); 341 debug_ps_bool(seen_case);
342 debug_ps_bool(prev_paren_was_cast); 342 debug_ps_bool(prev_paren_was_cast);
343 debug_ps_int(quest_level); 343 debug_ps_int(quest_level);
344 344
345 state.heading = "indentation of statements and declarations"; 345 state.heading = "indentation of statements and declarations";
346 debug_ps_int(ind_level); 346 debug_ps_int(ind_level);
347 debug_ps_int(ind_level_follow); 347 debug_ps_int(ind_level_follow);
348 debug_ps_bool(line_is_stmt_cont); 348 debug_ps_bool(line_is_stmt_cont);
349 debug_ps_int(decl_level); 349 debug_ps_int(decl_level);
350 debug_ps_di_stack(); 350 debug_ps_di_stack();
351 debug_ps_bool(decl_indent_done); 351 debug_ps_bool(decl_indent_done);
352 debug_ps_int(decl_ind); 352 debug_ps_int(decl_ind);
353 debug_ps_bool(tabs_to_var); 353 debug_ps_bool(tabs_to_var);
354 debug_ps_enum(extra_expr_indent, extra_expr_indent_name); 354 debug_ps_enum(extra_expr_indent, extra_expr_indent_name);
355 355
356 // The parser symbol stack is printed in debug_psyms_stack instead. 356 // The parser symbol stack is printed in debug_psyms_stack instead.
357 357
358 state.heading = "spacing inside a statement or declaration"; 358 state.heading = "spacing inside a statement or declaration";
359 debug_ps_bool(next_unary); 359 debug_ps_bool(next_unary);
360 debug_ps_bool(want_blank); 360 debug_ps_bool(want_blank);
361 debug_ps_int(ind_paren_level); 361 debug_ps_int(ind_paren_level);
362 debug_ps_paren(); 362 debug_ps_paren();
363 363
364 state.heading = "indentation of comments"; 364 state.heading = "indentation of comments";
365 debug_ps_int(comment_ind); 365 debug_ps_int(comment_ind);
366 debug_ps_int(comment_shift); 366 debug_ps_int(comment_shift);
367 debug_ps_bool(comment_cont); 367 debug_ps_bool(comment_cont);
368 368
369 state.heading = "vertical spacing"; 369 state.heading = "vertical spacing";
370 debug_ps_bool(break_after_comma); 370 debug_ps_bool(break_after_comma);
371 debug_ps_bool(want_newline); 371 debug_ps_bool(want_newline);
372 debug_ps_enum(declaration, declaration_name); 372 debug_ps_enum(declaration, declaration_name);
373 debug_ps_bool(blank_line_after_decl); 373 debug_ps_bool(blank_line_after_decl);
374 374
375 state.heading = NULL; 375 state.heading = NULL;
376 debug_blank_line(); 376 debug_blank_line();
377 377
378 state.prev_ps = ps; 378 state.prev_ps = ps;
379 state.ps_first = false; 379 state.ps_first = false;
380} 380}
381 381
382void 382void
383debug_psyms_stack(const char *situation) 383debug_psyms_stack(const char *situation)
384{ 384{
385 debug_printf("parse stack %s:", situation); 385 debug_printf("parse stack %s:", situation);
386 const struct psym_stack *psyms = &ps.psyms; 386 const struct psym_stack *psyms = &ps.psyms;
387 for (size_t i = 0; i < psyms->len; ++i) 387 for (size_t i = 0; i < psyms->len; i++)
388 debug_printf(" %d %s", 388 debug_printf(" %d %s",
389 psyms->ind_level[i], psym_name[psyms->sym[i]]); 389 psyms->ind_level[i], psym_name[psyms->sym[i]]);
390 debug_println(""); 390 debug_println("");
391} 391}
392#endif 392#endif

cvs diff -r1.379 -r1.380 src/usr.bin/indent/indent.c (switch to unified diff)

--- src/usr.bin/indent/indent.c 2023/06/16 23:51:32 1.379
+++ src/usr.bin/indent/indent.c 2023/06/17 22:28:49 1.380
@@ -1,1137 +1,1137 @@ @@ -1,1137 +1,1137 @@
1/* $NetBSD: indent.c,v 1.379 2023/06/16 23:51:32 rillig Exp $ */ 1/* $NetBSD: indent.c,v 1.380 2023/06/17 22:28:49 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) 1976 Board of Trustees of the University of Illinois. 7 * Copyright (c) 1976 Board of Trustees of the University of Illinois.
8 * Copyright (c) 1980, 1993 8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved. 9 * The Regents of the University of California. 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: indent.c,v 1.379 2023/06/16 23:51:32 rillig Exp $"); 41__RCSID("$NetBSD: indent.c,v 1.380 2023/06/17 22:28:49 rillig Exp $");
42 42
43#include <sys/param.h> 43#include <sys/param.h>
44#include <err.h> 44#include <err.h>
45#include <stdarg.h> 45#include <stdarg.h>
46#include <stdio.h> 46#include <stdio.h>
47#include <stdlib.h> 47#include <stdlib.h>
48#include <string.h> 48#include <string.h>
49 49
50#include "indent.h" 50#include "indent.h"
51 51
52struct options opt = { 52struct options opt = {
53 .brace_same_line = true, 53 .brace_same_line = true,
54 .comment_delimiter_on_blank_line = true, 54 .comment_delimiter_on_blank_line = true,
55 .cuddle_else = true, 55 .cuddle_else = true,
56 .comment_column = 33, 56 .comment_column = 33,
57 .decl_indent = 16, 57 .decl_indent = 16,
58 .else_if_in_same_line = true, 58 .else_if_in_same_line = true,
59 .function_brace_split = true, 59 .function_brace_split = true,
60 .format_col1_comments = true, 60 .format_col1_comments = true,
61 .format_block_comments = true, 61 .format_block_comments = true,
62 .indent_parameters = true, 62 .indent_parameters = true,
63 .indent_size = 8, 63 .indent_size = 8,
64 .local_decl_indent = -1, 64 .local_decl_indent = -1,
65 .lineup_to_parens = true, 65 .lineup_to_parens = true,
66 .procnames_start_line = true, 66 .procnames_start_line = true,
67 .star_comment_cont = true, 67 .star_comment_cont = true,
68 .tabsize = 8, 68 .tabsize = 8,
69 .max_line_length = 78, 69 .max_line_length = 78,
70 .use_tabs = true, 70 .use_tabs = true,
71}; 71};
72 72
73struct parser_state ps; 73struct parser_state ps;
74 74
75struct buffer token; 75struct buffer token;
76 76
77struct buffer lab; 77struct buffer lab;
78struct buffer code; 78struct buffer code;
79struct buffer com; 79struct buffer com;
80 80
81bool found_err; 81bool found_err;
82bool had_eof; 82bool had_eof;
83int line_no = 1; 83int line_no = 1;
84 84
85static struct { 85static struct {
86 struct parser_state *item; 86 struct parser_state *item;
87 size_t len; 87 size_t len;
88 size_t cap; 88 size_t cap;
89} ifdef; 89} ifdef;
90 90
91FILE *input; 91FILE *input;
92FILE *output; 92FILE *output;
93 93
94static const char *in_name = "Standard Input"; 94static const char *in_name = "Standard Input";
95static char backup_name[PATH_MAX]; 95static char backup_name[PATH_MAX];
96static const char *backup_suffix = ".BAK"; 96static const char *backup_suffix = ".BAK";
97 97
98 98
99void * 99void *
100nonnull(void *p) 100nonnull(void *p)
101{ 101{
102 if (p == NULL) 102 if (p == NULL)
103 err(EXIT_FAILURE, NULL); 103 err(EXIT_FAILURE, NULL);
104 return p; 104 return p;
105} 105}
106 106
107static void 107static void
108buf_expand(struct buffer *buf, size_t add_size) 108buf_expand(struct buffer *buf, size_t add_size)
109{ 109{
110 buf->cap = buf->cap + add_size + 400; 110 buf->cap = buf->cap + add_size + 400;
111 buf->s = nonnull(realloc(buf->s, buf->cap)); 111 buf->s = nonnull(realloc(buf->s, buf->cap));
112} 112}
113 113
114#ifdef debug 114#ifdef debug
115void 115void
116buf_terminate(struct buffer *buf) 116buf_terminate(struct buffer *buf)
117{ 117{
118 if (buf->len == buf->cap) 118 if (buf->len == buf->cap)
119 buf_expand(buf, 1); 119 buf_expand(buf, 1);
120 buf->s[buf->len] = '\0'; 120 buf->s[buf->len] = '\0';
121} 121}
122#endif 122#endif
123 123
124void 124void
125buf_add_char(struct buffer *buf, char ch) 125buf_add_char(struct buffer *buf, char ch)
126{ 126{
127 if (buf->len == buf->cap) 127 if (buf->len == buf->cap)
128 buf_expand(buf, 1); 128 buf_expand(buf, 1);
129 buf->s[buf->len++] = ch; 129 buf->s[buf->len++] = ch;
130 buf_terminate(buf); 130 buf_terminate(buf);
131} 131}
132 132
133void 133void
134buf_add_chars(struct buffer *buf, const char *s, size_t len) 134buf_add_chars(struct buffer *buf, const char *s, size_t len)
135{ 135{
136 if (len == 0) 136 if (len == 0)
137 return; 137 return;
138 if (len > buf->cap - buf->len) 138 if (len > buf->cap - buf->len)
139 buf_expand(buf, len); 139 buf_expand(buf, len);
140 memcpy(buf->s + buf->len, s, len); 140 memcpy(buf->s + buf->len, s, len);
141 buf->len += len; 141 buf->len += len;
142 buf_terminate(buf); 142 buf_terminate(buf);
143} 143}
144 144
145static void 145static void
146buf_add_buf(struct buffer *buf, const struct buffer *add) 146buf_add_buf(struct buffer *buf, const struct buffer *add)
147{ 147{
148 buf_add_chars(buf, add->s, add->len); 148 buf_add_chars(buf, add->s, add->len);
149} 149}
150 150
151void 151void
152diag(int level, const char *msg, ...) 152diag(int level, const char *msg, ...)
153{ 153{
154 va_list ap; 154 va_list ap;
155 155
156 if (level != 0) 156 if (level != 0)
157 found_err = true; 157 found_err = true;
158 158
159 va_start(ap, msg); 159 va_start(ap, msg);
160 fprintf(stderr, "%s: %s:%d: ", 160 fprintf(stderr, "%s: %s:%d: ",
161 level == 0 ? "warning" : "error", in_name, line_no); 161 level == 0 ? "warning" : "error", in_name, line_no);
162 vfprintf(stderr, msg, ap); 162 vfprintf(stderr, msg, ap);
163 fprintf(stderr, "\n"); 163 fprintf(stderr, "\n");
164 va_end(ap); 164 va_end(ap);
165} 165}
166 166
167/* 167/*
168 * Compute the indentation from starting at 'ind' and adding the text starting 168 * Compute the indentation from starting at 'ind' and adding the text starting
169 * at 's'. 169 * at 's'.
170 */ 170 */
171int 171int
172ind_add(int ind, const char *s, size_t len) 172ind_add(int ind, const char *s, size_t len)
173{ 173{
174 for (const char *p = s; len > 0; p++, len--) { 174 for (const char *p = s; len > 0; p++, len--) {
175 if (*p == '\n') 175 if (*p == '\n')
176 ind = 0; 176 ind = 0;
177 else if (*p == '\t') 177 else if (*p == '\t')
178 ind = next_tab(ind); 178 ind = next_tab(ind);
179 else if (*p == '\b') 179 else if (*p == '\b')
180 --ind; 180 ind--;
181 else 181 else
182 ++ind; 182 ind++;
183 } 183 }
184 return ind; 184 return ind;
185} 185}
186 186
187static void 187static void
188init_globals(void) 188init_globals(void)
189{ 189{
190 ps_push(psym_stmt, false); /* as a stop symbol */ 190 ps_push(psym_stmt, false); /* as a stop symbol */
191 ps.prev_lsym = lsym_semicolon; 191 ps.prev_lsym = lsym_semicolon;
192 ps.lbrace_kind = psym_lbrace_block; 192 ps.lbrace_kind = psym_lbrace_block;
193 193
194 const char *suffix = getenv("SIMPLE_BACKUP_SUFFIX"); 194 const char *suffix = getenv("SIMPLE_BACKUP_SUFFIX");
195 if (suffix != NULL) 195 if (suffix != NULL)
196 backup_suffix = suffix; 196 backup_suffix = suffix;
197} 197}
198 198
199static void 199static void
200load_profiles(int argc, char **argv) 200load_profiles(int argc, char **argv)
201{ 201{
202 const char *profile_name = NULL; 202 const char *profile_name = NULL;
203 203
204 for (int i = 1; i < argc; ++i) { 204 for (int i = 1; i < argc; i++) {
205 const char *arg = argv[i]; 205 const char *arg = argv[i];
206 206
207 if (strcmp(arg, "-npro") == 0) 207 if (strcmp(arg, "-npro") == 0)
208 return; 208 return;
209 if (arg[0] == '-' && arg[1] == 'P' && arg[2] != '\0') 209 if (arg[0] == '-' && arg[1] == 'P' && arg[2] != '\0')
210 profile_name = arg + 2; 210 profile_name = arg + 2;
211 } 211 }
212 212
213 load_profile_files(profile_name); 213 load_profile_files(profile_name);
214} 214}
215 215
216/* 216/*
217 * Copy the input file to the backup file, then make the backup file the input 217 * Copy the input file to the backup file, then make the backup file the input
218 * and the original input file the output. 218 * and the original input file the output.
219 */ 219 */
220static void 220static void
221copy_to_bak_file(void) 221copy_to_bak_file(void)
222{ 222{
223 size_t n; 223 size_t n;
224 char buff[BUFSIZ]; 224 char buff[BUFSIZ];
225 225
226 const char *last_slash = strrchr(in_name, '/'); 226 const char *last_slash = strrchr(in_name, '/');
227 const char *base = last_slash != NULL ? last_slash + 1 : in_name; 227 const char *base = last_slash != NULL ? last_slash + 1 : in_name;
228 snprintf(backup_name, sizeof(backup_name), "%s%s", base, backup_suffix); 228 snprintf(backup_name, sizeof(backup_name), "%s%s", base, backup_suffix);
229 229
230 /* copy the input file to the backup file */ 230 /* copy the input file to the backup file */
231 FILE *bak = fopen(backup_name, "w"); 231 FILE *bak = fopen(backup_name, "w");
232 if (bak == NULL) 232 if (bak == NULL)
233 err(1, "%s", backup_name); 233 err(1, "%s", backup_name);
234 234
235 while ((n = fread(buff, 1, sizeof(buff), input)) > 0) 235 while ((n = fread(buff, 1, sizeof(buff), input)) > 0)
236 if (fwrite(buff, 1, n, bak) != n) 236 if (fwrite(buff, 1, n, bak) != n)
237 err(1, "%s", backup_name); 237 err(1, "%s", backup_name);
238 if (fclose(input) != 0) 238 if (fclose(input) != 0)
239 err(1, "%s", in_name); 239 err(1, "%s", in_name);
240 if (fclose(bak) != 0) 240 if (fclose(bak) != 0)
241 err(1, "%s", backup_name); 241 err(1, "%s", backup_name);
242 242
243 /* re-open the backup file as the input file */ 243 /* re-open the backup file as the input file */
244 input = fopen(backup_name, "r"); 244 input = fopen(backup_name, "r");
245 if (input == NULL) 245 if (input == NULL)
246 err(1, "%s", backup_name); 246 err(1, "%s", backup_name);
247 /* now the original input file will be the output */ 247 /* now the original input file will be the output */
248 output = fopen(in_name, "w"); 248 output = fopen(in_name, "w");
249 if (output == NULL) { 249 if (output == NULL) {
250 remove(backup_name); 250 remove(backup_name);
251 err(1, "%s", in_name); 251 err(1, "%s", in_name);
252 } 252 }
253} 253}
254 254
255static void 255static void
256parse_command_line(int argc, char **argv) 256parse_command_line(int argc, char **argv)
257{ 257{
258 for (int i = 1; i < argc; ++i) { 258 for (int i = 1; i < argc; i++) {
259 const char *arg = argv[i]; 259 const char *arg = argv[i];
260 260
261 if (arg[0] == '-') { 261 if (arg[0] == '-') {
262 set_option(arg, "Command line"); 262 set_option(arg, "Command line");
263 263
264 } else if (input == NULL) { 264 } else if (input == NULL) {
265 in_name = arg; 265 in_name = arg;
266 if ((input = fopen(in_name, "r")) == NULL) 266 if ((input = fopen(in_name, "r")) == NULL)
267 err(1, "%s", in_name); 267 err(1, "%s", in_name);
268 268
269 } else if (output == NULL) { 269 } else if (output == NULL) {
270 if (strcmp(arg, in_name) == 0) 270 if (strcmp(arg, in_name) == 0)
271 errx(1, "input and output files " 271 errx(1, "input and output files "
272 "must be different"); 272 "must be different");
273 if ((output = fopen(arg, "w")) == NULL) 273 if ((output = fopen(arg, "w")) == NULL)
274 err(1, "%s", arg); 274 err(1, "%s", arg);
275 275
276 } else 276 } else
277 errx(1, "too many arguments: %s", arg); 277 errx(1, "too many arguments: %s", arg);
278 } 278 }
279 279
280 if (input == NULL) { 280 if (input == NULL) {
281 input = stdin; 281 input = stdin;
282 output = stdout; 282 output = stdout;
283 } else if (output == NULL) 283 } else if (output == NULL)
284 copy_to_bak_file(); 284 copy_to_bak_file();
285 285
286 if (opt.comment_column <= 1) 286 if (opt.comment_column <= 1)
287 opt.comment_column = 2; /* don't put normal comments in column 287 opt.comment_column = 2; /* don't put normal comments in column
288 * 1, see opt.format_col1_comments */ 288 * 1, see opt.format_col1_comments */
289 if (opt.block_comment_max_line_length <= 0) 289 if (opt.block_comment_max_line_length <= 0)
290 opt.block_comment_max_line_length = opt.max_line_length; 290 opt.block_comment_max_line_length = opt.max_line_length;
291 if (opt.local_decl_indent < 0) 291 if (opt.local_decl_indent < 0)
292 opt.local_decl_indent = opt.decl_indent; 292 opt.local_decl_indent = opt.decl_indent;
293 if (opt.decl_comment_column <= 0) 293 if (opt.decl_comment_column <= 0)
294 opt.decl_comment_column = opt.left_justify_decl 294 opt.decl_comment_column = opt.left_justify_decl
295 ? (opt.comment_column <= 10 ? 2 : opt.comment_column - 8) 295 ? (opt.comment_column <= 10 ? 2 : opt.comment_column - 8)
296 : opt.comment_column; 296 : opt.comment_column;
297 if (opt.continuation_indent == 0) 297 if (opt.continuation_indent == 0)
298 opt.continuation_indent = opt.indent_size; 298 opt.continuation_indent = opt.indent_size;
299} 299}
300 300
301static void 301static void
302set_initial_indentation(void) 302set_initial_indentation(void)
303{ 303{
304 inp_read_line(); 304 inp_read_line();
305 305
306 int ind = 0; 306 int ind = 0;
307 for (const char *p = inp_p;; p++) { 307 for (const char *p = inp_p;; p++) {
308 if (*p == ' ') 308 if (*p == ' ')
309 ind++; 309 ind++;
310 else if (*p == '\t') 310 else if (*p == '\t')
311 ind = next_tab(ind); 311 ind = next_tab(ind);
312 else 312 else
313 break; 313 break;
314 } 314 }
315 315
316 ps.ind_level = ps.ind_level_follow = ind / opt.indent_size; 316 ps.ind_level = ps.ind_level_follow = ind / opt.indent_size;
317} 317}
318 318
319static bool 319static bool
320should_break_line(lexer_symbol lsym) 320should_break_line(lexer_symbol lsym)
321{ 321{
322 if (lsym == lsym_semicolon) 322 if (lsym == lsym_semicolon)
323 return false; 323 return false;
324 if (ps.prev_lsym == lsym_lbrace || ps.prev_lsym == lsym_semicolon) 324 if (ps.prev_lsym == lsym_lbrace || ps.prev_lsym == lsym_semicolon)
325 return true; 325 return true;
326 if (lsym == lsym_lbrace && opt.brace_same_line) 326 if (lsym == lsym_lbrace && opt.brace_same_line)
327 return false; 327 return false;
328 return true; 328 return true;
329} 329}
330 330
331static void 331static void
332move_com_to_code(lexer_symbol lsym) 332move_com_to_code(lexer_symbol lsym)
333{ 333{
334 if (ps.want_blank) 334 if (ps.want_blank)
335 buf_add_char(&code, ' '); 335 buf_add_char(&code, ' ');
336 buf_add_buf(&code, &com); 336 buf_add_buf(&code, &com);
337 buf_clear(&com); 337 buf_clear(&com);
338 ps.want_blank = lsym != lsym_rparen && lsym != lsym_rbracket; 338 ps.want_blank = lsym != lsym_rparen && lsym != lsym_rbracket;
339} 339}
340 340
341static void 341static void
342update_ps_lbrace_kind(lexer_symbol lsym) 342update_ps_lbrace_kind(lexer_symbol lsym)
343{ 343{
344 if (lsym == lsym_tag) { 344 if (lsym == lsym_tag) {
345 ps.lbrace_kind = token.s[0] == 's' ? psym_lbrace_struct : 345 ps.lbrace_kind = token.s[0] == 's' ? psym_lbrace_struct :
346 token.s[0] == 'u' ? psym_lbrace_union : 346 token.s[0] == 'u' ? psym_lbrace_union :
347 psym_lbrace_enum; 347 psym_lbrace_enum;
348 } else if ((lsym == lsym_type && ps.paren.len == 0) 348 } else if ((lsym == lsym_type && ps.paren.len == 0)
349 || lsym == lsym_word 349 || lsym == lsym_word
350 || lsym == lsym_lbrace) { 350 || lsym == lsym_lbrace) {
351 /* Keep the current '{' kind. */ 351 /* Keep the current '{' kind. */
352 } else 352 } else
353 ps.lbrace_kind = psym_lbrace_block; 353 ps.lbrace_kind = psym_lbrace_block;
354} 354}
355 355
356static void 356static void
357indent_declarator(int decl_ind, bool tabs_to_var) 357indent_declarator(int decl_ind, bool tabs_to_var)
358{ 358{
359 int base = ps.ind_level * opt.indent_size; 359 int base = ps.ind_level * opt.indent_size;
360 int ind = ind_add(base, code.s, code.len); 360 int ind = ind_add(base, code.s, code.len);
361 int target = base + decl_ind; 361 int target = base + decl_ind;
362 size_t orig_code_len = code.len; 362 size_t orig_code_len = code.len;
363 363
364 if (tabs_to_var) 364 if (tabs_to_var)
365 for (int next; (next = next_tab(ind)) <= target; ind = next) 365 for (int next; (next = next_tab(ind)) <= target; ind = next)
366 buf_add_char(&code, '\t'); 366 buf_add_char(&code, '\t');
367 for (; ind < target; ind++) 367 for (; ind < target; ind++)
368 buf_add_char(&code, ' '); 368 buf_add_char(&code, ' ');
369 if (code.len == orig_code_len && ps.want_blank) 369 if (code.len == orig_code_len && ps.want_blank)
370 buf_add_char(&code, ' '); 370 buf_add_char(&code, ' ');
371 371
372 ps.want_blank = false; 372 ps.want_blank = false;
373 ps.decl_indent_done = true; 373 ps.decl_indent_done = true;
374} 374}
375 375
376static bool 376static bool
377is_function_pointer_declaration(void) 377is_function_pointer_declaration(void)
378{ 378{
379 return ps.in_decl 379 return ps.in_decl
380 && !ps.in_typedef_decl 380 && !ps.in_typedef_decl
381 && !ps.in_init 381 && !ps.in_init
382 && !ps.decl_indent_done 382 && !ps.decl_indent_done
383 && !ps.line_has_func_def 383 && !ps.line_has_func_def
384 && ps.ind_paren_level == 0; 384 && ps.ind_paren_level == 0;
385} 385}
386 386
387static int 387static int
388process_eof(void) 388process_eof(void)
389{ 389{
390 finish_output(); 390 finish_output();
391 391
392 if (ps.psyms.len > 2) /* check for balanced braces */ 392 if (ps.psyms.len > 2) /* check for balanced braces */
393 diag(1, "Stuff missing from end of file"); 393 diag(1, "Stuff missing from end of file");
394 394
395 return found_err ? EXIT_FAILURE : EXIT_SUCCESS; 395 return found_err ? EXIT_FAILURE : EXIT_SUCCESS;
396} 396}
397 397
398/* move the whole line to the 'label' buffer */ 398/* move the whole line to the 'label' buffer */
399static void 399static void
400read_preprocessing_line(void) 400read_preprocessing_line(void)
401{ 401{
402 enum { 402 enum {
403 PLAIN, STR, CHR, COMM 403 PLAIN, STR, CHR, COMM
404 } state = PLAIN; 404 } state = PLAIN;
405 405
406 buf_add_char(&lab, '#'); 406 buf_add_char(&lab, '#');
407 407
408 while (inp_p[0] != '\n' || (state == COMM && !had_eof)) { 408 while (inp_p[0] != '\n' || (state == COMM && !had_eof)) {
409 buf_add_char(&lab, inp_next()); 409 buf_add_char(&lab, inp_next());
410 switch (lab.s[lab.len - 1]) { 410 switch (lab.s[lab.len - 1]) {
411 case '\\': 411 case '\\':
412 if (state != COMM) 412 if (state != COMM)
413 buf_add_char(&lab, inp_next()); 413 buf_add_char(&lab, inp_next());
414 break; 414 break;
415 case '/': 415 case '/':
416 if (inp_p[0] == '*' && state == PLAIN) { 416 if (inp_p[0] == '*' && state == PLAIN) {
417 state = COMM; 417 state = COMM;
418 buf_add_char(&lab, *inp_p++); 418 buf_add_char(&lab, *inp_p++);
419 } 419 }
420 break; 420 break;
421 case '"': 421 case '"':
422 if (state == STR) 422 if (state == STR)
423 state = PLAIN; 423 state = PLAIN;
424 else if (state == PLAIN) 424 else if (state == PLAIN)
425 state = STR; 425 state = STR;
426 break; 426 break;
427 case '\'': 427 case '\'':
428 if (state == CHR) 428 if (state == CHR)
429 state = PLAIN; 429 state = PLAIN;
430 else if (state == PLAIN) 430 else if (state == PLAIN)
431 state = CHR; 431 state = CHR;
432 break; 432 break;
433 case '*': 433 case '*':
434 if (inp_p[0] == '/' && state == COMM) { 434 if (inp_p[0] == '/' && state == COMM) {
435 state = PLAIN; 435 state = PLAIN;
436 buf_add_char(&lab, *inp_p++); 436 buf_add_char(&lab, *inp_p++);
437 } 437 }
438 break; 438 break;
439 } 439 }
440 } 440 }
441 441
442 while (lab.len > 0 && ch_isblank(lab.s[lab.len - 1])) 442 while (lab.len > 0 && ch_isblank(lab.s[lab.len - 1]))
443 lab.len--; 443 lab.len--;
444 buf_terminate(&lab); 444 buf_terminate(&lab);
445} 445}
446 446
447static void 447static void
448paren_stack_push(struct paren_stack *s, int indent, enum paren_level_cast cast) 448paren_stack_push(struct paren_stack *s, int indent, enum paren_level_cast cast)
449{ 449{
450 if (s->len == s->cap) { 450 if (s->len == s->cap) {
451 s->cap = 10 + s->cap; 451 s->cap = 10 + s->cap;
452 s->item = nonnull(realloc(s->item, 452 s->item = nonnull(realloc(s->item,
453 sizeof(s->item[0]) * s->cap)); 453 sizeof(s->item[0]) * s->cap));
454 } 454 }
455 s->item[s->len++] = (struct paren_level){indent, cast}; 455 s->item[s->len++] = (struct paren_level){indent, cast};
456} 456}
457 457
458static void * 458static void *
459dup_mem(const void *src, size_t size) 459dup_mem(const void *src, size_t size)
460{ 460{
461 return memcpy(nonnull(malloc(size)), src, size); 461 return memcpy(nonnull(malloc(size)), src, size);
462} 462}
463 463
464#define dup_array(src, len) \ 464#define dup_array(src, len) \
465 dup_mem((src), sizeof((src)[0]) * (len)) 465 dup_mem((src), sizeof((src)[0]) * (len))
466#define copy_array(dst, src, len) \ 466#define copy_array(dst, src, len) \
467 memcpy((dst), (src), sizeof((dst)[0]) * (len)) 467 memcpy((dst), (src), sizeof((dst)[0]) * (len))
468 468
469static void 469static void
470parser_state_back_up(struct parser_state *dst) 470parser_state_back_up(struct parser_state *dst)
471{ 471{
472 *dst = ps; 472 *dst = ps;
473 473
474 dst->paren.item = dup_array(ps.paren.item, ps.paren.len); 474 dst->paren.item = dup_array(ps.paren.item, ps.paren.len);
475 dst->psyms.sym = dup_array(ps.psyms.sym, ps.psyms.len); 475 dst->psyms.sym = dup_array(ps.psyms.sym, ps.psyms.len);
476 dst->psyms.ind_level = dup_array(ps.psyms.ind_level, ps.psyms.len); 476 dst->psyms.ind_level = dup_array(ps.psyms.ind_level, ps.psyms.len);
477} 477}
478 478
479static void 479static void
480parser_state_restore(const struct parser_state *src) 480parser_state_restore(const struct parser_state *src)
481{ 481{
482 struct paren_level *ps_paren_item = ps.paren.item; 482 struct paren_level *ps_paren_item = ps.paren.item;
483 size_t ps_paren_cap = ps.paren.cap; 483 size_t ps_paren_cap = ps.paren.cap;
484 enum parser_symbol *ps_psyms_sym = ps.psyms.sym; 484 enum parser_symbol *ps_psyms_sym = ps.psyms.sym;
485 int *ps_psyms_ind_level = ps.psyms.ind_level; 485 int *ps_psyms_ind_level = ps.psyms.ind_level;
486 size_t ps_psyms_cap = ps.psyms.cap; 486 size_t ps_psyms_cap = ps.psyms.cap;
487 487
488 ps = *src; 488 ps = *src;
489 489
490 ps.paren.item = ps_paren_item; 490 ps.paren.item = ps_paren_item;
491 ps.paren.cap = ps_paren_cap; 491 ps.paren.cap = ps_paren_cap;
492 ps.psyms.sym = ps_psyms_sym; 492 ps.psyms.sym = ps_psyms_sym;
493 ps.psyms.ind_level = ps_psyms_ind_level; 493 ps.psyms.ind_level = ps_psyms_ind_level;
494 ps.psyms.cap = ps_psyms_cap; 494 ps.psyms.cap = ps_psyms_cap;
495 495
496 copy_array(ps.paren.item, src->paren.item, src->paren.len); 496 copy_array(ps.paren.item, src->paren.item, src->paren.len);
497 copy_array(ps.psyms.sym, src->psyms.sym, src->psyms.len); 497 copy_array(ps.psyms.sym, src->psyms.sym, src->psyms.len);
498 copy_array(ps.psyms.ind_level, src->psyms.ind_level, src->psyms.len); 498 copy_array(ps.psyms.ind_level, src->psyms.ind_level, src->psyms.len);
499} 499}
500 500
501static void 501static void
502parser_state_free(struct parser_state *pst) 502parser_state_free(struct parser_state *pst)
503{ 503{
504 free(pst->paren.item); 504 free(pst->paren.item);
505 free(pst->psyms.sym); 505 free(pst->psyms.sym);
506 free(pst->psyms.ind_level); 506 free(pst->psyms.ind_level);
507} 507}
508 508
509static void 509static void
510process_preprocessing(void) 510process_preprocessing(void)
511{ 511{
512 if (lab.len > 0 || code.len > 0 || com.len > 0) 512 if (lab.len > 0 || code.len > 0 || com.len > 0)
513 output_line(); 513 output_line();
514 514
515 read_preprocessing_line(); 515 read_preprocessing_line();
516 516
517 const char *dir = lab.s + 1, *line_end = lab.s + lab.len; 517 const char *dir = lab.s + 1, *line_end = lab.s + lab.len;
518 while (dir < line_end && ch_isblank(*dir)) 518 while (dir < line_end && ch_isblank(*dir))
519 dir++; 519 dir++;
520 size_t dir_len = 0; 520 size_t dir_len = 0;
521 while (dir + dir_len < line_end && ch_isalpha(dir[dir_len])) 521 while (dir + dir_len < line_end && ch_isalpha(dir[dir_len]))
522 dir_len++; 522 dir_len++;
523 523
524 if (dir_len >= 2 && memcmp(dir, "if", 2) == 0) { 524 if (dir_len >= 2 && memcmp(dir, "if", 2) == 0) {
525 if (ifdef.len >= ifdef.cap) { 525 if (ifdef.len >= ifdef.cap) {
526 ifdef.cap += 5; 526 ifdef.cap += 5;
527 ifdef.item = nonnull(realloc(ifdef.item, 527 ifdef.item = nonnull(realloc(ifdef.item,
528 sizeof(ifdef.item[0]) * ifdef.cap)); 528 sizeof(ifdef.item[0]) * ifdef.cap));
529 } 529 }
530 parser_state_back_up(ifdef.item + ifdef.len++); 530 parser_state_back_up(ifdef.item + ifdef.len++);
531 out.line_kind = lk_pre_if; 531 out.line_kind = lk_pre_if;
532 532
533 } else if (dir_len >= 2 && memcmp(dir, "el", 2) == 0) { 533 } else if (dir_len >= 2 && memcmp(dir, "el", 2) == 0) {
534 if (ifdef.len == 0) 534 if (ifdef.len == 0)
535 diag(1, "Unmatched #%.*s", (int)dir_len, dir); 535 diag(1, "Unmatched #%.*s", (int)dir_len, dir);
536 else 536 else
537 parser_state_restore(ifdef.item + ifdef.len - 1); 537 parser_state_restore(ifdef.item + ifdef.len - 1);
538 out.line_kind = lk_pre_other; 538 out.line_kind = lk_pre_other;
539 539
540 } else if (dir_len == 5 && memcmp(dir, "endif", 5) == 0) { 540 } else if (dir_len == 5 && memcmp(dir, "endif", 5) == 0) {
541 if (ifdef.len == 0) 541 if (ifdef.len == 0)
542 diag(1, "Unmatched #endif"); 542 diag(1, "Unmatched #endif");
543 else 543 else
544 parser_state_free(ifdef.item + --ifdef.len); 544 parser_state_free(ifdef.item + --ifdef.len);
545 out.line_kind = lk_pre_endif; 545 out.line_kind = lk_pre_endif;
546 } else 546 } else
547 out.line_kind = lk_pre_other; 547 out.line_kind = lk_pre_other;
548} 548}
549 549
550static void 550static void
551process_newline(void) 551process_newline(void)
552{ 552{
553 if (ps.prev_lsym == lsym_comma 553 if (ps.prev_lsym == lsym_comma
554 && ps.paren.len == 0 && !ps.in_init 554 && ps.paren.len == 0 && !ps.in_init
555 && !opt.break_after_comma && ps.break_after_comma 555 && !opt.break_after_comma && ps.break_after_comma
556 && lab.len == 0 /* for preprocessing lines */ 556 && lab.len == 0 /* for preprocessing lines */
557 && com.len == 0) 557 && com.len == 0)
558 goto stay_in_line; 558 goto stay_in_line;
559 if (ps.psyms.sym[ps.psyms.len - 1] == psym_switch_expr 559 if (ps.psyms.sym[ps.psyms.len - 1] == psym_switch_expr
560 && opt.brace_same_line 560 && opt.brace_same_line
561 && com.len == 0) { 561 && com.len == 0) {
562 ps.want_newline = true; 562 ps.want_newline = true;
563 goto stay_in_line; 563 goto stay_in_line;
564 } 564 }
565 565
566 output_line(); 566 output_line();
567 567
568stay_in_line: 568stay_in_line:
569 ++line_no; 569 line_no++;
570} 570}
571 571
572static bool 572static bool
573want_blank_before_lparen(void) 573want_blank_before_lparen(void)
574{ 574{
575 if (opt.proc_calls_space) 575 if (opt.proc_calls_space)
576 return true; 576 return true;
577 if (ps.prev_lsym == lsym_sizeof) 577 if (ps.prev_lsym == lsym_sizeof)
578 return opt.blank_after_sizeof; 578 return opt.blank_after_sizeof;
579 if (ps.prev_lsym == lsym_rparen 579 if (ps.prev_lsym == lsym_rparen
580 || ps.prev_lsym == lsym_rbracket 580 || ps.prev_lsym == lsym_rbracket
581 || ps.prev_lsym == lsym_postfix_op 581 || ps.prev_lsym == lsym_postfix_op
582 || ps.prev_lsym == lsym_offsetof 582 || ps.prev_lsym == lsym_offsetof
583 || ps.prev_lsym == lsym_word 583 || ps.prev_lsym == lsym_word
584 || ps.prev_lsym == lsym_funcname) 584 || ps.prev_lsym == lsym_funcname)
585 return false; 585 return false;
586 return true; 586 return true;
587} 587}
588 588
589static void 589static void
590process_lparen(void) 590process_lparen(void)
591{ 591{
592 592
593 if (is_function_pointer_declaration()) 593 if (is_function_pointer_declaration())
594 indent_declarator(ps.decl_ind, ps.tabs_to_var); 594 indent_declarator(ps.decl_ind, ps.tabs_to_var);
595 else if (ps.want_blank && want_blank_before_lparen()) 595 else if (ps.want_blank && want_blank_before_lparen())
596 buf_add_char(&code, ' '); 596 buf_add_char(&code, ' ');
597 ps.want_blank = false; 597 ps.want_blank = false;
598 buf_add_buf(&code, &token); 598 buf_add_buf(&code, &token);
599 599
600 if (opt.extra_expr_indent && ps.spaced_expr_psym != psym_0) 600 if (opt.extra_expr_indent && ps.spaced_expr_psym != psym_0)
601 ps.extra_expr_indent = eei_maybe; 601 ps.extra_expr_indent = eei_maybe;
602 602
603 if (ps.in_var_decl && ps.psyms.len <= 3 && !ps.in_init) { 603 if (ps.in_var_decl && ps.psyms.len <= 3 && !ps.in_init) {
604 parse(psym_stmt); /* prepare for function definition */ 604 parse(psym_stmt); /* prepare for function definition */
605 ps.in_var_decl = false; 605 ps.in_var_decl = false;
606 } 606 }
607 607
608 enum paren_level_cast cast = cast_unknown; 608 enum paren_level_cast cast = cast_unknown;
609 if (ps.prev_lsym == lsym_offsetof 609 if (ps.prev_lsym == lsym_offsetof
610 || ps.prev_lsym == lsym_sizeof 610 || ps.prev_lsym == lsym_sizeof
611 || ps.prev_lsym == lsym_for 611 || ps.prev_lsym == lsym_for
612 || ps.prev_lsym == lsym_if 612 || ps.prev_lsym == lsym_if
613 || ps.prev_lsym == lsym_switch 613 || ps.prev_lsym == lsym_switch
614 || ps.prev_lsym == lsym_while 614 || ps.prev_lsym == lsym_while
615 || ps.line_has_func_def) 615 || ps.line_has_func_def)
616 cast = cast_no; 616 cast = cast_no;
617 617
618 paren_stack_push(&ps.paren, ind_add(0, code.s, code.len), cast); 618 paren_stack_push(&ps.paren, ind_add(0, code.s, code.len), cast);
619} 619}
620 620
621static bool 621static bool
622rparen_is_cast(bool paren_cast) 622rparen_is_cast(bool paren_cast)
623{ 623{
624 if (ps.in_func_def_params) 624 if (ps.in_func_def_params)
625 return false; 625 return false;
626 if (ps.line_has_decl && !ps.in_init) 626 if (ps.line_has_decl && !ps.in_init)
627 return false; 627 return false;
628 if (ps.prev_lsym == lsym_unary_op) 628 if (ps.prev_lsym == lsym_unary_op)
629 return true; 629 return true;
630 if (ps.spaced_expr_psym != psym_0 && ps.paren.len == 0) 630 if (ps.spaced_expr_psym != psym_0 && ps.paren.len == 0)
631 return false; 631 return false;
632 return paren_cast || ch_isalpha(inp_p[0]) || inp_p[0] == '{'; 632 return paren_cast || ch_isalpha(inp_p[0]) || inp_p[0] == '{';
633} 633}
634 634
635static void 635static void
636process_rparen(void) 636process_rparen(void)
637{ 637{
638 if (ps.paren.len == 0) 638 if (ps.paren.len == 0)
639 diag(0, "Extra '%c'", *token.s); 639 diag(0, "Extra '%c'", *token.s);
640 640
641 bool paren_cast = ps.paren.len > 0 641 bool paren_cast = ps.paren.len > 0
642 && ps.paren.item[--ps.paren.len].cast == cast_maybe; 642 && ps.paren.item[--ps.paren.len].cast == cast_maybe;
643 ps.prev_paren_was_cast = rparen_is_cast(paren_cast); 643 ps.prev_paren_was_cast = rparen_is_cast(paren_cast);
644 if (ps.prev_paren_was_cast) { 644 if (ps.prev_paren_was_cast) {
645 ps.next_unary = true; 645 ps.next_unary = true;
646 ps.want_blank = opt.space_after_cast; 646 ps.want_blank = opt.space_after_cast;
647 } else 647 } else
648 ps.want_blank = true; 648 ps.want_blank = true;
649 649
650 if (code.len == 0) 650 if (code.len == 0)
651 ps.ind_paren_level = (int)ps.paren.len; 651 ps.ind_paren_level = (int)ps.paren.len;
652 652
653 buf_add_buf(&code, &token); 653 buf_add_buf(&code, &token);
654 654
655 if (ps.spaced_expr_psym != psym_0 && ps.paren.len == 0) { 655 if (ps.spaced_expr_psym != psym_0 && ps.paren.len == 0) {
656 parse(ps.spaced_expr_psym); 656 parse(ps.spaced_expr_psym);
657 ps.spaced_expr_psym = psym_0; 657 ps.spaced_expr_psym = psym_0;
658 658
659 ps.want_newline = true; 659 ps.want_newline = true;
660 ps.next_unary = true; 660 ps.next_unary = true;
661 ps.in_stmt_or_decl = false; 661 ps.in_stmt_or_decl = false;
662 ps.want_blank = true; 662 ps.want_blank = true;
663 out.line_kind = lk_stmt_head; 663 out.line_kind = lk_stmt_head;
664 if (ps.extra_expr_indent == eei_maybe) 664 if (ps.extra_expr_indent == eei_maybe)
665 ps.extra_expr_indent = eei_last; 665 ps.extra_expr_indent = eei_last;
666 } 666 }
667} 667}
668 668
669static void 669static void
670process_lbracket(void) 670process_lbracket(void)
671{ 671{
672 if (code.len > 0 672 if (code.len > 0
673 && (ps.prev_lsym == lsym_comma || ps.prev_lsym == lsym_binary_op)) 673 && (ps.prev_lsym == lsym_comma || ps.prev_lsym == lsym_binary_op))
674 buf_add_char(&code, ' '); 674 buf_add_char(&code, ' ');
675 buf_add_buf(&code, &token); 675 buf_add_buf(&code, &token);
676 ps.want_blank = false; 676 ps.want_blank = false;
677 677
678 paren_stack_push(&ps.paren, ind_add(0, code.s, code.len), cast_no); 678 paren_stack_push(&ps.paren, ind_add(0, code.s, code.len), cast_no);
679} 679}
680 680
681static void 681static void
682process_rbracket(void) 682process_rbracket(void)
683{ 683{
684 if (ps.paren.len == 0) 684 if (ps.paren.len == 0)
685 diag(0, "Extra '%c'", *token.s); 685 diag(0, "Extra '%c'", *token.s);
686 if (ps.paren.len > 0) 686 if (ps.paren.len > 0)
687 ps.paren.len--; 687 ps.paren.len--;
688 688
689 if (code.len == 0) 689 if (code.len == 0)
690 ps.ind_paren_level = (int)ps.paren.len; 690 ps.ind_paren_level = (int)ps.paren.len;
691 691
692 buf_add_buf(&code, &token); 692 buf_add_buf(&code, &token);
693 ps.want_blank = true; 693 ps.want_blank = true;
694} 694}
695 695
696static void 696static void
697process_lbrace(void) 697process_lbrace(void)
698{ 698{
699 if (ps.prev_lsym == lsym_rparen && ps.prev_paren_was_cast) { 699 if (ps.prev_lsym == lsym_rparen && ps.prev_paren_was_cast) {
700 ps.in_var_decl = true; // XXX: not really 700 ps.in_var_decl = true; // XXX: not really
701 ps.in_init = true; 701 ps.in_init = true;
702 } 702 }
703 703
704 if (out.line_kind == lk_stmt_head) 704 if (out.line_kind == lk_stmt_head)
705 out.line_kind = lk_other; 705 out.line_kind = lk_other;
706 706
707 ps.in_stmt_or_decl = false; /* don't indent the {} */ 707 ps.in_stmt_or_decl = false; /* don't indent the {} */
708 708
709 if (ps.in_init) 709 if (ps.in_init)
710 ps.init_level++; 710 ps.init_level++;
711 else 711 else
712 ps.want_newline = true; 712 ps.want_newline = true;
713 713
714 if (code.len > 0 && !ps.in_init) { 714 if (code.len > 0 && !ps.in_init) {
715 if (!opt.brace_same_line || 715 if (!opt.brace_same_line ||
716 (code.len > 0 && code.s[code.len - 1] == '}')) 716 (code.len > 0 && code.s[code.len - 1] == '}'))
717 output_line(); 717 output_line();
718 else if (ps.in_func_def_params && !ps.in_var_decl) { 718 else if (ps.in_func_def_params && !ps.in_var_decl) {
719 ps.ind_level_follow = 0; 719 ps.ind_level_follow = 0;
720 if (opt.function_brace_split) 720 if (opt.function_brace_split)
721 output_line(); 721 output_line();
722 else 722 else
723 ps.want_blank = true; 723 ps.want_blank = true;
724 } 724 }
725 } 725 }
726 726
727 if (ps.paren.len > 0 && ps.init_level == 0) { 727 if (ps.paren.len > 0 && ps.init_level == 0) {
728 diag(1, "Unbalanced parentheses"); 728 diag(1, "Unbalanced parentheses");
729 ps.paren.len = 0; 729 ps.paren.len = 0;
730 if (ps.spaced_expr_psym != psym_0) { 730 if (ps.spaced_expr_psym != psym_0) {
731 parse(ps.spaced_expr_psym); 731 parse(ps.spaced_expr_psym);
732 ps.spaced_expr_psym = psym_0; 732 ps.spaced_expr_psym = psym_0;
733 ps.ind_level = ps.ind_level_follow; 733 ps.ind_level = ps.ind_level_follow;
734 } 734 }
735 } 735 }
736 736
737 if (code.len == 0) 737 if (code.len == 0)
738 ps.line_is_stmt_cont = false; 738 ps.line_is_stmt_cont = false;
739 if (ps.in_decl && ps.in_var_decl) { 739 if (ps.in_decl && ps.in_var_decl) {
740 ps.di_stack[ps.decl_level] = ps.decl_ind; 740 ps.di_stack[ps.decl_level] = ps.decl_ind;
741 if (++ps.decl_level == (int)array_length(ps.di_stack)) { 741 if (++ps.decl_level == (int)array_length(ps.di_stack)) {
742 diag(0, "Reached internal limit of %zu struct levels", 742 diag(0, "Reached internal limit of %zu struct levels",
743 array_length(ps.di_stack)); 743 array_length(ps.di_stack));
744 ps.decl_level--; 744 ps.decl_level--;
745 } 745 }
746 } else { 746 } else {
747 ps.line_has_decl = false; /* don't do special indentation 747 ps.line_has_decl = false; /* don't do special indentation
748 * of comments */ 748 * of comments */
749 ps.in_func_def_params = false; 749 ps.in_func_def_params = false;
750 ps.in_decl = false; 750 ps.in_decl = false;
751 } 751 }
752 752
753 ps.decl_ind = 0; 753 ps.decl_ind = 0;
754 parse(ps.lbrace_kind); 754 parse(ps.lbrace_kind);
755 if (ps.want_blank) 755 if (ps.want_blank)
756 buf_add_char(&code, ' '); 756 buf_add_char(&code, ' ');
757 ps.want_blank = false; 757 ps.want_blank = false;
758 buf_add_char(&code, '{'); 758 buf_add_char(&code, '{');
759 ps.declaration = decl_no; 759 ps.declaration = decl_no;
760} 760}
761 761
762static void 762static void
763process_rbrace(void) 763process_rbrace(void)
764{ 764{
765 if (ps.paren.len > 0 && ps.init_level == 0) { 765 if (ps.paren.len > 0 && ps.init_level == 0) {
766 diag(1, "Unbalanced parentheses"); 766 diag(1, "Unbalanced parentheses");
767 ps.paren.len = 0; 767 ps.paren.len = 0;
768 ps.spaced_expr_psym = psym_0; 768 ps.spaced_expr_psym = psym_0;
769 } 769 }
770 770
771 ps.declaration = decl_no; 771 ps.declaration = decl_no;
772 if (ps.init_level > 0) 772 if (ps.init_level > 0)
773 ps.init_level--; 773 ps.init_level--;
774 774
775 if (code.len > 0 && !ps.in_init) 775 if (code.len > 0 && !ps.in_init)
776 output_line(); 776 output_line();
777 777
778 buf_add_char(&code, '}'); 778 buf_add_char(&code, '}');
779 ps.want_blank = true; 779 ps.want_blank = true;
780 ps.in_stmt_or_decl = false; // XXX: Initializers don't end a stmt 780 ps.in_stmt_or_decl = false; // XXX: Initializers don't end a stmt
781 ps.line_is_stmt_cont = false; 781 ps.line_is_stmt_cont = false;
782 782
783 if (ps.decl_level > 0) { /* multi-level structure declaration */ 783 if (ps.decl_level > 0) { /* multi-level structure declaration */
784 ps.decl_ind = ps.di_stack[--ps.decl_level]; 784 ps.decl_ind = ps.di_stack[--ps.decl_level];
785 if (ps.decl_level == 0 && !ps.in_func_def_params) { 785 if (ps.decl_level == 0 && !ps.in_func_def_params) {
786 ps.declaration = decl_begin; 786 ps.declaration = decl_begin;
787 ps.decl_ind = ps.ind_level == 0 787 ps.decl_ind = ps.ind_level == 0
788 ? opt.decl_indent : opt.local_decl_indent; 788 ? opt.decl_indent : opt.local_decl_indent;
789 } 789 }
790 ps.in_decl = true; 790 ps.in_decl = true;
791 } 791 }
792 792
793 if (ps.psyms.len == 3) 793 if (ps.psyms.len == 3)
794 out.line_kind = lk_func_end; 794 out.line_kind = lk_func_end;
795 795
796 parse(psym_rbrace); 796 parse(psym_rbrace);
797 797
798 if (!ps.in_var_decl 798 if (!ps.in_var_decl
799 && ps.psyms.sym[ps.psyms.len - 1] != psym_do_stmt 799 && ps.psyms.sym[ps.psyms.len - 1] != psym_do_stmt
800 && ps.psyms.sym[ps.psyms.len - 1] != psym_if_expr_stmt) 800 && ps.psyms.sym[ps.psyms.len - 1] != psym_if_expr_stmt)
801 ps.want_newline = true; 801 ps.want_newline = true;
802} 802}
803 803
804static void 804static void
805process_period(void) 805process_period(void)
806{ 806{
807 if (code.len > 0 && code.s[code.len - 1] == ',') 807 if (code.len > 0 && code.s[code.len - 1] == ',')
808 buf_add_char(&code, ' '); 808 buf_add_char(&code, ' ');
809 buf_add_char(&code, '.'); 809 buf_add_char(&code, '.');
810 ps.want_blank = false; 810 ps.want_blank = false;
811} 811}
812 812
813static void 813static void
814process_unary_op(void) 814process_unary_op(void)
815{ 815{
816 if (is_function_pointer_declaration()) { 816 if (is_function_pointer_declaration()) {
817 int ind = ps.decl_ind - (int)token.len; 817 int ind = ps.decl_ind - (int)token.len;
818 indent_declarator(ind, ps.tabs_to_var); 818 indent_declarator(ind, ps.tabs_to_var);
819 } else if ((token.s[0] == '+' || token.s[0] == '-') 819 } else if ((token.s[0] == '+' || token.s[0] == '-')
820 && code.len > 0 && code.s[code.len - 1] == token.s[0]) 820 && code.len > 0 && code.s[code.len - 1] == token.s[0])
821 ps.want_blank = true; 821 ps.want_blank = true;
822 822
823 if (ps.want_blank) 823 if (ps.want_blank)
824 buf_add_char(&code, ' '); 824 buf_add_char(&code, ' ');
825 buf_add_buf(&code, &token); 825 buf_add_buf(&code, &token);
826 ps.want_blank = false; 826 ps.want_blank = false;
827} 827}
828 828
829static void 829static void
830process_postfix_op(void) 830process_postfix_op(void)
831{ 831{
832 buf_add_buf(&code, &token); 832 buf_add_buf(&code, &token);
833 ps.want_blank = true; 833 ps.want_blank = true;
834} 834}
835 835
836static void 836static void
837process_comma(void) 837process_comma(void)
838{ 838{
839 ps.want_blank = code.len > 0; /* only put blank after comma if comma 839 ps.want_blank = code.len > 0; /* only put blank after comma if comma
840 * does not start the line */ 840 * does not start the line */
841 841
842 if (ps.in_decl && ps.ind_paren_level == 0 842 if (ps.in_decl && ps.ind_paren_level == 0
843 && !ps.line_has_func_def && !ps.in_init && !ps.decl_indent_done) { 843 && !ps.line_has_func_def && !ps.in_init && !ps.decl_indent_done) {
844 /* indent leading commas and not the actual identifiers */ 844 /* indent leading commas and not the actual identifiers */
845 indent_declarator(ps.decl_ind - 1, ps.tabs_to_var); 845 indent_declarator(ps.decl_ind - 1, ps.tabs_to_var);
846 } 846 }
847 847
848 buf_add_char(&code, ','); 848 buf_add_char(&code, ',');
849 849
850 if (ps.paren.len == 0) { 850 if (ps.paren.len == 0) {
851 if (ps.init_level == 0) 851 if (ps.init_level == 0)
852 ps.in_init = false; 852 ps.in_init = false;
853 int typical_varname_length = 8; 853 int typical_varname_length = 8;
854 if (ps.break_after_comma && (opt.break_after_comma || 854 if (ps.break_after_comma && (opt.break_after_comma ||
855 ind_add(compute_code_indent(), code.s, code.len) 855 ind_add(compute_code_indent(), code.s, code.len)
856 >= opt.max_line_length - typical_varname_length)) 856 >= opt.max_line_length - typical_varname_length))
857 ps.want_newline = true; 857 ps.want_newline = true;
858 } 858 }
859} 859}
860 860
861static void 861static void
862process_label_colon(void) 862process_label_colon(void)
863{ 863{
864 buf_add_buf(&lab, &code); 864 buf_add_buf(&lab, &code);
865 buf_add_char(&lab, ':'); 865 buf_add_char(&lab, ':');
866 buf_clear(&code); 866 buf_clear(&code);
867 867
868 if (ps.seen_case) 868 if (ps.seen_case)
869 out.line_kind = lk_case_or_default; 869 out.line_kind = lk_case_or_default;
870 ps.in_stmt_or_decl = false; 870 ps.in_stmt_or_decl = false;
871 ps.want_newline = ps.seen_case; 871 ps.want_newline = ps.seen_case;
872 ps.seen_case = false; 872 ps.seen_case = false;
873 ps.want_blank = false; 873 ps.want_blank = false;
874} 874}
875 875
876static void 876static void
877process_other_colon(void) 877process_other_colon(void)
878{ 878{
879 buf_add_char(&code, ':'); 879 buf_add_char(&code, ':');
880 ps.want_blank = ps.decl_level == 0; 880 ps.want_blank = ps.decl_level == 0;
881} 881}
882 882
883static void 883static void
884process_semicolon(void) 884process_semicolon(void)
885{ 885{
886 if (out.line_kind == lk_stmt_head) 886 if (out.line_kind == lk_stmt_head)
887 out.line_kind = lk_other; 887 out.line_kind = lk_other;
888 if (ps.decl_level == 0) { 888 if (ps.decl_level == 0) {
889 ps.in_var_decl = false; 889 ps.in_var_decl = false;
890 ps.in_typedef_decl = false; 890 ps.in_typedef_decl = false;
891 } 891 }
892 ps.seen_case = false; /* only needs to be reset on error */ 892 ps.seen_case = false; /* only needs to be reset on error */
893 ps.quest_level = 0; /* only needs to be reset on error */ 893 ps.quest_level = 0; /* only needs to be reset on error */
894 if (ps.prev_lsym == lsym_rparen) 894 if (ps.prev_lsym == lsym_rparen)
895 ps.in_func_def_params = false; 895 ps.in_func_def_params = false;
896 ps.in_init = false; 896 ps.in_init = false;
897 ps.init_level = 0; 897 ps.init_level = 0;
898 ps.declaration = ps.declaration == decl_begin ? decl_end : decl_no; 898 ps.declaration = ps.declaration == decl_begin ? decl_end : decl_no;
899 899
900 if (ps.in_decl && code.len == 0 && !ps.in_init && 900 if (ps.in_decl && code.len == 0 && !ps.in_init &&
901 !ps.decl_indent_done && ps.ind_paren_level == 0) { 901 !ps.decl_indent_done && ps.ind_paren_level == 0) {
902 /* indent stray semicolons in declarations */ 902 /* indent stray semicolons in declarations */
903 indent_declarator(ps.decl_ind - 1, ps.tabs_to_var); 903 indent_declarator(ps.decl_ind - 1, ps.tabs_to_var);
904 } 904 }
905 905
906 ps.in_decl = ps.decl_level > 0; /* if we were in a first level 906 ps.in_decl = ps.decl_level > 0; /* if we were in a first level
907 * structure declaration before, we 907 * structure declaration before, we
908 * aren't anymore */ 908 * aren't anymore */
909 909
910 if (ps.paren.len > 0 && ps.spaced_expr_psym != psym_for_exprs) { 910 if (ps.paren.len > 0 && ps.spaced_expr_psym != psym_for_exprs) {
911 diag(1, "Unbalanced parentheses"); 911 diag(1, "Unbalanced parentheses");
912 ps.paren.len = 0; 912 ps.paren.len = 0;
913 if (ps.spaced_expr_psym != psym_0) { 913 if (ps.spaced_expr_psym != psym_0) {
914 parse(ps.spaced_expr_psym); 914 parse(ps.spaced_expr_psym);
915 ps.spaced_expr_psym = psym_0; 915 ps.spaced_expr_psym = psym_0;
916 } 916 }
917 } 917 }
918 buf_add_char(&code, ';'); 918 buf_add_char(&code, ';');
919 ps.want_blank = true; 919 ps.want_blank = true;
920 ps.in_stmt_or_decl = ps.paren.len > 0; 920 ps.in_stmt_or_decl = ps.paren.len > 0;
921 ps.decl_ind = 0; 921 ps.decl_ind = 0;
922 922
923 if (ps.spaced_expr_psym == psym_0) { 923 if (ps.spaced_expr_psym == psym_0) {
924 parse(psym_stmt); 924 parse(psym_stmt);
925 ps.want_newline = true; 925 ps.want_newline = true;
926 } 926 }
927} 927}
928 928
929static void 929static void
930process_type_outside_parentheses(void) 930process_type_outside_parentheses(void)
931{ 931{
932 parse(psym_decl); /* let the parser worry about indentation */ 932 parse(psym_decl); /* let the parser worry about indentation */
933 933
934 if (ps.prev_lsym == lsym_rparen && ps.psyms.len <= 2 && code.len > 0) 934 if (ps.prev_lsym == lsym_rparen && ps.psyms.len <= 2 && code.len > 0)
935 output_line(); 935 output_line();
936 936
937 if (ps.in_func_def_params && opt.indent_parameters && 937 if (ps.in_func_def_params && opt.indent_parameters &&
938 ps.decl_level == 0) { 938 ps.decl_level == 0) {
939 ps.ind_level = ps.ind_level_follow = 1; 939 ps.ind_level = ps.ind_level_follow = 1;
940 ps.line_is_stmt_cont = false; 940 ps.line_is_stmt_cont = false;
941 } 941 }
942 942
943 ps.in_var_decl = /* maybe */ true; 943 ps.in_var_decl = /* maybe */ true;
944 ps.in_decl = true; 944 ps.in_decl = true;
945 ps.line_has_decl = ps.in_decl; 945 ps.line_has_decl = ps.in_decl;
946 if (ps.decl_level == 0) 946 if (ps.decl_level == 0)
947 ps.declaration = decl_begin; 947 ps.declaration = decl_begin;
948 948
949 int ind = ps.ind_level > 0 && ps.decl_level == 0 949 int ind = ps.ind_level > 0 && ps.decl_level == 0
950 ? opt.local_decl_indent /* local variable */ 950 ? opt.local_decl_indent /* local variable */
951 : opt.decl_indent; /* global variable, or member */ 951 : opt.decl_indent; /* global variable, or member */
952 if (ind == 0) { 952 if (ind == 0) {
953 int ind0 = code.len > 0 ? ind_add(0, code.s, code.len) + 1 : 0; 953 int ind0 = code.len > 0 ? ind_add(0, code.s, code.len) + 1 : 0;
954 ps.decl_ind = ind_add(ind0, token.s, token.len) + 1; 954 ps.decl_ind = ind_add(ind0, token.s, token.len) + 1;
955 } else 955 } else
956 ps.decl_ind = ind; 956 ps.decl_ind = ind;
957 ps.tabs_to_var = opt.use_tabs && ind > 0; 957 ps.tabs_to_var = opt.use_tabs && ind > 0;
958} 958}
959 959
960static void 960static void
961process_word(lexer_symbol lsym) 961process_word(lexer_symbol lsym)
962{ 962{
963 if (ps.in_decl) { 963 if (ps.in_decl) {
964 if (lsym == lsym_funcname) { 964 if (lsym == lsym_funcname) {
965 ps.in_decl = false; 965 ps.in_decl = false;
966 if (opt.procnames_start_line && code.len > 0) 966 if (opt.procnames_start_line && code.len > 0)
967 output_line(); 967 output_line();
968 else if (ps.want_blank) 968 else if (ps.want_blank)
969 buf_add_char(&code, ' '); 969 buf_add_char(&code, ' ');
970 ps.want_blank = false; 970 ps.want_blank = false;
971 } else if (ps.in_typedef_decl && ps.decl_level == 0) { 971 } else if (ps.in_typedef_decl && ps.decl_level == 0) {
972 /* Do not indent typedef declarators. */ 972 /* Do not indent typedef declarators. */
973 } else if (!ps.in_init && !ps.decl_indent_done && 973 } else if (!ps.in_init && !ps.decl_indent_done &&
974 ps.ind_paren_level == 0) { 974 ps.ind_paren_level == 0) {
975 if (opt.decl_indent == 0 975 if (opt.decl_indent == 0
976 && code.len > 0 && code.s[code.len - 1] == '}') 976 && code.len > 0 && code.s[code.len - 1] == '}')
977 ps.decl_ind = ind_add(0, code.s, code.len) + 1; 977 ps.decl_ind = ind_add(0, code.s, code.len) + 1;
978 indent_declarator(ps.decl_ind, ps.tabs_to_var); 978 indent_declarator(ps.decl_ind, ps.tabs_to_var);
979 } 979 }
980 980
981 } else if (ps.spaced_expr_psym != psym_0 && ps.paren.len == 0) { 981 } else if (ps.spaced_expr_psym != psym_0 && ps.paren.len == 0) {
982 parse(ps.spaced_expr_psym); 982 parse(ps.spaced_expr_psym);
983 ps.spaced_expr_psym = psym_0; 983 ps.spaced_expr_psym = psym_0;
984 ps.want_newline = true; 984 ps.want_newline = true;
985 ps.in_stmt_or_decl = false; 985 ps.in_stmt_or_decl = false;
986 ps.next_unary = true; 986 ps.next_unary = true;
987 } 987 }
988} 988}
989 989
990static void 990static void
991process_do(void) 991process_do(void)
992{ 992{
993 ps.in_stmt_or_decl = false; 993 ps.in_stmt_or_decl = false;
994 ps.in_decl = false; 994 ps.in_decl = false;
995 995
996 if (code.len > 0) 996 if (code.len > 0)
997 output_line(); 997 output_line();
998 998
999 parse(psym_do); 999 parse(psym_do);
1000 ps.want_newline = true; 1000 ps.want_newline = true;
1001} 1001}
1002 1002
1003static void 1003static void
1004process_else(void) 1004process_else(void)
1005{ 1005{
1006 ps.in_stmt_or_decl = false; 1006 ps.in_stmt_or_decl = false;
1007 ps.in_decl = false; 1007 ps.in_decl = false;
1008 1008
1009 if (code.len > 0 1009 if (code.len > 0
1010 && !(opt.cuddle_else && code.s[code.len - 1] == '}')) 1010 && !(opt.cuddle_else && code.s[code.len - 1] == '}'))
1011 output_line(); 1011 output_line();
1012 1012
1013 parse(psym_else); 1013 parse(psym_else);
1014 ps.want_newline = true; 1014 ps.want_newline = true;
1015} 1015}
1016 1016
1017static void 1017static void
1018process_lsym(lexer_symbol lsym) 1018process_lsym(lexer_symbol lsym)
1019{ 1019{
1020 switch (lsym) { 1020 switch (lsym) {
1021 /* INDENT OFF */ 1021 /* INDENT OFF */
1022 case lsym_preprocessing: process_preprocessing(); break; 1022 case lsym_preprocessing: process_preprocessing(); break;
1023 case lsym_newline: process_newline(); break; 1023 case lsym_newline: process_newline(); break;
1024 case lsym_comment: process_comment(); break; 1024 case lsym_comment: process_comment(); break;
1025 case lsym_lparen: process_lparen(); break; 1025 case lsym_lparen: process_lparen(); break;
1026 case lsym_lbracket: process_lbracket(); break; 1026 case lsym_lbracket: process_lbracket(); break;
1027 case lsym_rparen: process_rparen(); break; 1027 case lsym_rparen: process_rparen(); break;
1028 case lsym_rbracket: process_rbracket(); break; 1028 case lsym_rbracket: process_rbracket(); break;
1029 case lsym_lbrace: process_lbrace(); break; 1029 case lsym_lbrace: process_lbrace(); break;
1030 case lsym_rbrace: process_rbrace(); break; 1030 case lsym_rbrace: process_rbrace(); break;
1031 case lsym_period: process_period(); break; 1031 case lsym_period: process_period(); break;
1032 case lsym_unary_op: process_unary_op(); break; 1032 case lsym_unary_op: process_unary_op(); break;
1033 case lsym_postfix_op: process_postfix_op(); break; 1033 case lsym_postfix_op: process_postfix_op(); break;
1034 case lsym_binary_op: goto copy_token; 1034 case lsym_binary_op: goto copy_token;
1035 case lsym_question: ps.quest_level++; goto copy_token; 1035 case lsym_question: ps.quest_level++; goto copy_token;
1036 case lsym_question_colon: goto copy_token; 1036 case lsym_question_colon: goto copy_token;
1037 case lsym_label_colon: process_label_colon(); break; 1037 case lsym_label_colon: process_label_colon(); break;
1038 case lsym_other_colon: process_other_colon(); break; 1038 case lsym_other_colon: process_other_colon(); break;
1039 case lsym_comma: process_comma(); break; 1039 case lsym_comma: process_comma(); break;
1040 case lsym_semicolon: process_semicolon(); break; 1040 case lsym_semicolon: process_semicolon(); break;
1041 case lsym_typedef: ps.in_typedef_decl = true; goto copy_token; 1041 case lsym_typedef: ps.in_typedef_decl = true; goto copy_token;
1042 case lsym_modifier: goto copy_token; 1042 case lsym_modifier: goto copy_token;
1043 case lsym_case: ps.seen_case = true; goto copy_token; 1043 case lsym_case: ps.seen_case = true; goto copy_token;
1044 case lsym_default: ps.seen_case = true; goto copy_token; 1044 case lsym_default: ps.seen_case = true; goto copy_token;
1045 case lsym_do: process_do(); goto copy_token; 1045 case lsym_do: process_do(); goto copy_token;
1046 case lsym_else: process_else(); goto copy_token; 1046 case lsym_else: process_else(); goto copy_token;
1047 case lsym_for: ps.spaced_expr_psym = psym_for_exprs; goto copy_token; 1047 case lsym_for: ps.spaced_expr_psym = psym_for_exprs; goto copy_token;
1048 case lsym_if: ps.spaced_expr_psym = psym_if_expr; goto copy_token; 1048 case lsym_if: ps.spaced_expr_psym = psym_if_expr; goto copy_token;
1049 case lsym_switch: ps.spaced_expr_psym = psym_switch_expr; goto copy_token; 1049 case lsym_switch: ps.spaced_expr_psym = psym_switch_expr; goto copy_token;
1050 case lsym_while: ps.spaced_expr_psym = psym_while_expr; goto copy_token; 1050 case lsym_while: ps.spaced_expr_psym = psym_while_expr; goto copy_token;
1051 /* INDENT ON */ 1051 /* INDENT ON */
1052 1052
1053 case lsym_tag: 1053 case lsym_tag:
1054 if (ps.paren.len > 0) 1054 if (ps.paren.len > 0)
1055 goto copy_token; 1055 goto copy_token;
1056 /* FALLTHROUGH */ 1056 /* FALLTHROUGH */
1057 case lsym_type: 1057 case lsym_type:
1058 if (ps.paren.len == 0) { 1058 if (ps.paren.len == 0) {
1059 process_type_outside_parentheses(); 1059 process_type_outside_parentheses();
1060 goto copy_token; 1060 goto copy_token;
1061 } 1061 }
1062 /* FALLTHROUGH */ 1062 /* FALLTHROUGH */
1063 case lsym_sizeof: 1063 case lsym_sizeof:
1064 case lsym_offsetof: 1064 case lsym_offsetof:
1065 case lsym_word: 1065 case lsym_word:
1066 case lsym_funcname: 1066 case lsym_funcname:
1067 case lsym_return: 1067 case lsym_return:
1068 process_word(lsym); 1068 process_word(lsym);
1069copy_token: 1069copy_token:
1070 if (ps.want_blank) 1070 if (ps.want_blank)
1071 buf_add_char(&code, ' '); 1071 buf_add_char(&code, ' ');
1072 buf_add_buf(&code, &token); 1072 buf_add_buf(&code, &token);
1073 if (lsym != lsym_funcname) 1073 if (lsym != lsym_funcname)
1074 ps.want_blank = true; 1074 ps.want_blank = true;
1075 break; 1075 break;
1076 1076
1077 default: 1077 default:
1078 break; 1078 break;
1079 } 1079 }
1080} 1080}
1081 1081
1082static int 1082static int
1083indent(void) 1083indent(void)
1084{ 1084{
1085 debug_parser_state(); 1085 debug_parser_state();
1086 1086
1087 for (;;) { /* loop until we reach eof */ 1087 for (;;) { /* loop until we reach eof */
1088 lexer_symbol lsym = lexi(); 1088 lexer_symbol lsym = lexi();
1089 1089
1090 debug_blank_line(); 1090 debug_blank_line();
1091 debug_printf("line %d: %s", line_no, lsym_name[lsym]); 1091 debug_printf("line %d: %s", line_no, lsym_name[lsym]);
1092 debug_print_buf("token", &token); 1092 debug_print_buf("token", &token);
1093 debug_buffers(); 1093 debug_buffers();
1094 debug_blank_line(); 1094 debug_blank_line();
1095 1095
1096 if (lsym == lsym_eof) 1096 if (lsym == lsym_eof)
1097 return process_eof(); 1097 return process_eof();
1098 1098
1099 if (lsym == lsym_preprocessing || lsym == lsym_newline) 1099 if (lsym == lsym_preprocessing || lsym == lsym_newline)
1100 ps.want_newline = false; 1100 ps.want_newline = false;
1101 else if (lsym == lsym_comment) { 1101 else if (lsym == lsym_comment) {
1102 /* no special processing */ 1102 /* no special processing */
1103 } else { 1103 } else {
1104 if (lsym == lsym_if && ps.prev_lsym == lsym_else 1104 if (lsym == lsym_if && ps.prev_lsym == lsym_else
1105 && opt.else_if_in_same_line) 1105 && opt.else_if_in_same_line)
1106 ps.want_newline = false; 1106 ps.want_newline = false;
1107 1107
1108 if (ps.want_newline && should_break_line(lsym)) { 1108 if (ps.want_newline && should_break_line(lsym)) {
1109 ps.want_newline = false; 1109 ps.want_newline = false;
1110 output_line(); 1110 output_line();
1111 } 1111 }
1112 ps.in_stmt_or_decl = true; 1112 ps.in_stmt_or_decl = true;
1113 if (com.len > 0) 1113 if (com.len > 0)
1114 move_com_to_code(lsym); 1114 move_com_to_code(lsym);
1115 update_ps_lbrace_kind(lsym); 1115 update_ps_lbrace_kind(lsym);
1116 } 1116 }
1117 1117
1118 process_lsym(lsym); 1118 process_lsym(lsym);
1119 1119
1120 if (lsym != lsym_preprocessing 1120 if (lsym != lsym_preprocessing
1121 && lsym != lsym_newline 1121 && lsym != lsym_newline
1122 && lsym != lsym_comment) 1122 && lsym != lsym_comment)
1123 ps.prev_lsym = lsym; 1123 ps.prev_lsym = lsym;
1124 1124
1125 debug_parser_state(); 1125 debug_parser_state();
1126 } 1126 }
1127} 1127}
1128 1128
1129int 1129int
1130main(int argc, char **argv) 1130main(int argc, char **argv)
1131{ 1131{
1132 init_globals(); 1132 init_globals();
1133 load_profiles(argc, argv); 1133 load_profiles(argc, argv);
1134 parse_command_line(argc, argv); 1134 parse_command_line(argc, argv);
1135 set_initial_indentation(); 1135 set_initial_indentation();
1136 return indent(); 1136 return indent();
1137} 1137}

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

--- src/usr.bin/indent/io.c 2023/06/16 11:48:32 1.227
+++ src/usr.bin/indent/io.c 2023/06/17 22:28:49 1.228
@@ -1,438 +1,444 @@ @@ -1,438 +1,444 @@
1/* $NetBSD: io.c,v 1.227 2023/06/16 11:48:32 rillig Exp $ */ 1/* $NetBSD: io.c,v 1.228 2023/06/17 22:28:49 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.227 2023/06/16 11:48:32 rillig Exp $"); 41__RCSID("$NetBSD: io.c,v 1.228 2023/06/17 22:28:49 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 newlines = 2; /* the total of written and buffered newlines; 53static unsigned newlines = 2; /* the total of written and buffered newlines;
54 * 0 in the middle of a line, 1 after a single 54 * 0 in the middle of a line, 1 after a single
55 * finished line, anything > 1 are trailing 55 * finished line, anything > 1 are trailing
56 * blank lines */ 56 * blank lines */
57static unsigned buffered_newlines; /* not yet written */ 57static unsigned buffered_newlines; /* not yet written */
58static int paren_indent; /* total indentation when parenthesized */ 58static int paren_indent; /* total indentation when parenthesized */
59 59
60 60
61static void 61static void
62inp_read_next_line(void) 62inp_read_next_line(void)
63{ 63{
64 buf_clear(&inp); 64 buf_clear(&inp);
65 65
66 for (;;) { 66 for (;;) {
67 int ch = getc(input); 67 int ch = getc(input);
68 if (ch == EOF) { 68 if (ch == EOF) {
69 if (indent_enabled == indent_on) { 69 if (indent_enabled == indent_on) {
70 buf_add_char(&inp, ' '); 70 buf_add_char(&inp, ' ');
71 buf_add_char(&inp, '\n'); 71 buf_add_char(&inp, '\n');
72 } 72 }
73 had_eof = true; 73 had_eof = true;
74 break; 74 break;
75 } 75 }
76 76
77 if (ch != '\0') 77 if (ch != '\0')
78 buf_add_char(&inp, (char)ch); 78 buf_add_char(&inp, (char)ch);
79 if (ch == '\n') 79 if (ch == '\n')
80 break; 80 break;
81 } 81 }
82 buf_terminate(&inp); 82 buf_terminate(&inp);
83 inp_p = inp.s; 83 inp_p = inp.s;
84} 84}
85 85
86void 86void
87inp_read_line(void) 87inp_read_line(void)
88{ 88{
89 if (indent_enabled == indent_on) 89 if (indent_enabled == indent_on)
90 buf_clear(&out.indent_off_text); 90 buf_clear(&out.indent_off_text);
91 buf_add_chars(&out.indent_off_text, inp.s, inp.len); 91 buf_add_chars(&out.indent_off_text, inp.s, inp.len);
92 inp_read_next_line(); 92 inp_read_next_line();
93} 93}
94 94
95void 95void
96inp_skip(void) 96inp_skip(void)
97{ 97{
98 inp_p++; 98 inp_p++;
99 if ((size_t)(inp_p - inp.s) >= inp.len) 99 if ((size_t)(inp_p - inp.s) >= inp.len)
100 inp_read_line(); 100 inp_read_line();
101} 101}
102 102
103char 103char
104inp_next(void) 104inp_next(void)
105{ 105{
106 char ch = inp_p[0]; 106 char ch = inp_p[0];
107 inp_skip(); 107 inp_skip();
108 return ch; 108 return ch;
109} 109}
110 110
111 111
112static void 112static void
113add_buffered_newline(void) 113add_buffered_newline(void)
114{ 114{
115 buffered_newlines++; 115 buffered_newlines++;
116 newlines++; 116 newlines++;
117 out_ind = 0; 117 out_ind = 0;
118} 118}
119 119
120static void 120static void
121write_buffered_newlines(void) 121write_buffered_newlines(void)
122{ 122{
123 for (; buffered_newlines > 0; buffered_newlines--) { 123 for (; buffered_newlines > 0; buffered_newlines--) {
124 fputc('\n', output); 124 fputc('\n', output);
125 debug_println("write_newline"); 125 debug_println("write_newline");
126 } 126 }
127} 127}
128 128
129static void 129static void
130write_range(const char *s, size_t len) 130write_range(const char *s, size_t len)
131{ 131{
132 write_buffered_newlines(); 132 write_buffered_newlines();
133 fwrite(s, 1, len, output); 133 fwrite(s, 1, len, output);
134 debug_printf("write_range "); 134 debug_printf("write_range ");
135 debug_vis_range(s, len); 135 debug_vis_range(s, len);
136 debug_println(""); 136 debug_println("");
137 for (size_t i = 0; i < len; i++) 137 for (size_t i = 0; i < len; i++)
138 newlines = s[i] == '\n' ? newlines + 1 : 0; 138 newlines = s[i] == '\n' ? newlines + 1 : 0;
139 out_ind = ind_add(out_ind, s, len); 139 out_ind = ind_add(out_ind, s, len);
140} 140}
141 141
142static void 142static void
143write_indent(int new_ind) 143write_indent(int new_ind)
144{ 144{
145 write_buffered_newlines(); 145 write_buffered_newlines();
146 146
147 int ind = out_ind; 147 int ind = out_ind;
148 148
149 if (opt.use_tabs) { 149 if (opt.use_tabs) {
150 int n = new_ind / opt.tabsize - ind / opt.tabsize; 150 int n = new_ind / opt.tabsize - ind / opt.tabsize;
151 if (n > 0) { 151 if (n > 0) {
152 ind = ind - ind % opt.tabsize + n * opt.tabsize; 152 ind = ind - ind % opt.tabsize + n * opt.tabsize;
153 while (n-- > 0) 153 while (n-- > 0)
154 fputc('\t', output); 154 fputc('\t', output);
155 newlines = 0; 155 newlines = 0;
156 } 156 }
157 } 157 }
158 158
159 for (; ind < new_ind; ind++) { 159 for (; ind < new_ind; ind++) {
160 fputc(' ', output); 160 fputc(' ', output);
161 newlines = 0; 161 newlines = 0;
162 } 162 }
163 163
164 debug_println("write_indent %d", ind); 164 debug_println("write_indent %d", ind);
165 out_ind = ind; 165 out_ind = ind;
166} 166}
167 167
168static bool 168static bool
169want_blank_line(void) 169want_blank_line(void)
170{ 170{
171 debug_println("%s: %s -> %s", __func__, 171 debug_println("%s: %s -> %s", __func__,
172 line_kind_name[out.prev_line_kind], line_kind_name[out.line_kind]); 172 line_kind_name[out.prev_line_kind], line_kind_name[out.line_kind]);
173 173
174 if (ps.blank_line_after_decl && ps.declaration == decl_no) { 174 if (ps.blank_line_after_decl && ps.declaration == decl_no) {
175 ps.blank_line_after_decl = false; 175 ps.blank_line_after_decl = false;
176 return true; 176 return true;
177 } 177 }
178 if (opt.blank_line_around_conditional_compilation) { 178 if (opt.blank_line_around_conditional_compilation) {
179 if (out.prev_line_kind != lk_pre_if 179 if (out.prev_line_kind != lk_pre_if
180 && out.line_kind == lk_pre_if) 180 && out.line_kind == lk_pre_if)
181 return true; 181 return true;
182 if (out.prev_line_kind == lk_pre_endif 182 if (out.prev_line_kind == lk_pre_endif
183 && out.line_kind != lk_pre_endif) 183 && out.line_kind != lk_pre_endif)
184 return true; 184 return true;
185 } 185 }
186 if (opt.blank_line_after_proc && out.prev_line_kind == lk_func_end 186 if (opt.blank_line_after_proc && out.prev_line_kind == lk_func_end
187 && out.line_kind != lk_pre_endif && out.line_kind != lk_pre_other) 187 && out.line_kind != lk_pre_endif && out.line_kind != lk_pre_other)
188 return true; 188 return true;
189 if (opt.blank_line_before_block_comment 189 if (opt.blank_line_before_block_comment
190 && out.line_kind == lk_block_comment) 190 && out.line_kind == lk_block_comment)
191 return true; 191 return true;
192 return false; 192 return false;
193} 193}
194 194
195static bool 195static bool
196is_blank_line_optional(void) 196is_blank_line_optional(void)
197{ 197{
198 if (out.prev_line_kind == lk_stmt_head) 198 if (out.prev_line_kind == lk_stmt_head)
199 return newlines >= 1; 199 return newlines >= 1;
200 if (ps.psyms.len >= 3) 200 if (ps.psyms.len >= 3)
201 return newlines >= 2; 201 return newlines >= 2;
202 return newlines >= 3; 202 return newlines >= 3;
203} 203}
204 204
205static int 205static int
206compute_case_label_indent(void) 206compute_case_label_indent(void)
207{ 207{
208 size_t i = ps.psyms.len - 1; 208 size_t i = ps.psyms.len - 1;
209 while (i > 0 && ps.psyms.sym[i] != psym_switch_expr) 209 while (i > 0 && ps.psyms.sym[i] != psym_switch_expr)
210 i--; 210 i--;
211 float case_ind = (float)ps.psyms.ind_level[i] + opt.case_indent; 211 float case_ind = (float)ps.psyms.ind_level[i] + opt.case_indent;
212 // TODO: case_ind may become negative here. 212 // TODO: case_ind may become negative here.
213 return (int)(case_ind * (float)opt.indent_size); 213 return (int)(case_ind * (float)opt.indent_size);
214} 214}
215 215
216int 216int
217compute_label_indent(void) 217compute_label_indent(void)
218{ 218{
219 if (out.line_kind == lk_case_or_default) 219 if (out.line_kind == lk_case_or_default)
220 return compute_case_label_indent(); 220 return compute_case_label_indent();
221 if (lab.s[0] == '#') 221 if (lab.s[0] == '#')
222 return 0; 222 return 0;
223 // TODO: the indentation may become negative here. 223 // TODO: the indentation may become negative here.
224 return opt.indent_size * (ps.ind_level - 2); 224 return opt.indent_size * (ps.ind_level - 2);
225} 225}
226 226
227static void 227static void
228output_line_label(void) 228output_line_label(void)
229{ 229{
230 write_indent(compute_label_indent()); 230 write_indent(compute_label_indent());
231 write_range(lab.s, lab.len); 231 write_range(lab.s, lab.len);
232} 232}
233 233
234static int 234static int
235compute_lined_up_code_indent(int base_ind) 235compute_lined_up_code_indent(int base_ind)
236{ 236{
237 int ind = paren_indent; 237 int ind = paren_indent;
238 int overflow = ind_add(ind, code.s, code.len) - opt.max_line_length; 238 int overflow = ind_add(ind, code.s, code.len) - opt.max_line_length;
239 if (overflow >= 0 239 if (overflow >= 0
240 && ind_add(base_ind, code.s, code.len) < opt.max_line_length) { 240 && ind_add(base_ind, code.s, code.len) < opt.max_line_length) {
241 ind -= 2 + overflow; 241 ind -= 2 + overflow;
242 if (ind < base_ind) 242 if (ind < base_ind)
243 ind = base_ind; 243 ind = base_ind;
244 } 244 }
245 245
246 if (ps.extra_expr_indent != eei_no 246 if (ps.extra_expr_indent != eei_no
247 && ind == base_ind + opt.indent_size) 247 && ind == base_ind + opt.indent_size)
248 ind += opt.continuation_indent; 248 ind += opt.continuation_indent;
249 return ind; 249 return ind;
250} 250}
251 251
252int 252int
253compute_code_indent(void) 253compute_code_indent(void)
254{ 254{
255 int base_ind = ps.ind_level * opt.indent_size; 255 int base_ind = ps.ind_level * opt.indent_size;
256 256
257 if (ps.ind_paren_level == 0) { 257 if (ps.ind_paren_level == 0) {
258 if (ps.line_is_stmt_cont) 258 if (ps.line_is_stmt_cont)
259 return base_ind + opt.continuation_indent; 259 return base_ind + opt.continuation_indent;
260 return base_ind; 260 return base_ind;
261 } 261 }
262 262
263 if (opt.lineup_to_parens) { 263 if (opt.lineup_to_parens) {
264 if (opt.lineup_to_parens_always) 264 if (opt.lineup_to_parens_always)
265 return paren_indent; 265 return paren_indent;
266 return compute_lined_up_code_indent(base_ind); 266 return compute_lined_up_code_indent(base_ind);
267 } 267 }
268 268
269 int rel_ind = opt.continuation_indent * ps.ind_paren_level; 269 int rel_ind = opt.continuation_indent * ps.ind_paren_level;
270 if (ps.extra_expr_indent != eei_no && rel_ind == opt.indent_size) 270 if (ps.extra_expr_indent != eei_no && rel_ind == opt.indent_size)
271 rel_ind += opt.continuation_indent; 271 rel_ind += opt.continuation_indent;
272 return base_ind + rel_ind; 272 return base_ind + rel_ind;
273} 273}
274 274
275static void 275static void
276output_line_code(void) 276output_line_code(void)
277{ 277{
278 int target_ind = compute_code_indent(); 278 int target_ind = compute_code_indent();
279 for (size_t i = 0; i < ps.paren.len; i++) { 279 for (size_t i = 0; i < ps.paren.len; i++) {
280 int paren_ind = ps.paren.item[i].indent; 280 int paren_ind = ps.paren.item[i].indent;
281 if (paren_ind >= 0) { 281 if (paren_ind >= 0) {
282 ps.paren.item[i].indent = 282 ps.paren.item[i].indent =
283 -1 - (paren_ind + target_ind); 283 -1 - (paren_ind + target_ind);
284 debug_println( 284 debug_println(
285 "setting paren_indents[%zu] from %d to %d " 285 "setting paren_indents[%zu] from %d to %d "
286 "for column %d", 286 "for column %d",
287 i, paren_ind, 287 i, paren_ind,
288 ps.paren.item[i].indent, target_ind + 1); 288 ps.paren.item[i].indent, target_ind + 1);
289 } 289 }
290 } 290 }
291 291
292 if (lab.len > 0 && target_ind <= out_ind) 292 if (lab.len > 0 && target_ind <= out_ind)
293 write_range(" ", 1); 293 write_range(" ", 1);
294 write_indent(target_ind); 294 write_indent(target_ind);
295 write_range(code.s, code.len); 295 write_range(code.s, code.len);
296} 296}
297 297
298static void 298static void
299output_comment(void) 299output_comment(void)
300{ 300{
301 int target_ind = ps.comment_ind; 301 int target_ind = ps.comment_ind;
302 const char *p; 302 const char *p;
303 303
304 if (ps.comment_cont) 304 if (ps.comment_cont)
305 target_ind += ps.comment_shift; 305 target_ind += ps.comment_shift;
306 ps.comment_cont = true; 306 ps.comment_cont = true;
307 307
308 /* consider the original indentation in case this is a box comment */ 308 /* consider the original indentation in case this is a box comment */
309 for (p = com.s; *p == '\t'; p++) 309 for (p = com.s; *p == '\t'; p++)
310 target_ind += opt.tabsize; 310 target_ind += opt.tabsize;
311 311
312 for (; target_ind < 0; p++) { 312 for (; target_ind < 0; p++) {
313 if (*p == ' ') 313 if (*p == ' ')
314 target_ind++; 314 target_ind++;
315 else if (*p == '\t') 315 else if (*p == '\t')
316 target_ind = next_tab(target_ind); 316 target_ind = next_tab(target_ind);
317 else { 317 else {
318 target_ind = 0; 318 target_ind = 0;
319 break; 319 break;
320 } 320 }
321 } 321 }
322 322
323 if (out_ind > target_ind) 323 if (out_ind > target_ind)
324 add_buffered_newline(); 324 add_buffered_newline();
325 325
326 while (com.s + com.len > p && ch_isspace(com.s[com.len - 1])) 326 while (com.s + com.len > p && ch_isspace(com.s[com.len - 1]))
327 com.len--; 327 com.len--;
328 buf_terminate(&com); 328 buf_terminate(&com);
329 329
330 write_indent(target_ind); 330 write_indent(target_ind);
331 write_range(p, com.len - (size_t)(p - com.s)); 331 write_range(p, com.len - (size_t)(p - com.s));
332} 332}
333 333
 334/*
 335 * Write a line of formatted source to the output file. The line consists of
 336 * the label, the code and the comment.
 337 */
334static void 338static void
335output_indented_line(void) 339output_indented_line(void)
336{ 340{
337 if (lab.len == 0 && code.len == 0 && com.len == 0) 341 if (lab.len == 0 && code.len == 0 && com.len == 0)
338 out.line_kind = lk_blank; 342 out.line_kind = lk_blank;
339 343
340 if (want_blank_line() && newlines < 2 344 if (want_blank_line() && newlines < 2
341 && out.line_kind != lk_blank) 345 && out.line_kind != lk_blank)
342 add_buffered_newline(); 346 add_buffered_newline();
343 347
344 /* This kludge aligns function definitions correctly. */ 348 /* This kludge aligns function definitions correctly. */
345 if (ps.ind_level == 0) 349 if (ps.ind_level == 0)
346 ps.line_is_stmt_cont = false; 350 ps.line_is_stmt_cont = false;
347 351
348 if (opt.blank_line_after_decl && ps.declaration == decl_end 352 if (opt.blank_line_after_decl && ps.declaration == decl_end
349 && ps.psyms.len > 2) { 353 && ps.psyms.len > 2) {
350 ps.declaration = decl_no; 354 ps.declaration = decl_no;
351 ps.blank_line_after_decl = true; 355 ps.blank_line_after_decl = true;
352 } 356 }
353 357
354 if (opt.swallow_optional_blank_lines 358 if (opt.swallow_optional_blank_lines
355 && out.line_kind == lk_blank 359 && out.line_kind == lk_blank
356 && is_blank_line_optional()) 360 && is_blank_line_optional())
357 return; 361 return;
358 362
359 if (lab.len > 0) 363 if (lab.len > 0)
360 output_line_label(); 364 output_line_label();
361 if (code.len > 0) 365 if (code.len > 0)
362 output_line_code(); 366 output_line_code();
363 if (com.len > 0) 367 if (com.len > 0)
364 output_comment(); 368 output_comment();
365 add_buffered_newline(); 369 add_buffered_newline();
366 if (out.line_kind != lk_blank) 370 if (out.line_kind != lk_blank)
367 write_buffered_newlines(); 371 write_buffered_newlines();
368 372
369 out.prev_line_kind = out.line_kind; 373 out.prev_line_kind = out.line_kind;
370} 374}
371 375
372static bool 376static bool
373is_stmt_cont(void) 377is_stmt_cont(void)
374{ 378{
375 if (ps.psyms.len >= 2 379 if (ps.psyms.len >= 2
376 && ps.psyms.sym[ps.psyms.len - 2] == psym_lbrace_enum 380 && ps.psyms.sym[ps.psyms.len - 2] == psym_lbrace_enum
377 && ps.prev_lsym == lsym_comma 381 && ps.prev_lsym == lsym_comma
378 && ps.paren.len == 0) 382 && ps.paren.len == 0)
379 return false; 383 return false;
380 return ps.in_stmt_or_decl 384 return ps.in_stmt_or_decl
381 && (!ps.in_decl || ps.in_init) 385 && (!ps.in_decl || ps.in_init)
382 && ps.init_level == 0; 386 && ps.init_level == 0;
383} 387}
384 388
385/* 389static void
386 * Write a line of formatted source to the output file. The line consists of 390prepare_next_line(void)
387 * the label, the code and the comment. 
388 */ 
389void 
390output_line(void) 
391{ 391{
392 debug_blank_line(); 
393 debug_printf("%s", __func__); 
394 debug_buffers(); 
395 
396 if (indent_enabled == indent_on) 
397 output_indented_line(); 
398 else if (indent_enabled == indent_last_off_line) { 
399 indent_enabled = indent_on; 
400 write_range(out.indent_off_text.s, out.indent_off_text.len); 
401 buf_clear(&out.indent_off_text); 
402 } 
403 
404 buf_clear(&lab); 
405 buf_clear(&code); 
406 buf_clear(&com); 
407 
408 ps.line_has_decl = ps.in_decl; 392 ps.line_has_decl = ps.in_decl;
409 ps.line_has_func_def = false; 393 ps.line_has_func_def = false;
410 ps.line_is_stmt_cont = is_stmt_cont(); 394 ps.line_is_stmt_cont = is_stmt_cont();
411 ps.decl_indent_done = false; 395 ps.decl_indent_done = false;
412 if (ps.extra_expr_indent == eei_last) 396 if (ps.extra_expr_indent == eei_last)
413 ps.extra_expr_indent = eei_no; 397 ps.extra_expr_indent = eei_no;
414 if (!(ps.psyms.sym[ps.psyms.len - 1] == psym_if_expr_stmt_else 398 if (!(ps.psyms.sym[ps.psyms.len - 1] == psym_if_expr_stmt_else
415 && ps.paren.len > 0)) 399 && ps.paren.len > 0))
416 ps.ind_level = ps.ind_level_follow; 400 ps.ind_level = ps.ind_level_follow;
417 ps.ind_paren_level = (int)ps.paren.len; 401 ps.ind_paren_level = (int)ps.paren.len;
418 ps.want_blank = false; 402 ps.want_blank = false;
419 403
420 if (ps.paren.len > 0) { 404 if (ps.paren.len > 0) {
421 /* TODO: explain what negative indentation means */ 405 /* TODO: explain what negative indentation means */
422 paren_indent = -1 - ps.paren.item[ps.paren.len - 1].indent; 406 paren_indent = -1 - ps.paren.item[ps.paren.len - 1].indent;
423 debug_println("paren_indent is now %d", paren_indent); 407 debug_println("paren_indent is now %d", paren_indent);
424 } 408 }
425 409
426 out.line_kind = lk_other; 410 out.line_kind = lk_other;
427} 411}
428 412
429void 413void
 414output_line(void)
 415{
 416 debug_blank_line();
 417 debug_printf("%s", __func__);
 418 debug_buffers();
 419
 420 if (indent_enabled == indent_on)
 421 output_indented_line();
 422 else if (indent_enabled == indent_last_off_line) {
 423 indent_enabled = indent_on;
 424 write_range(out.indent_off_text.s, out.indent_off_text.len);
 425 buf_clear(&out.indent_off_text);
 426 }
 427
 428 buf_clear(&lab);
 429 buf_clear(&code);
 430 buf_clear(&com);
 431
 432 prepare_next_line();
 433}
 434
 435void
430finish_output(void) 436finish_output(void)
431{ 437{
432 output_line(); 438 output_line();
433 if (indent_enabled != indent_on) { 439 if (indent_enabled != indent_on) {
434 indent_enabled = indent_last_off_line; 440 indent_enabled = indent_last_off_line;
435 output_line(); 441 output_line();
436 } 442 }
437 fflush(output); 443 fflush(output);
438} 444}

cvs diff -r1.230 -r1.231 src/usr.bin/indent/lexi.c (switch to unified diff)

--- src/usr.bin/indent/lexi.c 2023/06/16 23:51:32 1.230
+++ src/usr.bin/indent/lexi.c 2023/06/17 22:28:49 1.231
@@ -1,682 +1,682 @@ @@ -1,682 +1,682 @@
1/* $NetBSD: lexi.c,v 1.230 2023/06/16 23:51:32 rillig Exp $ */ 1/* $NetBSD: lexi.c,v 1.231 2023/06/17 22:28:49 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: lexi.c,v 1.230 2023/06/16 23:51:32 rillig Exp $"); 41__RCSID("$NetBSD: lexi.c,v 1.231 2023/06/17 22:28:49 rillig Exp $");
42 42
43#include <stdlib.h> 43#include <stdlib.h>
44#include <string.h> 44#include <string.h>
45 45
46#include "indent.h" 46#include "indent.h"
47 47
48/* must be sorted alphabetically, is used in binary search */ 48/* must be sorted alphabetically, is used in binary search */
49static const struct keyword { 49static const struct keyword {
50 const char name[12]; 50 const char name[12];
51 lexer_symbol lsym; 51 lexer_symbol lsym;
52} keywords[] = { 52} keywords[] = {
53 {"_Bool", lsym_type}, 53 {"_Bool", lsym_type},
54 {"_Complex", lsym_type}, 54 {"_Complex", lsym_type},
55 {"_Imaginary", lsym_type}, 55 {"_Imaginary", lsym_type},
56 {"auto", lsym_modifier}, 56 {"auto", lsym_modifier},
57 {"bool", lsym_type}, 57 {"bool", lsym_type},
58 {"break", lsym_word}, 58 {"break", lsym_word},
59 {"case", lsym_case}, 59 {"case", lsym_case},
60 {"char", lsym_type}, 60 {"char", lsym_type},
61 {"complex", lsym_type}, 61 {"complex", lsym_type},
62 {"const", lsym_modifier}, 62 {"const", lsym_modifier},
63 {"continue", lsym_word}, 63 {"continue", lsym_word},
64 {"default", lsym_default}, 64 {"default", lsym_default},
65 {"do", lsym_do}, 65 {"do", lsym_do},
66 {"double", lsym_type}, 66 {"double", lsym_type},
67 {"else", lsym_else}, 67 {"else", lsym_else},
68 {"enum", lsym_tag}, 68 {"enum", lsym_tag},
69 {"extern", lsym_modifier}, 69 {"extern", lsym_modifier},
70 {"float", lsym_type}, 70 {"float", lsym_type},
71 {"for", lsym_for}, 71 {"for", lsym_for},
72 {"goto", lsym_word}, 72 {"goto", lsym_word},
73 {"if", lsym_if}, 73 {"if", lsym_if},
74 {"imaginary", lsym_type}, 74 {"imaginary", lsym_type},
75 {"inline", lsym_modifier}, 75 {"inline", lsym_modifier},
76 {"int", lsym_type}, 76 {"int", lsym_type},
77 {"long", lsym_type}, 77 {"long", lsym_type},
78 {"offsetof", lsym_offsetof}, 78 {"offsetof", lsym_offsetof},
79 {"register", lsym_modifier}, 79 {"register", lsym_modifier},
80 {"restrict", lsym_word}, 80 {"restrict", lsym_word},
81 {"return", lsym_return}, 81 {"return", lsym_return},
82 {"short", lsym_type}, 82 {"short", lsym_type},
83 {"signed", lsym_type}, 83 {"signed", lsym_type},
84 {"sizeof", lsym_sizeof}, 84 {"sizeof", lsym_sizeof},
85 {"static", lsym_modifier}, 85 {"static", lsym_modifier},
86 {"struct", lsym_tag}, 86 {"struct", lsym_tag},
87 {"switch", lsym_switch}, 87 {"switch", lsym_switch},
88 {"typedef", lsym_typedef}, 88 {"typedef", lsym_typedef},
89 {"union", lsym_tag}, 89 {"union", lsym_tag},
90 {"unsigned", lsym_type}, 90 {"unsigned", lsym_type},
91 {"void", lsym_type}, 91 {"void", lsym_type},
92 {"volatile", lsym_modifier}, 92 {"volatile", lsym_modifier},
93 {"while", lsym_while} 93 {"while", lsym_while}
94}; 94};
95 95
96static struct { 96static struct {
97 const char **items; 97 const char **items;
98 unsigned int len; 98 unsigned int len;
99 unsigned int cap; 99 unsigned int cap;
100} typenames; 100} typenames;
101 101
102/*- 102/*-
103 * The transition table below was rewritten by hand from lx's output, given 103 * The transition table below was rewritten by hand from lx's output, given
104 * the following definitions. lx is Katherine Flavel's lexer generator. 104 * the following definitions. lx is Katherine Flavel's lexer generator.
105 * 105 *
106 * O = /[0-7]/; D = /[0-9]/; NZ = /[1-9]/; 106 * O = /[0-7]/; D = /[0-9]/; NZ = /[1-9]/;
107 * H = /[a-f0-9]/i; B = /[0-1]/; HP = /0x/i; 107 * H = /[a-f0-9]/i; B = /[0-1]/; HP = /0x/i;
108 * BP = /0b/i; E = /e[+\-]?/i D+; P = /p[+\-]?/i D+; 108 * BP = /0b/i; E = /e[+\-]?/i D+; P = /p[+\-]?/i D+;
109 * FS = /[fl]/i; IS = /u/i /(l|L|ll|LL)/? | /(l|L|ll|LL)/ /u/i?; 109 * FS = /[fl]/i; IS = /u/i /(l|L|ll|LL)/? | /(l|L|ll|LL)/ /u/i?;
110 * 110 *
111 * D+ E FS? -> $float; 111 * D+ E FS? -> $float;
112 * D* "." D+ E? FS? -> $float; 112 * D* "." D+ E? FS? -> $float;
113 * D+ "." E? FS? -> $float; HP H+ IS? -> $int; 113 * D+ "." E? FS? -> $float; HP H+ IS? -> $int;
114 * HP H+ P FS? -> $float; NZ D* IS? -> $int; 114 * HP H+ P FS? -> $float; NZ D* IS? -> $int;
115 * HP H* "." H+ P FS? -> $float; "0" O* IS? -> $int; 115 * HP H* "." H+ P FS? -> $float; "0" O* IS? -> $int;
116 * HP H+ "." P FS -> $float; BP B+ IS? -> $int; 116 * HP H+ "." P FS -> $float; BP B+ IS? -> $int;
117 */ 117 */
118/* INDENT OFF */ 118/* INDENT OFF */
119static const unsigned char lex_number_state[][26] = { 119static const unsigned char lex_number_state[][26] = {
120 /* examples: 120 /* examples:
121 00 121 00
122 s 0xx 122 s 0xx
123 t 00xaa 123 t 00xaa
124 a 11 101100xxa.. 124 a 11 101100xxa..
125 r 11ee0001101lbuuxx.a.pp 125 r 11ee0001101lbuuxx.a.pp
126 t.01.e+008bLuxll0Ll.aa.p+0 126 t.01.e+008bLuxll0Ll.aa.p+0
127 states: ABCDEFGHIJKLMNOPQRSTUVWXYZ */ 127 states: ABCDEFGHIJKLMNOPQRSTUVWXYZ */
128 [0] = "uuiifuufiuuiiuiiiiiuiuuuuu", /* (other) */ 128 [0] = "uuiifuufiuuiiuiiiiiuiuuuuu", /* (other) */
129 [1] = "CEIDEHHHIJQ U Q VUVVZZZ", /* 0 */ 129 [1] = "CEIDEHHHIJQ U Q VUVVZZZ", /* 0 */
130 [2] = "DEIDEHHHIJQ U Q VUVVZZZ", /* 1 */ 130 [2] = "DEIDEHHHIJQ U Q VUVVZZZ", /* 1 */
131 [3] = "DEIDEHHHIJ U VUVVZZZ", /* 2 3 4 5 6 7 */ 131 [3] = "DEIDEHHHIJ U VUVVZZZ", /* 2 3 4 5 6 7 */
132 [4] = "DEJDEHHHJJ U VUVVZZZ", /* 8 9 */ 132 [4] = "DEJDEHHHJJ U VUVVZZZ", /* 8 9 */
133 [5] = " U VUVV ", /* A a C c D d */ 133 [5] = " U VUVV ", /* A a C c D d */
134 [6] = " K U VUVV ", /* B b */ 134 [6] = " K U VUVV ", /* B b */
135 [7] = " FFF FF U VUVV ", /* E e */ 135 [7] = " FFF FF U VUVV ", /* E e */
136 [8] = " f f U VUVV f", /* F f */ 136 [8] = " f f U VUVV f", /* F f */
137 [9] = " LLf fL PR Li L f", /* L */ 137 [9] = " LLf fL PR Li L f", /* L */
138 [10] = " OOf fO S P O i O f", /* l */ 138 [10] = " OOf fO S P O i O f", /* l */
139 [11] = " FFX ", /* P p */ 139 [11] = " FFX ", /* P p */
140 [12] = " MM M i iiM M ", /* U u */ 140 [12] = " MM M i iiM M ", /* U u */
141 [13] = " N ", /* X x */ 141 [13] = " N ", /* X x */
142 [14] = " G Y ", /* + - */ 142 [14] = " G Y ", /* + - */
143 [15] = "B EE EE T W ", /* . */ 143 [15] = "B EE EE T W ", /* . */
144 /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */ 144 /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
145}; 145};
146/* INDENT ON */ 146/* INDENT ON */
147 147
148static const unsigned char lex_number_row[] = { 148static const unsigned char lex_number_row[] = {
149 ['0'] = 1, 149 ['0'] = 1,
150 ['1'] = 2, 150 ['1'] = 2,
151 ['2'] = 3, ['3'] = 3, ['4'] = 3, ['5'] = 3, ['6'] = 3, ['7'] = 3, 151 ['2'] = 3, ['3'] = 3, ['4'] = 3, ['5'] = 3, ['6'] = 3, ['7'] = 3,
152 ['8'] = 4, ['9'] = 4, 152 ['8'] = 4, ['9'] = 4,
153 ['A'] = 5, ['a'] = 5, ['C'] = 5, ['c'] = 5, ['D'] = 5, ['d'] = 5, 153 ['A'] = 5, ['a'] = 5, ['C'] = 5, ['c'] = 5, ['D'] = 5, ['d'] = 5,
154 ['B'] = 6, ['b'] = 6, 154 ['B'] = 6, ['b'] = 6,
155 ['E'] = 7, ['e'] = 7, 155 ['E'] = 7, ['e'] = 7,
156 ['F'] = 8, ['f'] = 8, 156 ['F'] = 8, ['f'] = 8,
157 ['L'] = 9, 157 ['L'] = 9,
158 ['l'] = 10, 158 ['l'] = 10,
159 ['P'] = 11, ['p'] = 11, 159 ['P'] = 11, ['p'] = 11,
160 ['U'] = 12, ['u'] = 12, 160 ['U'] = 12, ['u'] = 12,
161 ['X'] = 13, ['x'] = 13, 161 ['X'] = 13, ['x'] = 13,
162 ['+'] = 14, ['-'] = 14, 162 ['+'] = 14, ['-'] = 14,
163 ['.'] = 15, 163 ['.'] = 15,
164}; 164};
165 165
166 166
167static bool 167static bool
168is_identifier_start(char ch) 168is_identifier_start(char ch)
169{ 169{
170 return ch_isalpha(ch) || ch == '_' || ch == '$'; 170 return ch_isalpha(ch) || ch == '_' || ch == '$';
171} 171}
172 172
173static bool 173static bool
174is_identifier_part(char ch) 174is_identifier_part(char ch)
175{ 175{
176 return ch_isalnum(ch) || ch == '_' || ch == '$'; 176 return ch_isalnum(ch) || ch == '_' || ch == '$';
177} 177}
178 178
179static void 179static void
180token_add_char(char ch) 180token_add_char(char ch)
181{ 181{
182 buf_add_char(&token, ch); 182 buf_add_char(&token, ch);
183} 183}
184 184
185static void 185static void
186lex_number(void) 186lex_number(void)
187{ 187{
188 for (unsigned char s = 'A'; s != 'f' && s != 'i' && s != 'u';) { 188 for (unsigned char s = 'A'; s != 'f' && s != 'i' && s != 'u';) {
189 unsigned char ch = (unsigned char)inp_p[0]; 189 unsigned char ch = (unsigned char)*inp_p;
190 if (ch == '\\' && inp_p[1] == '\n') { 190 if (ch == '\\' && inp_p[1] == '\n') {
191 inp_p++; 191 inp_p++;
192 inp_skip(); 192 inp_skip();
193 line_no++; 193 line_no++;
194 continue; 194 continue;
195 } 195 }
196 if (ch >= array_length(lex_number_row) 196 if (ch >= array_length(lex_number_row)
197 || lex_number_row[ch] == 0) 197 || lex_number_row[ch] == 0)
198 break; 198 break;
199 199
200 unsigned char row = lex_number_row[ch]; 200 unsigned char row = lex_number_row[ch];
201 if (lex_number_state[row][s - 'A'] == ' ') { 201 if (lex_number_state[row][s - 'A'] == ' ') {
202 /*- 202 // lex_number_state[0][s - 'A'] now indicates the type:
203 * lex_number_state[0][s - 'A'] now indicates the type: 203 // f = floating, i = integer, u = unknown
204 * f = floating, i = integer, u = unknown 
205 */ 
206 return; 204 return;
207 } 205 }
208 206
209 s = lex_number_state[row][s - 'A']; 207 s = lex_number_state[row][s - 'A'];
210 token_add_char(inp_next()); 208 token_add_char(inp_next());
211 } 209 }
212} 210}
213 211
214static void 212static void
215lex_word(void) 213lex_word(void)
216{ 214{
217 for (;;) { 215 for (;;) {
218 if (is_identifier_part(inp_p[0])) 216 if (is_identifier_part(inp_p[0]))
219 token_add_char(*inp_p++); 217 token_add_char(*inp_p++);
220 else if (inp_p[0] == '\\' && inp_p[1] == '\n') { 218 else if (inp_p[0] == '\\' && inp_p[1] == '\n') {
221 inp_p++; 219 inp_p++;
222 inp_skip(); 220 inp_skip();
223 line_no++; 221 line_no++;
224 } else 222 } else
225 return; 223 return;
226 } 224 }
227} 225}
228 226
229static void 227static void
230lex_char_or_string(void) 228lex_char_or_string(void)
231{ 229{
232 for (char delim = token.s[token.len - 1];;) { 230 for (char delim = token.s[token.len - 1];;) {
233 if (inp_p[0] == '\n') { 231 if (*inp_p == '\n') {
234 diag(1, "Unterminated literal"); 232 diag(1, "Unterminated literal");
235 return; 233 return;
236 } 234 }
237 235
238 token_add_char(*inp_p++); 236 token_add_char(*inp_p++);
239 if (token.s[token.len - 1] == delim) 237 if (token.s[token.len - 1] == delim)
240 return; 238 return;
241 239
242 if (token.s[token.len - 1] == '\\') { 240 if (token.s[token.len - 1] == '\\') {
243 if (inp_p[0] == '\n') 241 if (*inp_p == '\n')
244 ++line_no; 242 line_no++;
245 token_add_char(inp_next()); 243 token_add_char(inp_next());
246 } 244 }
247 } 245 }
248} 246}
249 247
250/* Guess whether the current token is a declared type. */ 248/* Guess whether the current token is a declared type. */
251static bool 249static bool
252probably_typename(void) 250probably_typename(void)
253{ 251{
254 if (ps.prev_lsym == lsym_modifier) 252 if (ps.prev_lsym == lsym_modifier)
255 return true; 253 return true;
256 if (ps.in_init) 254 if (ps.in_init)
257 return false; 255 return false;
258 if (ps.in_stmt_or_decl) /* XXX: this condition looks incorrect */ 256 if (ps.in_stmt_or_decl) /* XXX: this condition looks incorrect */
259 return false; 257 return false;
260 if (ps.prev_lsym == lsym_semicolon 258 if (ps.prev_lsym == lsym_semicolon
261 || ps.prev_lsym == lsym_lbrace 259 || ps.prev_lsym == lsym_lbrace
262 || ps.prev_lsym == lsym_rbrace) { 260 || ps.prev_lsym == lsym_rbrace) {
263 if (inp_p[0] == '*' && inp_p[1] != '=') 261 if (inp_p[0] == '*' && inp_p[1] != '=')
264 return true; 262 return true;
265 /* XXX: is_identifier_start */ 263 /* XXX: is_identifier_start */
266 if (ch_isalpha(inp_p[0])) 264 if (ch_isalpha(inp_p[0]))
267 return true; 265 return true;
268 } 266 }
269 return false; 267 return false;
270} 268}
271 269
272static int 270static int
273bsearch_typenames(const char *key) 271bsearch_typenames(const char *key)
274{ 272{
275 const char **arr = typenames.items; 273 const char **arr = typenames.items;
276 unsigned lo = 0; 274 unsigned lo = 0;
277 unsigned hi = typenames.len; 275 unsigned hi = typenames.len;
278 276
279 while (lo < hi) { 277 while (lo < hi) {
280 unsigned mid = (lo + hi) / 2; 278 unsigned mid = (lo + hi) / 2;
281 int cmp = strcmp(arr[mid], key); 279 int cmp = strcmp(arr[mid], key);
282 if (cmp < 0) 280 if (cmp < 0)
283 lo = mid + 1; 281 lo = mid + 1;
284 else if (cmp > 0) 282 else if (cmp > 0)
285 hi = mid; 283 hi = mid;
286 else 284 else
287 return (int)mid; 285 return (int)mid;
288 } 286 }
289 return -1 - (int)lo; 287 return -1 - (int)lo;
290} 288}
291 289
292static bool 290static bool
293is_typename(void) 291is_typename(void)
294{ 292{
295 if (opt.auto_typedefs && 293 if (opt.auto_typedefs &&
296 token.len >= 2 && memcmp(token.s + token.len - 2, "_t", 2) == 0) 294 token.len >= 2 && memcmp(token.s + token.len - 2, "_t", 2) == 0)
297 return true; 295 return true;
298 296
299 return bsearch_typenames(token.s) >= 0; 297 return bsearch_typenames(token.s) >= 0;
300} 298}
301 299
302void 300void
303register_typename(const char *name) 301register_typename(const char *name)
304{ 302{
305 if (typenames.len >= typenames.cap) { 303 if (typenames.len >= typenames.cap) {
306 typenames.cap = 16 + 2 * typenames.cap; 304 typenames.cap = 16 + 2 * typenames.cap;
307 typenames.items = nonnull(realloc(typenames.items, 305 typenames.items = nonnull(realloc(typenames.items,
308 sizeof(typenames.items[0]) * typenames.cap)); 306 sizeof(typenames.items[0]) * typenames.cap));
309 } 307 }
310 308
311 int pos = bsearch_typenames(name); 309 int pos = bsearch_typenames(name);
312 if (pos >= 0) 310 if (pos >= 0)
313 return; /* already in the list */ 311 return; /* already in the list */
314 312
315 pos = -1 - pos; 313 pos = -1 - pos;
316 memmove(typenames.items + pos + 1, typenames.items + pos, 314 memmove(typenames.items + pos + 1, typenames.items + pos,
317 sizeof(typenames.items[0]) * (typenames.len++ - (unsigned)pos)); 315 sizeof(typenames.items[0]) * (typenames.len++ - (unsigned)pos));
318 typenames.items[pos] = nonnull(strdup(name)); 316 typenames.items[pos] = nonnull(strdup(name));
319} 317}
320 318
321static int 319static int
322cmp_keyword_by_name(const void *key, const void *elem) 320cmp_keyword_by_name(const void *key, const void *elem)
323{ 321{
324 return strcmp(key, ((const struct keyword *)elem)->name); 322 return strcmp(key, ((const struct keyword *)elem)->name);
325} 323}
326 324
327/* 325/*
328 * Looking at something like 'function_name(...)' in a line, guess whether 326 * Looking at the '(', guess whether this starts a function definition or a
329 * this starts a function definition or a declaration. 327 * function declaration.
330 */ 328 */
331static bool 329static bool
332probably_function_definition(void) 330probably_function_definition(void)
333{ 331{
334 int paren_level = 0; 332 int paren_level = 0;
335 for (const char *p = inp_p; *p != '\n'; p++) { 333 for (const char *p = inp_p; *p != '\n'; p++) {
336 if (*p == '(') 334 if (*p == '(')
337 paren_level++; 335 paren_level++;
338 if (*p == ')' && --paren_level == 0) { 336 if (*p == ')' && --paren_level == 0) {
339 p++; 337 p++;
340 338
341 while (*p != '\n' 339 while (*p != '\n'
342 && (ch_isspace(*p) || is_identifier_part(*p))) 340 && (ch_isspace(*p) || is_identifier_part(*p)))
343 p++; /* '__dead' or '__unused' */ 341 p++; /* '__dead' or '__unused' */
344 342
345 if (*p == '\n') /* func(...) */ 343 if (*p == '\n') /* func(...) */
346 break; 344 break;
347 if (*p == ';') /* func(...); */ 345 if (*p == ';') /* func(...); */
348 return false; 346 return false;
349 if (*p == ',') /* double abs(), pi; */ 347 if (*p == ',') /* double abs(), pi; */
350 return false; 348 return false;
351 if (*p == '(') /* func(...) __attribute__((...)) */ 349 if (*p == '(') /* func(...) __attribute__((...)) */
352 paren_level++; /* func(...) __printflike(...) 350 paren_level++; /* func(...) __printflike(...)
353 */ 351 */
354 else 352 else
355 break; /* func(...) { ... */ 353 break; /* func(...) { ... */
356 } 354 }
357 355
358 if (paren_level == 1 && p[0] == '*' && p[1] == ',') 356 if (paren_level == 1 && p[0] == '*' && p[1] == ',')
359 return false; 357 return false;
360 } 358 }
361 359
362 /* To further reduce the cases where indent wrongly treats an 360 /*
 361 * To further reduce the cases where indent wrongly treats an
363 * incomplete function declaration as a function definition, thus 362 * incomplete function declaration as a function definition, thus
364 * adding a newline before the function name, it may be worth looking 363 * adding a newline before the function name, it may be worth looking
365 * for parameter names, as these are often omitted in function 364 * for parameter names, as these are often omitted in function
366 * declarations and only included in function definitions. Or just 365 * declarations and only included in function definitions. Or just
367 * increase the lookahead to more than just the current line of input, 366 * increase the lookahead to more than just the current line of input,
368 * until the next '{'. */ 367 * until the next '{'.
 368 */
369 return true; 369 return true;
370} 370}
371 371
372static lexer_symbol 372static lexer_symbol
373lexi_alnum(void) 373lexi_alnum(void)
374{ 374{
375 if (ch_isdigit(inp_p[0]) || 375 if (ch_isdigit(inp_p[0]) ||
376 (inp_p[0] == '.' && ch_isdigit(inp_p[1]))) { 376 (inp_p[0] == '.' && ch_isdigit(inp_p[1]))) {
377 lex_number(); 377 lex_number();
378 } else if (is_identifier_start(inp_p[0])) { 378 } else if (is_identifier_start(inp_p[0])) {
379 lex_word(); 379 lex_word();
380 380
381 if (token.len == 1 && token.s[0] == 'L' && 381 if (token.len == 1 && token.s[0] == 'L' &&
382 (inp_p[0] == '"' || inp_p[0] == '\'')) { 382 (inp_p[0] == '"' || inp_p[0] == '\'')) {
383 token_add_char(*inp_p++); 383 token_add_char(*inp_p++);
384 lex_char_or_string(); 384 lex_char_or_string();
385 ps.next_unary = false; 385 ps.next_unary = false;
386 return lsym_word; 386 return lsym_word;
387 } 387 }
388 } else 388 } else
389 return lsym_eof; /* just as a placeholder */ 389 return lsym_eof; /* just as a placeholder */
390 390
391 while (ch_isblank(inp_p[0])) 391 while (ch_isblank(*inp_p))
392 inp_p++; 392 inp_p++;
393 393
394 ps.next_unary = ps.prev_lsym == lsym_tag 394 ps.next_unary = ps.prev_lsym == lsym_tag
395 || ps.prev_lsym == lsym_typedef; 395 || ps.prev_lsym == lsym_typedef;
396 396
397 if (ps.prev_lsym == lsym_tag && ps.paren.len == 0) 397 if (ps.prev_lsym == lsym_tag && ps.paren.len == 0)
398 return lsym_type; 398 return lsym_type;
399 399
400 token_add_char('\0'); 400 token_add_char('\0'); // Terminate in non-debug mode as well.
401 token.len--; 401 token.len--;
402 const struct keyword *kw = bsearch(token.s, keywords, 402 const struct keyword *kw = bsearch(token.s, keywords,
403 array_length(keywords), sizeof(keywords[0]), cmp_keyword_by_name); 403 array_length(keywords), sizeof(keywords[0]), cmp_keyword_by_name);
404 lexer_symbol lsym = lsym_word; 404 lexer_symbol lsym = lsym_word;
405 if (kw != NULL) { 405 if (kw != NULL) {
406 if (kw->lsym == lsym_type) 406 if (kw->lsym == lsym_type)
407 lsym = lsym_type; 407 lsym = lsym_type;
408 ps.next_unary = true; 408 ps.next_unary = true;
409 if (kw->lsym == lsym_tag || kw->lsym == lsym_type) 409 if (kw->lsym == lsym_tag || kw->lsym == lsym_type)
410 goto found_typename; 410 goto found_typename;
411 return kw->lsym; 411 return kw->lsym;
412 } 412 }
413 413
414 if (is_typename()) { 414 if (is_typename()) {
415 lsym = lsym_type; 415 lsym = lsym_type;
416 ps.next_unary = true; 416 ps.next_unary = true;
417found_typename: 417found_typename:
418 if (ps.paren.len > 0) { 418 if (ps.paren.len > 0) {
419 /* inside parentheses: cast, param list, offsetof or 419 /* inside parentheses: cast, param list, offsetof or
420 * sizeof */ 420 * sizeof */
421 struct paren_level *paren_level = 421 struct paren_level *paren_level =
422 ps.paren.item + ps.paren.len - 1; 422 ps.paren.item + ps.paren.len - 1;
423 if (paren_level->cast == cast_unknown) 423 if (paren_level->cast == cast_unknown)
424 paren_level->cast = cast_maybe; 424 paren_level->cast = cast_maybe;
425 } 425 }
426 if (ps.prev_lsym != lsym_period 426 if (ps.prev_lsym != lsym_period
427 && ps.prev_lsym != lsym_unary_op) { 427 && ps.prev_lsym != lsym_unary_op) {
428 if (kw != NULL && kw->lsym == lsym_tag) 428 if (kw != NULL && kw->lsym == lsym_tag)
429 return lsym_tag; 429 return lsym_tag;
430 if (ps.paren.len == 0) 430 if (ps.paren.len == 0)
431 return lsym_type; 431 return lsym_type;
432 } 432 }
433 } 433 }
434 434
435 if (inp_p[0] == '(' && ps.psyms.len <= 2 && ps.ind_level == 0 && 435 if (*inp_p == '(' && ps.psyms.len < 3 && ps.ind_level == 0 &&
436 !ps.in_func_def_params && !ps.in_init) { 436 !ps.in_func_def_params && !ps.in_init) {
437 437
438 if (ps.paren.len == 0 && probably_function_definition()) { 438 if (ps.paren.len == 0 && probably_function_definition()) {
439 ps.line_has_func_def = true; 439 ps.line_has_func_def = true;
440 if (ps.in_decl) 440 if (ps.in_decl)
441 ps.in_func_def_params = true; 441 ps.in_func_def_params = true;
442 return lsym_funcname; 442 return lsym_funcname;
443 } 443 }
444 444
445 } else if (ps.paren.len == 0 && probably_typename()) { 445 } else if (ps.paren.len == 0 && probably_typename()) {
446 ps.next_unary = true; 446 ps.next_unary = true;
447 return lsym_type; 447 return lsym_type;
448 } 448 }
449 449
450 return lsym; 450 return lsym;
451} 451}
452 452
453static bool 453static bool
454is_asterisk_pointer(void) 454is_asterisk_pointer(void)
455{ 455{
456 if (inp_p[strspn(inp_p, "* \t")] == ')') 456 if (inp_p[strspn(inp_p, "* \t")] == ')')
457 return true; 457 return true;
458 if (ps.next_unary || ps.in_func_def_params) 458 if (ps.next_unary || ps.in_func_def_params)
459 return true; 459 return true;
460 if (ps.prev_lsym == lsym_word || 460 if (ps.prev_lsym == lsym_word ||
461 ps.prev_lsym == lsym_rparen || 461 ps.prev_lsym == lsym_rparen ||
462 ps.prev_lsym == lsym_rbracket) 462 ps.prev_lsym == lsym_rbracket)
463 return false; 463 return false;
464 return ps.in_decl && ps.paren.len > 0; 464 return ps.in_decl && ps.paren.len > 0;
465} 465}
466 466
467static bool 467static bool
468probably_in_function_definition(void) 468probably_in_function_definition(void)
469{ 469{
470 for (const char *tp = inp_p; *tp != '\n';) { 470 for (const char *p = inp_p; *p != '\n';) {
471 if (ch_isspace(*tp)) 471 if (ch_isspace(*p))
472 tp++; 472 p++;
473 else if (is_identifier_start(*tp)) { 473 else if (is_identifier_start(*p)) {
474 tp++; 474 p++;
475 while (is_identifier_part(*tp)) 475 while (is_identifier_part(*p))
476 tp++; 476 p++;
477 } else 477 } else
478 return *tp == '('; 478 return *p == '(';
479 } 479 }
480 return false; 480 return false;
481} 481}
482 482
483static void 483static void
484lex_asterisk_pointer(void) 484lex_asterisk_pointer(void)
485{ 485{
486 while (inp_p[0] == '*' || ch_isspace(inp_p[0])) { 486 while (*inp_p == '*' || ch_isspace(*inp_p)) {
487 if (inp_p[0] == '*') 487 if (*inp_p == '*')
488 token_add_char('*'); 488 token_add_char('*');
489 inp_skip(); 489 inp_skip();
490 } 490 }
491 491
492 if (ps.in_decl && probably_in_function_definition()) 492 if (ps.in_decl && probably_in_function_definition())
493 ps.line_has_func_def = true; 493 ps.line_has_func_def = true;
494} 494}
495 495
496static bool 496static bool
497skip(const char **pp, const char *s) 497skip(const char **pp, const char *s)
498{ 498{
499 size_t len = strlen(s); 499 size_t len = strlen(s);
500 while (ch_isblank(**pp)) 500 while (ch_isblank(**pp))
501 (*pp)++; 501 (*pp)++;
502 if (strncmp(*pp, s, len) == 0) { 502 if (strncmp(*pp, s, len) == 0) {
503 *pp += len; 503 *pp += len;
504 return true; 504 return true;
505 } 505 }
506 return false; 506 return false;
507} 507}
508 508
509static void 509static void
510lex_indent_comment(void) 510lex_indent_comment(void)
511{ 511{
512 const char *p = inp.s; 512 const char *p = inp.s;
513 if (skip(&p, "/*") && skip(&p, "INDENT")) { 513 if (skip(&p, "/*") && skip(&p, "INDENT")) {
514 enum indent_enabled enabled; 514 enum indent_enabled enabled;
515 if (skip(&p, "ON") || *p == '*') 515 if (skip(&p, "ON") || *p == '*')
516 enabled = indent_last_off_line; 516 enabled = indent_last_off_line;
517 else if (skip(&p, "OFF")) 517 else if (skip(&p, "OFF"))
518 enabled = indent_off; 518 enabled = indent_off;
519 else 519 else
520 return; 520 return;
521 if (skip(&p, "*/\n")) { 521 if (skip(&p, "*/\n")) {
522 if (lab.len > 0 || code.len > 0 || com.len > 0) 522 if (lab.len > 0 || code.len > 0 || com.len > 0)
523 output_line(); 523 output_line();
524 indent_enabled = enabled; 524 indent_enabled = enabled;
525 } 525 }
526 } 526 }
527} 527}
528 528
529/* Reads the next token, placing it in the global variable "token". */ 529/* Reads the next token, placing it in the global variable "token". */
530lexer_symbol 530lexer_symbol
531lexi(void) 531lexi(void)
532{ 532{
533 buf_clear(&token); 533 buf_clear(&token);
534 534
535 for (;;) { 535 for (;;) {
536 if (ch_isblank(inp_p[0])) 536 if (ch_isblank(inp_p[0]))
537 inp_p++; 537 inp_p++;
538 else if (inp_p[0] == '\\' && inp_p[1] == '\n') { 538 else if (inp_p[0] == '\\' && inp_p[1] == '\n') {
539 inp_p++; 539 inp_p++;
540 inp_skip(); 540 inp_skip();
541 line_no++; 541 line_no++;
542 } else 542 } else
543 break; 543 break;
544 } 544 }
545 545
546 lexer_symbol alnum_lsym = lexi_alnum(); 546 lexer_symbol alnum_lsym = lexi_alnum();
547 if (alnum_lsym != lsym_eof) 547 if (alnum_lsym != lsym_eof)
548 return alnum_lsym; 548 return alnum_lsym;
549 549
550 /* Scan a non-alphanumeric token */ 550 /* Scan a non-alphanumeric token */
551 551
552 token_add_char(inp_next()); 552 token_add_char(inp_next());
553 553
554 lexer_symbol lsym; 554 lexer_symbol lsym;
555 bool next_unary; 555 bool next_unary;
556 556
557 switch (token.s[token.len - 1]) { 557 switch (token.s[token.len - 1]) {
558 558
559 case '#': 559 case '#':
560 lsym = lsym_preprocessing; 560 lsym = lsym_preprocessing;
561 next_unary = ps.next_unary; 561 next_unary = ps.next_unary;
562 break; 562 break;
563 563
564 case '\n': 564 case '\n':
565 /* if data has been exhausted, the '\n' is a dummy. */ 565 /* if data has been exhausted, the '\n' is a dummy. */
566 lsym = had_eof ? lsym_eof : lsym_newline; 566 lsym = had_eof ? lsym_eof : lsym_newline;
567 next_unary = ps.next_unary; 567 next_unary = ps.next_unary;
568 break; 568 break;
569 569
570 /* INDENT OFF */ 570 /* INDENT OFF */
571 case '(': lsym = lsym_lparen; next_unary = true; break; 571 case '(': lsym = lsym_lparen; next_unary = true; break;
572 case ')': lsym = lsym_rparen; next_unary = false; break; 572 case ')': lsym = lsym_rparen; next_unary = false; break;
573 case '[': lsym = lsym_lbracket; next_unary = true; break; 573 case '[': lsym = lsym_lbracket; next_unary = true; break;
574 case ']': lsym = lsym_rbracket; next_unary = false; break; 574 case ']': lsym = lsym_rbracket; next_unary = false; break;
575 case '{': lsym = lsym_lbrace; next_unary = true; break; 575 case '{': lsym = lsym_lbrace; next_unary = true; break;
576 case '}': lsym = lsym_rbrace; next_unary = true; break; 576 case '}': lsym = lsym_rbrace; next_unary = true; break;
577 case '.': lsym = lsym_period; next_unary = false; break; 577 case '.': lsym = lsym_period; next_unary = false; break;
578 case '?': lsym = lsym_question; next_unary = true; break; 578 case '?': lsym = lsym_question; next_unary = true; break;
579 case ',': lsym = lsym_comma; next_unary = true; break; 579 case ',': lsym = lsym_comma; next_unary = true; break;
580 case ';': lsym = lsym_semicolon; next_unary = true; break; 580 case ';': lsym = lsym_semicolon; next_unary = true; break;
581 /* INDENT ON */ 581 /* INDENT ON */
582 582
583 case '-': 
584 case '+': 583 case '+':
 584 case '-':
585 lsym = ps.next_unary ? lsym_unary_op : lsym_binary_op; 585 lsym = ps.next_unary ? lsym_unary_op : lsym_binary_op;
586 next_unary = true; 586 next_unary = true;
587 587
588 /* '++' or '--' */ 588 /* '++' or '--' */
589 if (inp_p[0] == token.s[token.len - 1]) { 589 if (*inp_p == token.s[token.len - 1]) {
590 token_add_char(*inp_p++); 590 token_add_char(*inp_p++);
591 if (ps.prev_lsym == lsym_word || 591 if (ps.prev_lsym == lsym_word ||
592 ps.prev_lsym == lsym_rparen || 592 ps.prev_lsym == lsym_rparen ||
593 ps.prev_lsym == lsym_rbracket) { 593 ps.prev_lsym == lsym_rbracket) {
594 lsym = ps.next_unary 594 lsym = ps.next_unary
595 ? lsym_unary_op : lsym_postfix_op; 595 ? lsym_unary_op : lsym_postfix_op;
596 next_unary = false; 596 next_unary = false;
597 } 597 }
598 598
599 } else if (inp_p[0] == '=') { /* '+=' or '-=' */ 599 } else if (*inp_p == '=') { /* '+=' or '-=' */
600 token_add_char(*inp_p++); 600 token_add_char(*inp_p++);
601 601
602 } else if (inp_p[0] == '>') { /* '->' */ 602 } else if (*inp_p == '>') { /* '->' */
603 token_add_char(*inp_p++); 603 token_add_char(*inp_p++);
604 lsym = lsym_unary_op; 604 lsym = lsym_unary_op;
605 next_unary = false; 605 next_unary = false;
606 ps.want_blank = false; 606 ps.want_blank = false;
607 } 607 }
608 break; 608 break;
609 609
610 case ':': 610 case ':':
611 lsym = ps.quest_level > 0 611 lsym = ps.quest_level > 0
612 ? (ps.quest_level--, lsym_question_colon) 612 ? (ps.quest_level--, lsym_question_colon)
613 : ps.in_var_decl ? lsym_other_colon : lsym_label_colon; 613 : ps.in_var_decl ? lsym_other_colon : lsym_label_colon;
614 next_unary = true; 614 next_unary = true;
615 break; 615 break;
616 616
617 case '*': 617 case '*':
618 if (inp_p[0] == '=') { 618 if (*inp_p == '=') {
619 token_add_char(*inp_p++); 619 token_add_char(*inp_p++);
620 lsym = lsym_binary_op; 620 lsym = lsym_binary_op;
621 } else if (is_asterisk_pointer()) { 621 } else if (is_asterisk_pointer()) {
622 lex_asterisk_pointer(); 622 lex_asterisk_pointer();
623 lsym = lsym_unary_op; 623 lsym = lsym_unary_op;
624 } else 624 } else
625 lsym = lsym_binary_op; 625 lsym = lsym_binary_op;
626 next_unary = true; 626 next_unary = true;
627 break; 627 break;
628 628
629 case '=': 629 case '=':
630 if (ps.in_var_decl) 630 if (ps.in_var_decl)
631 ps.in_init = true; 631 ps.in_init = true;
632 if (inp_p[0] == '=') 632 if (*inp_p == '=')
633 token_add_char(*inp_p++); 633 token_add_char(*inp_p++);
634 lsym = lsym_binary_op; 634 lsym = lsym_binary_op;
635 next_unary = true; 635 next_unary = true;
636 break; 636 break;
637 637
638 case '>': 638 case '>':
639 case '<': 639 case '<':
640 case '!': /* ops like <, <<, <=, !=, etc. */ 640 case '!': /* ops like <, <<, <=, !=, etc. */
641 if (inp_p[0] == '>' || inp_p[0] == '<' || inp_p[0] == '=') 641 if (*inp_p == '>' || *inp_p == '<' || *inp_p == '=')
642 token_add_char(*inp_p++); 642 token_add_char(*inp_p++);
643 if (inp_p[0] == '=') 643 if (*inp_p == '=')
644 token_add_char(*inp_p++); 644 token_add_char(*inp_p++);
645 lsym = ps.next_unary ? lsym_unary_op : lsym_binary_op; 645 lsym = ps.next_unary ? lsym_unary_op : lsym_binary_op;
646 next_unary = true; 646 next_unary = true;
647 break; 647 break;
648 648
649 case '\'': 649 case '\'':
650 case '"': 650 case '"':
651 lex_char_or_string(); 651 lex_char_or_string();
652 lsym = lsym_word; 652 lsym = lsym_word;
653 next_unary = false; 653 next_unary = false;
654 break; 654 break;
655 655
656 default: 656 default:
657 if (token.s[token.len - 1] == '/' 657 if (token.s[token.len - 1] == '/'
658 && (inp_p[0] == '*' || inp_p[0] == '/')) { 658 && (*inp_p == '*' || *inp_p == '/')) {
659 enum indent_enabled prev = indent_enabled; 659 enum indent_enabled prev = indent_enabled;
660 lex_indent_comment(); 660 lex_indent_comment();
661 if (prev == indent_on && indent_enabled == indent_off) 661 if (prev == indent_on && indent_enabled == indent_off)
662 buf_clear(&out.indent_off_text); 662 buf_clear(&out.indent_off_text);
663 token_add_char(*inp_p++); 663 token_add_char(*inp_p++);
664 lsym = lsym_comment; 664 lsym = lsym_comment;
665 next_unary = ps.next_unary; 665 next_unary = ps.next_unary;
666 break; 666 break;
667 } 667 }
668 668
669 /* punctuation like '%', '&&', '/', '^', '||', '~' */ 669 /* punctuation like '%', '&&', '/', '^', '||', '~' */
670 lsym = ps.next_unary ? lsym_unary_op : lsym_binary_op; 670 lsym = ps.next_unary ? lsym_unary_op : lsym_binary_op;
671 if (inp_p[0] == token.s[token.len - 1]) 671 if (*inp_p == token.s[token.len - 1])
672 token_add_char(*inp_p++), lsym = lsym_binary_op; 672 token_add_char(*inp_p++), lsym = lsym_binary_op;
673 if (inp_p[0] == '=') 673 if (*inp_p == '=')
674 token_add_char(*inp_p++), lsym = lsym_binary_op; 674 token_add_char(*inp_p++), lsym = lsym_binary_op;
675 675
676 next_unary = true; 676 next_unary = true;
677 } 677 }
678 678
679 ps.next_unary = next_unary; 679 ps.next_unary = next_unary;
680 680
681 return lsym; 681 return lsym;
682} 682}

cvs diff -r1.77 -r1.78 src/usr.bin/indent/parse.c (switch to unified diff)

--- src/usr.bin/indent/parse.c 2023/06/14 20:46:08 1.77
+++ src/usr.bin/indent/parse.c 2023/06/17 22:28:49 1.78
@@ -1,263 +1,263 @@ @@ -1,263 +1,263 @@
1/* $NetBSD: parse.c,v 1.77 2023/06/14 20:46:08 rillig Exp $ */ 1/* $NetBSD: parse.c,v 1.78 2023/06/17 22:28:49 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: parse.c,v 1.77 2023/06/14 20:46:08 rillig Exp $"); 41__RCSID("$NetBSD: parse.c,v 1.78 2023/06/17 22:28:49 rillig Exp $");
42 42
43#include <stdlib.h> 43#include <stdlib.h>
44 44
45#include "indent.h" 45#include "indent.h"
46 46
47/* 47/*
48 * Try to combine the statement on the top of the parse stack with the symbol 48 * Try to combine the statement on the top of the parse stack with the symbol
49 * directly below it, replacing these two symbols with a single symbol. 49 * directly below it, replacing these two symbols with a single symbol.
50 */ 50 */
51static bool 51static bool
52psyms_reduce_stmt(void) 52psyms_reduce_stmt(void)
53{ 53{
54 struct psym_stack *psyms = &ps.psyms; 54 struct psym_stack *psyms = &ps.psyms;
55 switch (psyms->sym[psyms->len - 2]) { 55 switch (psyms->sym[psyms->len - 2]) {
56 56
57 case psym_stmt: 57 case psym_stmt:
58 psyms->sym[psyms->len-- - 2] = psym_stmt; 58 psyms->sym[psyms->len-- - 2] = psym_stmt;
59 return true; 59 return true;
60 60
61 case psym_do: 61 case psym_do:
62 psyms->sym[psyms->len-- - 2] = psym_do_stmt; 62 psyms->sym[psyms->len-- - 2] = psym_do_stmt;
63 ps.ind_level_follow = psyms->ind_level[psyms->len - 1]; 63 ps.ind_level_follow = psyms->ind_level[psyms->len - 1];
64 return true; 64 return true;
65 65
66 case psym_if_expr: 66 case psym_if_expr:
67 psyms->sym[psyms->len-- - 2] = psym_if_expr_stmt; 67 psyms->sym[psyms->len-- - 2] = psym_if_expr_stmt;
68 size_t i = psyms->len - 2; 68 size_t i = psyms->len - 2;
69 while (psyms->sym[i] != psym_stmt && 69 while (psyms->sym[i] != psym_stmt &&
70 psyms->sym[i] != psym_lbrace_block) 70 psyms->sym[i] != psym_lbrace_block)
71 --i; 71 i--;
72 ps.ind_level_follow = psyms->ind_level[i]; 72 ps.ind_level_follow = psyms->ind_level[i];
73 /* For the time being, assume that there is no 'else' on this 73 /* For the time being, assume that there is no 'else' on this
74 * 'if', and set the indentation level accordingly. If an 74 * 'if', and set the indentation level accordingly. If an
75 * 'else' is scanned, it will be fixed up later. */ 75 * 'else' is scanned, it will be fixed up later. */
76 return true; 76 return true;
77 77
78 case psym_switch_expr: 78 case psym_switch_expr:
79 case psym_decl: 79 case psym_decl:
80 case psym_if_expr_stmt_else: 80 case psym_if_expr_stmt_else:
81 case psym_for_exprs: 81 case psym_for_exprs:
82 case psym_while_expr: 82 case psym_while_expr:
83 psyms->sym[psyms->len-- - 2] = psym_stmt; 83 psyms->sym[psyms->len-- - 2] = psym_stmt;
84 ps.ind_level_follow = psyms->ind_level[psyms->len - 1]; 84 ps.ind_level_follow = psyms->ind_level[psyms->len - 1];
85 return true; 85 return true;
86 86
87 default: 87 default:
88 return false; 88 return false;
89 } 89 }
90} 90}
91 91
92static int 92static int
93decl_level(void) 93decl_level(void)
94{ 94{
95 int level = 0; 95 int level = 0;
96 for (size_t i = ps.psyms.len - 2; i > 0; i--) 96 for (size_t i = ps.psyms.len - 2; i > 0; i--)
97 if (ps.psyms.sym[i] == psym_decl) 97 if (ps.psyms.sym[i] == psym_decl)
98 level++; 98 level++;
99 return level; 99 return level;
100} 100}
101 101
102void 102void
103ps_push(parser_symbol psym, bool follow) 103ps_push(parser_symbol psym, bool follow)
104{ 104{
105 if (ps.psyms.len == ps.psyms.cap) { 105 if (ps.psyms.len == ps.psyms.cap) {
106 ps.psyms.cap += 16; 106 ps.psyms.cap += 16;
107 ps.psyms.sym = nonnull(realloc(ps.psyms.sym, 107 ps.psyms.sym = nonnull(realloc(ps.psyms.sym,
108 sizeof(ps.psyms.sym[0]) * ps.psyms.cap)); 108 sizeof(ps.psyms.sym[0]) * ps.psyms.cap));
109 ps.psyms.ind_level = nonnull(realloc(ps.psyms.ind_level, 109 ps.psyms.ind_level = nonnull(realloc(ps.psyms.ind_level,
110 sizeof(ps.psyms.ind_level[0]) * ps.psyms.cap)); 110 sizeof(ps.psyms.ind_level[0]) * ps.psyms.cap));
111 } 111 }
112 ps.psyms.len++; 112 ps.psyms.len++;
113 ps.psyms.sym[ps.psyms.len - 1] = psym; 113 ps.psyms.sym[ps.psyms.len - 1] = psym;
114 ps.psyms.ind_level[ps.psyms.len - 1] = 114 ps.psyms.ind_level[ps.psyms.len - 1] =
115 follow ? ps.ind_level_follow : ps.ind_level; 115 follow ? ps.ind_level_follow : ps.ind_level;
116} 116}
117 117
118/* 118/*
119 * Repeatedly try to reduce the top two symbols on the parse stack to a single 119 * Repeatedly try to reduce the top two symbols on the parse stack to a single
120 * symbol, until no more reductions are possible. 120 * symbol, until no more reductions are possible.
121 */ 121 */
122static void 122static void
123psyms_reduce(void) 123psyms_reduce(void)
124{ 124{
125 struct psym_stack *psyms = &ps.psyms; 125 struct psym_stack *psyms = &ps.psyms;
126again: 126again:
127 if (psyms->len >= 2 && psyms->sym[psyms->len - 1] == psym_stmt 127 if (psyms->len >= 2 && psyms->sym[psyms->len - 1] == psym_stmt
128 && psyms_reduce_stmt()) 128 && psyms_reduce_stmt())
129 goto again; 129 goto again;
130 if (psyms->sym[psyms->len - 1] == psym_while_expr && 130 if (psyms->sym[psyms->len - 1] == psym_while_expr &&
131 psyms->sym[psyms->len - 2] == psym_do_stmt) { 131 psyms->sym[psyms->len - 2] == psym_do_stmt) {
132 psyms->len -= 2; 132 psyms->len -= 2;
133 goto again; 133 goto again;
134 } 134 }
135} 135}
136 136
137static bool 137static bool
138is_lbrace(parser_symbol psym) 138is_lbrace(parser_symbol psym)
139{ 139{
140 return psym == psym_lbrace_block 140 return psym == psym_lbrace_block
141 || psym == psym_lbrace_struct 141 || psym == psym_lbrace_struct
142 || psym == psym_lbrace_union 142 || psym == psym_lbrace_union
143 || psym == psym_lbrace_enum; 143 || psym == psym_lbrace_enum;
144} 144}
145 145
146/* 146/*
147 * Shift the token onto the parser stack, then try to reduce it by combining it with 147 * Shift the token onto the parser stack, then try to reduce it by combining it with
148 * previous tokens. 148 * previous tokens.
149 */ 149 */
150void 150void
151parse(parser_symbol psym) 151parse(parser_symbol psym)
152{ 152{
153 debug_blank_line(); 153 debug_blank_line();
154 debug_println("parse token: %s", psym_name[psym]); 154 debug_println("parse token: %s", psym_name[psym]);
155 155
156 struct psym_stack *psyms = &ps.psyms; 156 struct psym_stack *psyms = &ps.psyms;
157 if (psym != psym_else) { 157 if (psym != psym_else) {
158 while (psyms->sym[psyms->len - 1] == psym_if_expr_stmt) { 158 while (psyms->sym[psyms->len - 1] == psym_if_expr_stmt) {
159 psyms->sym[psyms->len - 1] = psym_stmt; 159 psyms->sym[psyms->len - 1] = psym_stmt;
160 psyms_reduce(); 160 psyms_reduce();
161 } 161 }
162 } 162 }
163 163
164 switch (psym) { 164 switch (psym) {
165 165
166 case psym_lbrace_block: 166 case psym_lbrace_block:
167 case psym_lbrace_struct: 167 case psym_lbrace_struct:
168 case psym_lbrace_union: 168 case psym_lbrace_union:
169 case psym_lbrace_enum: 169 case psym_lbrace_enum:
170 ps.break_after_comma = false; 170 ps.break_after_comma = false;
171 if (psyms->sym[psyms->len - 1] == psym_decl 171 if (psyms->sym[psyms->len - 1] == psym_decl
172 || psyms->sym[psyms->len - 1] == psym_stmt) 172 || psyms->sym[psyms->len - 1] == psym_stmt)
173 ++ps.ind_level_follow; 173 ps.ind_level_follow++;
174 else if (code.len == 0) { 174 else if (code.len == 0) {
175 /* It is part of a while, for, etc. */ 175 /* It is part of a while, for, etc. */
176 --ps.ind_level; 176 ps.ind_level--;
177 177
178 /* for a switch, brace should be two levels out from 178 /* for a switch, brace should be two levels out from
179 * the code */ 179 * the code */
180 if (psyms->sym[psyms->len - 1] == psym_switch_expr 180 if (psyms->sym[psyms->len - 1] == psym_switch_expr
181 && opt.case_indent >= 1.0F) 181 && opt.case_indent >= 1.0F)
182 --ps.ind_level; 182 ps.ind_level--;
183 } 183 }
184 184
185 ps_push(psym, false); 185 ps_push(psym, false);
186 ps_push(psym_stmt, true); 186 ps_push(psym_stmt, true);
187 break; 187 break;
188 188
189 case psym_rbrace: 189 case psym_rbrace:
190 /* stack should have <lbrace> <stmt> or <lbrace> <decl> */ 190 /* stack should have <lbrace> <stmt> or <lbrace> <decl> */
191 if (!(psyms->len >= 2 191 if (!(psyms->len >= 2
192 && is_lbrace(psyms->sym[psyms->len - 2]))) { 192 && is_lbrace(psyms->sym[psyms->len - 2]))) {
193 diag(1, "Statement nesting error"); 193 diag(1, "Statement nesting error");
194 break; 194 break;
195 } 195 }
196 ps.ind_level = ps.ind_level_follow = 196 ps.ind_level = ps.ind_level_follow =
197 psyms->ind_level[psyms->len-- - 2]; 197 psyms->ind_level[psyms->len-- - 2];
198 psyms->sym[psyms->len - 1] = psym_stmt; 198 psyms->sym[psyms->len - 1] = psym_stmt;
199 break; 199 break;
200 200
201 case psym_decl: 201 case psym_decl:
202 if (psyms->sym[psyms->len - 1] == psym_decl) 202 if (psyms->sym[psyms->len - 1] == psym_decl)
203 break; /* only put one declaration onto stack */ 203 break; /* only put one declaration onto stack */
204 204
205 ps.break_after_comma = true; 205 ps.break_after_comma = true;
206 ps_push(psym_decl, true); 206 ps_push(psym_decl, true);
207 207
208 if (opt.left_justify_decl) 208 if (opt.left_justify_decl)
209 ps.ind_level_follow = ps.ind_level = decl_level(); 209 ps.ind_level_follow = ps.ind_level = decl_level();
210 break; 210 break;
211 211
212 case psym_stmt: 212 case psym_stmt:
213 ps.break_after_comma = false; 213 ps.break_after_comma = false;
214 ps_push(psym_stmt, false); 214 ps_push(psym_stmt, false);
215 break; 215 break;
216 216
217 case psym_if_expr: 217 case psym_if_expr:
218 if (psyms->sym[psyms->len - 1] == psym_if_expr_stmt_else 218 if (psyms->sym[psyms->len - 1] == psym_if_expr_stmt_else
219 && opt.else_if_in_same_line) 219 && opt.else_if_in_same_line)
220 ps.ind_level_follow = 220 ps.ind_level_follow =
221 psyms->ind_level[psyms->len-- - 1]; 221 psyms->ind_level[psyms->len-- - 1];
222 /* FALLTHROUGH */ 222 /* FALLTHROUGH */
223 case psym_do: 223 case psym_do:
224 case psym_for_exprs: 224 case psym_for_exprs:
225 ps.ind_level = ps.ind_level_follow++; 225 ps.ind_level = ps.ind_level_follow++;
226 ps_push(psym, false); 226 ps_push(psym, false);
227 break; 227 break;
228 228
229 case psym_else: 229 case psym_else:
230 if (psyms->sym[psyms->len - 1] != psym_if_expr_stmt) { 230 if (psyms->sym[psyms->len - 1] != psym_if_expr_stmt) {
231 diag(1, "Unmatched 'else'"); 231 diag(1, "Unmatched 'else'");
232 break; 232 break;
233 } 233 }
234 ps.ind_level = psyms->ind_level[psyms->len - 1]; 234 ps.ind_level = psyms->ind_level[psyms->len - 1];
235 ps.ind_level_follow = ps.ind_level + 1; 235 ps.ind_level_follow = ps.ind_level + 1;
236 psyms->sym[psyms->len - 1] = psym_if_expr_stmt_else; 236 psyms->sym[psyms->len - 1] = psym_if_expr_stmt_else;
237 break; 237 break;
238 238
239 case psym_switch_expr: 239 case psym_switch_expr:
240 ps_push(psym_switch_expr, true); 240 ps_push(psym_switch_expr, true);
241 ps.ind_level_follow += (int)opt.case_indent + 1; 241 ps.ind_level_follow += (int)opt.case_indent + 1;
242 break; 242 break;
243 243
244 case psym_while_expr: 244 case psym_while_expr:
245 if (psyms->sym[psyms->len - 1] == psym_do_stmt) { 245 if (psyms->sym[psyms->len - 1] == psym_do_stmt) {
246 ps.ind_level = ps.ind_level_follow = 246 ps.ind_level = ps.ind_level_follow =
247 psyms->ind_level[psyms->len - 1]; 247 psyms->ind_level[psyms->len - 1];
248 ps_push(psym_while_expr, false); 248 ps_push(psym_while_expr, false);
249 } else { 249 } else {
250 ps_push(psym_while_expr, true); 250 ps_push(psym_while_expr, true);
251 ++ps.ind_level_follow; 251 ps.ind_level_follow++;
252 } 252 }
253 break; 253 break;
254 254
255 default: 255 default:
256 diag(1, "Unknown code to parser"); 256 diag(1, "Unknown code to parser");
257 return; 257 return;
258 } 258 }
259 259
260 debug_psyms_stack("before reduction"); 260 debug_psyms_stack("before reduction");
261 psyms_reduce(); 261 psyms_reduce();
262 debug_psyms_stack("after reduction"); 262 debug_psyms_stack("after reduction");
263} 263}

cvs diff -r1.166 -r1.167 src/usr.bin/indent/pr_comment.c (switch to unified diff)

--- src/usr.bin/indent/pr_comment.c 2023/06/16 11:27:49 1.166
+++ src/usr.bin/indent/pr_comment.c 2023/06/17 22:28:49 1.167
@@ -1,355 +1,349 @@ @@ -1,355 +1,349 @@
1/* $NetBSD: pr_comment.c,v 1.166 2023/06/16 11:27:49 rillig Exp $ */ 1/* $NetBSD: pr_comment.c,v 1.167 2023/06/17 22:28:49 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: pr_comment.c,v 1.166 2023/06/16 11:27:49 rillig Exp $"); 41__RCSID("$NetBSD: pr_comment.c,v 1.167 2023/06/17 22:28:49 rillig Exp $");
42 42
43#include <string.h> 43#include <string.h>
44 44
45#include "indent.h" 45#include "indent.h"
46 46
47static void 47static void
48com_add_char(char ch) 48com_add_char(char ch)
49{ 49{
50 buf_add_char(&com, ch); 50 buf_add_char(&com, ch);
51} 51}
52 52
53static void 53static void
54com_add_delim(void) 54com_add_star(void)
55{ 55{
56 if (opt.star_comment_cont) 56 if (opt.star_comment_cont)
57 buf_add_chars(&com, " * ", 3); 57 buf_add_chars(&com, " * ", 3);
58} 58}
59 59
60static bool 60static bool
61fits_in_one_line(int max_line_length) 61fits_in_one_line(int max_line_length)
62{ 62{
63 for (const char *start = inp_p, *p = start; *p != '\n'; p++) { 63 for (const char *start = inp_p, *p = start; *p != '\n'; p++) {
64 if (p[0] == '*' && p[1] == '/') { 64 if (p[0] == '*' && p[1] == '/') {
65 while (p - inp_p >= 2 65 while (p - inp_p >= 2
66 && ch_isblank(p[-1]) 66 && ch_isblank(p[-1])
67 && ch_isblank(p[-2])) 67 && ch_isblank(p[-2]))
68 p--; 68 p--;
69 int ind = ind_add(ps.comment_ind + 3, 69 int ind = ind_add(ps.comment_ind + 3,
70 start, (size_t)(p - start)); 70 start, (size_t)(p - start));
71 ind += p == start || ch_isblank(p[-1]) ? 2 : 3; 71 ind += p == start || ch_isblank(p[-1]) ? 2 : 3;
72 return ind <= max_line_length; 72 return ind <= max_line_length;
73 } 73 }
74 } 74 }
75 return false; 75 return false;
76} 76}
77 77
78static void 78static void
79analyze_comment(bool *p_may_wrap, bool *p_delim, int *p_line_length) 79analyze_comment(bool *p_may_wrap, bool *p_delim, int *p_line_length)
80{ 80{
81 bool may_wrap = true; 81 bool may_wrap = true;
82 bool delim = false; 82 bool delim = false; // only relevant if may_wrap
83 int ind; 83 int ind;
84 int line_length = opt.max_line_length; 84 int line_length = opt.max_line_length;
85 85
86 if (inp_p - inp.s == 2 && !opt.format_col1_comments) { 86 if (inp_p - inp.s == 2 && !opt.format_col1_comments) {
87 may_wrap = false; 87 may_wrap = false;
88 ind = 0; 88 ind = 0;
89 } else { 89 } else {
90 if (inp_p[0] == '-' || inp_p[0] == '*' || 90 if (inp_p[0] == '-' || inp_p[0] == '*' ||
91 token.s[token.len - 1] == '/' || 91 token.s[token.len - 1] == '/' ||
92 (inp_p[0] == '\n' && !opt.format_block_comments)) 92 (inp_p[0] == '\n' && !opt.format_block_comments))
93 may_wrap = false; 93 may_wrap = false;
94 if (code.len == 0 && inp_p[strspn(inp_p, "*")] == '\n') 94 if (code.len == 0 && inp_p[strspn(inp_p, "*")] == '\n')
95 out.line_kind = lk_block_comment; 95 out.line_kind = lk_block_comment;
96 96
97 if (com.len > 0) 97 if (com.len > 0)
98 output_line(); 98 output_line();
99 if (lab.len == 0 && code.len == 0) { 99 if (lab.len == 0 && code.len == 0) {
100 ind = (ps.ind_level - opt.unindent_displace) 100 ind = (ps.ind_level - opt.unindent_displace)
101 * opt.indent_size; 101 * opt.indent_size;
102 if (ind <= 0) 102 if (ind <= 0)
103 ind = opt.format_col1_comments ? 0 : 1; 103 ind = opt.format_col1_comments ? 0 : 1;
104 line_length = opt.block_comment_max_line_length; 104 line_length = opt.block_comment_max_line_length;
105 if (may_wrap && inp_p[0] == '\n') 105 if (may_wrap && inp_p[0] == '\n')
106 delim = true; 106 delim = true;
107 if (may_wrap && opt.comment_delimiter_on_blank_line) 107 if (may_wrap && opt.comment_delimiter_on_blank_line)
108 delim = true; 108 delim = true;
109 } else { 109 } else {
110 int target_ind = code.len > 0 110 int min_ind = code.len > 0
111 ? ind_add(compute_code_indent(), code.s, code.len) 111 ? ind_add(compute_code_indent(), code.s, code.len)
112 : ind_add(compute_label_indent(), lab.s, lab.len); 112 : ind_add(compute_label_indent(), lab.s, lab.len);
113 113
114 ind = ps.line_has_decl || ps.ind_level == 0 114 ind = ps.line_has_decl || ps.ind_level == 0
115 ? opt.decl_comment_column - 1 115 ? opt.decl_comment_column - 1
116 : opt.comment_column - 1; 116 : opt.comment_column - 1;
117 if (ind <= target_ind) 117 if (ind <= min_ind)
118 ind = next_tab(target_ind); 118 ind = next_tab(min_ind);
119 if (ind + 25 > line_length) 119 if (ind + 25 > line_length)
120 line_length = ind + 25; 120 line_length = ind + 25;
121 } 121 }
122 } 122 }
123 123
124 if (!may_wrap) { 124 if (!may_wrap) {
125 /* Find out how much indentation there was originally, because 125 /* Find out how much indentation there was originally, because
126 * that much will have to be ignored by output_line. */ 126 * that much will have to be ignored by output_line. */
127 size_t len = (size_t)(inp_p - 2 - inp.s); 127 size_t len = (size_t)(inp_p - 2 - inp.s);
128 ps.comment_shift = -ind_add(0, inp.s, len); 128 ps.comment_shift = -ind_add(0, inp.s, len);
129 } else { 129 } else {
130 ps.comment_shift = 0; 130 ps.comment_shift = 0;
131 if (!(inp_p[0] == '\t' && !ch_isblank(inp_p[1]))) 131 if (!(inp_p[0] == '\t' && !ch_isblank(inp_p[1])))
132 while (ch_isblank(inp_p[0])) 132 while (ch_isblank(inp_p[0]))
133 inp_p++; 133 inp_p++;
134 } 134 }
135 135
136 ps.comment_ind = ind; 136 ps.comment_ind = ind;
137 *p_may_wrap = may_wrap; 137 *p_may_wrap = may_wrap;
138 *p_delim = delim; 138 *p_delim = delim;
139 *p_line_length = line_length; 139 *p_line_length = line_length;
140} 140}
141 141
142static void 142static void
143copy_comment_start(bool may_wrap, bool *delim, int line_length) 143copy_comment_start(bool may_wrap, bool *delim, int line_length)
144{ 144{
145 ps.comment_cont = false; 145 ps.comment_cont = false;
146 com_add_char('/'); 146 com_add_char('/');
147 com_add_char(token.s[token.len - 1]); /* either '*' or '/' */ 147 com_add_char(token.s[token.len - 1]); /* either '*' or '/' */
148 148
149 if (may_wrap) { 149 if (may_wrap) {
150 if (!ch_isblank(inp_p[0])) 150 if (!ch_isblank(inp_p[0]))
151 com_add_char(' '); 151 com_add_char(' ');
152 152
153 if (*delim && fits_in_one_line(line_length)) 153 if (*delim && fits_in_one_line(line_length))
154 *delim = false; 154 *delim = false;
155 if (*delim) { 155 if (*delim) {
156 output_line(); 156 output_line();
157 com_add_delim(); 157 com_add_star();
158 } 158 }
159 } 159 }
160} 160}
161 161
162static void 162static void
163copy_comment_wrap_text(int line_length, ssize_t *last_blank) 163copy_comment_wrap_text(int line_length, ssize_t *last_blank)
164{ 164{
165 int now_len = ind_add(ps.comment_ind, com.s, com.len); 165 int ind = ind_add(ps.comment_ind, com.s, com.len);
166 for (;;) { 166 for (;;) {
167 char ch = inp_next(); 167 char ch = inp_next();
168 if (ch_isblank(ch)) 168 if (ch_isblank(ch))
169 *last_blank = (ssize_t)com.len; 169 *last_blank = (ssize_t)com.len;
170 com_add_char(ch); 170 com_add_char(ch);
171 now_len++; 171 ind++;
172 if (memchr("*\n\r\b\t", inp_p[0], 6) != NULL) 172 if (memchr("*\n\r\b\t", inp_p[0], 6) != NULL)
173 break; 173 break;
174 if (now_len >= line_length && *last_blank != -1) 174 if (ind >= line_length && *last_blank != -1)
175 break; 175 break;
176 } 176 }
177 177
178 if (now_len <= line_length) 178 if (ind <= line_length)
179 return; 179 return;
180 if (ch_isspace(com.s[com.len - 1])) 180 if (ch_isspace(com.s[com.len - 1]))
181 return; 181 return;
182 182
183 if (*last_blank == -1) { 183 if (*last_blank == -1) {
184 /* only a single word in this line */ 184 /* only a single word in this line */
185 output_line(); 185 output_line();
186 com_add_delim(); 186 com_add_star();
187 return; 187 return;
188 } 188 }
189 189
190 const char *last_word_s = com.s + *last_blank + 1; 190 // Move the overlong word to the next line.
 191 const char *last_word = com.s + *last_blank + 1;
191 size_t last_word_len = com.len - (size_t)(*last_blank + 1); 192 size_t last_word_len = com.len - (size_t)(*last_blank + 1);
192 com.len = (size_t)*last_blank; 193 com.len = (size_t)*last_blank;
 194 buf_terminate(&com);
193 output_line(); 195 output_line();
194 com_add_delim(); 196 com_add_star();
195 197
196 /* Assume that output_line and com_add_delim don't invalidate the 198 /* Assume that output_line and com_add_delim left the "unused" part of
197 * "unused" part of the buffer beyond com.s + com.len. */ 199 * the now truncated buffer beyond com.s + com.len as-is. */
198 memmove(com.s + com.len, last_word_s, last_word_len); 200 memmove(com.s + com.len, last_word, last_word_len);
199 com.len += last_word_len; 201 com.len += last_word_len;
 202 buf_terminate(&com);
200 *last_blank = -1; 203 *last_blank = -1;
201} 204}
202 205
 206/* In a comment that is re-wrapped, handle a single newline character. */
203static bool 207static bool
204copy_comment_wrap_newline(ssize_t *last_blank, bool seen_newline) 208copy_comment_wrap_newline(ssize_t *last_blank, bool seen_newline)
205{ 209{
206 *last_blank = -1; 210 *last_blank = -1;
207 if (seen_newline) { 211 if (seen_newline) {
208 if (com.len == 0) 212 if (com.len == 0)
209 com_add_char(' '); /* force empty output line */ 213 com_add_char(' '); /* force empty output line */
210 if (com.len > 3) { 214 if (com.len > 3) {
211 output_line(); 215 output_line();
212 com_add_delim(); 216 com_add_star();
213 } 217 }
214 output_line(); 218 output_line();
215 com_add_delim(); 219 com_add_star();
216 } else { 220 } else {
217 if (!(com.len > 0 && ch_isblank(com.s[com.len - 1]))) 221 if (!(com.len > 0 && ch_isblank(com.s[com.len - 1])))
218 com_add_char(' '); 222 com_add_char(' ');
219 *last_blank = (int)com.len - 1; 223 *last_blank = (int)com.len - 1;
220 } 224 }
221 ++line_no; 225 line_no++;
222 226
223 /* flush any blanks and/or tabs at start of next line */ 227 /* flush any blanks and/or tabs at start of next line */
224 inp_skip(); /* '\n' */ 228 inp_skip(); /* '\n' */
225 while (ch_isblank(inp_p[0])) 229 while (ch_isblank(inp_p[0]))
226 inp_p++; 230 inp_p++;
227 if (inp_p[0] == '*' && inp_p[1] == '/') 231 if (inp_p[0] == '*' && inp_p[1] == '/')
228 return false; 232 return false;
229 if (inp_p[0] == '*') { 233 if (inp_p[0] == '*') {
230 inp_p++; 234 inp_p++;
231 while (ch_isblank(inp_p[0])) 235 while (ch_isblank(inp_p[0]))
232 inp_p++; 236 inp_p++;
233 } 237 }
234 238
235 return true; 239 return true;
236} 240}
237 241
238static void 242static void
239copy_comment_wrap_finish(int line_length, bool delim) 243copy_comment_wrap_finish(int line_length, bool delim)
240{ 244{
241 if (delim) { 245 if (delim) {
242 if (com.len > 3) 246 if (com.len > 3)
243 output_line(); 247 output_line();
244 else 248 else
245 buf_clear(&com); 249 buf_clear(&com);
246 com_add_char(' '); 250 com_add_char(' ');
247 } else { 251 } else {
248 size_t len = com.len; 252 size_t len = com.len;
 253 // XXX: This loop differs from the one below.
249 while (ch_isblank(com.s[len - 1])) 254 while (ch_isblank(com.s[len - 1]))
250 len--; 255 len--;
251 int end_ind = ind_add(ps.comment_ind, com.s, len); 256 if (ind_add(ps.comment_ind, com.s, len) + 3 > line_length)
252 if (end_ind + 3 > line_length) 
253 output_line(); 257 output_line();
254 } 258 }
255 259
256 while (com.len >= 2 260 while (com.len >= 2
257 && ch_isblank(com.s[com.len - 1]) 261 && ch_isblank(com.s[com.len - 1])
258 && ch_isblank(com.s[com.len - 2])) 262 && ch_isblank(com.s[com.len - 2]))
259 com.len--; 263 com.len--;
260 buf_terminate(&com); 264 buf_terminate(&com);
261 265
262 inp_p += 2; 266 inp_p += 2;
263 if (com.len > 0 && ch_isblank(com.s[com.len - 1])) 267 if (com.len > 0 && ch_isblank(com.s[com.len - 1]))
264 buf_add_chars(&com, "*/", 2); 268 buf_add_chars(&com, "*/", 2);
265 else 269 else
266 buf_add_chars(&com, " */", 3); 270 buf_add_chars(&com, " */", 3);
267} 271}
268 272
269/* 
270 * Copy characters from 'inp' to 'com'. Try to keep comments from going over 
271 * the maximum line length. To do that, remember where the last blank, tab, or 
272 * newline was. When a line is filled, print up to the last blank and continue 
273 * copying. 
274 */ 
275static void 273static void
276copy_comment_wrap(int line_length, bool delim) 274copy_comment_wrap(int line_length, bool delim)
277{ 275{
278 ssize_t last_blank = -1; /* index of the last blank in 'com' */ 276 ssize_t last_blank = -1; /* index of the last blank in 'com' */
279 bool seen_newline = false; 277 bool seen_newline = false;
280 278
281 for (;;) { 279 for (;;) {
282 if (inp_p[0] == '\n') { 280 if (inp_p[0] == '\n') {
283 if (had_eof) 281 if (had_eof)
284 goto unterminated_comment; 282 goto unterminated_comment;
285 if (!copy_comment_wrap_newline(&last_blank, 283 if (!copy_comment_wrap_newline(&last_blank,
286 seen_newline)) 284 seen_newline))
287 break; 285 break;
288 seen_newline = true; 286 seen_newline = true;
289 } else if (inp_p[0] == '*' && inp_p[1] == '/') 287 } else if (inp_p[0] == '*' && inp_p[1] == '/')
290 break; 288 break;
291 else { 289 else {
292 copy_comment_wrap_text(line_length, &last_blank); 290 copy_comment_wrap_text(line_length, &last_blank);
293 seen_newline = false; 291 seen_newline = false;
294 } 292 }
295 } 293 }
296 294
297 copy_comment_wrap_finish(line_length, delim); 295 copy_comment_wrap_finish(line_length, delim);
298 return; 296 return;
299 297
300unterminated_comment: 298unterminated_comment:
301 diag(1, "Unterminated comment"); 299 diag(1, "Unterminated comment");
302 output_line(); 300 output_line();
303} 301}
304 302
305static void 303static void
306copy_comment_nowrap(void) 304copy_comment_nowrap(void)
307{ 305{
308 char kind = token.s[token.len - 1]; 306 char kind = token.s[token.len - 1];
309 307
310 for (;;) { 308 for (;;) {
311 if (inp_p[0] == '\n') { 309 if (inp_p[0] == '\n') {
312 if (kind == '/') 310 if (kind == '/')
313 return; 311 return;
314 312
315 if (had_eof) { 313 if (had_eof) {
316 diag(1, "Unterminated comment"); 314 diag(1, "Unterminated comment");
317 output_line(); 315 output_line();
318 return; 316 return;
319 } 317 }
320 318
321 if (com.len == 0) 319 if (com.len == 0)
322 com_add_char(' '); /* force output of an 320 com_add_char(' '); /* force output of an
323 * empty line */ 321 * empty line */
324 output_line(); 322 output_line();
325 ++line_no; 323 line_no++;
326 inp_skip(); 324 inp_skip();
327 continue; 325 continue;
328 } 326 }
329 327
330 com_add_char(*inp_p++); 328 com_add_char(*inp_p++);
331 if (com.len >= 2 329 if (com.len >= 2
332 && com.s[com.len - 2] == '*' 330 && com.s[com.len - 2] == '*'
333 && com.s[com.len - 1] == '/' 331 && com.s[com.len - 1] == '/'
334 && kind == '*') 332 && kind == '*')
335 return; 333 return;
336 } 334 }
337} 335}
338 336
339/* 
340 * Scan, reformat and output a single comment, which is either a block comment 
341 * starting with '/' '*' or an end-of-line comment starting with '//'. 
342 */ 
343void 337void
344process_comment(void) 338process_comment(void)
345{ 339{
346 bool may_wrap, delim; 340 bool may_wrap, delim;
347 int line_length; 341 int line_length;
348 342
349 analyze_comment(&may_wrap, &delim, &line_length); 343 analyze_comment(&may_wrap, &delim, &line_length);
350 copy_comment_start(may_wrap, &delim, line_length); 344 copy_comment_start(may_wrap, &delim, line_length);
351 if (may_wrap) 345 if (may_wrap)
352 copy_comment_wrap(line_length, delim); 346 copy_comment_wrap(line_length, delim);
353 else 347 else
354 copy_comment_nowrap(); 348 copy_comment_nowrap();
355} 349}