1 /* $NetBSD: indent.h,v 1.112 2022/04/23 06:43:22 rillig Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5 * 6 * Copyright (c) 2001 Jens Schweikhardt 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 /*- 31 * SPDX-License-Identifier: BSD-4-Clause 32 * 33 * Copyright (c) 1985 Sun Microsystems, Inc. 34 * Copyright (c) 1980, 1993 35 * The Regents of the University of California. All rights reserved. 36 * All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by the University of 49 * California, Berkeley and its contributors. 50 * 4. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 */ 66 67 #if 0 68 __FBSDID("$FreeBSD: head/usr.bin/indent/indent.h 336333 2018-07-16 05:46:50Z pstef $"); 69 #endif 70 71 #include <ctype.h> 72 #include <stdbool.h> 73 #include <stdio.h> 74 75 typedef enum lexer_symbol { 76 lsym_eof, 77 lsym_preprocessing, /* '#' */ 78 lsym_newline, 79 lsym_form_feed, 80 lsym_comment, /* the initial '/ *' or '//' of a comment */ 81 lsym_lparen_or_lbracket, 82 lsym_rparen_or_rbracket, 83 lsym_lbrace, 84 lsym_rbrace, 85 lsym_period, 86 lsym_unary_op, /* e.g. '*', '&', '-' or leading '++' */ 87 lsym_binary_op, /* e.g. '*', '&', '<<', '&&' or '/=' */ 88 lsym_postfix_op, /* trailing '++' or '--' */ 89 lsym_question, /* the '?' from a '?:' expression */ 90 lsym_colon, 91 lsym_comma, 92 lsym_semicolon, 93 lsym_typedef, 94 lsym_storage_class, 95 lsym_type_outside_parentheses, 96 lsym_type_in_parentheses, 97 lsym_tag, /* 'struct', 'union' or 'enum' */ 98 lsym_case_label, /* 'case' or 'default' */ 99 lsym_sizeof, 100 lsym_offsetof, 101 lsym_word, /* identifier, constant or string */ 102 lsym_funcname, 103 lsym_do, 104 lsym_else, 105 lsym_for, 106 lsym_if, 107 lsym_switch, 108 lsym_while, 109 lsym_return 110 } lexer_symbol; 111 112 typedef enum parser_symbol { 113 psym_semicolon, /* rather a placeholder than a semicolon */ 114 psym_lbrace, 115 psym_rbrace, 116 psym_decl, 117 psym_stmt, 118 psym_stmt_list, 119 psym_for_exprs, /* 'for' '(' ... ')' */ 120 psym_if_expr, /* 'if' '(' expr ')' */ 121 psym_if_expr_stmt, /* 'if' '(' expr ')' stmt */ 122 psym_if_expr_stmt_else, /* 'if' '(' expr ')' stmt 'else' */ 123 psym_else, /* 'else' */ 124 psym_switch_expr, /* 'switch' '(' expr ')' */ 125 psym_do, /* 'do' */ 126 psym_do_stmt, /* 'do' stmt */ 127 psym_while_expr, /* 'while' '(' expr ')' */ 128 } parser_symbol; 129 130 typedef enum stmt_head { 131 hd_0, /* placeholder for uninitialized */ 132 hd_for, 133 hd_if, 134 hd_switch, 135 hd_while, 136 } stmt_head; 137 138 /* A range of characters, in some cases null-terminated. */ 139 struct buffer { 140 char *s; /* start of the usable text */ 141 char *e; /* end of the usable text */ 142 char *buf; /* start of the allocated memory */ 143 char *l; /* end of the allocated memory */ 144 }; 145 146 extern struct output_control { 147 int blank_lines_to_output; 148 bool blank_line_before; 149 bool blank_line_after; 150 bool suppress_blanklines; 151 } out; 152 153 extern FILE *input; 154 extern FILE *output; 155 156 extern struct buffer token; /* the current token to be processed, is 157 * typically copied to the buffer 'code', or 158 * in some cases to 'lab'. */ 159 160 extern struct buffer lab; /* the label or preprocessor directive */ 161 extern struct buffer code; /* the main part of the current line of code */ 162 extern struct buffer com; /* the trailing comment of the line, or the 163 * start or end of a multi-line comment, or 164 * while in process_comment, a single line of 165 * a multi-line comment */ 166 167 extern struct options { 168 bool blanklines_around_conditional_compilation; 169 bool blanklines_after_decl_at_top; /* this is vaguely similar to 170 * blanklines_after_decl except that 171 * it only applies to the first set of 172 * declarations in a procedure (just 173 * after the first '{') and it causes 174 * a blank line to be generated even 175 * if there are no declarations */ 176 bool blanklines_after_decl; 177 bool blanklines_after_procs; 178 bool blanklines_before_block_comments; 179 bool break_after_comma; /* whether to break declarations after commas */ 180 bool brace_same_line; /* whether brace should be on same line as if, 181 * while, etc */ 182 bool blank_after_sizeof; /* whether a blank should always be inserted 183 * after sizeof */ 184 bool comment_delimiter_on_blankline; 185 int decl_comment_column; /* the column in which comments after 186 * declarations should be put */ 187 bool cuddle_else; /* whether 'else' should cuddle up to '}' */ 188 int continuation_indent; /* the indentation between the edge of code 189 * and continuation lines */ 190 float case_indent; /* The distance (measured in indentation 191 * levels) to indent case labels from the 192 * switch statement */ 193 int comment_column; /* the column in which comments to the right 194 * of code should start */ 195 int decl_indent; /* indentation of identifier in declaration */ 196 bool ljust_decl; /* true if declarations should be left 197 * justified */ 198 int unindent_displace; /* comments not to the right of code will be 199 * placed this many indentation levels to the 200 * left of code */ 201 bool extra_expr_indent; /* whether continuation lines from the 202 * expression part of "if(e)", "while(e)", 203 * "for(e;e;e)" should be indented an extra 204 * tab stop so that they don't conflict with 205 * the code that follows */ 206 bool else_if; /* whether else-if pairs should be handled 207 * specially */ 208 bool function_brace_split; /* split function declaration and brace onto 209 * separate lines */ 210 bool format_col1_comments; /* If comments which start in column 1 are to 211 * be magically reformatted (just like 212 * comments that begin in later columns) */ 213 bool format_block_comments; /* whether comments beginning with '/ * \n' 214 * are to be reformatted */ 215 bool indent_parameters; 216 int indent_size; /* the size of one indentation level */ 217 int block_comment_max_line_length; 218 int local_decl_indent; /* like decl_indent but for locals */ 219 bool lineup_to_parens_always; /* whether to not(?) attempt to keep 220 * lined-up code within the margin */ 221 bool lineup_to_parens; /* whether continued code within parens will 222 * be lined up to the open paren */ 223 bool proc_calls_space; /* whether function calls look like: foo (bar) 224 * rather than foo(bar) */ 225 bool procnames_start_line; /* whether the names of procedures being 226 * defined get placed in column 1 (i.e. a 227 * newline is placed between the type of the 228 * procedure and its name) */ 229 bool space_after_cast; /* "b = (int) a" vs "b = (int)a" */ 230 bool star_comment_cont; /* whether comment continuation lines should 231 * have stars at the beginning of each line. */ 232 bool swallow_optional_blanklines; 233 bool auto_typedefs; /* whether to recognize identifiers ending in 234 * "_t" like typedefs */ 235 int tabsize; /* the size of a tab */ 236 int max_line_length; 237 bool use_tabs; /* set true to use tabs for spacing, false 238 * uses all spaces */ 239 bool verbose; /* whether non-essential error messages are 240 * printed */ 241 } opt; 242 243 extern bool found_err; 244 extern bool break_comma; /* when true and not in parentheses, break 245 * after a comma */ 246 extern float case_ind; /* indentation level to be used for a "case 247 * n:" */ 248 extern bool had_eof; /* whether input is exhausted */ 249 extern int line_no; /* the current line number. */ 250 extern bool inhibit_formatting; /* true if INDENT OFF is in effect */ 251 252 #define STACKSIZE 256 253 254 /* Properties of each level of parentheses or brackets. */ 255 typedef struct paren_level_props { 256 short indent; /* indentation of the operand/argument, 257 * relative to the enclosing statement; if 258 * negative, reflected at -1 */ 259 bool maybe_cast; /* whether the parentheses may form a type 260 * cast */ 261 bool no_cast; /* whether the parentheses definitely do not 262 * form a type cast */ 263 } paren_level_props; 264 265 extern struct parser_state { 266 lexer_symbol prev_token; /* the previous token, but never comment, 267 * newline or preprocessing line */ 268 bool curr_col_1; /* whether the current token started in column 269 * 1 of the unformatted input */ 270 bool next_col_1; 271 bool next_unary; /* whether the following operator should be 272 * unary */ 273 274 bool is_function_definition; 275 276 bool want_blank; /* whether the following token should be 277 * prefixed by a blank. (Said prefixing is 278 * ignored in some cases.) */ 279 280 int line_start_nparen; /* the number of parentheses or brackets that 281 * were already open at the beginning of the 282 * current line; used to indent within 283 * statements, initializers and declarations */ 284 int nparen; /* the number of parentheses or brackets that 285 * are currently open; used to indent the 286 * remaining lines of the statement, 287 * initializer or declaration */ 288 paren_level_props paren[20]; 289 290 int comment_delta; /* used to set up indentation for all lines of 291 * a boxed comment after the first one */ 292 int n_comment_delta; /* remembers how many columns there were 293 * before the start of a box comment so that 294 * forthcoming lines of the comment are 295 * indented properly */ 296 int com_ind; /* indentation of the current comment */ 297 298 bool block_init; /* whether inside a block initialization */ 299 int block_init_level; /* The level of brace nesting in an 300 * initialization */ 301 bool init_or_struct; /* whether there has been a declarator (e.g. 302 * int or char) and no left parenthesis since 303 * the last semicolon. When true, a '{' is 304 * starting a structure definition or an 305 * initialization list */ 306 307 int ind_level; /* the indentation level for the line that is 308 * currently prepared for output */ 309 int ind_level_follow; /* the level to which ind_level should be set 310 * after the current line is printed */ 311 312 int decl_level; /* current nesting level for a structure 313 * declaration or an initializer */ 314 bool decl_on_line; /* whether this line of code has part of a 315 * declaration on it */ 316 bool in_decl; /* whether we are in a declaration. The 317 * processing of braces is then slightly 318 * different */ 319 int just_saw_decl; 320 bool in_func_def_params; 321 enum { 322 in_enum_no, /* outside any 'enum { ... }' */ 323 in_enum_enum, /* after keyword 'enum' */ 324 in_enum_type, /* after 'enum' or 'enum tag' */ 325 in_enum_brace /* between '{' and '}' */ 326 } in_enum; /* enum { . } */ 327 bool decl_indent_done; /* whether the indentation for a declaration 328 * has been added to the code buffer. */ 329 330 bool in_stmt_or_decl; /* whether in a statement or a struct 331 * declaration or a plain declaration */ 332 bool in_stmt_cont; /* whether the next line should have an extra 333 * indentation level because we are in the 334 * middle of a statement */ 335 bool is_case_label; /* 'case' and 'default' labels are indented 336 * differently from regular labels */ 337 338 bool search_stmt; /* whether it is necessary to buffer up all 339 * text up to the start of a statement after 340 * an 'if (expr)', 'while (expr)', etc., to 341 * move the comments after the opening brace 342 * of the following statement */ 343 344 int tos; /* pointer to top of stack */ 345 parser_symbol s_sym[STACKSIZE]; 346 int s_ind_level[STACKSIZE]; 347 float s_case_ind_level[STACKSIZE]; 348 349 struct { 350 int comments; 351 int lines; 352 int code_lines; 353 int comment_lines; 354 } stats; 355 } ps; 356 357 358 #define array_length(array) (sizeof(array) / sizeof((array)[0])) 359 360 #ifdef debug 361 void 362 debug_vis_range(const char *, const char *, const char *, 363 const char *); 364 void debug_printf(const char *, ...)__printflike(1, 2); 365 void debug_println(const char *, ...)__printflike(1, 2); 366 #else 367 #define debug_printf(fmt, ...) do { } while (false) 368 #define debug_println(fmt, ...) do { } while (false) 369 #define debug_vis_range(prefix, s, e, suffix) do { } while (false) 370 #endif 371 372 void register_typename(const char *); 373 int compute_code_indent(void); 374 int compute_label_indent(void); 375 int ind_add(int, const char *, const char *); 376 377 void inp_init(void); 378 379 const char *inp_p(void); 380 const char *inp_line_start(void); 381 const char *inp_line_end(void); 382 char inp_peek(void); 383 char inp_lookahead(size_t); 384 void inp_skip(void); 385 char inp_next(void); 386 387 void inp_comment_init_newline(void); 388 void inp_comment_init_comment(void); 389 void inp_comment_init_preproc(void); 390 void inp_comment_add_char(char); 391 void inp_comment_add_range(const char *, const char *); 392 bool inp_comment_complete_block(void); 393 bool inp_comment_seen(void); 394 void inp_comment_rtrim_blank(void); 395 void inp_comment_rtrim_newline(void); 396 void inp_comment_insert_lbrace(void); 397 398 void inp_from_comment(void); 399 400 #ifdef debug 401 void debug_inp(const char *); 402 #else 403 #define debug_inp(prefix) do { } while (false) 404 #endif 405 406 lexer_symbol lexi(void); 407 void diag(int, const char *, ...)__printflike(2, 3); 408 void output_line(void); 409 void output_line_ff(void); 410 void inp_read_line(void); 411 void parse(parser_symbol); 412 void parse_stmt_head(stmt_head); 413 void process_comment(void); 414 void set_option(const char *, const char *); 415 void load_profiles(const char *); 416 417 void *xmalloc(size_t); 418 void *xrealloc(void *, size_t); 419 char *xstrdup(const char *); 420 421 void buf_expand(struct buffer *, size_t); 422 void buf_add_char(struct buffer *, char); 423 void buf_add_range(struct buffer *, const char *, const char *); 424 425 static inline bool 426 ch_isalnum(char ch) 427 { 428 return isalnum((unsigned char)ch) != 0; 429 } 430 431 static inline bool 432 ch_isalpha(char ch) 433 { 434 return isalpha((unsigned char)ch) != 0; 435 } 436 437 static inline bool 438 ch_isblank(char ch) 439 { 440 return ch == ' ' || ch == '\t'; 441 } 442 443 static inline bool 444 ch_isdigit(char ch) 445 { 446 return '0' <= ch && ch <= '9'; 447 } 448 449 static inline bool 450 ch_isspace(char ch) 451 { 452 return isspace((unsigned char)ch) != 0; 453 } 454 455 static inline int 456 next_tab(int ind) 457 { 458 return ind - ind % opt.tabsize + opt.tabsize; 459 } 460