home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Archive / OS2_Archive_CD-ROM_Walnut_Creek_May_1992.iso / novell / progrmng / indent.zoo / indent.c < prev    next >
C/C++ Source or Header  |  1989-10-30  |  38KB  |  1,315 lines

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