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