]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/indent/io.c
Add UPDATING entries and bump version.
[FreeBSD/FreeBSD.git] / usr.bin / indent / io.c
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