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