home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / INDENTSR.ZIP / INDENT.C < prev    next >
C/C++ Source or Header  |  1992-08-27  |  42KB  |  1,394 lines

  1. /*
  2.  * Copyright 1989 Object Design, Inc.
  3.  * Copyright (c) 1985 Sun Microsystems, Inc.
  4.  * Copyright (c) 1980 The Regents of the University of California.
  5.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms are permitted
  9.  * provided that the above copyright notice and this paragraph are
  10.  * duplicated in all such forms and that any documentation,
  11.  * advertising materials, and other materials related to such
  12.  * distribution and use acknowledge that the software was developed
  13.  * by the University of California, Berkeley, the University of Illinois,
  14.  * Urbana, and Sun Microsystems, Inc.  The name of either University
  15.  * or Sun Microsystems may not be used to endorse or promote products
  16.  * derived from this software without specific prior written permission.
  17.  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  19.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21.  
  22. #ifndef lint
  23. char copyright[] =
  24. "@(#) Copyright 1989 Object Design, Inc.\n\
  25.  @(#) Copyright (c) 1985 Sun Microsystems, Inc.\n\
  26.  @(#) Copyright (c) 1980 The Regents of the University of California.\n\
  27.  @(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\
  28.  All rights reserved.\n";
  29.  
  30. #endif                    /* not lint */
  31.  
  32. #ifndef lint
  33. static char sccsid[] = "@(#)indent.c    5.11 (Berkeley) 88/09/15";
  34.  
  35. #endif                    /* not lint */
  36.  
  37. #include "globals.h"
  38. #include "codes.h"
  39.  
  40. #ifdef MSDOS                /* or OS/2 */
  41. #include <malloc.h>
  42. #include <stdlib.h>
  43. #include <process.h>
  44. #include <string.h>
  45. #include <io.h>
  46. #define R_OK 4
  47. #define INCL_NOPM
  48. #define INCL_BASE
  49. #define INCL_DOSFILEMGR
  50. #include <os2.h>
  51. #else                    /* not MSDOS or OS/2 */
  52. #include <sys/param.h>
  53. #include <unistd.h>
  54. #endif                    /* BSD */
  55.  
  56. #include <ctype.h>
  57.  
  58. char *in_name = "Standard Input";    /* will always point to name of input
  59.                      * file */
  60. char *out_name = "Standard Output";    /* will always point to name of
  61.                      * output file */
  62. char bakfile[MAXPATHLEN] = "";
  63.  
  64. #ifdef ANSIC
  65. static void bakcopy(void);
  66.  
  67. #endif
  68.  
  69. #ifdef ANSIC
  70. void 
  71. main(int argc, char **argv)
  72. #else
  73. main(argc, argv)
  74.     int argc;
  75.     char **argv;
  76.  
  77. #endif
  78. {
  79.  
  80.     extern int found_err;        /* flag set in diag() on error */
  81.     int dec_ind;            /* current indentation for
  82.                      * declarations */
  83.     int di_stack[20];            /* a stack of structure indentation
  84.                      * levels */
  85.     int flushed_nl;            /* used when buffering up comments to
  86.                      * remember that a newline was passed
  87.                      * over */
  88.     int force_nl;            /* when true, code must be broken */
  89.     int hd_type;            /* used to store type of stmt for if
  90.                      * (...), for (...), etc */
  91.     register int i;            /* local loop counter */
  92.     int scase;                /* set to true when we see a case, so
  93.                      * we will know what to do with the
  94.                      * following colon */
  95.     int sp_sw;                /* when true, we are in the expressin
  96.                      * of if(...), while(...), etc. */
  97.     int squest;                /* when this is positive, we have
  98.                      * seen a ? without the matching : in
  99.                      * a <c>?<s>:<s> construct */
  100.     register char *t_ptr;        /* used for copying tokens */
  101.     int type_code;            /* the type of token, returned by
  102.                      * lexi */
  103.  
  104.     int last_else = 0;            /* true iff last keyword was an else */
  105.     int ch;                /* answer to Y/N prompt */
  106.  
  107.     /*-----------------------------------------------*\
  108.     |          INITIALIZATION              |
  109.     \*-----------------------------------------------*/
  110.  
  111.  
  112.     ps.p_stack[0] = stmt;        /* this is the parser's stack */
  113.     ps.last_nl = true;            /* this is true if the last thing
  114.                      * scanned was a newline */
  115.     ps.last_token = semicolon;
  116.     combuf = (char *) malloc(bufsize);
  117.     labbuf = (char *) malloc(bufsize);
  118.     codebuf = (char *) malloc(bufsize);
  119.     l_com = combuf + bufsize - 5;
  120.     l_lab = labbuf + bufsize - 5;
  121.     l_code = codebuf + bufsize - 5;
  122.     combuf[0] = codebuf[0] = labbuf[0] = ' ';    /* set up code, label, and
  123.                          * comment buffers */
  124.     combuf[1] = codebuf[1] = labbuf[1] = '\0';
  125.     ps.else_if = 1;            /* Default else-if special processing
  126.                      * to on */
  127.     s_lab = e_lab = labbuf + 1;
  128.     s_code = e_code = codebuf + 1;
  129.     s_com = e_com = combuf + 1;
  130.  
  131.     buf_ptr = buf_end = in_buffer;
  132.     line_no = 1;
  133.     had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
  134.     sp_sw = force_nl = false;
  135.     ps.in_or_st = false;
  136.     ps.bl_line = true;
  137.     dec_ind = 0;
  138.     di_stack[ps.dec_nest = 0] = 0;
  139.     ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
  140.     ps.cc_comment = 0;
  141.  
  142.  
  143.     scase = ps.pcase = false;
  144.     squest = 0;
  145.     sc_end = 0;
  146.     bp_save = 0;
  147.     be_save = 0;
  148.  
  149.     output = NULL;
  150.  
  151.  
  152.  
  153.     /*--------------------------------------------------*\
  154.     |        COMMAND LINE SCAN             |
  155.     \*--------------------------------------------------*/
  156.  
  157. #ifdef undef
  158.     max_col = 78;            /* -l78 */
  159.     lineup_to_parens = 1;        /* -lp */
  160.     ps.ljust_decl = 0;            /* -ndj */
  161.     ps.com_ind = 33;            /* -c33 */
  162.     star_comment_cont = 1;        /* -sc */
  163.     ps.ind_size = 8;            /* -i8 */
  164.     verbose = 0;
  165.     ps.decl_indent = 16;        /* -di16 */
  166.     ps.indent_parameters = 1;        /* -ip */
  167.     ps.decl_com_ind = 0;        /* if this is not set to some
  168.                      * positive value by an arg, we will
  169.                      * set this equal to ps.com_ind */
  170.     btype_2 = 1;            /* -br */
  171.     btype_3 = 0;            /* not -brr */
  172.     cuddle_else = 1;            /* -ce */
  173.     ps.unindent_displace = 0;        /* -d0 */
  174.     ps.case_indent = 0;            /* -cli0 */
  175.     ps.case_code_indent = 1;        /* -cci1 */
  176.     format_col1_comments = 1;        /* -fc1 */
  177.     procnames_start_line = 1;        /* -psl */
  178.     proc_calls_space = 0;        /* -npcs */
  179.     parens_space = 0;            /* -nprs */
  180.     comment_delimiter_on_blankline = 1;    /* -cdb */
  181.     ps.leave_comma = 1;            /* -nbc */
  182. #endif
  183.  
  184.     for (i = 1; i < argc; ++i)
  185.     if (strcmp(argv[i], "-npro") == 0)
  186.         break;
  187.     set_defaults();
  188.     if (i >= argc)
  189.     set_profile();
  190.  
  191.     for (i = 1; i < argc; ++i) {
  192.  
  193.     /*
  194.      * look thru args (if any) for changes to defaults
  195.      */
  196.     if (argv[i][0] != '-') {    /* no flag on parameter */
  197.         if (input == NULL) {    /* we must have the input file */
  198.         in_name = argv[i];    /* remember name of input file */
  199.         input = fopen(in_name, "r");
  200.         if (input == NULL) {    /* check for open error */
  201.             fprintf(stderr, "indent: can't open %s\n", argv[i]);
  202.             exit(1);
  203.         }
  204.         continue;
  205.         } else if (output == NULL) {/* we have the output file */
  206.         out_name = argv[i];    /* remember name of output file */
  207.         if (strcmp(in_name, out_name) == 0) {    /* attempt to overwrite
  208.                              * the file */
  209.             fprintf(stderr, "indent: input and output files must be different\n");
  210.             exit(1);
  211.         }
  212.         if (access(out_name, R_OK) == 0) {
  213.             fprintf(stderr, "Reformatting input file %s to produce output file %s\n",
  214.             in_name, out_name);
  215.             fprintf(stderr, "Output file %s exists; overwrite it? ", out_name);
  216.             fflush(stderr);
  217.             if ((ch = getchar()) != 'y' && ch != 'Y') {
  218.             fprintf(stderr, "indent: can't create %s\n", argv[i]);
  219.             exit(1);
  220.             }
  221.         }
  222.         output = fopen(out_name, "w");
  223.         if (output == NULL) {    /* check for create error */
  224.             fprintf(stderr, "indent: can't create %s\n", argv[i]);
  225.             exit(1);
  226.         }
  227.         continue;
  228.         }
  229.         fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
  230.         exit(1);
  231.     } else
  232.         set_option(argv[i]);
  233.     }                    /* end of for */
  234.     if (input == NULL) {
  235.     fprintf(stderr, "indent: usage: indent file [ outfile ] [ options ]\n");
  236.     exit(1);
  237.     }
  238.     /* set -+ mode by default for .C */
  239.     if (!cplus) {            /* don't bother if explicit */
  240.     char *dot;
  241.  
  242.     dot = in_name + strlen(in_name) - 2;
  243.     if ((dot > in_name) && (strcmp(dot, ".C") == 0))
  244.         set_option("-+");
  245.     }
  246.     if (output == NULL)
  247.     if (troff)
  248.         output = stdout;
  249.     else {
  250.         out_name = in_name;
  251.         bakcopy();
  252.     }
  253.     if (ps.com_ind <= 1)
  254.     ps.com_ind = 2;            /* don't put normal comments before
  255.                      * column 2 */
  256.     if (troff) {
  257.     if (bodyf.font[0] == 0)
  258.         parsefont(&bodyf, "R");
  259.     if (scomf.font[0] == 0)
  260.         parsefont(&scomf, "I");
  261.     if (blkcomf.font[0] == 0)
  262.         blkcomf = scomf, blkcomf.size += 2;
  263.     if (boxcomf.font[0] == 0)
  264.         boxcomf = blkcomf;
  265.     if (stringf.font[0] == 0)
  266.         parsefont(&stringf, "L");
  267.     if (keywordf.font[0] == 0)
  268.         parsefont(&keywordf, "B");
  269.     writefdef(&bodyf, 'B');
  270.     writefdef(&scomf, 'C');
  271.     writefdef(&blkcomf, 'L');
  272.     writefdef(&boxcomf, 'X');
  273.     writefdef(&stringf, 'S');
  274.     writefdef(&keywordf, 'K');
  275.     }
  276.     if (block_comment_max_col <= 0)
  277.     block_comment_max_col = max_col;
  278.     if (ps.decl_com_ind <= 0)        /* if not specified by user, set this */
  279.     ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
  280.     if (continuation_indent == 0)
  281.     continuation_indent = ps.ind_size;
  282.     fill_buffer();            /* get first batch of stuff into
  283.                      * input buffer */
  284.  
  285.     parse(semicolon);
  286.     {
  287.     register char *p = buf_ptr;
  288.     register col = 1;
  289.  
  290.     while (1) {
  291.         if (*p == ' ')
  292.         col++;
  293.         else if (*p == '\t')
  294.         col += (tabsize - ((col - 1) % tabsize));    /* JHT 22oct89 */
  295.         else
  296.         break;
  297.         p++;
  298.     };
  299.     if (col > ps.ind_size)
  300.         ps.ind_level = ps.i_l_follow = col / ps.ind_size;
  301.     }
  302.     if (troff) {
  303.     register char *p = in_name, *beg = in_name;
  304.  
  305.     while (*p)
  306.         if (*p++ == '/')
  307.         beg = p;
  308.     fprintf(output, ".Fn \"%s\"\n", beg);
  309.     }
  310.     /*
  311.      * START OF MAIN LOOP
  312.      */
  313.  
  314.     while (1) {                /* this is the main loop.  it will go
  315.                      * until we reach eof */
  316.     int is_procname;
  317.  
  318.     type_code = lexi();        /* lexi reads one token.  The actual
  319.                      * characters read are stored in
  320.                      * "token". lexi returns a code
  321.                      * indicating the type of token */
  322.     is_procname = ps.procname[0];
  323.  
  324.     /*
  325.      * The following code moves everything following an if (), while (),
  326.      * else, etc. up to the start of the following stmt to a buffer. This
  327.      * allows proper handling of both kinds of brace placement.
  328.      */
  329.  
  330.     flushed_nl = false;
  331.     while (ps.search_brace) {    /* if we scanned an if(), while(),
  332.                      * etc., we might need to copy stuff
  333.                      * into a buffer we must loop,
  334.                      * copying stuff into save_com, until
  335.                      * we find the start of the stmt
  336.                      * which follows the if, or whatever */
  337.         switch (type_code) {
  338.         case newline:
  339.         ++line_no;
  340.         flushed_nl = true;
  341.         case form_feed:
  342.         break;            /* form feeds and newlines found here
  343.                      * will be ignored */
  344.  
  345.         case lbrace:        /* this is a brace that starts the
  346.                      * compound stmt */
  347.         if (sc_end == 0) {    /* ignore buffering if a comment
  348.                      * wasn't stored up */
  349.             ps.search_brace = false;
  350.             goto check_type;
  351.         }
  352.         /* if (btype_2)        Bug notified by Steve Comen, 16 Mar 92 */
  353.         {
  354.             save_com[0] = '{';    /* we either want to put the brace
  355.                      * right after the if */
  356.             goto sw_buffer;    /* go to common code to get out of
  357.                      * this loop */
  358.         }
  359.         case comment:        /* we have a comment, so we must copy
  360.                      * it into the buffer */
  361.         if (!flushed_nl || sc_end != 0) {
  362.             if (sc_end == 0) {    /* if this is the first comment, we
  363.                      * must set up the buffer */
  364.             save_com[0] = save_com[1] = ' ';
  365.             sc_end = &(save_com[2]);
  366.             } else {
  367.             *sc_end++ = '\n';    /* add newline between
  368.                          * comments */
  369.             *sc_end++ = ' ';
  370.             --line_no;
  371.             }
  372.             *sc_end++ = '/';    /* copy in start of comment */
  373.             *sc_end++ = '*';
  374.  
  375.             for (;;) {        /* loop until we get to the end of
  376.                      * the comment */
  377.             *sc_end = *buf_ptr++;
  378.             if (buf_ptr >= buf_end)
  379.                 fill_buffer();
  380.  
  381.             if (*sc_end++ == '*' && *buf_ptr == '/')
  382.                 break;    /* we are at end of comment */
  383.  
  384.             if (sc_end >= &(save_com[sc_size])) {    /* check for temp buffer
  385.                                  * overflow */
  386.                 diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
  387.                 fflush(output);
  388.                 exit(1);
  389.             }
  390.             }
  391.             *sc_end++ = '/';    /* add ending slash */
  392.             if (++buf_ptr >= buf_end)    /* get past / in buffer */
  393.             fill_buffer();
  394.             break;
  395.         }
  396.         case cc_commnt:        /* we have a comment, so we must copy
  397.                      * it into the buffer */
  398.         /* C++ comment */
  399.         if (!flushed_nl || sc_end != 0) {
  400.             if (sc_end == 0) {    /* if this is the first comment, we
  401.                      * must set up the buffer */
  402.             save_com[0] = save_com[1] = ' ';
  403.             sc_end = &(save_com[2]);
  404.             } else {
  405.             *sc_end++ = '\n';    /* add newline between
  406.                          * comments */
  407.             *sc_end++ = ' ';
  408.             --line_no;
  409.             }
  410.             *sc_end++ = '/';    /* copy in start of comment */
  411.             *sc_end++ = '/';
  412.  
  413.             for (;;) {        /* loop until we get to the end of
  414.                      * the comment */
  415.             *sc_end++ = *buf_ptr++;
  416.             if (buf_ptr >= buf_end)
  417.                 fill_buffer();
  418.  
  419.             if (*buf_ptr == '\n')
  420.                 break;    /* we are at end of comment */
  421.  
  422.             if (sc_end >= &(save_com[sc_size])) {    /* check for temp buffer
  423.                                  * overflow */
  424.                 diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
  425.                 fflush(output);
  426.                 exit(1);
  427.             }
  428.             }
  429.             if (++buf_ptr >= buf_end)    /* eat '\n' */
  430.             fill_buffer();
  431.             break;
  432.         }
  433.         default:            /* it is the start of a normal
  434.                      * statment */
  435.         if (flushed_nl)        /* if we flushed a newline, make sure
  436.                      * it is put back */
  437.             force_nl = true;
  438.         if (type_code == sp_paren && *token == 'i'
  439.             && last_else && ps.else_if
  440.             || type_code == sp_nparen && *token == 'e'
  441.             && e_code != s_code && e_code[-1] == '}')
  442.             force_nl = false;
  443.  
  444.         if (sc_end == 0) {    /* ignore buffering if comment wasnt
  445.                      * saved up */
  446.             ps.search_brace = false;
  447.             goto check_type;
  448.         }
  449.         if (force_nl) {        /* if we should insert a nl here, put
  450.                      * it into the buffer */
  451.             force_nl = false;
  452.             --line_no;        /* this will be re-increased when the
  453.                      * nl is read from the buffer */
  454.             *sc_end++ = '\n';
  455.             *sc_end++ = ' ';
  456.             if (verbose && !flushed_nl)    /* print error msg if the
  457.                          * line was not already
  458.                          * broken */
  459.             diag(0, "Line broken");
  460.             flushed_nl = false;
  461.         }
  462.         for (t_ptr = token; *t_ptr; ++t_ptr)
  463.             *sc_end++ = *t_ptr;    /* copy token into temp buffer */
  464.         ps.procname[0] = 0;
  465.  
  466.     sw_buffer:
  467.         ps.search_brace = false;/* stop looking for start of stmt */
  468.         bp_save = buf_ptr;    /* save current input buffer */
  469.         be_save = buf_end;
  470.         buf_ptr = save_com;    /* fix so that subsequent calls to
  471.                      * lexi will take tokens out of
  472.                      * save_com */
  473.         *sc_end++ = ' ';    /* add trailing blank, just in case */
  474.         buf_end = sc_end;
  475.         sc_end = 0;
  476.         break;
  477.         }                /* end of switch */
  478.         if (type_code != 0)        /* we must make this check, just in
  479.                      * case there was an unexpected EOF */
  480.         type_code = lexi();    /* read another token */
  481.         /* if (ps.search_brace) ps.procname[0] = 0; */
  482.         if ((is_procname = ps.procname[0]) && flushed_nl
  483.         && !procnames_start_line && ps.in_decl
  484.         && type_code == ident)
  485.         flushed_nl = 0;
  486.     }                /* end of while (search_brace) */
  487.     last_else = 0;
  488. check_type:
  489.     if (type_code == 0) {        /* we got eof */
  490.         if (s_lab != e_lab || s_code != e_code
  491.         || s_com != e_com)    /* must dump end of line */
  492.         dump_line();
  493.         if (ps.tos > 1)        /* check for balanced braces */
  494.         diag(1, "Stuff missing from end of file.");
  495.  
  496.         if (verbose) {
  497.         printf("There were %d output lines and %d comments\n",
  498.             ps.out_lines, ps.out_coms);
  499.         printf("(Lines with comments)/(Lines with code): %6.3f\n",
  500.             (1.0 * ps.com_lines) / code_lines);
  501.         }
  502.         fflush(output);
  503.         exit(found_err);
  504.     }
  505.     if (
  506.         (type_code != comment) &&
  507.         (type_code != cc_commnt) &&
  508.         (type_code != newline) &&
  509.         (type_code != preesc) &&
  510.         (type_code != form_feed)) {
  511.         if (force_nl &&
  512.         (type_code != semicolon) &&
  513.         (type_code != lbrace || btype_3 || !btype_2)) {
  514.         /* we should force a broken line here */
  515.         if (verbose && !flushed_nl)
  516.             diag(0, "Line broken");
  517.         flushed_nl = false;
  518.         dump_line();
  519.         ps.want_blank = false;    /* dont insert blank at line start */
  520.         force_nl = false;
  521.         }
  522.         ps.in_stmt = true;        /* turn on flag which causes an extra
  523.                      * level of indentation. this is
  524.                      * turned off by a ; or '}' */
  525.         if (s_com != e_com) {    /* the turkey has embedded a comment
  526.                      * in a line. fix it */
  527.         *e_code++ = ' ';
  528.         for (t_ptr = s_com; *t_ptr; ++t_ptr) {
  529.             check_size(code);
  530.             *e_code++ = *t_ptr;
  531.         }
  532.         *e_code++ = ' ';
  533.         *e_code = '\0';        /* null terminate code sect */
  534.         ps.want_blank = false;
  535.         e_com = s_com;
  536.         }
  537.     } else if (type_code != comment && type_code != cc_commnt)
  538.         /* preserve force_nl thru a comment */
  539.         force_nl = false;        /* cancel forced newline after
  540.                      * newline, form feed, etc */
  541.  
  542.  
  543.  
  544.     /*-----------------------------------------------------*\
  545.     |      do switch on type of token scanned        |
  546.     \*-----------------------------------------------------*/
  547.     check_size(code);
  548.     switch (type_code) {        /* now, decide what to do with the
  549.                      * token */
  550.  
  551.     case form_feed:        /* found a form feed in line */
  552.         ps.use_ff = true;        /* a form feed is treated much like a
  553.                      * newline */
  554.         dump_line();
  555.         ps.want_blank = false;
  556.         break;
  557.  
  558.     case newline:
  559.         if (ps.last_token != comma || ps.p_l_follow > 0
  560.         || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com) {
  561.         dump_line();
  562.         ps.want_blank = false;
  563.         }
  564.         ++line_no;            /* keep track of input line number */
  565.         break;
  566.  
  567.     case lparen:            /* got a '(' or '[' */
  568.         ++ps.p_l_follow;        /* count parens to make Healy happy */
  569.         if (ps.want_blank && *token != '[' &&
  570.         (ps.last_token != ident || proc_calls_space
  571.             || (ps.its_a_keyword && (!ps.sizeof_keyword || Bill_Shannon))))
  572.         *e_code++ = ' ';
  573.         if (ps.in_decl && !ps.block_init)
  574.         if (troff && !ps.dumped_decl_indent && !is_procname && ps.last_token == decl) {
  575.             ps.dumped_decl_indent = 1;
  576.             sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
  577.             e_code += strlen(e_code);
  578.         } else {
  579.             while ((e_code - s_code) < dec_ind) {
  580.             check_size(code);
  581.             *e_code++ = ' ';
  582.             }
  583.             *e_code++ = token[0];
  584.         }
  585.         else
  586.         *e_code++ = token[0];
  587.         if (parens_space && *token != '[')
  588.         *e_code++ = ' ';
  589.         ps.paren_indents[ps.p_l_follow - 1] = (short) (e_code - s_code);
  590.         if (sp_sw && ps.p_l_follow == 1 && extra_expression_indent
  591.         && ps.paren_indents[0] < (short) (2 * ps.ind_size))
  592.         ps.paren_indents[0] = (short) (2 * ps.ind_size);
  593.         ps.want_blank = false;
  594.         if (ps.in_or_st && *token == '(' && ps.tos <= 2) {
  595.         /*
  596.          * this is a kluge to make sure that declarations will be
  597.          * aligned right if proc decl has an explicit type on it,
  598.          * i.e. "int a(x) {..."
  599.          */
  600.         parse(semicolon);    /* I said this was a kluge... */
  601.         ps.in_or_st = false;    /* turn off flag for structure decl
  602.                      * or initialization */
  603.         }
  604.         if (ps.sizeof_keyword)
  605.         ps.sizeof_mask |= 1 << ps.p_l_follow;
  606.         break;
  607.  
  608.     case rparen:            /* got a ')' or ']' */
  609.         if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask) {
  610.         ps.last_u_d = true;
  611.         ps.cast_mask &= (1 << ps.p_l_follow) - 1;
  612.         }
  613.         ps.sizeof_mask &= (1 << ps.p_l_follow) - 1;
  614.         if (--ps.p_l_follow < 0) {
  615.         ps.p_l_follow = 0;
  616.         diag(0, "Extra %c", *token);
  617.         }
  618.         if (e_code == s_code)    /* if the paren starts the line */
  619.         ps.paren_level = ps.p_l_follow;    /* then indent it */
  620.  
  621.         if (parens_space && *token != ']')
  622.         *e_code++ = ' ';
  623.         *e_code++ = token[0];
  624.         ps.want_blank = true;
  625.  
  626.         if (sp_sw && (ps.p_l_follow == 0)) {    /* check for end of if
  627.                              * (...), or some such */
  628.         sp_sw = false;
  629.         force_nl = true;    /* must force newline after if */
  630.         ps.last_u_d = true;    /* inform lexi that a following
  631.                      * operator is unary */
  632.         ps.in_stmt = false;    /* dont use stmt continuation
  633.                      * indentation */
  634.  
  635.         parse(hd_type);        /* let parser worry about if, or
  636.                      * whatever */
  637.         }
  638.         ps.search_brace = btype_2 && !btype_3;
  639.         /*
  640.          * this should insure that constructs such as main(){...} and
  641.          * int[]{...} have their braces put in the right place
  642.          */
  643.         break;
  644.  
  645.     case unary_op:            /* this could be any unary operation */
  646.         if (ps.want_blank)
  647.         *e_code++ = ' ';
  648.  
  649.         if (troff && !ps.dumped_decl_indent && ps.in_decl && !is_procname) {
  650.         sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
  651.         ps.dumped_decl_indent = 1;
  652.         e_code += strlen(e_code);
  653.         } else {
  654.         char *res = token;
  655.  
  656.         if (ps.in_decl && !ps.block_init) {    /* if this is a unary op
  657.                              * in a declaration, we
  658.                              * should indent this
  659.                              * token */
  660.             for (i = 0; token[i]; ++i);    /* find length of token */
  661.             while ((e_code - s_code) < (dec_ind - i)) {
  662.             check_size(code);
  663.             *e_code++ = ' ';/* pad it */
  664.             }
  665.         }
  666.         if (troff && token[0] == '-' && token[1] == '>')
  667.             res = "\\(->";
  668.         for (t_ptr = res; *t_ptr; ++t_ptr) {
  669.             check_size(code);
  670.             *e_code++ = *t_ptr;
  671.         }
  672.         }
  673.         ps.want_blank = false;
  674.         break;
  675.  
  676.     case binary_op:        /* any binary operation */
  677.  
  678.         if (ps.want_blank)
  679.         *e_code++ = ' ';
  680.         {
  681.         char *res = token;
  682.  
  683.         if (troff)
  684.             switch (token[0]) {
  685.             case '<':
  686.             if (token[1] == '=')
  687.                 res = "\\(<=";
  688.             break;
  689.             case '>':
  690.             if (token[1] == '=')
  691.                 res = "\\(>=";
  692.             break;
  693.             case '!':
  694.             if (token[1] == '=')
  695.                 res = "\\(!=";
  696.             break;
  697.             case '|':
  698.             if (token[1] == '|')
  699.                 res = "\\(br\\(br";
  700.             else if (token[1] == 0)
  701.                 res = "\\(br";
  702.             break;
  703.             }
  704.         for (t_ptr = res; *t_ptr; ++t_ptr) {
  705.             check_size(code);
  706.             *e_code++ = *t_ptr;    /* move the operator */
  707.         }
  708.         }
  709.         ps.want_blank = true;
  710.         break;
  711.  
  712.     case postop:            /* got a trailing ++ or -- */
  713.         *e_code++ = token[0];
  714.         *e_code++ = token[1];
  715.         ps.want_blank = true;
  716.         break;
  717.  
  718.     case question:            /* got a ? */
  719.         squest++;            /* this will be used when a later
  720.                      * colon appears so we can
  721.                      * distinguish the <c>?<n>:<n>
  722.                      * construct */
  723.         if (ps.want_blank)
  724.         *e_code++ = ' ';
  725.         *e_code++ = '?';
  726.         ps.want_blank = true;
  727.         break;
  728.  
  729.     case casestmt:            /* got word 'case' or 'default' */
  730.         scase = true;        /* so we can process the later colon
  731.                      * properly */
  732.         goto copy_id;
  733.  
  734.     case privpub:            /* got public, private or protected */
  735.         strcpy(s_lab, token);
  736.         e_lab = s_lab + strlen(token);
  737.         *e_lab++ = ':';
  738.         *e_lab++ = ' ';
  739.         *e_lab = '\0';
  740.         force_nl = true;
  741.         break;
  742.  
  743.     case colon:            /* got a ':' */
  744.         if (squest > 0) {        /* it is part of the <c>?<n>: <n>
  745.                      * construct */
  746.         --squest;
  747.         if (ps.want_blank)
  748.             *e_code++ = ' ';
  749.         *e_code++ = ':';
  750.         ps.want_blank = true;
  751.         break;
  752.         }
  753.         if (ps.in_decl) {
  754.         if (cplus) {        /* assume public, private, or
  755.                      * protected */
  756.             for (t_ptr = s_code; *t_ptr; ++t_ptr)
  757.             *e_lab++ = *t_ptr;    /* turn everything so far
  758.                          * into a label */
  759.             e_code = s_code;
  760.             *e_lab++ = ':';
  761.             *e_lab++ = ' ';
  762.             *e_lab = '\0';
  763.             force_nl = true;
  764.             scase = false;
  765.             ps.pcase = true;
  766.             break;
  767.         }
  768.         *e_code++ = ':';
  769.         ps.want_blank = false;
  770.         break;
  771.         }
  772.         ps.in_stmt = false;        /* seeing a label does not imply we
  773.                      * are in a stmt */
  774.         for (t_ptr = s_code; *t_ptr; ++t_ptr)
  775.         *e_lab++ = *t_ptr;    /* turn everything so far into a
  776.                      * label */
  777.         e_code = s_code;
  778.         *e_lab++ = ':';
  779.         *e_lab++ = ' ';
  780.         *e_lab = '\0';
  781.  
  782.         force_nl = ps.pcase = scase;/* ps.pcase will be used by dump_line
  783.                      * to decide how to indent the label.
  784.                      * force_nl will force a case n: to
  785.                      * be on a line by itself */
  786.         scase = false;
  787.         ps.want_blank = false;
  788.         break;
  789.  
  790.     case semicolon:        /* got a ';' */
  791.         ps.in_or_st = false;    /* we are not in an initialization or
  792.                      * structure declaration */
  793.         scase = false;        /* these will only need resetting in
  794.                      * a error */
  795.         squest = 0;
  796.         if (ps.last_token == rparen)
  797.         ps.in_parameter_declaration = 0;
  798.         ps.cast_mask = 0;
  799.         ps.sizeof_mask = 0;
  800.         ps.block_init = 0;
  801.         ps.block_init_level = 0;
  802.         ps.just_saw_decl--;
  803.  
  804.         if (ps.in_decl && s_code == e_code && !ps.block_init)
  805.         while ((e_code - s_code) < (dec_ind - 1)) {
  806.             check_size(code);
  807.             *e_code++ = ' ';
  808.         }
  809.  
  810.         ps.in_decl = (ps.dec_nest > 0);    /* if we were in a first
  811.                          * level structure
  812.                          * declaration, we arent any
  813.                          * more */
  814.  
  815.         if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
  816.  
  817.         /*
  818.          * This should be true iff there were unbalanced parens in
  819.          * the stmt.  It is a bit complicated, because the semicolon
  820.          * might be in a for stmt
  821.          */
  822.         diag(1, "Unbalanced parens");
  823.         ps.p_l_follow = 0;
  824.         if (sp_sw) {        /* this is a check for a if, while,
  825.                      * etc. with unbalanced parens */
  826.             sp_sw = false;
  827.             parse(hd_type);    /* dont lose the if, or whatever */
  828.         }
  829.         }
  830.         *e_code++ = ';';
  831.         ps.want_blank = true;
  832.         ps.in_stmt = (ps.p_l_follow > 0);    /* we are no longer in the
  833.                          * middle of a stmt */
  834.  
  835.         if (!sp_sw) {        /* if not if for (;;) */
  836.         parse(semicolon);    /* let parser know about end of stmt */
  837.         force_nl = true;    /* force newline after a end of stmt */
  838.         }
  839.         break;
  840.  
  841.     case lbrace:            /* got a '{' */
  842.         ps.in_stmt = false;        /* dont indent the {} */
  843.         if (!ps.block_init)
  844.         force_nl = true;    /* force other stuff on same line as
  845.                      * '{' onto new line */
  846.         else if (ps.block_init_level <= 0)
  847.         ps.block_init_level = 1;
  848.         else
  849.         ps.block_init_level++;
  850.  
  851.         if (s_code != e_code && !ps.block_init) {
  852.         if (btype_3 || !btype_2) {
  853.             dump_line();
  854.             ps.want_blank = false;
  855.         } else if (ps.in_parameter_declaration && !ps.in_or_st) {
  856.             ps.i_l_follow = 0;
  857.             dump_line();
  858.             ps.want_blank = false;
  859.         }
  860.         }
  861.         if (ps.in_parameter_declaration)
  862.         prefix_blankline_requested = 0;
  863.  
  864.         if (ps.p_l_follow > 0) {    /* check for preceeding unbalanced
  865.                      * parens */
  866.         diag(1, "Unbalanced parens");
  867.         ps.p_l_follow = 0;
  868.         if (sp_sw) {        /* check for unclosed if, for, etc. */
  869.             sp_sw = false;
  870.             parse(hd_type);
  871.             ps.ind_level = ps.i_l_follow;
  872.         }
  873.         }
  874.         if (btype_3)
  875.         ps.ind_stmt = true;
  876.         else if (s_code == e_code)
  877.         ps.ind_stmt = false;    /* dont put extra indentation on line
  878.                      * with '{' */
  879.         if (ps.in_decl && ps.in_or_st) {    /* this is either a structure
  880.                          * declaration or an init */
  881.         di_stack[ps.dec_nest++] = dec_ind;
  882.         /* ?        dec_ind = 0; */
  883.         } else {
  884.         ps.decl_on_line = false;/* we cant be in the middle of a
  885.                      * declaration, so dont do special
  886.                      * indentation of comments */
  887.         if (blanklines_after_declarations_at_proctop
  888.             && ps.in_parameter_declaration)
  889.             postfix_blankline_requested = 1;
  890.         ps.in_parameter_declaration = 0;
  891.         }
  892.         dec_ind = 0;
  893.         parse(lbrace);        /* let parser know about this */
  894.         if (ps.want_blank)        /* put a blank before '{' if '{' is
  895.                      * not at start of line */
  896.         *e_code++ = ' ';
  897.         ps.want_blank = false;
  898.         *e_code++ = '{';
  899.         ps.just_saw_decl = 0;
  900.         break;
  901.  
  902.     case rbrace:            /* got a '}' */
  903.         if (ps.p_stack[ps.tos] == decl && !ps.block_init)    /* semicolons can be
  904.                                  * omitted in
  905.                                  * declarations */
  906.         parse(semicolon);
  907.         if (ps.p_l_follow) {    /* check for unclosed if, for, else. */
  908.         diag(1, "Unbalanced parens");
  909.         ps.p_l_follow = 0;
  910.         sp_sw = false;
  911.         }
  912.         ps.just_saw_decl = 0;
  913.         ps.block_init_level--;
  914.         if (s_code != e_code && !ps.block_init) {    /* '}' must be first on
  915.                              * line */
  916.         if (verbose)
  917.             diag(0, "Line broken");
  918.         dump_line();
  919.         }
  920.         *e_code++ = '}';
  921.         ps.want_blank = true;
  922.         ps.in_stmt = ps.ind_stmt = false;
  923.         if (ps.dec_nest > 0) {    /* we are in multi-level structure
  924.                      * declaration */
  925.         dec_ind = di_stack[--ps.dec_nest];
  926.         if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
  927.             ps.just_saw_decl = 2;
  928.         ps.in_decl = true;
  929.         }
  930.         prefix_blankline_requested = 0;
  931.         parse(rbrace);        /* let parser know about this */
  932.         ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead
  933.         && ps.il[ps.tos] >= ps.ind_level;
  934.         if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0)
  935.         postfix_blankline_requested = 1;
  936.         if (btype_3 && ps.p_stack[ps.tos] == dohead) {
  937.         if (verbose)
  938.             diag(0, "Line broken");
  939.         dump_line();
  940.         ps.want_blank = false;
  941.         }
  942.         break;
  943.  
  944.     case swstmt:            /* got keyword "switch" */
  945.         sp_sw = true;
  946.         hd_type = swstmt;        /* keep this for when we have seen
  947.                      * the expression */
  948.         goto copy_id;        /* go move the token into buffer */
  949.  
  950.     case sp_paren:            /* token is if, while, for */
  951.         sp_sw = true;        /* the interesting stuff is done
  952.                      * after the expression is scanned */
  953.         hd_type = (*token == 'i' ? ifstmt :
  954.         (*token == 'w' ? whilestmt : forstmt));
  955.  
  956.         /*
  957.          * remember the type of header for later use by parser
  958.          */
  959.         goto copy_id;        /* copy the token into line */
  960.  
  961.     case sp_nparen:        /* got else, do */
  962.         ps.in_stmt = false;
  963.         if (*token == 'e') {
  964.         if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) {
  965.             if (verbose)
  966.             diag(0, "Line broken");
  967.             dump_line();    /* make sure this starts a line */
  968.             ps.want_blank = false;
  969.         }
  970.         force_nl = true;    /* also, following stuff must go onto
  971.                      * new line */
  972.         last_else = 1;
  973.         parse(elselit);
  974.         } else {
  975.         if (e_code != s_code) {    /* make sure this starts a line */
  976.             if (verbose)
  977.             diag(0, "Line broken");
  978.             dump_line();
  979.             ps.want_blank = false;
  980.         }
  981.         force_nl = true;    /* also, following stuff must go onto
  982.                      * new line */
  983.         last_else = 0;
  984.         parse(dolit);
  985.         }
  986.         goto copy_id;        /* move the token into line */
  987.  
  988.     case decl:            /* we have a declaration type (int,
  989.                      * register, etc.) */
  990.         parse(decl);        /* let parser worry about indentation */
  991.         if (ps.last_token == rparen && ps.tos <= 1) {
  992.         ps.in_parameter_declaration = 1;
  993.         if (s_code != e_code) {
  994.             dump_line();
  995.             ps.want_blank = 0;
  996.         }
  997.         }
  998.         if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) {
  999.         ps.ind_level = ps.i_l_follow = 1;
  1000.         ps.ind_stmt = 0;
  1001.         }
  1002.         ps.in_or_st = true;        /* this might be a structure or
  1003.                      * initialization declaration */
  1004.         ps.in_decl = ps.decl_on_line = true;
  1005.         if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
  1006.         ps.just_saw_decl = 2;
  1007.         prefix_blankline_requested = 0;
  1008.         for (i = 0; token[i++];);    /* get length of token */
  1009.  
  1010.         /*
  1011.          * dec_ind = e_code - s_code + (ps.decl_indent>i ? ps.decl_indent
  1012.          * : i);
  1013.          */
  1014.         dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
  1015.         goto copy_id;
  1016.  
  1017.     case ident:            /* got an identifier or constant */
  1018.         if (ps.in_decl) {        /* if we are in a declaration, we
  1019.                      * must indent identifier */
  1020.         if (ps.want_blank)
  1021.             *e_code++ = ' ';
  1022.         ps.want_blank = false;
  1023.         if (is_procname == 0 || !procnames_start_line) {
  1024.             if (!ps.block_init)
  1025.             if (troff && !ps.dumped_decl_indent) {
  1026.                 sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
  1027.                 ps.dumped_decl_indent = 1;
  1028.                 e_code += strlen(e_code);
  1029.             } else
  1030.                 while ((e_code - s_code) < dec_ind) {
  1031.                 check_size(code);
  1032.                 *e_code++ = ' ';
  1033.                 }
  1034.         } else {
  1035.             if (dec_ind && s_code != e_code)
  1036.             dump_line();
  1037.             dec_ind = 0;
  1038.             ps.want_blank = false;
  1039.         }
  1040.         } else if (sp_sw && ps.p_l_follow == 0) {
  1041.         sp_sw = false;
  1042.         force_nl = true;
  1043.         ps.last_u_d = true;
  1044.         ps.in_stmt = false;
  1045.         parse(hd_type);
  1046.         }
  1047.     copy_id:
  1048.         if (ps.want_blank)
  1049.         *e_code++ = ' ';
  1050.         if (troff && ps.its_a_keyword) {
  1051.         e_code = chfont(&bodyf, &keywordf, e_code);
  1052.         for (t_ptr = token; *t_ptr; ++t_ptr) {
  1053.             check_size(code);
  1054.             *e_code++ = keywordf.allcaps && islower(*t_ptr)
  1055.             ? (char) toupper(*t_ptr) : *t_ptr;
  1056.         }
  1057.         e_code = chfont(&keywordf, &bodyf, e_code);
  1058.         } else
  1059.         for (t_ptr = token; *t_ptr; ++t_ptr) {
  1060.             check_size(code);
  1061.             *e_code++ = *t_ptr;
  1062.         }
  1063.         ps.want_blank = true;
  1064.         break;
  1065.  
  1066.     case period:            /* treat a period kind of like a
  1067.                      * binary operation */
  1068.         *e_code++ = '.';        /* move the period into line */
  1069.         ps.want_blank = false;    /* dont put a blank after a period */
  1070.         break;
  1071.  
  1072.     case comma:
  1073.         ps.want_blank = (s_code != e_code);    /* only put blank after comma
  1074.                          * if comma does not start
  1075.                          * the line */
  1076.         if (ps.in_decl && is_procname == 0 && !ps.block_init)
  1077.         while ((e_code - s_code) < (dec_ind - 1)) {
  1078.             check_size(code);
  1079.             *e_code++ = ' ';
  1080.         }
  1081.  
  1082.         *e_code++ = ',';
  1083.         if (ps.p_l_follow == 0) {
  1084.         if (ps.block_init_level <= 0)
  1085.             ps.block_init = 0;
  1086.         if (break_comma && !ps.leave_comma)
  1087.             force_nl = true;
  1088.         }
  1089.         break;
  1090.  
  1091.     case preesc:            /* got the character '#' */
  1092.         if ((s_com != e_com) ||
  1093.         (s_lab != e_lab) ||
  1094.         (s_code != e_code))
  1095.         dump_line();
  1096.         *e_lab++ = '#';        /* move whole line to 'label' buffer */
  1097.         {
  1098.         int in_comment = 0;
  1099.         int com_start = 0;
  1100.         char quote = 0;
  1101.         int com_end = 0;
  1102.  
  1103.         while (*buf_ptr != '\n' || in_comment) {
  1104.             check_size(lab);
  1105.             *e_lab = *buf_ptr++;
  1106.             if (buf_ptr >= buf_end)
  1107.             fill_buffer();
  1108.             switch (*e_lab++) {
  1109.             case BACKSLASH:
  1110.             if (troff)
  1111.                 *e_lab++ = BACKSLASH;
  1112.             if (!in_comment) {
  1113.                 *e_lab++ = *buf_ptr++;
  1114.                 if (buf_ptr >= buf_end)
  1115.                 fill_buffer();
  1116.             }
  1117.             break;
  1118.             case '/':
  1119.             if (*buf_ptr == '*' && !in_comment && !quote) {
  1120.                 in_comment = 1;
  1121.                 *e_lab++ = *buf_ptr++;
  1122.                 com_start = e_lab - s_lab - 2;
  1123.             } else if (*buf_ptr == '/' && !in_comment && !quote) {
  1124.                 in_comment = 2;
  1125.                 *e_lab++ = *buf_ptr++;
  1126.                 com_start = e_lab - s_lab - 2;
  1127.             }
  1128.             break;
  1129.             case '"':
  1130.             if (quote == '"')
  1131.                 quote = 0;
  1132.             break;
  1133.             case '\'':
  1134.             if (quote == '\'')
  1135.                 quote = 0;
  1136.             break;
  1137.             case '*':
  1138.             if (*buf_ptr == '/' && in_comment == 1) {
  1139.                 in_comment = 0;
  1140.                 *e_lab++ = *buf_ptr++;
  1141.                 com_end = e_lab - s_lab;
  1142.             }
  1143.             break;
  1144.             case '\n':
  1145.             if (in_comment == 2) {
  1146.                 in_comment = 0;
  1147.                 --buf_ptr;    /* so while loop will exit */
  1148.                 com_end = e_lab - s_lab;
  1149.             }
  1150.             break;
  1151.             }
  1152.         }
  1153.  
  1154.         while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  1155.             e_lab--;
  1156.         if (e_lab - s_lab == com_end && bp_save == 0) {    /* comment on
  1157.                                  * preprocessor line */
  1158.             if (sc_end == 0)    /* if this is the first comment, we
  1159.                      * must set up the buffer */
  1160.             sc_end = &(save_com[0]);
  1161.             else {
  1162.             *sc_end++ = '\n';    /* add newline between
  1163.                          * comments */
  1164.             *sc_end++ = ' ';
  1165.             --line_no;
  1166.             }
  1167. #ifdef BSD                /* gst 24 Mar 89 */
  1168.             bcopy(s_lab + com_start, sc_end, com_end - com_start);
  1169. #else
  1170.             memcpy(sc_end, s_lab + com_start, com_end - com_start);
  1171. #endif
  1172.             sc_end += com_end - com_start;
  1173.             if (sc_end >= &save_com[sc_size])
  1174.             abort();
  1175.             e_lab = s_lab + com_start;
  1176.             while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  1177.             e_lab--;
  1178.             bp_save = buf_ptr;    /* save current input buffer */
  1179.             be_save = buf_end;
  1180.             buf_ptr = save_com;    /* fix so that subsequent calls to
  1181.                      * lexi will take tokens out of
  1182.                      * save_com */
  1183.             *sc_end++ = ' ';    /* add trailing blank, just in case */
  1184.             buf_end = sc_end;
  1185.             sc_end = 0;
  1186.         }
  1187.         *e_lab = '\0';        /* null terminate line */
  1188.         ps.pcase = false;
  1189.         }
  1190.  
  1191.         if (strncmp(s_lab, "#if", 3) == 0) {
  1192.         if (blanklines_around_conditional_compilation) {
  1193.             register c;
  1194.  
  1195.             prefix_blankline_requested++;
  1196.             while ((c = getc(input)) == '\n');
  1197.             ungetc(c, input);
  1198.         }
  1199.         if (ifdef_level < sizeof state_stack / sizeof state_stack[0]) {
  1200.             match_state[ifdef_level].tos = -1;
  1201.             state_stack[ifdef_level++] = ps;
  1202.         } else
  1203.             diag(1, "#if stack overflow");
  1204.         } else if (strncmp(s_lab, "#else", 5) == 0)
  1205.         if (ifdef_level <= 0)
  1206.             diag(1, "Unmatched #else");
  1207.         else {
  1208.             match_state[ifdef_level - 1] = ps;
  1209.             ps = state_stack[ifdef_level - 1];
  1210.         }
  1211.         else if (strncmp(s_lab, "#endif", 6) == 0) {
  1212.         if (ifdef_level <= 0)
  1213.             diag(1, "Unmatched #endif");
  1214.         else {
  1215.             ifdef_level--;
  1216.  
  1217. #ifdef undef
  1218.             /*
  1219.              * This match needs to be more intelligent before the
  1220.              * message is useful
  1221.              */
  1222.             if (match_state[ifdef_level].tos >= 0
  1223.             && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
  1224.             diag(0, "Syntactically inconsistant #ifdef alternatives.");
  1225. #endif
  1226.         }
  1227.         if (blanklines_around_conditional_compilation) {
  1228.             postfix_blankline_requested++;
  1229.             n_real_blanklines = 0;
  1230.         }
  1231.         }
  1232.         break;            /* subsequent processing of the
  1233.                      * newline character will cause the
  1234.                      * line to be printed */
  1235.  
  1236.     case cc_commnt:        /* we have gotten a //  this is a
  1237.                      * biggie */
  1238.     case comment:            /* we have gotten a /*    this is a
  1239.                      * biggie */
  1240.  
  1241.         if (flushed_nl) {        /* we should force a broken line here */
  1242.         flushed_nl = false;
  1243.         dump_line();
  1244.         ps.want_blank = false;    /* dont insert blank at line start */
  1245.         force_nl = false;
  1246.         }
  1247.         pr_comment();
  1248.         /*
  1249.          * pr_comment()'s parsing sequence for a C++ comment is quite
  1250.          * different from that for a standard comment and without the
  1251.          * next statement a C++ comment causes the next line to be
  1252.          * formatted with an extra blank space before the code or to be
  1253.          * preceded by an extra blank line.    jrs 12 Mar 92
  1254.          */
  1255.         if (type_code == cc_commnt)    /* jrs 12 Mar 92 */
  1256.         force_nl = ps.want_blank = false;    /* jrs 12 Mar 92 */
  1257.         break;
  1258.     }                /* end of big switch stmt */
  1259.  
  1260.     *e_code = '\0';            /* make sure code section is null
  1261.                      * terminated */
  1262.     if (type_code != comment && type_code != newline && type_code != preesc && type_code != cc_commnt)
  1263.         ps.last_token = type_code;
  1264.     }                    /* end of main while (1) loop */
  1265. };
  1266.  
  1267. /*
  1268.  * copy input file to backup file if in_name is /blah/blah/blah/file, then
  1269.  * backup file will be ".Bfile" then make the backup file the input and
  1270.  * original input file the output
  1271.  */
  1272. #ifdef ANSIC
  1273. static void 
  1274. bakcopy(void)
  1275. #else
  1276. bakcopy()
  1277. #endif
  1278. {
  1279. #ifdef MSDOS                /* or OS/2 */
  1280.     int fat = 0;            /* File system type = FAT? */
  1281.     char *q;
  1282.  
  1283. #endif
  1284.     int n, bakchn;
  1285.  
  1286. /*  char    buff[8 * 1024];        Ouch!  Such a big stack!
  1287.     Let's allocate a buffer from the heap instead .... jrs 12 Mar 92 */
  1288.  
  1289.     char *buff;
  1290.  
  1291. # define COPY_BUFFER_SIZE 8*1024
  1292.     register char *p;
  1293.  
  1294.     if ((buff = (char *) malloc(COPY_BUFFER_SIZE)) == NULL) {
  1295.     fprintf(stderr, "indent: no memory for backup file copy buffer");
  1296.     exit(1);
  1297.     }
  1298.     /* construct file name .Bfile */
  1299.  
  1300. #ifdef MSDOS                /* or OS/2 */
  1301. # ifndef M_I386                /* then must be OS/2 1.x or MSDOS */
  1302. #   define DosQueryFSAttach(a,b,c,d,e) DosQFSAttach(a,b,c,(BYTE *)d,e,0L)
  1303. #   define DosQueryCurrentDisk DosQCurDisk
  1304. #   define PARAM_T USHORT
  1305.  
  1306.     DosGetMachineMode(&buff[0]);
  1307.     if (buff[0] == MODE_REAL)        /* DOS can only handle FAT */
  1308.     fat = 1;
  1309. # else
  1310. #   define PARAM_T ULONG
  1311. # endif
  1312.  
  1313.     if (!fat) {
  1314.     PARAM_T DriveNumber, cbData;
  1315.     ULONG DriveMap;
  1316.     struct fsqb {
  1317. # ifdef M_I386
  1318.         FSQBUFFER2 bData;
  1319. # else
  1320.         FSQBUFFER bData;
  1321. # endif
  1322.         BYTE filler[60];
  1323.     }
  1324.      fsq;
  1325.  
  1326.     cbData = sizeof fsq;
  1327.     if (isalpha(in_name[0]) && in_name[1] == ':')
  1328.         DriveNumber = toupper(in_name[0]) - '@';
  1329.     else
  1330.         DosQueryCurrentDisk(&DriveNumber, &DriveMap);
  1331.  
  1332.     if (DosQueryFSAttach(NULL, DriveNumber, FSAIL_DRVNUMBER,
  1333.         &fsq.bData, &cbData))
  1334.         fat = 0;
  1335.     else
  1336.         fat = !strcmp(&fsq.bData.szFSDName[fsq.bData.cbName], "FAT");
  1337.     }
  1338.     for (p = strcpy(bakfile, in_name); *p; ++p);    /* skip to end of string */
  1339.     while (p > bakfile && *p != '/' && *p != '\\')
  1340.     p--;
  1341.     if (*p == '/' || *p == '\\')
  1342.     p++;
  1343.     if (fat && (q = strchr(p, '.')) != NULL)
  1344.     *q = '\0';
  1345.     strcat(bakfile, ".BAK");
  1346.  
  1347. #else                    /* it isn't MSDOS or OS/2 */
  1348.  
  1349.     for (p = in_name; *p; p++);        /* skip to end of string */
  1350.     while (p > in_name && *p != '/')    /* find last '/' */
  1351.     p--;
  1352.     if (*p == '/')
  1353.     p++;
  1354.  
  1355.     sprintf(bakfile, "%s.BAK", p);
  1356.  
  1357. #endif
  1358.  
  1359.     /* copy in_name to backup file */
  1360.     bakchn = creat(bakfile, 0600);
  1361.     if (bakchn < 0) {
  1362.     fprintf(stderr, "indent: can't create backup file \"%s\"\n", bakfile);
  1363.     exit(1);
  1364.     }
  1365.     while (n = read(fileno(input), buff, COPY_BUFFER_SIZE))
  1366.     if (write(bakchn, buff, n) != n) {
  1367.         fprintf(stderr, "indent: error writing backup file \"%s\"\n",
  1368.         bakfile);
  1369.         exit(1);
  1370.     }
  1371.     if (n < 0) {
  1372.     fprintf(stderr, "indent: error reading input file \"%s\"\n", in_name);
  1373.     exit(1);
  1374.     }
  1375.     close(bakchn);
  1376.     fclose(input);
  1377.  
  1378.     free(buff);
  1379.  
  1380.     /* re-open backup file as the input file */
  1381.     input = fopen(bakfile, "r");
  1382.     if (input == NULL) {
  1383.     fprintf(stderr, "indent: can't re-open backup file\n");
  1384.     exit(1);
  1385.     }
  1386.     /* now the original input file will be the output */
  1387.     output = fopen(in_name, "w");
  1388.     if (output == NULL) {
  1389.     fprintf(stderr, "indent: can't create %s\n", in_name);
  1390.     unlink(bakfile);
  1391.     exit(1);
  1392.     }
  1393. }
  1394.