[BACK]Return to io.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.bin / indent

Annotation of src/usr.bin/indent/io.c, Revision 1.64

1.64    ! rillig      1: /*     $NetBSD: io.c,v 1.63 2021/09/25 20:23:42 rillig Exp $   */
1.3       tls         2:
1.19      kamil       3: /*-
                      4:  * SPDX-License-Identifier: BSD-4-Clause
                      5:  *
                      6:  * Copyright (c) 1985 Sun Microsystems, Inc.
1.4       mrg         7:  * Copyright (c) 1980, 1993
                      8:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         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:
1.19      kamil      40: #if 0
                     41: static char sccsid[] = "@(#)io.c       8.1 (Berkeley) 6/6/93";
                     42: #endif
                     43:
1.5       lukem      44: #include <sys/cdefs.h>
1.19      kamil      45: #if defined(__NetBSD__)
1.64    ! rillig     46: __RCSID("$NetBSD: io.c,v 1.63 2021/09/25 20:23:42 rillig Exp $");
1.19      kamil      47: #elif defined(__FreeBSD__)
                     48: __FBSDID("$FreeBSD: head/usr.bin/indent/io.c 334927 2018-06-10 16:44:18Z pstef $");
                     49: #endif
1.1       cgd        50:
1.5       lukem      51: #include <ctype.h>
                     52: #include <err.h>
1.1       cgd        53: #include <stdio.h>
                     54: #include <stdlib.h>
                     55: #include <string.h>
1.20      christos   56: #include <stdarg.h>
1.22      rillig     57:
1.19      kamil      58: #include "indent.h"
1.1       cgd        59:
1.62      rillig     60: bool comment_open;
1.31      rillig     61: static int  paren_indent;
1.1       cgd        62:
1.28      rillig     63: static void
                     64: output_char(char ch)
                     65: {
                     66:     fputc(ch, output);
1.36      rillig     67:     debug_vis_range("output_char '", &ch, &ch + 1, "'\n");
1.28      rillig     68: }
                     69:
                     70: static void
                     71: output_range(const char *s, const char *e)
                     72: {
                     73:     fwrite(s, 1, (size_t)(e - s), output);
1.36      rillig     74:     debug_vis_range("output_range \"", s, e, "\"\n");
1.28      rillig     75: }
                     76:
1.29      rillig     77: static inline void
1.28      rillig     78: output_string(const char *s)
                     79: {
                     80:     output_range(s, s + strlen(s));
                     81: }
                     82:
1.34      rillig     83: static int
                     84: output_indent(int old_ind, int new_ind)
                     85: {
                     86:     int ind = old_ind;
                     87:
                     88:     if (opt.use_tabs) {
                     89:        int tabsize = opt.tabsize;
                     90:        int n = new_ind / tabsize - ind / tabsize;
                     91:        if (n > 0)
                     92:            ind -= ind % tabsize;
                     93:        for (int i = 0; i < n; i++) {
1.36      rillig     94:            fputc('\t', output);
1.34      rillig     95:            ind += tabsize;
                     96:        }
                     97:     }
                     98:
                     99:     for (; ind < new_ind; ind++)
1.36      rillig    100:         fputc(' ', output);
1.34      rillig    101:
1.36      rillig    102:     debug_println("output_indent %d", ind);
1.34      rillig    103:     return ind;
                    104: }
                    105:
1.26      rillig    106: /*
                    107:  * dump_line is the routine that actually effects the printing of the new
                    108:  * source. It prints the label section, followed by the code section with
                    109:  * the appropriate nesting level, followed by any comments.
                    110:  */
1.5       lukem     111: void
1.11      wiz       112: dump_line(void)
1.26      rillig    113: {
1.44      rillig    114:     int cur_col;
1.62      rillig    115:     static bool not_first_line;
1.19      kamil     116:
1.60      rillig    117:     if (ps.procname[0] != '\0') {
1.19      kamil     118:        ps.ind_level = 0;
1.60      rillig    119:        ps.procname[0] = '\0';
1.19      kamil     120:     }
1.30      rillig    121:
1.55      rillig    122:     if (code.s == code.e && lab.s == lab.e && com.s == com.e) {
1.19      kamil     123:        if (suppress_blanklines > 0)
                    124:            suppress_blanklines--;
1.63      rillig    125:        else
1.19      kamil     126:            n_real_blanklines++;
1.30      rillig    127:     } else if (!inhibit_formatting) {
1.19      kamil     128:        suppress_blanklines = 0;
                    129:        if (prefix_blankline_requested && not_first_line) {
                    130:            if (opt.swallow_optional_blanklines) {
                    131:                if (n_real_blanklines == 1)
                    132:                    n_real_blanklines = 0;
1.30      rillig    133:            } else {
1.19      kamil     134:                if (n_real_blanklines == 0)
                    135:                    n_real_blanklines = 1;
                    136:            }
                    137:        }
                    138:        while (--n_real_blanklines >= 0)
1.28      rillig    139:            output_char('\n');
1.19      kamil     140:        n_real_blanklines = 0;
                    141:        if (ps.ind_level == 0)
1.60      rillig    142:            ps.ind_stmt = false;/* this is a class A kludge. don't do
1.19      kamil     143:                                 * additional statement indentation if we are
                    144:                                 * at bracket level 0 */
                    145:
1.55      rillig    146:        if (lab.e != lab.s || code.e != code.s)
1.58      rillig    147:            ps.stats.code_lines++;
1.19      kamil     148:
                    149:
1.54      rillig    150:        if (lab.e != lab.s) {   /* print lab, if any */
1.19      kamil     151:            if (comment_open) {
1.60      rillig    152:                comment_open = false;
1.28      rillig    153:                output_string(".*/\n");
1.19      kamil     154:            }
1.54      rillig    155:            while (lab.e > lab.s && (lab.e[-1] == ' ' || lab.e[-1] == '\t'))
                    156:                lab.e--;
                    157:            *lab.e = '\0';
1.38      rillig    158:            cur_col = 1 + output_indent(0, compute_label_indent());
1.54      rillig    159:            if (lab.s[0] == '#' && (strncmp(lab.s, "#else", 5) == 0
                    160:                                    || strncmp(lab.s, "#endif", 6) == 0)) {
                    161:                char *s = lab.s;
                    162:                if (lab.e[-1] == '\n') lab.e--;
1.25      rillig    163:                do {
1.28      rillig    164:                    output_char(*s++);
1.54      rillig    165:                } while (s < lab.e && 'a' <= *s && *s <= 'z');
                    166:                while ((*s == ' ' || *s == '\t') && s < lab.e)
1.19      kamil     167:                    s++;
1.54      rillig    168:                if (s < lab.e) {
1.28      rillig    169:                    if (s[0] == '/' && s[1] == '*') {
                    170:                        output_char('\t');
1.54      rillig    171:                        output_range(s, lab.e);
1.28      rillig    172:                    } else {
                    173:                        output_string("\t/* ");
1.54      rillig    174:                        output_range(s, lab.e);
1.28      rillig    175:                        output_string(" */");
                    176:                    }
                    177:                }
                    178:            } else
1.54      rillig    179:                output_range(lab.s, lab.e);
                    180:            cur_col = 1 + indentation_after(cur_col - 1, lab.s);
1.30      rillig    181:        } else
1.19      kamil     182:            cur_col = 1;        /* there is no label section */
                    183:
                    184:        ps.pcase = false;
                    185:
1.55      rillig    186:        if (code.s != code.e) { /* print code section, if any */
1.19      kamil     187:            if (comment_open) {
1.60      rillig    188:                comment_open = false;
1.28      rillig    189:                output_string(".*/\n");
1.19      kamil     190:            }
1.44      rillig    191:            int target_col = 1 + compute_code_indent();
1.19      kamil     192:            {
                    193:                int i;
                    194:
1.36      rillig    195:                for (i = 0; i < ps.p_l_follow; i++) {
                    196:                    if (ps.paren_indents[i] >= 0) {
                    197:                        int ind = ps.paren_indents[i];
                    198:                        /*
                    199:                         * XXX: this mix of 'indent' and 'column' smells like
                    200:                         * an off-by-one error.
                    201:                         */
                    202:                        ps.paren_indents[i] = -(ind + target_col);
                    203:                        debug_println(
                    204:                            "setting pi[%d] from %d to %d for column %d",
                    205:                            i, ind, ps.paren_indents[i], target_col);
                    206:                    }
                    207:                }
1.19      kamil     208:            }
1.34      rillig    209:            cur_col = 1 + output_indent(cur_col - 1, target_col - 1);
1.55      rillig    210:            output_range(code.s, code.e);
                    211:            cur_col = 1 + indentation_after(cur_col - 1, code.s);
1.19      kamil     212:        }
1.52      rillig    213:        if (com.s != com.e) {           /* print comment, if any */
1.45      rillig    214:            int target_col = ps.com_col;
1.52      rillig    215:            char *com_st = com.s;
1.19      kamil     216:
1.45      rillig    217:            target_col += ps.comment_delta;
1.19      kamil     218:            while (*com_st == '\t')     /* consider original indentation in
1.46      rillig    219:                                 * case this is a box comment */
1.45      rillig    220:                com_st++, target_col += opt.tabsize;
                    221:            while (target_col <= 0)
1.19      kamil     222:                if (*com_st == ' ')
1.45      rillig    223:                    target_col++, com_st++;
1.19      kamil     224:                else if (*com_st == '\t') {
1.45      rillig    225:                    target_col = opt.tabsize * (1 + (target_col - 1) / opt.tabsize) + 1;
1.19      kamil     226:                    com_st++;
1.30      rillig    227:                } else
1.45      rillig    228:                    target_col = 1;
                    229:            if (cur_col > target_col) { /* if comment can't fit on this line,
1.46      rillig    230:                                 * put it on next line */
1.28      rillig    231:                output_char('\n');
1.19      kamil     232:                cur_col = 1;
1.58      rillig    233:                ps.stats.lines++;
1.19      kamil     234:            }
1.52      rillig    235:            while (com.e > com_st && isspace((unsigned char)com.e[-1]))
                    236:                com.e--;
1.45      rillig    237:            (void)output_indent(cur_col - 1, target_col - 1);
1.52      rillig    238:            output_range(com_st, com.e);
1.19      kamil     239:            ps.comment_delta = ps.n_comment_delta;
1.58      rillig    240:            ps.stats.comment_lines++;
1.19      kamil     241:        }
                    242:        if (ps.use_ff)
1.28      rillig    243:            output_char('\014');
1.19      kamil     244:        else
1.28      rillig    245:            output_char('\n');
1.58      rillig    246:        ps.stats.lines++;
1.19      kamil     247:        if (ps.just_saw_decl == 1 && opt.blanklines_after_declarations) {
1.60      rillig    248:            prefix_blankline_requested = true;
1.19      kamil     249:            ps.just_saw_decl = 0;
1.30      rillig    250:        } else
1.19      kamil     251:            prefix_blankline_requested = postfix_blankline_requested;
1.60      rillig    252:        postfix_blankline_requested = false;
1.19      kamil     253:     }
1.24      rillig    254:
                    255:     /* keep blank lines after '//' comments */
1.52      rillig    256:     if (com.e - com.s > 1 && com.s[1] == '/'
1.56      rillig    257:        && token.s < token.e && isspace((unsigned char)token.s[0]))
                    258:        output_range(token.s, token.e);
1.24      rillig    259:
1.46      rillig    260:     ps.decl_on_line = ps.in_decl; /* if we are in the middle of a declaration,
                    261:                                 * remember that fact for proper comment
                    262:                                 * indentation */
1.60      rillig    263:     ps.ind_stmt = ps.in_stmt && !ps.in_decl; /* next line should be indented if
                    264:                                 * we have not completed this stmt and if we
                    265:                                 * are not in the middle of a declaration */
1.19      kamil     266:     ps.use_ff = false;
1.60      rillig    267:     ps.dumped_decl_indent = false;
1.54      rillig    268:     *(lab.e = lab.s) = '\0';   /* reset buffers */
1.55      rillig    269:     *(code.e = code.s) = '\0';
1.52      rillig    270:     *(com.e = com.s = com.buf + 1) = '\0';
1.64    ! rillig    271:     ps.ind_level = ps.ind_level_follow;
1.19      kamil     272:     ps.paren_level = ps.p_l_follow;
1.36      rillig    273:     if (ps.paren_level > 0) {
                    274:         /* TODO: explain what negative indentation means */
1.31      rillig    275:        paren_indent = -ps.paren_indents[ps.paren_level - 1];
1.36      rillig    276:        debug_println("paren_indent is now %d", paren_indent);
                    277:     }
1.60      rillig    278:     not_first_line = true;
1.1       cgd       279: }
                    280:
1.5       lukem     281: int
1.39      rillig    282: compute_code_indent(void)
1.1       cgd       283: {
1.43      rillig    284:     int target_ind = opt.indent_size * ps.ind_level;
1.19      kamil     285:
1.39      rillig    286:     if (ps.paren_level != 0) {
1.19      kamil     287:        if (!opt.lineup_to_parens)
1.49      rillig    288:            if (2 * opt.continuation_indent == opt.indent_size)
                    289:                target_ind += opt.continuation_indent;
                    290:            else
                    291:                target_ind += opt.continuation_indent * ps.paren_level;
1.19      kamil     292:        else if (opt.lineup_to_parens_always)
1.39      rillig    293:            /*
                    294:             * XXX: where does this '- 1' come from?  It looks strange but is
                    295:             * nevertheless needed for proper indentation, as demonstrated in
                    296:             * the test opt-lpl.0.
                    297:             */
                    298:            target_ind = paren_indent - 1;
1.19      kamil     299:        else {
                    300:            int w;
1.31      rillig    301:            int t = paren_indent;
1.1       cgd       302:
1.55      rillig    303:            if ((w = 1 + indentation_after(t - 1, code.s) - opt.max_line_length) > 0
                    304:                && 1 + indentation_after(target_ind, code.s) <= opt.max_line_length) {
1.19      kamil     305:                t -= w + 1;
1.39      rillig    306:                if (t > target_ind + 1)
                    307:                    target_ind = t - 1;
1.30      rillig    308:            } else
1.39      rillig    309:                target_ind = t - 1;
1.19      kamil     310:        }
1.30      rillig    311:     } else if (ps.ind_stmt)
1.39      rillig    312:        target_ind += opt.continuation_indent;
                    313:     return target_ind;
1.1       cgd       314: }
                    315:
1.5       lukem     316: int
1.38      rillig    317: compute_label_indent(void)
1.1       cgd       318: {
1.38      rillig    319:     if (ps.pcase)
1.43      rillig    320:        return (int) (case_ind * opt.indent_size);
1.54      rillig    321:     if (lab.s[0] == '#')
1.38      rillig    322:         return 0;
1.43      rillig    323:     return opt.indent_size * (ps.ind_level - label_offset);
1.1       cgd       324: }
                    325:
1.53      rillig    326: static void
                    327: skip_hspace(const char **pp)
                    328: {
                    329:     while (**pp == ' ' || **pp == '\t')
                    330:        (*pp)++;
                    331: }
                    332:
                    333: static void
                    334: parse_indent_comment(void)
                    335: {
                    336:     int on_off = 0;            /* 0 = keep, 1 = ON, 2 = OFF */
                    337:
                    338:     const char *p = in_buffer;
                    339:
                    340:     skip_hspace(&p);
                    341:
                    342:     if (!(*p == '/' && p[1] == '*'))
                    343:        return;
                    344:     p += 2;
                    345:
                    346:     skip_hspace(&p);
                    347:
                    348:     if (!(p[0] == 'I' && p[1] == 'N' && p[2] == 'D'
                    349:          && p[3] == 'E' && p[4] == 'N' && p[5] == 'T'))
                    350:        return;
                    351:     p += 6;
                    352:
                    353:     skip_hspace(&p);
                    354:
                    355:     if (*p == '*')
                    356:        on_off = 1;
                    357:     else if (*p == 'O') {
                    358:        if (*++p == 'N')
                    359:            p++, on_off = 1;
                    360:        else if (*p == 'F' && *++p == 'F')
                    361:            p++, on_off = 2;
                    362:     }
                    363:     if (on_off == 0)
                    364:        return;
                    365:
                    366:     skip_hspace(&p);
                    367:
                    368:     if (!(p[0] == '*' && p[1] == '/' && p[2] == '\n'))
                    369:        return;
                    370:
1.55      rillig    371:     if (com.s != com.e || lab.s != lab.e || code.s != code.e)
1.53      rillig    372:        dump_line();
                    373:
1.62      rillig    374:     if (!(inhibit_formatting = (on_off == 2))) {
1.53      rillig    375:        n_real_blanklines = 0;
1.60      rillig    376:        postfix_blankline_requested = false;
                    377:        prefix_blankline_requested = false;
1.53      rillig    378:        suppress_blanklines = 1;
                    379:     }
                    380: }
1.1       cgd       381:
                    382: /*
                    383:  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
1.5       lukem     384:  *
1.1       cgd       385:  * All rights reserved
1.5       lukem     386:  *
1.33      rillig    387:  * FUNCTION: Reads one block of input into the input buffer
1.1       cgd       388:  */
1.5       lukem     389: void
1.11      wiz       390: fill_buffer(void)
1.1       cgd       391: {                              /* this routine reads stuff from the input */
1.19      kamil     392:     char *p;
                    393:     int i;
                    394:     FILE *f = input;
                    395:
                    396:     if (bp_save != NULL) {     /* there is a partly filled input buffer left */
                    397:        buf_ptr = bp_save;      /* do not read anything, just switch buffers */
                    398:        buf_end = be_save;
                    399:        bp_save = be_save = NULL;
1.47      rillig    400:        debug_println("switched buf_ptr back to bp_save");
1.19      kamil     401:        if (buf_ptr < buf_end)
                    402:            return;             /* only return if there is really something in
1.1       cgd       403:                                 * this buffer */
1.19      kamil     404:     }
                    405:     for (p = in_buffer;;) {
                    406:        if (p >= in_buffer_limit) {
1.48      rillig    407:            size_t size = (in_buffer_limit - in_buffer) * 2 + 10;
                    408:            size_t offset = p - in_buffer;
1.57      rillig    409:            in_buffer = xrealloc(in_buffer, size);
1.19      kamil     410:            p = in_buffer + offset;
                    411:            in_buffer_limit = in_buffer + size - 2;
                    412:        }
                    413:        if ((i = getc(f)) == EOF) {
1.37      rillig    414:            *p++ = ' ';
                    415:            *p++ = '\n';
                    416:            had_eof = true;
                    417:            break;
1.1       cgd       418:        }
1.19      kamil     419:        if (i != '\0')
                    420:            *p++ = i;
                    421:        if (i == '\n')
1.37      rillig    422:            break;
1.19      kamil     423:     }
                    424:     buf_ptr = in_buffer;
                    425:     buf_end = p;
                    426:     if (p - in_buffer > 2 && p[-2] == '/' && p[-3] == '*') {
                    427:        if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0)
                    428:            fill_buffer();      /* flush indent error message */
1.53      rillig    429:        else
                    430:            parse_indent_comment();
1.19      kamil     431:     }
                    432:     if (inhibit_formatting) {
                    433:        p = in_buffer;
1.25      rillig    434:        do {
1.28      rillig    435:            output_char(*p);
1.25      rillig    436:        } while (*p++ != '\n');
1.19      kamil     437:     }
1.1       cgd       438: }
1.19      kamil     439:
1.1       cgd       440: int
1.40      rillig    441: indentation_after_range(int ind, const char *start, const char *end)
1.1       cgd       442: {
1.40      rillig    443:     for (const char *p = start; *p != '\0' && p != end; ++p) {
                    444:        if (*p == '\n' || *p == '\f')
                    445:            ind = 0;
                    446:        else if (*p == '\t')
                    447:            ind = opt.tabsize * (ind / opt.tabsize + 1);
                    448:        else if (*p == '\b')
                    449:            --ind;
                    450:        else
                    451:            ++ind;
                    452:     }
                    453:     return ind;
                    454: }
1.1       cgd       455:
1.40      rillig    456: int
                    457: indentation_after(int ind, const char *s)
                    458: {
                    459:     return indentation_after_range(ind, s, NULL);
                    460: }
1.19      kamil     461:
1.5       lukem     462: void
1.20      christos  463: diag(int level, const char *msg, ...)
1.1       cgd       464: {
1.20      christos  465:     va_list ap;
                    466:     const char *s, *e;
                    467:
1.60      rillig    468:     if (level != 0)
1.19      kamil     469:        found_err = 1;
1.1       cgd       470:
1.19      kamil     471:     if (output == stdout) {
1.20      christos  472:        s = "/**INDENT** ";
                    473:        e = " */";
                    474:     } else {
                    475:        s = e = "";
1.19      kamil     476:     }
1.1       cgd       477:
1.20      christos  478:     va_start(ap, msg);
                    479:     fprintf(stderr, "%s%s@%d: ", s, level == 0 ? "Warning" : "Error", line_no);
                    480:     vfprintf(stderr, msg, ap);
                    481:     fprintf(stderr, "%s\n", e);
                    482:     va_end(ap);
1.1       cgd       483: }

CVSweb <webmaster@jp.NetBSD.org>