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

Annotation of src/usr.bin/indent/indent.c, Revision 1.37

1.37    ! rillig      1: /*     $NetBSD: indent.c,v 1.36 2021/03/09 16:48:28 rillig Exp $       */
1.4       tls         2:
1.25      kamil       3: /*-
                      4:  * SPDX-License-Identifier: BSD-4-Clause
                      5:  *
                      6:  * Copyright (c) 1985 Sun Microsystems, Inc.
                      7:  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
1.5       mrg         8:  * Copyright (c) 1980, 1993
                      9:  *     The Regents of the University of California.  All rights reserved.
1.15      agc        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.
1.1       cgd        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.25      kamil      40: #if 0
1.1       cgd        41: #ifndef lint
1.25      kamil      42: static char sccsid[] = "@(#)indent.c   5.17 (Berkeley) 6/7/93";
                     43: #endif /* not lint */
                     44: #endif
1.1       cgd        45:
1.25      kamil      46: #include <sys/cdefs.h>
1.1       cgd        47: #ifndef lint
1.25      kamil      48: #if defined(__NetBSD__)
1.37    ! rillig     49: __RCSID("$NetBSD: indent.c,v 1.36 2021/03/09 16:48:28 rillig Exp $");
1.25      kamil      50: #elif defined(__FreeBSD__)
                     51: __FBSDID("$FreeBSD: head/usr.bin/indent/indent.c 340138 2018-11-04 19:24:49Z oshogbo $");
                     52: #endif
1.5       mrg        53: #endif
1.1       cgd        54:
                     55: #include <sys/param.h>
1.25      kamil      56: #if HAVE_CAPSICUM
                     57: #include <sys/capsicum.h>
                     58: #include <capsicum_helpers.h>
                     59: #endif
1.6       lukem      60: #include <err.h>
                     61: #include <errno.h>
1.1       cgd        62: #include <fcntl.h>
1.25      kamil      63: #include <unistd.h>
1.1       cgd        64: #include <stdio.h>
                     65: #include <stdlib.h>
                     66: #include <string.h>
1.25      kamil      67: #include <ctype.h>
1.29      rillig     68:
1.25      kamil      69: #include "indent.h"
                     70:
1.27      joerg      71: struct options opt;
                     72: struct parser_state ps;
                     73:
                     74: char       *labbuf;
                     75: char       *s_lab;
                     76: char       *e_lab;
                     77: char       *l_lab;
                     78:
                     79: char       *codebuf;
                     80: char       *s_code;
                     81: char       *e_code;
                     82: char       *l_code;
                     83:
                     84: char       *combuf;
                     85: char       *s_com;
                     86: char       *e_com;
                     87: char       *l_com;
                     88:
                     89: char       *tokenbuf;
                     90: char      *s_token;
                     91: char       *e_token;
                     92: char      *l_token;
                     93:
                     94: char       *in_buffer;
                     95: char      *in_buffer_limit;
                     96: char       *buf_ptr;
                     97: char       *buf_end;
                     98:
                     99: char        sc_buf[sc_size];
                    100: char       *save_com;
                    101: char       *sc_end;
                    102:
                    103: char       *bp_save;
                    104: char       *be_save;
                    105:
                    106: int         found_err;
                    107: int         n_real_blanklines;
                    108: int         prefix_blankline_requested;
                    109: int         postfix_blankline_requested;
                    110: int         break_comma;
                    111: float       case_ind;
                    112: int         code_lines;
                    113: int         had_eof;
                    114: int         line_no;
                    115: int         inhibit_formatting;
                    116: int         suppress_blanklines;
                    117:
                    118: int         ifdef_level;
                    119: struct parser_state state_stack[5];
                    120: struct parser_state match_state[5];
                    121:
                    122: FILE       *input;
                    123: FILE       *output;
                    124:
1.25      kamil     125: static void bakcopy(void);
                    126: static void indent_declaration(int, int);
1.1       cgd       127:
1.25      kamil     128: const char *in_name = "Standard Input";        /* will always point to name of input
                    129:                                         * file */
                    130: const char *out_name = "Standard Output";      /* will always point to name
                    131:                                                 * of output file */
                    132: const char *simple_backup_suffix = ".BAK";     /* Suffix to use for backup
                    133:                                                 * files */
                    134: char        bakfile[MAXPATHLEN] = "";
1.1       cgd       135:
1.34      rillig    136: static void
                    137: check_size_code(size_t desired_size)
                    138: {
                    139:     if (e_code + (desired_size) >= l_code) {
                    140:        int nsize = l_code - s_code + 400 + desired_size;
                    141:        int code_len = e_code - s_code;
                    142:        codebuf = (char *)realloc(codebuf, nsize);
                    143:        if (codebuf == NULL)
                    144:            err(1, NULL);
                    145:        e_code = codebuf + code_len + 1;
                    146:        l_code = codebuf + nsize - 5;
                    147:        s_code = codebuf + 1;
                    148:     }
                    149: }
                    150:
                    151: static void
                    152: check_size_label(size_t desired_size)
                    153: {
                    154:     if (e_lab + (desired_size) >= l_lab) {
                    155:        int nsize = l_lab - s_lab + 400 + desired_size;
                    156:        int label_len = e_lab - s_lab;
                    157:        labbuf = (char *)realloc(labbuf, nsize);
                    158:        if (labbuf == NULL)
                    159:            err(1, NULL);
                    160:        e_lab = labbuf + label_len + 1;
                    161:        l_lab = labbuf + nsize - 5;
                    162:        s_lab = labbuf + 1;
                    163:     }
                    164: }
                    165:
1.6       lukem     166: int
1.13      wiz       167: main(int argc, char **argv)
1.1       cgd       168: {
1.25      kamil     169: #if HAVE_CAPSICUM
                    170:     cap_rights_t rights;
                    171: #endif
1.1       cgd       172:
1.25      kamil     173:     int         dec_ind;       /* current indentation for declarations */
                    174:     int         di_stack[20];  /* a stack of structure indentation levels */
                    175:     int         force_nl;      /* when true, code must be broken */
1.30      rillig    176:     token_type  hd_type = end_of_file; /* used to store type of stmt
                    177:                                 * for if (...), for (...), etc */
1.25      kamil     178:     int                i;              /* local loop counter */
                    179:     int         scase;         /* set to true when we see a case, so we will
1.1       cgd       180:                                 * know what to do with the following colon */
1.25      kamil     181:     int         sp_sw;         /* when true, we are in the expression of
1.1       cgd       182:                                 * if(...), while(...), etc. */
1.25      kamil     183:     int         squest;                /* when this is positive, we have seen a ?
1.1       cgd       184:                                 * without the matching : in a <c>?<s>:<s>
                    185:                                 * construct */
1.25      kamil     186:     const char *t_ptr;         /* used for copying tokens */
                    187:     int                tabs_to_var;    /* true if using tabs to indent to var name */
1.30      rillig    188:     token_type type_code;      /* returned by lexi */
1.25      kamil     189:
                    190:     int         last_else = 0; /* true iff last keyword was an else */
                    191:     const char *profile_name = NULL;
                    192:     const char *envval = NULL;
                    193:     struct parser_state transient_state; /* a copy for lookup */
                    194:
                    195:     /*-----------------------------------------------*\
                    196:     |                INITIALIZATION                  |
                    197:     \*-----------------------------------------------*/
1.1       cgd       198:
1.25      kamil     199:     found_err = 0;
1.1       cgd       200:
1.25      kamil     201:     ps.p_stack[0] = stmt;      /* this is the parser's stack */
                    202:     ps.last_nl = true;         /* this is true if the last thing scanned was
1.1       cgd       203:                                 * a newline */
1.25      kamil     204:     ps.last_token = semicolon;
                    205:     combuf = (char *) malloc(bufsize);
                    206:     if (combuf == NULL)
                    207:        err(1, NULL);
                    208:     labbuf = (char *) malloc(bufsize);
                    209:     if (labbuf == NULL)
                    210:        err(1, NULL);
                    211:     codebuf = (char *) malloc(bufsize);
                    212:     if (codebuf == NULL)
                    213:        err(1, NULL);
                    214:     tokenbuf = (char *) malloc(bufsize);
                    215:     if (tokenbuf == NULL)
                    216:        err(1, NULL);
                    217:     alloc_typenames();
                    218:     init_constant_tt();
                    219:     l_com = combuf + bufsize - 5;
                    220:     l_lab = labbuf + bufsize - 5;
                    221:     l_code = codebuf + bufsize - 5;
                    222:     l_token = tokenbuf + bufsize - 5;
                    223:     combuf[0] = codebuf[0] = labbuf[0] = ' ';  /* set up code, label, and
                    224:                                                 * comment buffers */
1.33      rillig    225:     combuf[1] = codebuf[1] = labbuf[1] = tokenbuf[1] = '\0';
1.25      kamil     226:     opt.else_if = 1;           /* Default else-if special processing to on */
                    227:     s_lab = e_lab = labbuf + 1;
                    228:     s_code = e_code = codebuf + 1;
                    229:     s_com = e_com = combuf + 1;
                    230:     s_token = e_token = tokenbuf + 1;
                    231:
                    232:     in_buffer = (char *) malloc(10);
                    233:     if (in_buffer == NULL)
                    234:        err(1, NULL);
                    235:     in_buffer_limit = in_buffer + 8;
                    236:     buf_ptr = buf_end = in_buffer;
                    237:     line_no = 1;
                    238:     had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
                    239:     sp_sw = force_nl = false;
                    240:     ps.in_or_st = false;
                    241:     ps.bl_line = true;
                    242:     dec_ind = 0;
                    243:     di_stack[ps.dec_nest = 0] = 0;
                    244:     ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
                    245:
                    246:     scase = ps.pcase = false;
                    247:     squest = 0;
                    248:     sc_end = NULL;
                    249:     bp_save = NULL;
                    250:     be_save = NULL;
                    251:
                    252:     output = NULL;
                    253:     tabs_to_var = 0;
                    254:
                    255:     envval = getenv("SIMPLE_BACKUP_SUFFIX");
                    256:     if (envval)
                    257:         simple_backup_suffix = envval;
                    258:
                    259:     /*--------------------------------------------------*\
1.28      rillig    260:     |                  COMMAND LINE SCAN                |
1.25      kamil     261:     \*--------------------------------------------------*/
1.1       cgd       262:
                    263: #ifdef undef
1.25      kamil     264:     max_col = 78;              /* -l78 */
                    265:     lineup_to_parens = 1;      /* -lp */
                    266:     lineup_to_parens_always = 0;       /* -nlpl */
                    267:     ps.ljust_decl = 0;         /* -ndj */
                    268:     ps.com_ind = 33;           /* -c33 */
                    269:     star_comment_cont = 1;     /* -sc */
                    270:     ps.ind_size = 8;           /* -i8 */
                    271:     verbose = 0;
                    272:     ps.decl_indent = 16;       /* -di16 */
                    273:     ps.local_decl_indent = -1; /* if this is not set to some nonnegative value
                    274:                                 * by an arg, we will set this equal to
                    275:                                 * ps.decl_ind */
                    276:     ps.indent_parameters = 1;  /* -ip */
                    277:     ps.decl_com_ind = 0;       /* if this is not set to some positive value
1.1       cgd       278:                                 * by an arg, we will set this equal to
                    279:                                 * ps.com_ind */
1.25      kamil     280:     btype_2 = 1;               /* -br */
                    281:     cuddle_else = 1;           /* -ce */
                    282:     ps.unindent_displace = 0;  /* -d0 */
                    283:     ps.case_indent = 0;                /* -cli0 */
                    284:     format_block_comments = 1; /* -fcb */
                    285:     format_col1_comments = 1;  /* -fc1 */
                    286:     procnames_start_line = 1;  /* -psl */
                    287:     proc_calls_space = 0;      /* -npcs */
                    288:     comment_delimiter_on_blankline = 1;        /* -cdb */
                    289:     ps.leave_comma = 1;                /* -nbc */
1.1       cgd       290: #endif
                    291:
1.25      kamil     292:     for (i = 1; i < argc; ++i)
                    293:        if (strcmp(argv[i], "-npro") == 0)
                    294:            break;
                    295:        else if (argv[i][0] == '-' && argv[i][1] == 'P' && argv[i][2] != '\0')
                    296:            profile_name = argv[i];     /* non-empty -P (set profile) */
                    297:     set_defaults();
                    298:     if (i >= argc)
                    299:        set_profile(profile_name);
1.1       cgd       300:
1.25      kamil     301:     for (i = 1; i < argc; ++i) {
1.1       cgd       302:
1.25      kamil     303:        /*
                    304:         * look thru args (if any) for changes to defaults
                    305:         */
                    306:        if (argv[i][0] != '-') {/* no flag on parameter */
                    307:            if (input == NULL) {        /* we must have the input file */
                    308:                in_name = argv[i];      /* remember name of input file */
                    309:                input = fopen(in_name, "r");
                    310:                if (input == NULL)      /* check for open error */
                    311:                        err(1, "%s", in_name);
                    312:                continue;
                    313:            }
                    314:            else if (output == NULL) {  /* we have the output file */
                    315:                out_name = argv[i];     /* remember name of output file */
                    316:                if (strcmp(in_name, out_name) == 0) {   /* attempt to overwrite
                    317:                                                         * the file */
                    318:                    errx(1, "input and output files must be different");
1.1       cgd       319:                }
1.25      kamil     320:                output = fopen(out_name, "w");
                    321:                if (output == NULL)     /* check for create error */
                    322:                        err(1, "%s", out_name);
                    323:                continue;
                    324:            }
                    325:            errx(1, "unknown parameter: %s", argv[i]);
1.7       ross      326:        }
1.25      kamil     327:        else
                    328:            set_option(argv[i]);
                    329:     }                          /* end of for */
                    330:     if (input == NULL)
                    331:        input = stdin;
                    332:     if (output == NULL) {
                    333:        if (input == stdin)
                    334:            output = stdout;
                    335:        else {
                    336:            out_name = in_name;
                    337:            bakcopy();
1.1       cgd       338:        }
1.25      kamil     339:     }
                    340:
                    341: #if HAVE_CAPSICUM
                    342:     /* Restrict input/output descriptors and enter Capsicum sandbox. */
                    343:     cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE);
                    344:     if (caph_rights_limit(fileno(output), &rights) < 0)
                    345:        err(EXIT_FAILURE, "unable to limit rights for %s", out_name);
                    346:     cap_rights_init(&rights, CAP_FSTAT, CAP_READ);
                    347:     if (caph_rights_limit(fileno(input), &rights) < 0)
                    348:        err(EXIT_FAILURE, "unable to limit rights for %s", in_name);
                    349:     if (caph_enter() < 0)
                    350:        err(EXIT_FAILURE, "unable to enter capability mode");
                    351: #endif
1.6       lukem     352:
1.25      kamil     353:     if (opt.com_ind <= 1)
                    354:        opt.com_ind = 2;        /* don't put normal comments before column 2 */
                    355:     if (opt.block_comment_max_col <= 0)
                    356:        opt.block_comment_max_col = opt.max_col;
                    357:     if (opt.local_decl_indent < 0) /* if not specified by user, set this */
                    358:        opt.local_decl_indent = opt.decl_indent;
                    359:     if (opt.decl_com_ind <= 0) /* if not specified by user, set this */
                    360:        opt.decl_com_ind = opt.ljust_decl ? (opt.com_ind <= 10 ? 2 : opt.com_ind - 8) : opt.com_ind;
                    361:     if (opt.continuation_indent == 0)
                    362:        opt.continuation_indent = opt.ind_size;
                    363:     fill_buffer();             /* get first batch of stuff into input buffer */
                    364:
                    365:     parse(semicolon);
                    366:     {
                    367:        char *p = buf_ptr;
                    368:        int col = 1;
                    369:
                    370:        while (1) {
                    371:            if (*p == ' ')
                    372:                col++;
                    373:            else if (*p == '\t')
                    374:                col = opt.tabsize * (1 + (col - 1) / opt.tabsize) + 1;
                    375:            else
                    376:                break;
                    377:            p++;
1.1       cgd       378:        }
1.25      kamil     379:        if (col > opt.ind_size)
                    380:            ps.ind_level = ps.i_l_follow = col / opt.ind_size;
                    381:     }
                    382:
                    383:     /*
                    384:      * START OF MAIN LOOP
                    385:      */
1.1       cgd       386:
1.25      kamil     387:     while (1) {                        /* this is the main loop.  it will go until we
1.1       cgd       388:                                 * reach eof */
1.25      kamil     389:        int comment_buffered = false;
1.1       cgd       390:
1.25      kamil     391:        type_code = lexi(&ps);  /* lexi reads one token.  The actual
                    392:                                 * characters read are stored in "token". lexi
                    393:                                 * returns a code indicating the type of token */
1.1       cgd       394:
1.25      kamil     395:        /*
                    396:         * The following code moves newlines and comments following an if (),
                    397:         * while (), else, etc. up to the start of the following stmt to
                    398:         * a buffer. This allows proper handling of both kinds of brace
                    399:         * placement (-br, -bl) and cuddling "else" (-ce).
                    400:         */
                    401:
                    402:        while (ps.search_brace) {
                    403:            switch (type_code) {
                    404:            case newline:
                    405:                if (sc_end == NULL) {
                    406:                    save_com = sc_buf;
                    407:                    save_com[0] = save_com[1] = ' ';
                    408:                    sc_end = &save_com[2];
                    409:                }
                    410:                *sc_end++ = '\n';
1.6       lukem     411:                /*
1.25      kamil     412:                 * We may have inherited a force_nl == true from the previous
                    413:                 * token (like a semicolon). But once we know that a newline
                    414:                 * has been scanned in this loop, force_nl should be false.
                    415:                 *
                    416:                 * However, the force_nl == true must be preserved if newline
                    417:                 * is never scanned in this loop, so this assignment cannot be
                    418:                 * done earlier.
1.6       lukem     419:                 */
1.25      kamil     420:                force_nl = false;
                    421:            case form_feed:
                    422:                break;
                    423:            case comment:
                    424:                if (sc_end == NULL) {
                    425:                    /*
                    426:                     * Copy everything from the start of the line, because
                    427:                     * pr_comment() will use that to calculate original
                    428:                     * indentation of a boxed comment.
                    429:                     */
                    430:                    memcpy(sc_buf, in_buffer, buf_ptr - in_buffer - 4);
                    431:                    save_com = sc_buf + (buf_ptr - in_buffer - 4);
                    432:                    save_com[0] = save_com[1] = ' ';
                    433:                    sc_end = &save_com[2];
                    434:                }
                    435:                comment_buffered = true;
                    436:                *sc_end++ = '/';        /* copy in start of comment */
                    437:                *sc_end++ = '*';
1.36      rillig    438:                for (;;) {      /* loop until the end of the comment */
1.25      kamil     439:                    *sc_end = *buf_ptr++;
                    440:                    if (buf_ptr >= buf_end)
                    441:                        fill_buffer();
                    442:                    if (*sc_end++ == '*' && *buf_ptr == '/')
                    443:                        break;  /* we are at end of comment */
                    444:                    if (sc_end >= &save_com[sc_size]) { /* check for temp buffer
                    445:                                                         * overflow */
1.26      christos  446:                        diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever");
1.6       lukem     447:                        fflush(output);
1.25      kamil     448:                        exit(1);
                    449:                    }
                    450:                }
                    451:                *sc_end++ = '/';        /* add ending slash */
                    452:                if (++buf_ptr >= buf_end)       /* get past / in buffer */
                    453:                    fill_buffer();
                    454:                break;
                    455:            case lbrace:
                    456:                /*
                    457:                 * Put KNF-style lbraces before the buffered up tokens and
                    458:                 * jump out of this loop in order to avoid copying the token
                    459:                 * again under the default case of the switch below.
                    460:                 */
                    461:                if (sc_end != NULL && opt.btype_2) {
                    462:                    save_com[0] = '{';
                    463:                    /*
                    464:                     * Originally the lbrace may have been alone on its own
                    465:                     * line, but it will be moved into "the else's line", so
                    466:                     * if there was a newline resulting from the "{" before,
                    467:                     * it must be scanned now and ignored.
                    468:                     */
                    469:                    while (isspace((unsigned char)*buf_ptr)) {
                    470:                        if (++buf_ptr >= buf_end)
                    471:                            fill_buffer();
                    472:                        if (*buf_ptr == '\n')
                    473:                            break;
                    474:                    }
                    475:                    goto sw_buffer;
1.1       cgd       476:                }
1.25      kamil     477:                /* FALLTHROUGH */
                    478:            default:            /* it is the start of a normal statement */
                    479:                {
                    480:                    int remove_newlines;
                    481:
                    482:                    remove_newlines =
                    483:                        /* "} else" */
1.37    ! rillig    484:                        (type_code == keyword_do_else && *token == 'e' &&
1.25      kamil     485:                            e_code != s_code && e_code[-1] == '}')
                    486:                        /* "else if" */
1.37    ! rillig    487:                        || (type_code == keyword_for_if_while &&
        !           488:                            *token == 'i' && last_else && opt.else_if);
1.25      kamil     489:                    if (remove_newlines)
                    490:                        force_nl = false;
                    491:                    if (sc_end == NULL) {       /* ignore buffering if
                    492:                                                 * comment wasn't saved up */
                    493:                        ps.search_brace = false;
                    494:                        goto check_type;
                    495:                    }
                    496:                    while (sc_end > save_com && isblank((unsigned char)sc_end[-1])) {
                    497:                        sc_end--;
                    498:                    }
                    499:                    if (opt.swallow_optional_blanklines ||
                    500:                        (!comment_buffered && remove_newlines)) {
                    501:                        force_nl = !remove_newlines;
                    502:                        while (sc_end > save_com && sc_end[-1] == '\n') {
                    503:                            sc_end--;
1.6       lukem     504:                        }
1.25      kamil     505:                    }
                    506:                    if (force_nl) {     /* if we should insert a nl here, put
                    507:                                         * it into the buffer */
                    508:                        force_nl = false;
                    509:                        --line_no;      /* this will be re-increased when the
                    510:                                         * newline is read from the buffer */
                    511:                        *sc_end++ = '\n';
                    512:                        *sc_end++ = ' ';
                    513:                        if (opt.verbose) /* print error msg if the line was
                    514:                                         * not already broken */
1.26      christos  515:                            diag(0, "Line broken");
1.25      kamil     516:                    }
                    517:                    for (t_ptr = token; *t_ptr; ++t_ptr)
                    518:                        *sc_end++ = *t_ptr;
                    519:
                    520:            sw_buffer:
                    521:                    ps.search_brace = false;    /* stop looking for start of
                    522:                                                 * stmt */
                    523:                    bp_save = buf_ptr;  /* save current input buffer */
                    524:                    be_save = buf_end;
                    525:                    buf_ptr = save_com; /* fix so that subsequent calls to
                    526:                                         * lexi will take tokens out of
                    527:                                         * save_com */
1.36      rillig    528:                    *sc_end++ = ' ';    /* add trailing blank, just in case */
1.25      kamil     529:                    buf_end = sc_end;
                    530:                    sc_end = NULL;
                    531:                    break;
                    532:                }
                    533:            }                   /* end of switch */
                    534:            /*
                    535:             * We must make this check, just in case there was an unexpected
                    536:             * EOF.
                    537:             */
1.30      rillig    538:            if (type_code != end_of_file) {
1.25      kamil     539:                /*
                    540:                 * The only intended purpose of calling lexi() below is to
                    541:                 * categorize the next token in order to decide whether to
                    542:                 * continue buffering forthcoming tokens. Once the buffering
                    543:                 * is over, lexi() will be called again elsewhere on all of
                    544:                 * the tokens - this time for normal processing.
                    545:                 *
                    546:                 * Calling it for this purpose is a bug, because lexi() also
                    547:                 * changes the parser state and discards leading whitespace,
                    548:                 * which is needed mostly for comment-related considerations.
                    549:                 *
                    550:                 * Work around the former problem by giving lexi() a copy of
                    551:                 * the current parser state and discard it if the call turned
                    552:                 * out to be just a look ahead.
                    553:                 *
                    554:                 * Work around the latter problem by copying all whitespace
                    555:                 * characters into the buffer so that the later lexi() call
                    556:                 * will read them.
                    557:                 */
                    558:                if (sc_end != NULL) {
                    559:                    while (*buf_ptr == ' ' || *buf_ptr == '\t') {
                    560:                        *sc_end++ = *buf_ptr++;
                    561:                        if (sc_end >= &save_com[sc_size]) {
                    562:                            errx(1, "input too long");
                    563:                        }
                    564:                    }
                    565:                    if (buf_ptr >= buf_end) {
                    566:                        fill_buffer();
                    567:                    }
                    568:                }
                    569:                transient_state = ps;
                    570:                type_code = lexi(&transient_state);     /* read another token */
                    571:                if (type_code != newline && type_code != form_feed &&
                    572:                    type_code != comment && !transient_state.search_brace) {
                    573:                    ps = transient_state;
                    574:                }
                    575:            }
                    576:        }                       /* end of while (search_brace) */
                    577:        last_else = 0;
                    578: check_type:
1.30      rillig    579:        if (type_code == end_of_file) { /* we got eof */
1.25      kamil     580:            if (s_lab != e_lab || s_code != e_code
                    581:                    || s_com != e_com)  /* must dump end of line */
                    582:                dump_line();
                    583:            if (ps.tos > 1)     /* check for balanced braces */
1.26      christos  584:                diag(1, "Stuff missing from end of file");
1.25      kamil     585:
                    586:            if (opt.verbose) {
                    587:                printf("There were %d output lines and %d comments\n",
                    588:                       ps.out_lines, ps.out_coms);
                    589:                printf("(Lines with comments)/(Lines with code): %6.3f\n",
                    590:                       (1.0 * ps.com_lines) / code_lines);
                    591:            }
                    592:            fflush(output);
                    593:            exit(found_err);
                    594:        }
                    595:        if (
                    596:                (type_code != comment) &&
                    597:                (type_code != newline) &&
                    598:                (type_code != preesc) &&
                    599:                (type_code != form_feed)) {
                    600:            if (force_nl &&
                    601:                    (type_code != semicolon) &&
                    602:                    (type_code != lbrace || !opt.btype_2)) {
                    603:                /* we should force a broken line here */
                    604:                if (opt.verbose)
1.26      christos  605:                    diag(0, "Line broken");
1.25      kamil     606:                dump_line();
                    607:                ps.want_blank = false;  /* dont insert blank at line start */
                    608:                force_nl = false;
                    609:            }
                    610:            ps.in_stmt = true;  /* turn on flag which causes an extra level of
                    611:                                 * indentation. this is turned off by a ; or
                    612:                                 * '}' */
                    613:            if (s_com != e_com) {       /* the turkey has embedded a comment
                    614:                                         * in a line. fix it */
                    615:                int len = e_com - s_com;
                    616:
1.34      rillig    617:                check_size_code(len + 3);
1.25      kamil     618:                *e_code++ = ' ';
                    619:                memcpy(e_code, s_com, len);
                    620:                e_code += len;
                    621:                *e_code++ = ' ';
                    622:                *e_code = '\0'; /* null terminate code sect */
                    623:                ps.want_blank = false;
                    624:                e_com = s_com;
                    625:            }
                    626:        }
                    627:        else if (type_code != comment)  /* preserve force_nl thru a comment */
                    628:            force_nl = false;   /* cancel forced newline after newline, form
                    629:                                 * feed, etc */
1.1       cgd       630:
                    631:
                    632:
1.25      kamil     633:        /*-----------------------------------------------------*\
                    634:        |          do switch on type of token scanned           |
                    635:        \*-----------------------------------------------------*/
1.34      rillig    636:        check_size_code(3);     /* maximum number of increments of e_code
                    637:                                 * before the next check_size_code or
1.25      kamil     638:                                 * dump_line() is 2. After that there's the
                    639:                                 * final increment for the null character. */
                    640:        switch (type_code) {    /* now, decide what to do with the token */
                    641:
1.36      rillig    642:        case form_feed:         /* found a form feed in line */
1.25      kamil     643:            ps.use_ff = true;   /* a form feed is treated much like a newline */
                    644:            dump_line();
                    645:            ps.want_blank = false;
                    646:            break;
                    647:
                    648:        case newline:
                    649:            if (ps.last_token != comma || ps.p_l_follow > 0
                    650:                    || !opt.leave_comma || ps.block_init || !break_comma || s_com != e_com) {
                    651:                dump_line();
                    652:                ps.want_blank = false;
                    653:            }
                    654:            ++line_no;          /* keep track of input line number */
                    655:            break;
                    656:
                    657:        case lparen:            /* got a '(' or '[' */
                    658:            /* count parens to make Healy happy */
                    659:            if (++ps.p_l_follow == nitems(ps.paren_indents)) {
1.26      christos  660:                diag(0, "Reached internal limit of %zu unclosed parens",
1.25      kamil     661:                    nitems(ps.paren_indents));
                    662:                ps.p_l_follow--;
                    663:            }
                    664:            if (*token == '[')
                    665:                /* not a function pointer declaration or a function call */;
                    666:            else if (ps.in_decl && !ps.block_init && !ps.dumped_decl_indent &&
                    667:                ps.procname[0] == '\0' && ps.paren_level == 0) {
                    668:                /* function pointer declarations */
                    669:                indent_declaration(dec_ind, tabs_to_var);
                    670:                ps.dumped_decl_indent = true;
                    671:            }
                    672:            else if (ps.want_blank &&
                    673:                    ((ps.last_token != ident && ps.last_token != funcname) ||
                    674:                    opt.proc_calls_space ||
1.31      rillig    675:                    (ps.keyword == rw_sizeof ? opt.Bill_Shannon :
                    676:                    ps.keyword != rw_0 && ps.keyword != rw_offsetof)))
1.25      kamil     677:                *e_code++ = ' ';
                    678:            ps.want_blank = false;
                    679:            *e_code++ = token[0];
                    680:            ps.paren_indents[ps.p_l_follow - 1] = count_spaces_until(1, s_code, e_code) - 1;
                    681:            if (sp_sw && ps.p_l_follow == 1 && opt.extra_expression_indent
                    682:                    && ps.paren_indents[0] < 2 * opt.ind_size)
                    683:                ps.paren_indents[0] = 2 * opt.ind_size;
                    684:            if (ps.in_or_st && *token == '(' && ps.tos <= 2) {
                    685:                /*
                    686:                 * this is a kluge to make sure that declarations will be
                    687:                 * aligned right if proc decl has an explicit type on it, i.e.
                    688:                 * "int a(x) {..."
                    689:                 */
                    690:                parse(semicolon);       /* I said this was a kluge... */
                    691:                ps.in_or_st = false;    /* turn off flag for structure decl or
                    692:                                         * initialization */
                    693:            }
                    694:            /* parenthesized type following sizeof or offsetof is not a cast */
1.31      rillig    695:            if (ps.keyword == rw_offsetof || ps.keyword == rw_sizeof)
1.25      kamil     696:                ps.not_cast_mask |= 1 << ps.p_l_follow;
                    697:            break;
                    698:
                    699:        case rparen:            /* got a ')' or ']' */
                    700:            if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.not_cast_mask) {
                    701:                ps.last_u_d = true;
                    702:                ps.cast_mask &= (1 << ps.p_l_follow) - 1;
                    703:                ps.want_blank = opt.space_after_cast;
                    704:            } else
                    705:                ps.want_blank = true;
                    706:            ps.not_cast_mask &= (1 << ps.p_l_follow) - 1;
                    707:            if (--ps.p_l_follow < 0) {
                    708:                ps.p_l_follow = 0;
1.26      christos  709:                diag(0, "Extra %c", *token);
1.25      kamil     710:            }
                    711:            if (e_code == s_code)       /* if the paren starts the line */
                    712:                ps.paren_level = ps.p_l_follow; /* then indent it */
                    713:
                    714:            *e_code++ = token[0];
                    715:
                    716:            if (sp_sw && (ps.p_l_follow == 0)) {        /* check for end of if
                    717:                                                         * (...), or some such */
                    718:                sp_sw = false;
1.36      rillig    719:                force_nl = true;        /* must force newline after if */
1.25      kamil     720:                ps.last_u_d = true;     /* inform lexi that a following
                    721:                                         * operator is unary */
                    722:                ps.in_stmt = false;     /* dont use stmt continuation
                    723:                                         * indentation */
                    724:
                    725:                parse(hd_type); /* let parser worry about if, or whatever */
                    726:            }
                    727:            ps.search_brace = opt.btype_2; /* this should ensure that
                    728:                                         * constructs such as main(){...}
                    729:                                         * and int[]{...} have their braces
                    730:                                         * put in the right place */
                    731:            break;
                    732:
                    733:        case unary_op:          /* this could be any unary operation */
                    734:            if (!ps.dumped_decl_indent && ps.in_decl && !ps.block_init &&
                    735:                ps.procname[0] == '\0' && ps.paren_level == 0) {
                    736:                /* pointer declarations */
1.6       lukem     737:
1.25      kamil     738:                /*
                    739:                 * if this is a unary op in a declaration, we should indent
                    740:                 * this token
                    741:                 */
                    742:                for (i = 0; token[i]; ++i)
                    743:                    /* find length of token */;
                    744:                indent_declaration(dec_ind - i, tabs_to_var);
                    745:                ps.dumped_decl_indent = true;
                    746:            }
                    747:            else if (ps.want_blank)
                    748:                *e_code++ = ' ';
                    749:
                    750:            {
                    751:                int len = e_token - s_token;
                    752:
1.34      rillig    753:                check_size_code(len);
1.25      kamil     754:                memcpy(e_code, token, len);
                    755:                e_code += len;
                    756:            }
                    757:            ps.want_blank = false;
                    758:            break;
                    759:
1.36      rillig    760:        case binary_op:         /* any binary operation */
1.25      kamil     761:            {
                    762:                int len = e_token - s_token;
                    763:
1.34      rillig    764:                check_size_code(len + 1);
1.25      kamil     765:                if (ps.want_blank)
                    766:                    *e_code++ = ' ';
                    767:                memcpy(e_code, token, len);
                    768:                e_code += len;
                    769:            }
                    770:            ps.want_blank = true;
                    771:            break;
                    772:
                    773:        case postop:            /* got a trailing ++ or -- */
                    774:            *e_code++ = token[0];
                    775:            *e_code++ = token[1];
                    776:            ps.want_blank = true;
                    777:            break;
                    778:
                    779:        case question:          /* got a ? */
                    780:            squest++;           /* this will be used when a later colon
                    781:                                 * appears so we can distinguish the
                    782:                                 * <c>?<n>:<n> construct */
                    783:            if (ps.want_blank)
                    784:                *e_code++ = ' ';
                    785:            *e_code++ = '?';
                    786:            ps.want_blank = true;
                    787:            break;
                    788:
                    789:        case casestmt:          /* got word 'case' or 'default' */
                    790:            scase = true;       /* so we can process the later colon properly */
                    791:            goto copy_id;
                    792:
                    793:        case colon:             /* got a ':' */
                    794:            if (squest > 0) {   /* it is part of the <c>?<n>: <n> construct */
                    795:                --squest;
                    796:                if (ps.want_blank)
                    797:                    *e_code++ = ' ';
                    798:                *e_code++ = ':';
                    799:                ps.want_blank = true;
                    800:                break;
                    801:            }
                    802:            if (ps.in_or_st) {
                    803:                *e_code++ = ':';
                    804:                ps.want_blank = false;
                    805:                break;
                    806:            }
                    807:            ps.in_stmt = false; /* seeing a label does not imply we are in a
                    808:                                 * stmt */
                    809:            /*
                    810:             * turn everything so far into a label
                    811:             */
                    812:            {
                    813:                int len = e_code - s_code;
                    814:
1.34      rillig    815:                check_size_label(len + 3);
1.25      kamil     816:                memcpy(e_lab, s_code, len);
                    817:                e_lab += len;
                    818:                *e_lab++ = ':';
                    819:                *e_lab = '\0';
                    820:                e_code = s_code;
                    821:            }
                    822:            force_nl = ps.pcase = scase;        /* ps.pcase will be used by
                    823:                                                 * dump_line to decide how to
                    824:                                                 * indent the label. force_nl
                    825:                                                 * will force a case n: to be
                    826:                                                 * on a line by itself */
                    827:            scase = false;
                    828:            ps.want_blank = false;
                    829:            break;
                    830:
                    831:        case semicolon: /* got a ';' */
                    832:            if (ps.dec_nest == 0)
1.36      rillig    833:                ps.in_or_st = false;    /* we are not in an initialization or
                    834:                                         * structure declaration */
1.25      kamil     835:            scase = false;      /* these will only need resetting in an error */
                    836:            squest = 0;
                    837:            if (ps.last_token == rparen)
                    838:                ps.in_parameter_declaration = 0;
                    839:            ps.cast_mask = 0;
                    840:            ps.not_cast_mask = 0;
                    841:            ps.block_init = 0;
                    842:            ps.block_init_level = 0;
                    843:            ps.just_saw_decl--;
                    844:
                    845:            if (ps.in_decl && s_code == e_code && !ps.block_init &&
                    846:                !ps.dumped_decl_indent && ps.paren_level == 0) {
                    847:                /* indent stray semicolons in declarations */
                    848:                indent_declaration(dec_ind - 1, tabs_to_var);
                    849:                ps.dumped_decl_indent = true;
                    850:            }
                    851:
                    852:            ps.in_decl = (ps.dec_nest > 0);     /* if we were in a first level
                    853:                                                 * structure declaration, we
                    854:                                                 * arent any more */
1.1       cgd       855:
1.25      kamil     856:            if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
1.6       lukem     857:
1.25      kamil     858:                /*
                    859:                 * This should be true iff there were unbalanced parens in the
                    860:                 * stmt.  It is a bit complicated, because the semicolon might
                    861:                 * be in a for stmt
                    862:                 */
1.26      christos  863:                diag(1, "Unbalanced parens");
1.25      kamil     864:                ps.p_l_follow = 0;
                    865:                if (sp_sw) {    /* this is a check for an if, while, etc. with
                    866:                                 * unbalanced parens */
                    867:                    sp_sw = false;
                    868:                    parse(hd_type);     /* dont lose the if, or whatever */
                    869:                }
                    870:            }
                    871:            *e_code++ = ';';
                    872:            ps.want_blank = true;
                    873:            ps.in_stmt = (ps.p_l_follow > 0);   /* we are no longer in the
                    874:                                                 * middle of a stmt */
                    875:
                    876:            if (!sp_sw) {       /* if not if for (;;) */
                    877:                parse(semicolon);       /* let parser know about end of stmt */
                    878:                force_nl = true;/* force newline after an end of stmt */
                    879:            }
                    880:            break;
                    881:
                    882:        case lbrace:            /* got a '{' */
                    883:            ps.in_stmt = false; /* dont indent the {} */
                    884:            if (!ps.block_init)
                    885:                force_nl = true;/* force other stuff on same line as '{' onto
                    886:                                 * new line */
                    887:            else if (ps.block_init_level <= 0)
                    888:                ps.block_init_level = 1;
                    889:            else
                    890:                ps.block_init_level++;
                    891:
                    892:            if (s_code != e_code && !ps.block_init) {
                    893:                if (!opt.btype_2) {
                    894:                    dump_line();
                    895:                    ps.want_blank = false;
                    896:                }
                    897:                else if (ps.in_parameter_declaration && !ps.in_or_st) {
                    898:                    ps.i_l_follow = 0;
                    899:                    if (opt.function_brace_split) { /* dump the line prior
                    900:                                 * to the brace ... */
                    901:                        dump_line();
1.6       lukem     902:                        ps.want_blank = false;
1.25      kamil     903:                    } else      /* add a space between the decl and brace */
1.6       lukem     904:                        ps.want_blank = true;
1.25      kamil     905:                }
                    906:            }
                    907:            if (ps.in_parameter_declaration)
                    908:                prefix_blankline_requested = 0;
                    909:
                    910:            if (ps.p_l_follow > 0) {    /* check for preceding unbalanced
                    911:                                         * parens */
1.26      christos  912:                diag(1, "Unbalanced parens");
1.25      kamil     913:                ps.p_l_follow = 0;
                    914:                if (sp_sw) {    /* check for unclosed if, for, etc. */
                    915:                    sp_sw = false;
                    916:                    parse(hd_type);
                    917:                    ps.ind_level = ps.i_l_follow;
                    918:                }
                    919:            }
                    920:            if (s_code == e_code)
                    921:                ps.ind_stmt = false;    /* dont put extra indentation on line
                    922:                                         * with '{' */
                    923:            if (ps.in_decl && ps.in_or_st) {    /* this is either a structure
                    924:                                                 * declaration or an init */
                    925:                di_stack[ps.dec_nest] = dec_ind;
                    926:                if (++ps.dec_nest == nitems(di_stack)) {
1.26      christos  927:                    diag(0, "Reached internal limit of %zu struct levels",
1.25      kamil     928:                        nitems(di_stack));
                    929:                    ps.dec_nest--;
                    930:                }
                    931:                /* ?            dec_ind = 0; */
                    932:            }
                    933:            else {
                    934:                ps.decl_on_line = false;        /* we can't be in the middle of
                    935:                                                 * a declaration, so don't do
                    936:                                                 * special indentation of
                    937:                                                 * comments */
                    938:                if (opt.blanklines_after_declarations_at_proctop
                    939:                        && ps.in_parameter_declaration)
                    940:                    postfix_blankline_requested = 1;
                    941:                ps.in_parameter_declaration = 0;
                    942:                ps.in_decl = false;
                    943:            }
                    944:            dec_ind = 0;
                    945:            parse(lbrace);      /* let parser know about this */
                    946:            if (ps.want_blank)  /* put a blank before '{' if '{' is not at
                    947:                                 * start of line */
                    948:                *e_code++ = ' ';
                    949:            ps.want_blank = false;
                    950:            *e_code++ = '{';
                    951:            ps.just_saw_decl = 0;
                    952:            break;
                    953:
                    954:        case rbrace:            /* got a '}' */
                    955:            if (ps.p_stack[ps.tos] == decl && !ps.block_init)   /* semicolons can be
                    956:                                                                 * omitted in
                    957:                                                                 * declarations */
                    958:                parse(semicolon);
                    959:            if (ps.p_l_follow) {/* check for unclosed if, for, else. */
1.26      christos  960:                diag(1, "Unbalanced parens");
1.25      kamil     961:                ps.p_l_follow = 0;
                    962:                sp_sw = false;
                    963:            }
                    964:            ps.just_saw_decl = 0;
                    965:            ps.block_init_level--;
                    966:            if (s_code != e_code && !ps.block_init) {   /* '}' must be first on
                    967:                                                         * line */
                    968:                if (opt.verbose)
1.26      christos  969:                    diag(0, "Line broken");
1.25      kamil     970:                dump_line();
                    971:            }
                    972:            *e_code++ = '}';
                    973:            ps.want_blank = true;
                    974:            ps.in_stmt = ps.ind_stmt = false;
                    975:            if (ps.dec_nest > 0) {      /* we are in multi-level structure
                    976:                                         * declaration */
                    977:                dec_ind = di_stack[--ps.dec_nest];
                    978:                if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
                    979:                    ps.just_saw_decl = 2;
                    980:                ps.in_decl = true;
                    981:            }
                    982:            prefix_blankline_requested = 0;
                    983:            parse(rbrace);      /* let parser know about this */
                    984:            ps.search_brace = opt.cuddle_else && ps.p_stack[ps.tos] == ifhead
                    985:                && ps.il[ps.tos] >= ps.ind_level;
                    986:            if (ps.tos <= 1 && opt.blanklines_after_procs && ps.dec_nest <= 0)
                    987:                postfix_blankline_requested = 1;
                    988:            break;
                    989:
                    990:        case swstmt:            /* got keyword "switch" */
                    991:            sp_sw = true;
                    992:            hd_type = swstmt;   /* keep this for when we have seen the
                    993:                                 * expression */
                    994:            goto copy_id;       /* go move the token into buffer */
                    995:
1.37    ! rillig    996:        case keyword_for_if_while:
1.25      kamil     997:            sp_sw = true;       /* the interesting stuff is done after the
                    998:                                 * expression is scanned */
                    999:            hd_type = (*token == 'i' ? ifstmt :
                   1000:                       (*token == 'w' ? whilestmt : forstmt));
                   1001:
                   1002:            /*
                   1003:             * remember the type of header for later use by parser
                   1004:             */
                   1005:            goto copy_id;       /* copy the token into line */
                   1006:
1.37    ! rillig   1007:        case keyword_do_else:
1.25      kamil    1008:            ps.in_stmt = false;
                   1009:            if (*token == 'e') {
                   1010:                if (e_code != s_code && (!opt.cuddle_else || e_code[-1] != '}')) {
                   1011:                    if (opt.verbose)
1.26      christos 1012:                        diag(0, "Line broken");
1.25      kamil    1013:                    dump_line();/* make sure this starts a line */
                   1014:                    ps.want_blank = false;
                   1015:                }
                   1016:                force_nl = true;/* also, following stuff must go onto new line */
                   1017:                last_else = 1;
                   1018:                parse(elselit);
                   1019:            }
                   1020:            else {
                   1021:                if (e_code != s_code) { /* make sure this starts a line */
                   1022:                    if (opt.verbose)
1.26      christos 1023:                        diag(0, "Line broken");
1.25      kamil    1024:                    dump_line();
                   1025:                    ps.want_blank = false;
                   1026:                }
                   1027:                force_nl = true;/* also, following stuff must go onto new line */
                   1028:                last_else = 0;
                   1029:                parse(dolit);
                   1030:            }
                   1031:            goto copy_id;       /* move the token into line */
                   1032:
                   1033:        case type_def:
                   1034:        case storage:
                   1035:            prefix_blankline_requested = 0;
                   1036:            goto copy_id;
                   1037:
                   1038:        case structure:
                   1039:            if (ps.p_l_follow > 0)
                   1040:                goto copy_id;
                   1041:            /* FALLTHROUGH */
                   1042:        case decl:              /* we have a declaration type (int, etc.) */
                   1043:            parse(decl);        /* let parser worry about indentation */
                   1044:            if (ps.last_token == rparen && ps.tos <= 1) {
                   1045:                if (s_code != e_code) {
                   1046:                    dump_line();
                   1047:                    ps.want_blank = 0;
                   1048:                }
                   1049:            }
                   1050:            if (ps.in_parameter_declaration && opt.indent_parameters && ps.dec_nest == 0) {
                   1051:                ps.ind_level = ps.i_l_follow = 1;
                   1052:                ps.ind_stmt = 0;
                   1053:            }
                   1054:            ps.in_or_st = true; /* this might be a structure or initialization
                   1055:                                 * declaration */
                   1056:            ps.in_decl = ps.decl_on_line = ps.last_token != type_def;
                   1057:            if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
                   1058:                ps.just_saw_decl = 2;
                   1059:            prefix_blankline_requested = 0;
                   1060:            for (i = 0; token[i++];);   /* get length of token */
                   1061:
                   1062:            if (ps.ind_level == 0 || ps.dec_nest > 0) {
                   1063:                /* global variable or struct member in local variable */
                   1064:                dec_ind = opt.decl_indent > 0 ? opt.decl_indent : i;
                   1065:                tabs_to_var = (opt.use_tabs ? opt.decl_indent > 0 : 0);
                   1066:            } else {
                   1067:                /* local variable */
                   1068:                dec_ind = opt.local_decl_indent > 0 ? opt.local_decl_indent : i;
                   1069:                tabs_to_var = (opt.use_tabs ? opt.local_decl_indent > 0 : 0);
                   1070:            }
                   1071:            goto copy_id;
                   1072:
                   1073:        case funcname:
                   1074:        case ident:             /* got an identifier or constant */
                   1075:            if (ps.in_decl) {
                   1076:                if (type_code == funcname) {
                   1077:                    ps.in_decl = false;
                   1078:                    if (opt.procnames_start_line && s_code != e_code) {
                   1079:                        *e_code = '\0';
                   1080:                        dump_line();
                   1081:                    }
                   1082:                    else if (ps.want_blank) {
                   1083:                        *e_code++ = ' ';
                   1084:                    }
                   1085:                    ps.want_blank = false;
                   1086:                }
                   1087:                else if (!ps.block_init && !ps.dumped_decl_indent &&
                   1088:                    ps.paren_level == 0) { /* if we are in a declaration, we
                   1089:                                            * must indent identifier */
                   1090:                    indent_declaration(dec_ind, tabs_to_var);
                   1091:                    ps.dumped_decl_indent = true;
                   1092:                    ps.want_blank = false;
                   1093:                }
                   1094:            }
                   1095:            else if (sp_sw && ps.p_l_follow == 0) {
                   1096:                sp_sw = false;
                   1097:                force_nl = true;
                   1098:                ps.last_u_d = true;
                   1099:                ps.in_stmt = false;
                   1100:                parse(hd_type);
                   1101:            }
                   1102:     copy_id:
                   1103:            {
                   1104:                int len = e_token - s_token;
                   1105:
1.34      rillig   1106:                check_size_code(len + 1);
1.25      kamil    1107:                if (ps.want_blank)
                   1108:                    *e_code++ = ' ';
                   1109:                memcpy(e_code, s_token, len);
                   1110:                e_code += len;
                   1111:            }
                   1112:            if (type_code != funcname)
                   1113:                ps.want_blank = true;
                   1114:            break;
                   1115:
                   1116:        case strpfx:
                   1117:            {
                   1118:                int len = e_token - s_token;
                   1119:
1.34      rillig   1120:                check_size_code(len + 1);
1.25      kamil    1121:                if (ps.want_blank)
                   1122:                    *e_code++ = ' ';
                   1123:                memcpy(e_code, token, len);
                   1124:                e_code += len;
                   1125:            }
                   1126:            ps.want_blank = false;
                   1127:            break;
1.1       cgd      1128:
1.25      kamil    1129:        case period:            /* treat a period kind of like a binary
                   1130:                                 * operation */
                   1131:            *e_code++ = '.';    /* move the period into line */
                   1132:            ps.want_blank = false;      /* dont put a blank after a period */
                   1133:            break;
                   1134:
                   1135:        case comma:
                   1136:            ps.want_blank = (s_code != e_code); /* only put blank after comma
                   1137:                                                 * if comma does not start the
                   1138:                                                 * line */
                   1139:            if (ps.in_decl && ps.procname[0] == '\0' && !ps.block_init &&
                   1140:                !ps.dumped_decl_indent && ps.paren_level == 0) {
                   1141:                /* indent leading commas and not the actual identifiers */
                   1142:                indent_declaration(dec_ind - 1, tabs_to_var);
                   1143:                ps.dumped_decl_indent = true;
                   1144:            }
                   1145:            *e_code++ = ',';
                   1146:            if (ps.p_l_follow == 0) {
                   1147:                if (ps.block_init_level <= 0)
                   1148:                    ps.block_init = 0;
                   1149:                if (break_comma && (!opt.leave_comma ||
                   1150:                    count_spaces_until(compute_code_target(), s_code, e_code) >
                   1151:                    opt.max_col - opt.tabsize))
                   1152:                    force_nl = true;
                   1153:            }
                   1154:            break;
                   1155:
                   1156:        case preesc:            /* got the character '#' */
                   1157:            if ((s_com != e_com) ||
                   1158:                    (s_lab != e_lab) ||
                   1159:                    (s_code != e_code))
                   1160:                dump_line();
1.34      rillig   1161:            check_size_label(1);
1.25      kamil    1162:            *e_lab++ = '#';     /* move whole line to 'label' buffer */
                   1163:            {
                   1164:                int         in_comment = 0;
                   1165:                int         com_start = 0;
                   1166:                char        quote = 0;
                   1167:                int         com_end = 0;
                   1168:
                   1169:                while (*buf_ptr == ' ' || *buf_ptr == '\t') {
                   1170:                    buf_ptr++;
                   1171:                    if (buf_ptr >= buf_end)
                   1172:                        fill_buffer();
                   1173:                }
                   1174:                while (*buf_ptr != '\n' || (in_comment && !had_eof)) {
1.34      rillig   1175:                    check_size_label(2);
1.25      kamil    1176:                    *e_lab = *buf_ptr++;
                   1177:                    if (buf_ptr >= buf_end)
                   1178:                        fill_buffer();
                   1179:                    switch (*e_lab++) {
1.35      rillig   1180:                    case '\\':
1.25      kamil    1181:                        if (!in_comment) {
                   1182:                            *e_lab++ = *buf_ptr++;
                   1183:                            if (buf_ptr >= buf_end)
                   1184:                                fill_buffer();
1.6       lukem    1185:                        }
                   1186:                        break;
1.25      kamil    1187:                    case '/':
                   1188:                        if (*buf_ptr == '*' && !in_comment && !quote) {
                   1189:                            in_comment = 1;
                   1190:                            *e_lab++ = *buf_ptr++;
                   1191:                            com_start = e_lab - s_lab - 2;
1.1       cgd      1192:                        }
1.6       lukem    1193:                        break;
1.25      kamil    1194:                    case '"':
                   1195:                        if (quote == '"')
                   1196:                            quote = 0;
1.6       lukem    1197:                        break;
1.25      kamil    1198:                    case '\'':
                   1199:                        if (quote == '\'')
                   1200:                            quote = 0;
1.6       lukem    1201:                        break;
1.25      kamil    1202:                    case '*':
                   1203:                        if (*buf_ptr == '/' && in_comment) {
                   1204:                            in_comment = 0;
                   1205:                            *e_lab++ = *buf_ptr++;
                   1206:                            com_end = e_lab - s_lab;
1.6       lukem    1207:                        }
1.1       cgd      1208:                        break;
1.25      kamil    1209:                    }
                   1210:                }
1.6       lukem    1211:
1.25      kamil    1212:                while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
                   1213:                    e_lab--;
                   1214:                if (e_lab - s_lab == com_end && bp_save == NULL) {
                   1215:                    /* comment on preprocessor line */
                   1216:                    if (sc_end == NULL) {       /* if this is the first comment,
                   1217:                                                 * we must set up the buffer */
                   1218:                        save_com = sc_buf;
                   1219:                        sc_end = &save_com[0];
                   1220:                    }
                   1221:                    else {
                   1222:                        *sc_end++ = '\n';       /* add newline between
                   1223:                                                 * comments */
                   1224:                        *sc_end++ = ' ';
                   1225:                        --line_no;
                   1226:                    }
                   1227:                    if (sc_end - save_com + com_end - com_start > sc_size)
                   1228:                        errx(1, "input too long");
                   1229:                    memmove(sc_end, s_lab + com_start, com_end - com_start);
                   1230:                    sc_end += com_end - com_start;
                   1231:                    e_lab = s_lab + com_start;
                   1232:                    while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
                   1233:                        e_lab--;
                   1234:                    bp_save = buf_ptr;  /* save current input buffer */
                   1235:                    be_save = buf_end;
                   1236:                    buf_ptr = save_com; /* fix so that subsequent calls to
                   1237:                                         * lexi will take tokens out of
                   1238:                                         * save_com */
                   1239:                    *sc_end++ = ' ';    /* add trailing blank, just in case */
                   1240:                    buf_end = sc_end;
                   1241:                    sc_end = NULL;
                   1242:                }
1.34      rillig   1243:                check_size_label(1);
1.25      kamil    1244:                *e_lab = '\0';  /* null terminate line */
                   1245:                ps.pcase = false;
                   1246:            }
                   1247:
                   1248:            if (strncmp(s_lab, "#if", 3) == 0) { /* also ifdef, ifndef */
                   1249:                if ((size_t)ifdef_level < nitems(state_stack)) {
                   1250:                    match_state[ifdef_level].tos = -1;
                   1251:                    state_stack[ifdef_level++] = ps;
                   1252:                }
                   1253:                else
1.26      christos 1254:                    diag(1, "#if stack overflow");
1.25      kamil    1255:            }
                   1256:            else if (strncmp(s_lab, "#el", 3) == 0) { /* else, elif */
                   1257:                if (ifdef_level <= 0)
1.26      christos 1258:                    diag(1, s_lab[3] == 'i' ? "Unmatched #elif" : "Unmatched #else");
1.25      kamil    1259:                else {
                   1260:                    match_state[ifdef_level - 1] = ps;
                   1261:                    ps = state_stack[ifdef_level - 1];
                   1262:                }
                   1263:            }
                   1264:            else if (strncmp(s_lab, "#endif", 6) == 0) {
                   1265:                if (ifdef_level <= 0)
1.26      christos 1266:                    diag(1, "Unmatched #endif");
1.25      kamil    1267:                else
                   1268:                    ifdef_level--;
                   1269:            } else {
1.32      rillig   1270:                static const struct directives {
1.25      kamil    1271:                    int size;
                   1272:                    const char *string;
1.32      rillig   1273:                } recognized[] = {
1.25      kamil    1274:                    {7, "include"},
                   1275:                    {6, "define"},
                   1276:                    {5, "undef"},
                   1277:                    {4, "line"},
                   1278:                    {5, "error"},
                   1279:                    {6, "pragma"}
                   1280:                };
                   1281:                int d = nitems(recognized);
                   1282:                while (--d >= 0)
                   1283:                    if (strncmp(s_lab + 1, recognized[d].string, recognized[d].size) == 0)
1.1       cgd      1284:                        break;
1.25      kamil    1285:                if (d < 0) {
1.26      christos 1286:                    diag(1, "Unrecognized cpp directive");
1.25      kamil    1287:                    break;
                   1288:                }
                   1289:            }
                   1290:            if (opt.blanklines_around_conditional_compilation) {
                   1291:                postfix_blankline_requested++;
                   1292:                n_real_blanklines = 0;
                   1293:            }
                   1294:            else {
                   1295:                postfix_blankline_requested = 0;
                   1296:                prefix_blankline_requested = 0;
                   1297:            }
                   1298:            break;              /* subsequent processing of the newline
1.1       cgd      1299:                                 * character will cause the line to be printed */
                   1300:
1.25      kamil    1301:        case comment:           /* we have gotten a / followed by * this is a biggie */
                   1302:            pr_comment();
                   1303:            break;
1.30      rillig   1304:
                   1305:        default:
                   1306:            break;
1.25      kamil    1307:        }                       /* end of big switch stmt */
                   1308:
                   1309:        *e_code = '\0';         /* make sure code section is null terminated */
                   1310:        if (type_code != comment && type_code != newline && type_code != preesc)
                   1311:            ps.last_token = type_code;
                   1312:     }                          /* end of main while (1) loop */
                   1313: }
1.6       lukem    1314:
1.1       cgd      1315: /*
                   1316:  * copy input file to backup file if in_name is /blah/blah/blah/file, then
                   1317:  * backup file will be ".Bfile" then make the backup file the input and
                   1318:  * original input file the output
                   1319:  */
1.25      kamil    1320: static void
1.13      wiz      1321: bakcopy(void)
1.1       cgd      1322: {
1.25      kamil    1323:     int         n,
                   1324:                 bakchn;
                   1325:     char        buff[8 * 1024];
                   1326:     const char *p;
                   1327:
                   1328:     /* construct file name .Bfile */
                   1329:     for (p = in_name; *p; p++);        /* skip to end of string */
                   1330:     while (p > in_name && *p != '/')   /* find last '/' */
                   1331:        p--;
                   1332:     if (*p == '/')
                   1333:        p++;
                   1334:     sprintf(bakfile, "%s%s", p, simple_backup_suffix);
                   1335:
                   1336:     /* copy in_name to backup file */
                   1337:     bakchn = creat(bakfile, 0600);
                   1338:     if (bakchn < 0)
                   1339:        err(1, "%s", bakfile);
                   1340:     while ((n = read(fileno(input), buff, sizeof(buff))) > 0)
                   1341:        if (write(bakchn, buff, n) != n)
                   1342:            err(1, "%s", bakfile);
                   1343:     if (n < 0)
                   1344:        err(1, "%s", in_name);
                   1345:     close(bakchn);
                   1346:     fclose(input);
                   1347:
                   1348:     /* re-open backup file as the input file */
                   1349:     input = fopen(bakfile, "r");
                   1350:     if (input == NULL)
                   1351:        err(1, "%s", bakfile);
                   1352:     /* now the original input file will be the output */
                   1353:     output = fopen(in_name, "w");
                   1354:     if (output == NULL) {
                   1355:        unlink(bakfile);
                   1356:        err(1, "%s", in_name);
                   1357:     }
                   1358: }
                   1359:
                   1360: static void
                   1361: indent_declaration(int cur_dec_ind, int tabs_to_var)
                   1362: {
                   1363:     int pos = e_code - s_code;
                   1364:     char *startpos = e_code;
                   1365:
                   1366:     /*
                   1367:      * get the tab math right for indentations that are not multiples of tabsize
                   1368:      */
                   1369:     if ((ps.ind_level * opt.ind_size) % opt.tabsize != 0) {
                   1370:        pos += (ps.ind_level * opt.ind_size) % opt.tabsize;
                   1371:        cur_dec_ind += (ps.ind_level * opt.ind_size) % opt.tabsize;
                   1372:     }
                   1373:     if (tabs_to_var) {
                   1374:        int tpos;
                   1375:
1.34      rillig   1376:        check_size_code(cur_dec_ind / opt.tabsize);
1.25      kamil    1377:        while ((tpos = opt.tabsize * (1 + pos / opt.tabsize)) <= cur_dec_ind) {
                   1378:            *e_code++ = '\t';
                   1379:            pos = tpos;
1.6       lukem    1380:        }
1.25      kamil    1381:     }
1.34      rillig   1382:     check_size_code(cur_dec_ind - pos + 1);
1.25      kamil    1383:     while (pos < cur_dec_ind) {
                   1384:        *e_code++ = ' ';
                   1385:        pos++;
                   1386:     }
                   1387:     if (e_code == startpos && ps.want_blank) {
                   1388:        *e_code++ = ' ';
                   1389:        ps.want_blank = false;
                   1390:     }
1.1       cgd      1391: }

CVSweb <webmaster@jp.NetBSD.org>