1 1.237 rillig /* $NetBSD: io.c,v 1.237 2025/01/04 10:28:08 rillig Exp $ */ 2 1.3 tls 3 1.19 kamil /*- 4 1.19 kamil * SPDX-License-Identifier: BSD-4-Clause 5 1.19 kamil * 6 1.19 kamil * Copyright (c) 1985 Sun Microsystems, Inc. 7 1.4 mrg * Copyright (c) 1980, 1993 8 1.4 mrg * The Regents of the University of California. All rights reserved. 9 1.1 cgd * All rights reserved. 10 1.1 cgd * 11 1.1 cgd * Redistribution and use in source and binary forms, with or without 12 1.1 cgd * modification, are permitted provided that the following conditions 13 1.1 cgd * are met: 14 1.1 cgd * 1. Redistributions of source code must retain the above copyright 15 1.1 cgd * notice, this list of conditions and the following disclaimer. 16 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 cgd * notice, this list of conditions and the following disclaimer in the 18 1.1 cgd * documentation and/or other materials provided with the distribution. 19 1.1 cgd * 3. All advertising materials mentioning features or use of this software 20 1.1 cgd * must display the following acknowledgement: 21 1.1 cgd * This product includes software developed by the University of 22 1.1 cgd * California, Berkeley and its contributors. 23 1.1 cgd * 4. Neither the name of the University nor the names of its contributors 24 1.1 cgd * may be used to endorse or promote products derived from this software 25 1.1 cgd * without specific prior written permission. 26 1.1 cgd * 27 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 1.1 cgd * SUCH DAMAGE. 38 1.1 cgd */ 39 1.1 cgd 40 1.5 lukem #include <sys/cdefs.h> 41 1.237 rillig __RCSID("$NetBSD: io.c,v 1.237 2025/01/04 10:28:08 rillig Exp $"); 42 1.1 cgd 43 1.236 rillig #include <err.h> 44 1.1 cgd #include <stdio.h> 45 1.22 rillig 46 1.19 kamil #include "indent.h" 47 1.1 cgd 48 1.234 rillig struct input_state in = { 49 1.234 rillig .token_end_line = 1, 50 1.234 rillig }; 51 1.194 rillig 52 1.183 rillig struct output_state out; 53 1.208 rillig enum indent_enabled indent_enabled; 54 1.194 rillig static int out_ind; /* width of the line that is being written */ 55 1.214 rillig static unsigned newlines = 2; /* the total of written and buffered newlines; 56 1.214 rillig * 0 in the middle of a line, 1 after a single 57 1.214 rillig * finished line, anything > 1 are trailing 58 1.214 rillig * blank lines */ 59 1.214 rillig static unsigned buffered_newlines; /* not yet written */ 60 1.225 rillig static int paren_indent; /* total indentation when parenthesized */ 61 1.1 cgd 62 1.118 rillig 63 1.138 rillig static void 64 1.222 rillig inp_read_next_line(void) 65 1.137 rillig { 66 1.235 rillig buf_clear(&in.line); 67 1.137 rillig 68 1.177 rillig for (;;) { 69 1.235 rillig int ch = getc(in.f); 70 1.177 rillig if (ch == EOF) { 71 1.177 rillig if (indent_enabled == indent_on) { 72 1.235 rillig buf_add_char(&in.line, ' '); 73 1.235 rillig buf_add_char(&in.line, '\n'); 74 1.177 rillig } 75 1.177 rillig had_eof = true; 76 1.177 rillig break; 77 1.177 rillig } 78 1.177 rillig 79 1.177 rillig if (ch != '\0') 80 1.235 rillig buf_add_char(&in.line, (char)ch); 81 1.177 rillig if (ch == '\n') 82 1.177 rillig break; 83 1.177 rillig } 84 1.235 rillig buf_terminate(&in.line); 85 1.235 rillig in.p = in.line.s; 86 1.137 rillig } 87 1.137 rillig 88 1.200 rillig void 89 1.200 rillig inp_read_line(void) 90 1.200 rillig { 91 1.200 rillig if (indent_enabled == indent_on) 92 1.215 rillig buf_clear(&out.indent_off_text); 93 1.235 rillig buf_add_chars(&out.indent_off_text, in.line.s, in.line.len); 94 1.222 rillig inp_read_next_line(); 95 1.200 rillig } 96 1.200 rillig 97 1.200 rillig void 98 1.200 rillig inp_skip(void) 99 1.200 rillig { 100 1.235 rillig in.p++; 101 1.235 rillig if ((size_t)(in.p - in.line.s) >= in.line.len) 102 1.200 rillig inp_read_line(); 103 1.200 rillig } 104 1.200 rillig 105 1.200 rillig char 106 1.200 rillig inp_next(void) 107 1.200 rillig { 108 1.235 rillig char ch = in.p[0]; 109 1.200 rillig inp_skip(); 110 1.200 rillig return ch; 111 1.200 rillig } 112 1.200 rillig 113 1.200 rillig 114 1.28 rillig static void 115 1.216 rillig add_buffered_newline(void) 116 1.28 rillig { 117 1.214 rillig buffered_newlines++; 118 1.214 rillig newlines++; 119 1.194 rillig out_ind = 0; 120 1.28 rillig } 121 1.28 rillig 122 1.28 rillig static void 123 1.214 rillig write_buffered_newlines(void) 124 1.208 rillig { 125 1.214 rillig for (; buffered_newlines > 0; buffered_newlines--) { 126 1.236 rillig if (fputc('\n', output) == EOF) 127 1.236 rillig err(1, "cannot write output"); 128 1.214 rillig debug_println("write_newline"); 129 1.208 rillig } 130 1.208 rillig } 131 1.208 rillig 132 1.208 rillig static void 133 1.211 rillig write_range(const char *s, size_t len) 134 1.28 rillig { 135 1.214 rillig write_buffered_newlines(); 136 1.236 rillig if (fwrite(s, 1, len, output) != len) 137 1.236 rillig err(1, "cannot write output"); 138 1.219 rillig debug_printf("write_range "); 139 1.219 rillig debug_vis_range(s, len); 140 1.219 rillig debug_println(""); 141 1.179 rillig for (size_t i = 0; i < len; i++) 142 1.214 rillig newlines = s[i] == '\n' ? newlines + 1 : 0; 143 1.194 rillig out_ind = ind_add(out_ind, s, len); 144 1.28 rillig } 145 1.28 rillig 146 1.194 rillig static void 147 1.211 rillig write_indent(int new_ind) 148 1.34 rillig { 149 1.214 rillig write_buffered_newlines(); 150 1.208 rillig 151 1.194 rillig int ind = out_ind; 152 1.34 rillig 153 1.177 rillig if (opt.use_tabs) { 154 1.201 rillig int n = new_ind / opt.tabsize - ind / opt.tabsize; 155 1.201 rillig if (n > 0) { 156 1.201 rillig ind = ind - ind % opt.tabsize + n * opt.tabsize; 157 1.201 rillig while (n-- > 0) 158 1.236 rillig if (fputc('\t', output) == EOF) 159 1.236 rillig err(1, "cannot write output"); 160 1.214 rillig newlines = 0; 161 1.177 rillig } 162 1.34 rillig } 163 1.34 rillig 164 1.179 rillig for (; ind < new_ind; ind++) { 165 1.236 rillig if (fputc(' ', output) == EOF) 166 1.236 rillig err(1, "cannot write output"); 167 1.214 rillig newlines = 0; 168 1.179 rillig } 169 1.34 rillig 170 1.214 rillig debug_println("write_indent %d", ind); 171 1.194 rillig out_ind = ind; 172 1.34 rillig } 173 1.34 rillig 174 1.180 rillig static bool 175 1.180 rillig want_blank_line(void) 176 1.179 rillig { 177 1.183 rillig debug_println("%s: %s -> %s", __func__, 178 1.183 rillig line_kind_name[out.prev_line_kind], line_kind_name[out.line_kind]); 179 1.237 rillig debug_blank_line(); 180 1.183 rillig 181 1.232 rillig if (((ps.blank_line_after_decl && ps.declaration == decl_no) 182 1.232 rillig || ps.badp == badp_yes) 183 1.230 rillig && (lab.len > 0 || code.len > 0)) { 184 1.179 rillig ps.blank_line_after_decl = false; 185 1.231 rillig ps.badp = badp_none; 186 1.231 rillig return true; 187 1.231 rillig } 188 1.231 rillig 189 1.216 rillig if (opt.blank_line_around_conditional_compilation) { 190 1.227 rillig if (out.prev_line_kind != lk_pre_if 191 1.227 rillig && out.line_kind == lk_pre_if) 192 1.180 rillig return true; 193 1.227 rillig if (out.prev_line_kind == lk_pre_endif 194 1.227 rillig && out.line_kind != lk_pre_endif) 195 1.180 rillig return true; 196 1.179 rillig } 197 1.216 rillig if (opt.blank_line_after_proc && out.prev_line_kind == lk_func_end 198 1.227 rillig && out.line_kind != lk_pre_endif && out.line_kind != lk_pre_other) 199 1.181 rillig return true; 200 1.216 rillig if (opt.blank_line_before_block_comment 201 1.183 rillig && out.line_kind == lk_block_comment) 202 1.182 rillig return true; 203 1.180 rillig return false; 204 1.179 rillig } 205 1.179 rillig 206 1.185 rillig static bool 207 1.185 rillig is_blank_line_optional(void) 208 1.185 rillig { 209 1.197 rillig if (out.prev_line_kind == lk_stmt_head) 210 1.214 rillig return newlines >= 1; 211 1.221 rillig if (ps.psyms.len >= 3) 212 1.214 rillig return newlines >= 2; 213 1.214 rillig return newlines >= 3; 214 1.185 rillig } 215 1.185 rillig 216 1.200 rillig static int 217 1.200 rillig compute_case_label_indent(void) 218 1.200 rillig { 219 1.221 rillig size_t i = ps.psyms.len - 1; 220 1.202 rillig while (i > 0 && ps.psyms.sym[i] != psym_switch_expr) 221 1.200 rillig i--; 222 1.202 rillig float case_ind = (float)ps.psyms.ind_level[i] + opt.case_indent; 223 1.222 rillig // TODO: case_ind may become negative here. 224 1.200 rillig return (int)(case_ind * (float)opt.indent_size); 225 1.200 rillig } 226 1.200 rillig 227 1.200 rillig int 228 1.200 rillig compute_label_indent(void) 229 1.200 rillig { 230 1.200 rillig if (out.line_kind == lk_case_or_default) 231 1.200 rillig return compute_case_label_indent(); 232 1.200 rillig if (lab.s[0] == '#') 233 1.200 rillig return 0; 234 1.222 rillig // TODO: the indentation may become negative here. 235 1.200 rillig return opt.indent_size * (ps.ind_level - 2); 236 1.200 rillig } 237 1.200 rillig 238 1.194 rillig static void 239 1.141 rillig output_line_label(void) 240 1.86 rillig { 241 1.211 rillig write_indent(compute_label_indent()); 242 1.211 rillig write_range(lab.s, lab.len); 243 1.86 rillig } 244 1.86 rillig 245 1.200 rillig static int 246 1.216 rillig compute_lined_up_code_indent(int base_ind) 247 1.200 rillig { 248 1.200 rillig int ind = paren_indent; 249 1.200 rillig int overflow = ind_add(ind, code.s, code.len) - opt.max_line_length; 250 1.207 rillig if (overflow >= 0 251 1.207 rillig && ind_add(base_ind, code.s, code.len) < opt.max_line_length) { 252 1.222 rillig ind -= 2 + overflow; 253 1.207 rillig if (ind < base_ind) 254 1.207 rillig ind = base_ind; 255 1.200 rillig } 256 1.200 rillig 257 1.207 rillig if (ps.extra_expr_indent != eei_no 258 1.207 rillig && ind == base_ind + opt.indent_size) 259 1.207 rillig ind += opt.continuation_indent; 260 1.200 rillig return ind; 261 1.200 rillig } 262 1.200 rillig 263 1.200 rillig int 264 1.200 rillig compute_code_indent(void) 265 1.200 rillig { 266 1.200 rillig int base_ind = ps.ind_level * opt.indent_size; 267 1.200 rillig 268 1.217 rillig if (ps.ind_paren_level == 0) { 269 1.224 rillig if (ps.line_is_stmt_cont) 270 1.200 rillig return base_ind + opt.continuation_indent; 271 1.200 rillig return base_ind; 272 1.200 rillig } 273 1.200 rillig 274 1.200 rillig if (opt.lineup_to_parens) { 275 1.200 rillig if (opt.lineup_to_parens_always) 276 1.200 rillig return paren_indent; 277 1.216 rillig return compute_lined_up_code_indent(base_ind); 278 1.200 rillig } 279 1.200 rillig 280 1.217 rillig int rel_ind = opt.continuation_indent * ps.ind_paren_level; 281 1.207 rillig if (ps.extra_expr_indent != eei_no && rel_ind == opt.indent_size) 282 1.207 rillig rel_ind += opt.continuation_indent; 283 1.207 rillig return base_ind + rel_ind; 284 1.200 rillig } 285 1.200 rillig 286 1.194 rillig static void 287 1.194 rillig output_line_code(void) 288 1.86 rillig { 289 1.177 rillig int target_ind = compute_code_indent(); 290 1.220 rillig for (size_t i = 0; i < ps.paren.len; i++) { 291 1.220 rillig int paren_ind = ps.paren.item[i].indent; 292 1.177 rillig if (paren_ind >= 0) { 293 1.220 rillig ps.paren.item[i].indent = 294 1.220 rillig -1 - (paren_ind + target_ind); 295 1.177 rillig debug_println( 296 1.220 rillig "setting paren_indents[%zu] from %d to %d " 297 1.178 rillig "for column %d", 298 1.220 rillig i, paren_ind, 299 1.220 rillig ps.paren.item[i].indent, target_ind + 1); 300 1.177 rillig } 301 1.177 rillig } 302 1.177 rillig 303 1.195 rillig if (lab.len > 0 && target_ind <= out_ind) 304 1.211 rillig write_range(" ", 1); 305 1.211 rillig write_indent(target_ind); 306 1.211 rillig write_range(code.s, code.len); 307 1.86 rillig } 308 1.86 rillig 309 1.86 rillig static void 310 1.216 rillig output_comment(void) 311 1.86 rillig { 312 1.218 rillig int target_ind = ps.comment_ind; 313 1.194 rillig const char *p; 314 1.86 rillig 315 1.226 rillig if (ps.comment_cont) 316 1.218 rillig target_ind += ps.comment_shift; 317 1.226 rillig ps.comment_cont = true; 318 1.218 rillig 319 1.218 rillig /* consider the original indentation in case this is a box comment */ 320 1.194 rillig for (p = com.s; *p == '\t'; p++) 321 1.177 rillig target_ind += opt.tabsize; 322 1.177 rillig 323 1.177 rillig for (; target_ind < 0; p++) { 324 1.177 rillig if (*p == ' ') 325 1.177 rillig target_ind++; 326 1.177 rillig else if (*p == '\t') 327 1.177 rillig target_ind = next_tab(target_ind); 328 1.177 rillig else { 329 1.177 rillig target_ind = 0; 330 1.177 rillig break; 331 1.177 rillig } 332 1.177 rillig } 333 1.86 rillig 334 1.194 rillig if (out_ind > target_ind) 335 1.216 rillig add_buffered_newline(); 336 1.86 rillig 337 1.193 rillig while (com.s + com.len > p && ch_isspace(com.s[com.len - 1])) 338 1.177 rillig com.len--; 339 1.215 rillig buf_terminate(&com); 340 1.86 rillig 341 1.211 rillig write_indent(target_ind); 342 1.211 rillig write_range(p, com.len - (size_t)(p - com.s)); 343 1.86 rillig } 344 1.86 rillig 345 1.228 rillig /* 346 1.228 rillig * Write a line of formatted source to the output file. The line consists of 347 1.228 rillig * the label, the code and the comment. 348 1.228 rillig */ 349 1.212 rillig static void 350 1.216 rillig output_indented_line(void) 351 1.212 rillig { 352 1.212 rillig if (lab.len == 0 && code.len == 0 && com.len == 0) 353 1.212 rillig out.line_kind = lk_blank; 354 1.212 rillig 355 1.229 rillig if (want_blank_line() && newlines < 2 && out.line_kind != lk_blank) 356 1.216 rillig add_buffered_newline(); 357 1.212 rillig 358 1.212 rillig /* This kludge aligns function definitions correctly. */ 359 1.212 rillig if (ps.ind_level == 0) 360 1.224 rillig ps.line_is_stmt_cont = false; 361 1.212 rillig 362 1.212 rillig if (opt.blank_line_after_decl && ps.declaration == decl_end 363 1.221 rillig && ps.psyms.len > 2) { 364 1.212 rillig ps.declaration = decl_no; 365 1.212 rillig ps.blank_line_after_decl = true; 366 1.212 rillig } 367 1.212 rillig 368 1.216 rillig if (opt.swallow_optional_blank_lines 369 1.212 rillig && out.line_kind == lk_blank 370 1.212 rillig && is_blank_line_optional()) 371 1.212 rillig return; 372 1.212 rillig 373 1.212 rillig if (lab.len > 0) 374 1.212 rillig output_line_label(); 375 1.212 rillig if (code.len > 0) 376 1.212 rillig output_line_code(); 377 1.212 rillig if (com.len > 0) 378 1.216 rillig output_comment(); 379 1.216 rillig add_buffered_newline(); 380 1.214 rillig if (out.line_kind != lk_blank) 381 1.214 rillig write_buffered_newlines(); 382 1.212 rillig 383 1.212 rillig out.prev_line_kind = out.line_kind; 384 1.212 rillig } 385 1.212 rillig 386 1.225 rillig static bool 387 1.225 rillig is_stmt_cont(void) 388 1.225 rillig { 389 1.225 rillig if (ps.psyms.len >= 2 390 1.225 rillig && ps.psyms.sym[ps.psyms.len - 2] == psym_lbrace_enum 391 1.225 rillig && ps.prev_lsym == lsym_comma 392 1.225 rillig && ps.paren.len == 0) 393 1.225 rillig return false; 394 1.225 rillig return ps.in_stmt_or_decl 395 1.225 rillig && (!ps.in_decl || ps.in_init) 396 1.225 rillig && ps.init_level == 0; 397 1.225 rillig } 398 1.225 rillig 399 1.228 rillig static void 400 1.228 rillig prepare_next_line(void) 401 1.26 rillig { 402 1.209 rillig ps.line_has_decl = ps.in_decl; 403 1.210 rillig ps.line_has_func_def = false; 404 1.225 rillig ps.line_is_stmt_cont = is_stmt_cont(); 405 1.177 rillig ps.decl_indent_done = false; 406 1.177 rillig if (ps.extra_expr_indent == eei_last) 407 1.177 rillig ps.extra_expr_indent = eei_no; 408 1.221 rillig if (!(ps.psyms.sym[ps.psyms.len - 1] == psym_if_expr_stmt_else 409 1.220 rillig && ps.paren.len > 0)) 410 1.204 rillig ps.ind_level = ps.ind_level_follow; 411 1.220 rillig ps.ind_paren_level = (int)ps.paren.len; 412 1.203 rillig ps.want_blank = false; 413 1.231 rillig if ((ps.badp == badp_seen_lbrace || ps.badp == badp_seen_decl) 414 1.231 rillig && !ps.in_decl) 415 1.231 rillig ps.badp = badp_yes; 416 1.177 rillig 417 1.220 rillig if (ps.paren.len > 0) { 418 1.177 rillig /* TODO: explain what negative indentation means */ 419 1.220 rillig paren_indent = -1 - ps.paren.item[ps.paren.len - 1].indent; 420 1.177 rillig debug_println("paren_indent is now %d", paren_indent); 421 1.177 rillig } 422 1.161 rillig 423 1.183 rillig out.line_kind = lk_other; 424 1.1 cgd } 425 1.211 rillig 426 1.211 rillig void 427 1.228 rillig output_line(void) 428 1.228 rillig { 429 1.228 rillig debug_blank_line(); 430 1.237 rillig debug_buffers(__func__); 431 1.228 rillig 432 1.228 rillig if (indent_enabled == indent_on) 433 1.228 rillig output_indented_line(); 434 1.228 rillig else if (indent_enabled == indent_last_off_line) { 435 1.228 rillig indent_enabled = indent_on; 436 1.228 rillig write_range(out.indent_off_text.s, out.indent_off_text.len); 437 1.228 rillig buf_clear(&out.indent_off_text); 438 1.228 rillig } 439 1.228 rillig 440 1.228 rillig buf_clear(&lab); 441 1.228 rillig buf_clear(&code); 442 1.228 rillig buf_clear(&com); 443 1.228 rillig 444 1.228 rillig prepare_next_line(); 445 1.228 rillig } 446 1.228 rillig 447 1.228 rillig void 448 1.216 rillig finish_output(void) 449 1.211 rillig { 450 1.214 rillig output_line(); 451 1.214 rillig if (indent_enabled != indent_on) { 452 1.211 rillig indent_enabled = indent_last_off_line; 453 1.211 rillig output_line(); 454 1.211 rillig } 455 1.236 rillig if (fflush(output) != 0) 456 1.236 rillig err(1, "output file"); 457 1.211 rillig } 458