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