1 /* $NetBSD: io.c,v 1.19 2019/04/04 15:22:13 kamil Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-4-Clause 5 * 6 * Copyright (c) 1985 Sun Microsystems, Inc. 7 * Copyright (c) 1980, 1993 8 * The Regents of the University of California. All rights reserved. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and 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 25 * without specific prior written permission. 26 * 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 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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 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 37 * SUCH DAMAGE. 38 */ 39 40 #if 0 41 #ifndef lint 42 static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 6/6/93"; 43 #endif /* not lint */ 44 #endif 45 46 #include <sys/cdefs.h> 47 #ifndef lint 48 #if defined(__NetBSD__) 49 __RCSID("$NetBSD: io.c,v 1.19 2019/04/04 15:22:13 kamil Exp $"); 50 #elif defined(__FreeBSD__) 51 __FBSDID("$FreeBSD: head/usr.bin/indent/io.c 334927 2018-06-10 16:44:18Z pstef $"); 52 #endif 53 #endif 54 55 #include <ctype.h> 56 #include <err.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include "indent_globs.h" 61 #include "indent.h" 62 63 int comment_open; 64 static int paren_target; 65 static int pad_output(int current, int target); 66 67 void 68 dump_line(void) 69 { /* dump_line is the routine that actually 70 * effects the printing of the new source. It 71 * prints the label section, followed by the 72 * code section with the appropriate nesting 73 * level, followed by any comments */ 74 int cur_col, 75 target_col = 1; 76 static int not_first_line; 77 78 if (ps.procname[0]) { 79 ps.ind_level = 0; 80 ps.procname[0] = 0; 81 } 82 if (s_code == e_code && s_lab == e_lab && s_com == e_com) { 83 if (suppress_blanklines > 0) 84 suppress_blanklines--; 85 else { 86 ps.bl_line = true; 87 n_real_blanklines++; 88 } 89 } 90 else if (!inhibit_formatting) { 91 suppress_blanklines = 0; 92 ps.bl_line = false; 93 if (prefix_blankline_requested && not_first_line) { 94 if (opt.swallow_optional_blanklines) { 95 if (n_real_blanklines == 1) 96 n_real_blanklines = 0; 97 } 98 else { 99 if (n_real_blanklines == 0) 100 n_real_blanklines = 1; 101 } 102 } 103 while (--n_real_blanklines >= 0) 104 putc('\n', output); 105 n_real_blanklines = 0; 106 if (ps.ind_level == 0) 107 ps.ind_stmt = 0; /* this is a class A kludge. dont do 108 * additional statement indentation if we are 109 * at bracket level 0 */ 110 111 if (e_lab != s_lab || e_code != s_code) 112 ++code_lines; /* keep count of lines with code */ 113 114 115 if (e_lab != s_lab) { /* print lab, if any */ 116 if (comment_open) { 117 comment_open = 0; 118 fprintf(output, ".*/\n"); 119 } 120 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) 121 e_lab--; 122 *e_lab = '\0'; 123 cur_col = pad_output(1, compute_label_target()); 124 if (s_lab[0] == '#' && (strncmp(s_lab, "#else", 5) == 0 125 || strncmp(s_lab, "#endif", 6) == 0)) { 126 char *s = s_lab; 127 if (e_lab[-1] == '\n') e_lab--; 128 do putc(*s++, output); 129 while (s < e_lab && 'a' <= *s && *s<='z'); 130 while ((*s == ' ' || *s == '\t') && s < e_lab) 131 s++; 132 if (s < e_lab) 133 fprintf(output, s[0]=='/' && s[1]=='*' ? "\t%.*s" : "\t/* %.*s */", 134 (int)(e_lab - s), s); 135 } 136 else fprintf(output, "%.*s", (int)(e_lab - s_lab), s_lab); 137 cur_col = count_spaces(cur_col, s_lab); 138 } 139 else 140 cur_col = 1; /* there is no label section */ 141 142 ps.pcase = false; 143 144 if (s_code != e_code) { /* print code section, if any */ 145 char *p; 146 147 if (comment_open) { 148 comment_open = 0; 149 fprintf(output, ".*/\n"); 150 } 151 target_col = compute_code_target(); 152 { 153 int i; 154 155 for (i = 0; i < ps.p_l_follow; i++) 156 if (ps.paren_indents[i] >= 0) 157 ps.paren_indents[i] = -(ps.paren_indents[i] + target_col); 158 } 159 cur_col = pad_output(cur_col, target_col); 160 for (p = s_code; p < e_code; p++) 161 if (*p == (char) 0200) 162 fprintf(output, "%d", target_col * 7); 163 else 164 putc(*p, output); 165 cur_col = count_spaces(cur_col, s_code); 166 } 167 if (s_com != e_com) { /* print comment, if any */ 168 int target = ps.com_col; 169 char *com_st = s_com; 170 171 target += ps.comment_delta; 172 while (*com_st == '\t') /* consider original indentation in 173 * case this is a box comment */ 174 com_st++, target += opt.tabsize; 175 while (target <= 0) 176 if (*com_st == ' ') 177 target++, com_st++; 178 else if (*com_st == '\t') { 179 target = opt.tabsize * (1 + (target - 1) / opt.tabsize) + 1; 180 com_st++; 181 } 182 else 183 target = 1; 184 if (cur_col > target) { /* if comment can't fit on this line, 185 * put it on next line */ 186 putc('\n', output); 187 cur_col = 1; 188 ++ps.out_lines; 189 } 190 while (e_com > com_st && isspace((unsigned char)e_com[-1])) 191 e_com--; 192 (void)pad_output(cur_col, target); 193 fwrite(com_st, e_com - com_st, 1, output); 194 ps.comment_delta = ps.n_comment_delta; 195 ++ps.com_lines; /* count lines with comments */ 196 } 197 if (ps.use_ff) 198 putc('\014', output); 199 else 200 putc('\n', output); 201 ++ps.out_lines; 202 if (ps.just_saw_decl == 1 && opt.blanklines_after_declarations) { 203 prefix_blankline_requested = 1; 204 ps.just_saw_decl = 0; 205 } 206 else 207 prefix_blankline_requested = postfix_blankline_requested; 208 postfix_blankline_requested = 0; 209 } 210 ps.decl_on_line = ps.in_decl; /* if we are in the middle of a 211 * declaration, remember that fact for 212 * proper comment indentation */ 213 ps.ind_stmt = ps.in_stmt & ~ps.in_decl; /* next line should be 214 * indented if we have not 215 * completed this stmt and if 216 * we are not in the middle of 217 * a declaration */ 218 ps.use_ff = false; 219 ps.dumped_decl_indent = 0; 220 *(e_lab = s_lab) = '\0'; /* reset buffers */ 221 *(e_code = s_code) = '\0'; 222 *(e_com = s_com = combuf + 1) = '\0'; 223 ps.ind_level = ps.i_l_follow; 224 ps.paren_level = ps.p_l_follow; 225 if (ps.paren_level > 0) 226 paren_target = -ps.paren_indents[ps.paren_level - 1]; 227 not_first_line = 1; 228 } 229 230 int 231 compute_code_target(void) 232 { 233 int target_col = opt.ind_size * ps.ind_level + 1; 234 235 if (ps.paren_level) 236 if (!opt.lineup_to_parens) 237 target_col += opt.continuation_indent * 238 (2 * opt.continuation_indent == opt.ind_size ? 1 : ps.paren_level); 239 else if (opt.lineup_to_parens_always) 240 target_col = paren_target; 241 else { 242 int w; 243 int t = paren_target; 244 245 if ((w = count_spaces(t, s_code) - opt.max_col) > 0 246 && count_spaces(target_col, s_code) <= opt.max_col) { 247 t -= w + 1; 248 if (t > target_col) 249 target_col = t; 250 } 251 else 252 target_col = t; 253 } 254 else if (ps.ind_stmt) 255 target_col += opt.continuation_indent; 256 return target_col; 257 } 258 259 int 260 compute_label_target(void) 261 { 262 return 263 ps.pcase ? (int) (case_ind * opt.ind_size) + 1 264 : *s_lab == '#' ? 1 265 : opt.ind_size * (ps.ind_level - label_offset) + 1; 266 } 267 268 269 /* 270 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois 271 * 272 * All rights reserved 273 * 274 * 275 * NAME: fill_buffer 276 * 277 * FUNCTION: Reads one block of input into input_buffer 278 * 279 * HISTORY: initial coding November 1976 D A Willcox of CAC 1/7/77 A 280 * Willcox of CAC Added check for switch back to partly full input 281 * buffer from temporary buffer 282 * 283 */ 284 void 285 fill_buffer(void) 286 { /* this routine reads stuff from the input */ 287 char *p; 288 int i; 289 FILE *f = input; 290 291 if (bp_save != NULL) { /* there is a partly filled input buffer left */ 292 buf_ptr = bp_save; /* do not read anything, just switch buffers */ 293 buf_end = be_save; 294 bp_save = be_save = NULL; 295 if (buf_ptr < buf_end) 296 return; /* only return if there is really something in 297 * this buffer */ 298 } 299 for (p = in_buffer;;) { 300 if (p >= in_buffer_limit) { 301 int size = (in_buffer_limit - in_buffer) * 2 + 10; 302 int offset = p - in_buffer; 303 in_buffer = realloc(in_buffer, size); 304 if (in_buffer == NULL) 305 errx(1, "input line too long"); 306 p = in_buffer + offset; 307 in_buffer_limit = in_buffer + size - 2; 308 } 309 if ((i = getc(f)) == EOF) { 310 *p++ = ' '; 311 *p++ = '\n'; 312 had_eof = true; 313 break; 314 } 315 if (i != '\0') 316 *p++ = i; 317 if (i == '\n') 318 break; 319 } 320 buf_ptr = in_buffer; 321 buf_end = p; 322 if (p - in_buffer > 2 && p[-2] == '/' && p[-3] == '*') { 323 if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0) 324 fill_buffer(); /* flush indent error message */ 325 else { 326 int com = 0; 327 328 p = in_buffer; 329 while (*p == ' ' || *p == '\t') 330 p++; 331 if (*p == '/' && p[1] == '*') { 332 p += 2; 333 while (*p == ' ' || *p == '\t') 334 p++; 335 if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E' 336 && p[4] == 'N' && p[5] == 'T') { 337 p += 6; 338 while (*p == ' ' || *p == '\t') 339 p++; 340 if (*p == '*') 341 com = 1; 342 else if (*p == 'O') { 343 if (*++p == 'N') 344 p++, com = 1; 345 else if (*p == 'F' && *++p == 'F') 346 p++, com = 2; 347 } 348 while (*p == ' ' || *p == '\t') 349 p++; 350 if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) { 351 if (s_com != e_com || s_lab != e_lab || s_code != e_code) 352 dump_line(); 353 if (!(inhibit_formatting = com - 1)) { 354 n_real_blanklines = 0; 355 postfix_blankline_requested = 0; 356 prefix_blankline_requested = 0; 357 suppress_blanklines = 1; 358 } 359 } 360 } 361 } 362 } 363 } 364 if (inhibit_formatting) { 365 p = in_buffer; 366 do 367 putc(*p, output); 368 while (*p++ != '\n'); 369 } 370 } 371 372 /* 373 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois 374 * 375 * All rights reserved 376 * 377 * 378 * NAME: pad_output 379 * 380 * FUNCTION: Writes tabs and spaces to move the current column up to the desired 381 * position. 382 * 383 * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf. 384 * 385 * PARAMETERS: current integer The current column target 386 * nteger The desired column 387 * 388 * RETURNS: Integer value of the new column. (If current >= target, no action is 389 * taken, and current is returned. 390 * 391 * GLOBALS: None 392 * 393 * CALLS: write (sys) 394 * 395 * CALLED BY: dump_line 396 * 397 * HISTORY: initial coding November 1976 D A Willcox of CAC 398 * 399 */ 400 static int 401 pad_output(int current, int target) 402 /* writes tabs and blanks (if necessary) to 403 * get the current output position up to the 404 * target column */ 405 /* current: the current column value */ 406 /* target: position we want it at */ 407 { 408 int curr; /* internal column pointer */ 409 410 if (current >= target) 411 return (current); /* line is already long enough */ 412 curr = current; 413 if (opt.use_tabs) { 414 int tcur; 415 416 while ((tcur = opt.tabsize * (1 + (curr - 1) / opt.tabsize) + 1) <= target) { 417 putc('\t', output); 418 curr = tcur; 419 } 420 } 421 while (curr++ < target) 422 putc(' ', output); /* pad with final blanks */ 423 424 return (target); 425 } 426 427 /* 428 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois 429 * 430 * All rights reserved 431 * 432 * 433 * NAME: count_spaces 434 * 435 * FUNCTION: Find out where printing of a given string will leave the current 436 * character position on output. 437 * 438 * ALGORITHM: Run thru input string and add appropriate values to current 439 * position. 440 * 441 * RETURNS: Integer value of position after printing "buffer" starting in column 442 * "current". 443 * 444 * HISTORY: initial coding November 1976 D A Willcox of CAC 445 * 446 */ 447 int 448 count_spaces_until(int cur, char *buffer, char *end) 449 /* 450 * this routine figures out where the character position will be after 451 * printing the text in buffer starting at column "current" 452 */ 453 { 454 char *buf; /* used to look thru buffer */ 455 456 for (buf = buffer; *buf != '\0' && buf != end; ++buf) { 457 switch (*buf) { 458 459 case '\n': 460 case 014: /* form feed */ 461 cur = 1; 462 break; 463 464 case '\t': 465 cur = opt.tabsize * (1 + (cur - 1) / opt.tabsize) + 1; 466 break; 467 468 case 010: /* backspace */ 469 --cur; 470 break; 471 472 default: 473 ++cur; 474 break; 475 } /* end of switch */ 476 } /* end of for loop */ 477 return (cur); 478 } 479 480 int 481 count_spaces(int cur, char *buffer) 482 { 483 return (count_spaces_until(cur, buffer, NULL)); 484 } 485 486 void 487 diag4(int level, const char *msg, int a, int b) 488 { 489 if (level) 490 found_err = 1; 491 if (output == stdout) { 492 fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no); 493 fprintf(stdout, msg, a, b); 494 fprintf(stdout, " */\n"); 495 } 496 else { 497 fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no); 498 fprintf(stderr, msg, a, b); 499 fprintf(stderr, "\n"); 500 } 501 } 502 503 void 504 diag3(int level, const char *msg, int a) 505 { 506 if (level) 507 found_err = 1; 508 if (output == stdout) { 509 fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no); 510 fprintf(stdout, msg, a); 511 fprintf(stdout, " */\n"); 512 } 513 else { 514 fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no); 515 fprintf(stderr, msg, a); 516 fprintf(stderr, "\n"); 517 } 518 } 519 520 void 521 diag2(int level, const char *msg) 522 { 523 if (level) 524 found_err = 1; 525 if (output == stdout) { 526 fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no); 527 fprintf(stdout, "%s", msg); 528 fprintf(stdout, " */\n"); 529 } 530 else { 531 fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no); 532 fprintf(stderr, "%s", msg); 533 fprintf(stderr, "\n"); 534 } 535 } 536