text: /**
   * Copyright (c) 1985 Sun Microsystems, Inc.
   * Copyright (c) 1980 The Regents of the University of California.
   * Copyright (c) 1976 Board of Trustees of the University of Illinois.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms are permitted
   * provided that the above copyright notice and this paragraph are
   * duplicated in all such forms and that any documentation,
   * advertising materials, and other materials related to such
   * distribution and use acknowledge that the software was developed
   * by the University of California, Berkeley, the University of Illinois,
   * Urbana, and Sun Microsystems, Inc.  The name of either University
   * or Sun Microsystems may not be used to endorse or promote products
   * derived from this software without specific prior written permission.
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
   * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   */
  
  /* ported to MINIX by: Robert R. Hall <hall@pnet01.cts.com>  */
  
  #define _POSIX_SOURCE 1
  #define	PUBLIC
  #define NAME_SIZE _POSIX_NAME_MAX
  
  #include <ctype.h>
  #include <string.h>
  #include <sys/types.h>
  #include <fcntl.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <limits.h>
  #include "globs.h"
  #include "codes.h"
  #include "proto.h"
  
  char           *in_name = "Standard Input";	/* will always point to
  						   name of input file */
  char           *out_name = "Standard Output";	/* will always point to
  						   name of output file */
  char            bakfile[60];
  
  void main(argc, argv)
     int             argc;
     char          **argv;
  {
  
     extern int      found_err;		/* flag set in diag() on error */
     int             dec_ind;		/* current indentation for
  					   declarations */
     int             di_stack[20];	/* a stack of structure
  					   indentation levels */
     int             flushed_nl;		/* used when buffering up
  					   comments to remember that a
  					   newline was passed over */
     int             force_nl;		/* when true, code must be
  					   broken */
     int             hd_type;		/* used to store type of stmt
  					   for if (...), for (...), etc */
     register int    i;			/* local loop counter */
     int             scase;		/* set to true when we see a
  					   case, so we will know what
  					   to do with the following
  					   colon */
     int             sp_sw;		/* when true, we are in the
  					   expressin of if(...),
  					   while(...), etc. */
     int             squest;		/* when this is positive, we
  					   have seen a ? without the
  					   matching : in a <c>?<s>:<s>
  					   construct */
     register char  *t_ptr;		/* used for copying tokens */
     int             type_code;		/* the type of token, returned
  					   by lexi */
  
     int             last_else = 0;	/* true iff last keyword was an
  					   else */
  
  
     /*-----------------------------------------------*\
      |		      INITIALIZATION		      |
      \*-----------------------------------------------*/
  
  
     ps.p_stack[0] = stmt;		/* this is the parser's stack */
     ps.last_nl = true;			/* this is true if the last
  					   thing scanned was a newline */
     ps.last_token = semicolon;
     combuf = (char *) malloc(bufsize);
     labbuf = (char *) malloc(bufsize);
     codebuf = (char *) malloc(bufsize);
     l_com = combuf + bufsize - 5;
     l_lab = labbuf + bufsize - 5;
     l_code = codebuf + bufsize - 5;
     combuf[0] = codebuf[0] = labbuf[0] = ' ';	/* set up code, label,
  						   and comment buffers */
     combuf[1] = codebuf[1] = labbuf[1] = '\0';
     ps.else_if = 1;			/* Default else-if special
  					   processing to on */
     s_lab = e_lab = labbuf + 1;
     s_code = e_code = codebuf + 1;
     s_com = e_com = combuf + 1;
  
     buf_ptr = buf_end = in_buffer;
     line_no = 1;
     had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
     sp_sw = force_nl = false;
     ps.in_or_st = false;
     ps.bl_line = true;
     dec_ind = 0;
     di_stack[ps.dec_nest = 0] = 0;
     ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
  
  
     scase = ps.pcase = false;
     squest = 0;
     sc_end = 0;
     bp_save = 0;
     be_save = 0;
  
     output = 0;
  
  
  
     /*--------------------------------------------------*\
      |   		COMMAND LINE SCAN		 |
      \*--------------------------------------------------*/
  
  #ifdef undef
     max_col = 78;			/* -l78 */
     lineup_to_parens = 1;		/* -lp */
     ps.ljust_decl = 0;			/* -ndj */
     ps.com_ind = 33;			/* -c33 */
     star_comment_cont = 1;		/* -sc */
     ps.ind_size = 8;			/* -i8 */
     verbose = 0;
     ps.decl_indent = 16;			/* -di16 */
     ps.indent_parameters = 1;		/* -ip */
     ps.decl_com_ind = 0;			/* if this is not set to some
  					   positive value by an arg, we
  					   will set this equal to
  					   ps.com_ind */
     btype_2 = 1;				/* -br */
     cuddle_else = 1;			/* -ce */
     ps.unindent_displace = 0;		/* -d0 */
     ps.case_indent = 0;			/* -cli0 */
     format_col1_comments = 1;		/* -fc1 */
     procnames_start_line = 1;		/* -psl */
     proc_calls_space = 0;		/* -npcs */
     comment_delimiter_on_blankline = 1;	/* -cdb */
     ps.leave_comma = 1;			/* -nbc */
  #endif
  
     for (i = 1; i < argc; ++i)
        if (strcmp(argv[i], "-npro") == 0)
  	 break;
     set_defaults();
     if (i >= argc)
        set_profile();
  
     for (i = 1; i < argc; ++i)
     {
  
        /* look thru args (if any) for changes to defaults */
        if (argv[i][0] != '-')
        {					/* no flag on parameter */
  	 if (input == 0)
  	 {				/* we must have the input file */
  	    in_name = argv[i];		/* remember name of input file */
  	    input = fopen(in_name, "r");
  	    if (input == 0)
  	    {				/* check for open error */
  	       fprintf(stderr, "indent: can't open %s\n", argv[i]);
  	       exit(1);
  	    }
  	    continue;
  	 } else if (output == 0)
  	 {				/* we have the output file */
  	    out_name = argv[i];		/* remember name of output file */
  	    if (strcmp(in_name, out_name) == 0)
  	    {				/* attempt to overwrite the
  					   file */
  	       fprintf(stderr, "indent: input and output files must be different\n");
  	       exit(1);
  	    }
  	    output = fopen(out_name, "w");
  	    if (output == 0)
  	    {				/* check for create error */
  	       fprintf(stderr, "indent: can't create %s\n", argv[i]);
  	       exit(1);
  	    }
  	    continue;
  	 }
  	 fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
  	 exit(1);
        } else
  	 set_option(argv[i]);
     }					/* end of for */
     if (input == 0)
     {
        fprintf(stderr, "indent: usage: indent file [ outfile ] [ options ]\n");
        exit(1);
     }
     if (output == 0)
        if (troff)
  	 output = stdout;
        else
        {
  	 out_name = in_name;
  	 bakcopy();
        }
     if (ps.com_ind <= 1)
        ps.com_ind = 2;			/* dont put normal comments
  					   before column 2 */
     if (troff)
     {
        if (bodyf.font[0] == 0)
  	 parsefont(&bodyf, "R");
        if (scomf.font[0] == 0)
  	 parsefont(&scomf, "I");
        if (blkcomf.font[0] == 0)
  	 blkcomf = scomf, blkcomf.size += 2;
        if (boxcomf.font[0] == 0)
  	 boxcomf = blkcomf;
        if (stringf.font[0] == 0)
  	 parsefont(&stringf, "L");
        if (keywordf.font[0] == 0)
  	 parsefont(&keywordf, "B");
        writefdef(&bodyf, 'B');
        writefdef(&scomf, 'C');
        writefdef(&blkcomf, 'L');
        writefdef(&boxcomf, 'X');
        writefdef(&stringf, 'S');
        writefdef(&keywordf, 'K');
     }
     if (bk_max_col <= 0)
        bk_max_col = max_col;
     if (ps.decl_com_ind <= 0)		/* if not specified by user,
  					   set this */
        ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
     if (continuation_indent == 0)
        continuation_indent = ps.ind_size;
     fill_buffer();			/* get first batch of stuff
  					   into input buffer */
  
     parse(semicolon);
     {
        register char  *p = buf_ptr;
        register        col = 1;
  
        while (1)
        {
  	 if (*p == ' ')
  	    col++;
  	 else if (*p == '\t')
  	    col = ((col - 1) & ~7) + 9;
  	 else
  	    break;
  	 p++;
        };
        if (col > ps.ind_size)
  	 ps.ind_level = ps.i_l_follow = col / ps.ind_size;
     }
     if (troff)
     {
        register char  *p = in_name, *beg = in_name;
  
        while (*p)
  	 if (*p++ == '/')
  	    beg = p;
        fprintf(output, ".Fn \"%s\"\n", beg);
     }
     /* START OF MAIN LOOP */
  
     while (1)
     {					/* this is the main loop.  it
  					   will go until we reach eof */
        int             is_procname;
  
        type_code = lexi();		/* lexi reads one token.  The
  					   actual characters read are
  					   stored in "token". lexi
  					   returns a code indicating
  					   the type of token */
        is_procname = ps.procname[0];
  
        /* The following code moves everything following an if (), while
           (), else, etc. up to the start of the following stmt to a
           buffer. This allows proper handling of both kinds of brace
           placement. */
  
        flushed_nl = false;
        while (ps.search_brace)
        {					/* if we scanned an if(),
  					   while(), etc., we might need
  					   to copy stuff into a buffer
  					   we must loop, copying stuff
  					   into save_com, until we find
  					   the start of the stmt which
  					   follows the if, or whatever */
  	 switch (type_code)
  	 {
  	 case newline:
  	    ++line_no;
  	    flushed_nl = true;
  	 case form_feed:
  	    break;			/* form feeds and newlines
  					   found here will be ignored */
  
  	 case lbrace:			/* this is a brace that starts
  					   the compound stmt */
  	    if (sc_end == 0)
  	    {				/* ignore buffering if a
  					   comment wasnt stored up */
  	       ps.search_brace = false;
  	       goto check_type;
  	    }
  	    if (btype_2)
  	    {
  	       save_com[0] = '{';	/* we either want to put the
  					   brace right after the if */
  	       goto sw_buffer;		/* go to common code to get out
  					   of this loop */
  	    }
  /*
   * Something is buffered up in save_com, and -bl processing is in effect.
   * Add the brace after the comment so it will come out on the next line.
   */
  	    flushed_nl = 0;	/* comment can start on the same line */
  	    *sc_end++ = '\n';	/* break line after comment */
  	    *sc_end++ = '{';
  	    goto sw_buffer;
  
  	 case comment:			/* we have a comment, so we
  					   must copy it into the buffer */
  	    if (!flushed_nl || sc_end != 0)
  	    {
  	       if (sc_end == 0)
  	       {			/* if this is the first
  					   comment, we must set up the
  					   buffer */
  		  save_com[0] = save_com[1] = ' ';
  		  sc_end = &(save_com[2]);
  	       } else
  	       {
  		  *sc_end++ = '\n';	/* add newline between comments */
  		  *sc_end++ = ' ';
  		  --line_no;
  	       }
  	       *sc_end++ = '/';		/* copy in start of comment */
  	       *sc_end++ = '*';
  
  	       for (;;)
  	       {			/* loop until we get to the end
  					   of the comment */
  		  *sc_end = *buf_ptr++;
  		  if (buf_ptr >= buf_end)
  		     fill_buffer();
  
  		  if (*sc_end++ == '*' && *buf_ptr == '/')
  		     break;		/* we are at end of comment */
  
  		  if (sc_end >= &(save_com[sc_size]))
  		  {			/* check for temp buffer
  					   overflow */
  		     diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
  		     fflush(output);
  		     exit(1);
  		  }
  	       }
  	       *sc_end++ = '/';		/* add ending slash */
  	       if (++buf_ptr >= buf_end)/* get past / in buffer */
  		  fill_buffer();
  	       break;
  	    }
  	 default:			/* it is the start of a normal
  					   statment */
  	    if (flushed_nl)		/* if we flushed a newline,
  					   make sure it is put back */
  	       force_nl = true;
  	    if ((type_code == sp_paren && *token == 'i'
  		    && last_else && ps.else_if)
  		|| (type_code == sp_nparen && *token == 'e'
  		    && e_code != s_code && e_code[-1] == '}'))
  	       force_nl = false;
  
  	    if (sc_end == 0)
  	    {				/* ignore buffering if comment
  					   wasnt saved up */
  	       ps.search_brace = false;
  	       goto check_type;
  	    }
  	    if (force_nl)
  	    {				/* if we should insert a nl
  					   here, put it into the buffer */
  	       force_nl = false;
  	       --line_no;		/* this will be re-increased
  					   when the nl is read from the
  					   buffer */
  	       *sc_end++ = '\n';
  	       *sc_end++ = ' ';
  	       if (verbose && !flushed_nl)	/* print error msg if
  						   the line was not
  						   already broken */
  		  diag(0, "Line broken");
  	       flushed_nl = false;
  	    }
  	    for (t_ptr = token; *t_ptr; ++t_ptr)
  	       *sc_end++ = *t_ptr;	/* copy token into temp buffer */
  	    ps.procname[0] = 0;
  
        sw_buffer:
  	    ps.search_brace = false;	/* stop looking for start of
  					   stmt */
  	    bp_save = buf_ptr;		/* save current input buffer */
  	    be_save = buf_end;
  	    buf_ptr = save_com;		/* fix so that subsequent calls
  					   to lexi will take tokens out
  					   of save_com */
  	    *sc_end++ = ' ';		/* add trailing blank, just in
  					   case */
  	    buf_end = sc_end;
  	    sc_end = 0;
  	    break;
  	 }				/* end of switch */
  	 if (type_code != 0)		/* we must make this check,
  					   just in case there was an
  					   unexpected EOF */
  	    type_code = lexi();		/* read another token */
  	 /* if (ps.search_brace) ps.procname[0] = 0; */
  	 if ((is_procname = ps.procname[0]) && flushed_nl
  	     && !proc_str_line && ps.in_decl
  	     && type_code == ident)
  	    flushed_nl = 0;
        }					/* end of while (search_brace) */
        last_else = 0;
  check_type:
        if (type_code == 0)
        {					/* we got eof */
  	 if (s_lab != e_lab || s_code != e_code
  	     || s_com != e_com)		/* must dump end of line */
  	    dump_line();
  	 if (ps.tos > 1)		/* check for balanced braces */
  	    diag(1, "Stuff missing from end of file.");
  
  	 if (verbose)
  	 {
  	    printf("There were %d output lines and %d comments\n",
  		   ps.out_lines, ps.out_coms);
  	    printf("(Lines with comments)/(Lines with code): %6d\n",
  		   ps.com_lines / code_lines);
  	 }
  	 fflush(output);
  	 exit(found_err);
        }
        if (
  	  (type_code != comment) &&
  	  (type_code != newline) &&
  	  (type_code != preesc) &&
  	  (type_code != form_feed))
        {
  	 if (force_nl &&
  	     (type_code != semicolon) &&
  	     (type_code != lbrace || !btype_2))
  	 {
  	    /* we should force a broken line here */
  	    if (verbose && !flushed_nl)
  	       diag(0, "Line broken");
  	    flushed_nl = false;
  	    dump_line();
  	    ps.want_blank = false;	/* dont insert blank at line
  					   start */
  	    force_nl = false;
  	 }
  	 ps.in_stmt = true;		/* turn on flag which causes an
  					   extra level of indentation.
  					   this is turned off by a ; or
  					   '}' */
  	 if (s_com != e_com)
  	 {				/* the turkey has embedded a
  					   comment in a line. fix it */
  	    *e_code++ = ' ';
  	    for (t_ptr = s_com; *t_ptr; ++t_ptr)
  	    {
  	       if (e_code >= l_code)
  	       {
  		  register        nsize = l_code - s_code + 400;
  		  codebuf = (char *) realloc(codebuf, nsize);
  		  e_code = codebuf + (e_code - s_code) + 1;
  		  l_code = codebuf + nsize - 5;
  		  s_code = codebuf + 1;
  	       }
  	       *e_code++ = *t_ptr;
  	    }
  	    *e_code++ = ' ';
  	    *e_code = '\0';		/* null terminate code sect */
  	    ps.want_blank = false;
  	    e_com = s_com;
  	 }
        } else if (type_code != comment)	/* preserve force_nl thru a
  					   comment */
  	 force_nl = false;		/* cancel forced newline after
  					   newline, form feed, etc */
  
  
  
        /*-----------------------------------------------------*\
          |	   do switch on type of token scanned		|
          \*-----------------------------------------------------*/
        if (e_code >= l_code)
        {
  	 register        nsize = l_code - s_code + 400;
  	 codebuf = (char *) realloc(codebuf, nsize);
  	 e_code = codebuf + (e_code - s_code) + 1;
  	 l_code = codebuf + nsize - 5;
  	 s_code = codebuf + 1;
        }
        switch (type_code)
        {					/* now, decide what to do with
  					   the token */
  
        case form_feed:			/* found a form feed in line */
  	 ps.use_ff = true;		/* a form feed is treated much
  					   like a newline */
  	 dump_line();
  	 ps.want_blank = false;
  	 break;
  
        case newline:
  	 if (ps.last_token != comma || ps.p_l_follow > 0
  	     || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com)
  	 {
  	    dump_line();
  	    ps.want_blank = false;
  	 }
  	 ++line_no;			/* keep track of input line
  					   number */
  	 break;
  
        case lparen:			/* got a '(' or '[' */
  	 ++ps.p_l_follow;		/* count parens to make Healy
  					   happy */
  	 if (ps.want_blank && *token != '[' &&
  	     (ps.last_token != ident || proc_calls_space
  	      || (ps.its_a_keyword && (!ps.sizeof_keyword || Bill_Shannon))))
  	    *e_code++ = ' ';
  	 if (ps.in_decl && !ps.block_init)
  	    if (troff && !ps.dumped_decl_indent && !is_procname && ps.last_token == decl)
  	    {
  	       ps.dumped_decl_indent = 1;
  	       sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
  	       e_code += strlen(e_code);
  	    } else
  	    {
  	       while ((e_code - s_code) < dec_ind)
  	       {
  		  if (e_code >= l_code)
  		  {
  		     register        nsize = l_code - s_code + 400;
  		     codebuf = (char *) realloc(codebuf, nsize);
  		     e_code = codebuf + (e_code - s_code) + 1;
  		     l_code = codebuf + nsize - 5;
  		     s_code = codebuf + 1;
  		  }
  		  *e_code++ = ' ';
  	       }
  	       *e_code++ = token[0];
  	    }
  	 else
  	    *e_code++ = token[0];
  	 ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code;
  	 if (sp_sw && ps.p_l_follow == 1 && ex_expr_indent
  	     && ps.paren_indents[0] < 2 * ps.ind_size)
  	    ps.paren_indents[0] = 2 * ps.ind_size;
  	 ps.want_blank = false;
  	 if (ps.in_or_st && *token == '(' && ps.tos <= 2)
  	 {
  	    /* this is a kluge to make sure that declarations will be
  	       aligned right if proc decl has an explicit type on it,
  	       i.e. "int a(x) {..." */
  	    parse(semicolon);		/* I said this was a kluge... */
  	    ps.in_or_st = false;	/* turn off flag for structure
  					   decl or initialization */
  	 }
  	 if (ps.sizeof_keyword)
  	    ps.sizeof_mask |= 1 << ps.p_l_follow;
  	 break;
  
        case rparen:			/* got a ')' or ']' */
  	 if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask)
  	 {
  	    ps.last_u_d = true;
  	    ps.cast_mask &= (1 << ps.p_l_follow) - 1;
  	 }
  	 ps.sizeof_mask &= (1 << ps.p_l_follow) - 1;
  	 if (--ps.p_l_follow < 0)
  	 {
  	    ps.p_l_follow = 0;
  	    diag(0, "Extra %c", *token);
  	 }
  	 if (e_code == s_code)		/* if the paren starts the line */
  	    ps.paren_level = ps.p_l_follow;	/* then indent it */
  
  	 *e_code++ = token[0];
  	 ps.want_blank = true;
  
  	 if (sp_sw && (ps.p_l_follow == 0))
  	 {				/* check for end of if (...),
  					   or some such */
  	    sp_sw = false;
  	    force_nl = true;		/* must force newline after if */
  	    ps.last_u_d = true;		/* inform lexi that a following
  					   operator is unary */
  	    ps.in_stmt = false;		/* dont use stmt continuation
  					   indentation */
  
  	    parse(hd_type);		/* let parser worry about if,
  					   or whatever */
  	 }
  	 ps.search_brace = btype_2;	/* this should insure that
  					   constructs such as
  					   main(){...} and int[]{...}
  					   have their braces put in the
  					   right place */
  	 break;
  
        case unary_op:			/* this could be any unary
  					   operation */
  	 if (ps.want_blank)
  	    *e_code++ = ' ';
  
  	 if (troff && !ps.dumped_decl_indent && ps.in_decl && !is_procname)
  	 {
  	    sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
  	    ps.dumped_decl_indent = 1;
  	    e_code += strlen(e_code);
  	 } else
  	 {
  	    char           *res = token;
  
  	    if (ps.in_decl && !ps.block_init)
  	    {				/* if this is a unary op in a
  					   declaration, we should
  					   indent this token */
  	       for (i = 0; token[i]; ++i);	/* find length of token */
  	       while ((e_code - s_code) < (dec_ind - i))
  	       {
  		  if (e_code >= l_code)
  		  {
  		     register        nsize = l_code - s_code + 400;
  		     codebuf = (char *) realloc(codebuf, nsize);
  		     e_code = codebuf + (e_code - s_code) + 1;
  		     l_code = codebuf + nsize - 5;
  		     s_code = codebuf + 1;
  		  }
  		  *e_code++ = ' ';	/* pad it */
  	       }
  	    }
  	    if (troff && token[0] == '-' && token[1] == '>')
  	       res = "\\(->";
  	    for (t_ptr = res; *t_ptr; ++t_ptr)
  	    {
  	       if (e_code >= l_code)
  	       {
  		  register        nsize = l_code - s_code + 400;
  		  codebuf = (char *) realloc(codebuf, nsize);
  		  e_code = codebuf + (e_code - s_code) + 1;
  		  l_code = codebuf + nsize - 5;
  		  s_code = codebuf + 1;
  	       }
  	       *e_code++ = *t_ptr;
  	    }
  	 }
  	 ps.want_blank = false;
  	 break;
  
        case binary_op:			/* any binary operation */
  	 if (ps.want_blank)
  	    *e_code++ = ' ';
  	 {
  	    char           *res = token;
  
  	    if (troff)
  	       switch (token[0])
  	       {
  	       case '<':
  		  if (token[1] == '=')
  		     res = "\\(<=";
  		  break;
  	       case '>':
  		  if (token[1] == '=')
  		     res = "\\(>=";
  		  break;
  	       case '!':
  		  if (token[1] == '=')
  		     res = "\\(!=";
  		  break;
  	       case '|':
  		  if (token[1] == '|')
  		     res = "\\(br\\(br";
  		  else if (token[1] == 0)
  		     res = "\\(br";
  		  break;
  	       }
  	    for (t_ptr = res; *t_ptr; ++t_ptr)
  	    {
  	       if (e_code >= l_code)
  	       {
  		  register        nsize = l_code - s_code + 400;
  		  codebuf = (char *) realloc(codebuf, nsize);
  		  e_code = codebuf + (e_code - s_code) + 1;
  		  l_code = codebuf + nsize - 5;
  		  s_code = codebuf + 1;
  	       }
  	       *e_code++ = *t_ptr;	/* move the operator */
  	    }
  	 }
  	 ps.want_blank = true;
  	 break;
  
        case postop:			/* got a trailing ++ or -- */
  	 *e_code++ = token[0];
  	 *e_code++ = token[1];
  	 ps.want_blank = true;
  	 break;
  
        case question:			/* got a ? */
  	 squest++;			/* this will be used when a
  					   later colon appears so we
  					   can distinguish the
  					   <c>?<n>:<n> construct */
  	 if (ps.want_blank)
  	    *e_code++ = ' ';
  	 *e_code++ = '?';
  	 ps.want_blank = true;
  	 break;
  
        case casestmt:			/* got word 'case' or 'default' */
  	 scase = true;			/* so we can process the later
  					   colon properly */
  	 goto copy_id;
  
        case colon:			/* got a ':' */
  	 if (squest > 0)
  	 {				/* it is part of the <c>?<n>:
  					   <n> construct */
  	    --squest;
  	    if (ps.want_blank)
  	       *e_code++ = ' ';
  	    *e_code++ = ':';
  	    ps.want_blank = true;
  	    break;
  	 }
  	 if (ps.in_decl)
  	 {
  	    *e_code++ = ':';
  	    ps.want_blank = false;
  	    break;
  	 }
  	 ps.in_stmt = false;		/* seeing a label does not
  					   imply we are in a stmt */
  	 for (t_ptr = s_code; *t_ptr; ++t_ptr)
  	    *e_lab++ = *t_ptr;		/* turn everything so far into
  					   a label */
  	 e_code = s_code;
  	 *e_lab++ = ':';
  	 *e_lab++ = ' ';
  	 *e_lab = '\0';
  
  	 force_nl = ps.pcase = scase;	/* ps.pcase will be used by
  					   dump_line to decide how to
  					   indent the label. force_nl
  					   will force a case n: to be
  					   on a line by itself */
  	 scase = false;
  	 ps.want_blank = false;
  	 break;
  
        case semicolon:			/* got a ';' */
  	 ps.in_or_st = false;		/* we are not in an
  					   initialization or structure
  					   declaration */
  	 scase = false;			/* these will only need
  					   resetting in a error */
  	 squest = 0;
  	 if (ps.last_token == rparen)
  	    ps.in_par_decl = 0;
  	 ps.cast_mask = 0;
  	 ps.sizeof_mask = 0;
  	 ps.block_init = 0;
  	 ps.block_init_level = 0;
  	 ps.just_saw_decl--;
  
  	 if (ps.in_decl && s_code == e_code && !ps.block_init)
  	    while ((e_code - s_code) < (dec_ind - 1))
  	    {
  	       if (e_code >= l_code)
  	       {
  		  register        nsize = l_code - s_code + 400;
  		  codebuf = (char *) realloc(codebuf, nsize);
  		  e_code = codebuf + (e_code - s_code) + 1;
  		  l_code = codebuf + nsize - 5;
  		  s_code = codebuf + 1;
  	       }
  	       *e_code++ = ' ';
  	    }
  
  	 ps.in_decl = (ps.dec_nest > 0);/* if we were in a first level
  					   structure declaration, we
  					   arent any more */
  
  	 if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0)
  	 {
  
  	    /* This should be true iff there were unbalanced parens in
  	       the stmt.  It is a bit complicated, because the
  	       semicolon might be in a for stmt */
  	    diag(1, "Unbalanced parens");
  	    ps.p_l_follow = 0;
  	    if (sp_sw)
  	    {				/* this is a check for a if,
  					   while, etc. with unbalanced
  					   parens */
  	       sp_sw = false;
  	       parse(hd_type);		/* dont lose the if, or
  					   whatever */
  	    }
  	 }
  	 *e_code++ = ';';
  	 ps.want_blank = true;
  	 ps.in_stmt = (ps.p_l_follow > 0);	/* we are no longer in
  						   the middle of a stmt */
  
  	 if (!sp_sw)
  	 {				/* if not if for (;;) */
  	    parse(semicolon);		/* let parser know about end of
  					   stmt */
  	    force_nl = true;		/* force newline after a end of
  					   stmt */
  	 }
  	 break;
  
        case lbrace:			/* got a '{' */
  	 ps.in_stmt = false;		/* dont indent the {} */
  	 if (!ps.block_init)
  	    force_nl = true;		/* force other stuff on same
  					   line as '{' onto new line */
  	 else if (ps.block_init_level <= 0)
  	    ps.block_init_level = 1;
  	 else
  	    ps.block_init_level++;
  
  	 if (s_code != e_code && !ps.block_init)
  	 {
  	    if (!btype_2)
  	    {
  	       dump_line();
  	       ps.want_blank = false;
  	    } else if (ps.in_par_decl && !ps.in_or_st)
  	    {
  	       ps.i_l_follow = 0;
  	       dump_line();
  	       ps.want_blank = false;
  	    }
  	 }
  	 if (ps.in_par_decl)
  	    prefix_blankline_requested = 0;
  
  	 if (ps.p_l_follow > 0)
  	 {				/* check for preceeding
  					   unbalanced parens */
  	    diag(1, "Unbalanced parens");
  	    ps.p_l_follow = 0;
  	    if (sp_sw)
  	    {				/* check for unclosed if, for,
  					   etc. */
  	       sp_sw = false;
  	       parse(hd_type);
  	       ps.ind_level = ps.i_l_follow;
  	    }
  	 }
  	 if (s_code == e_code)
  	    ps.ind_stmt = false;	/* dont put extra indentation
  					   on line with '{' */
  	 if (ps.in_decl && ps.in_or_st)
  	 {				/* this is either a structure
  					   declaration or an init */
  	    di_stack[ps.dec_nest++] = dec_ind;
  	    /* ?		dec_ind = 0; */
  	 } else
  	 {
  	    ps.decl_on_line = false;	/* we cant be in the middle of
  					   a declaration, so dont do
  					   special indentation of
  					   comments */
  	    if (bl_at_proctop
  		&& ps.in_par_decl)
  	       postfix_blankline_requested = 1;
  	    ps.in_par_decl = 0;
  	 }
  	 dec_ind = 0;
  	 parse(lbrace);			/* let parser know about this */
  	 if (ps.want_blank)		/* put a blank before '{' if
  					   '{' is not at start of line */
  	    *e_code++ = ' ';
  	 ps.want_blank = false;
  	 *e_code++ = '{';
  	 ps.just_saw_decl = 0;
  	 break;
  
        case rbrace:			/* got a '}' */
  	 if (ps.p_stack[ps.tos] == decl && !ps.block_init)	/* semicolons can be
  								   omitted in
  								   declarations */
  	    parse(semicolon);
  	 if (ps.p_l_follow)
  	 {				/* check for unclosed if, for,
  					   else. */
  	    diag(1, "Unbalanced parens");
  	    ps.p_l_follow = 0;
  	    sp_sw = false;
  	 }
  	 ps.just_saw_decl = 0;
  	 ps.block_init_level--;
  	 if (s_code != e_code && !ps.block_init)
  	 {				/* '}' must be first on line */
  	    if (verbose)
  	       diag(0, "Line broken");
  	    dump_line();
  	 }
  	 *e_code++ = '}';
  	 ps.want_blank = true;
  	 ps.in_stmt = ps.ind_stmt = false;
  	 if (ps.dec_nest > 0)
  	 {				/* we are in multi-level
  					   structure declaration */
  	    dec_ind = di_stack[--ps.dec_nest];
  	    if (ps.dec_nest == 0 && !ps.in_par_decl)
  	       ps.just_saw_decl = 2;
  	    ps.in_decl = true;
  	 }
  	 prefix_blankline_requested = 0;
  	 parse(rbrace);			/* let parser know about this */
  	 ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead
  	    && ps.il[ps.tos] >= ps.ind_level;
  	 if (ps.tos <= 1 && bl_a_procs && ps.dec_nest <= 0)
  	    postfix_blankline_requested = 1;
  	 break;
  
        case swstmt:			/* got keyword "switch" */
  	 sp_sw = true;
  	 hd_type = swstmt;		/* keep this for when we have
  					   seen the expression */
  	 goto copy_id;			/* go move the token into
  					   buffer */
  
        case sp_paren:			/* token is if, while, for */
  	 sp_sw = true;			/* the interesting stuff is
  					   done after the expression is
  					   scanned */
  	 hd_type = (*token == 'i' ? ifstmt :
  		    (*token == 'w' ? whilestmt : forstmt));
  
  	 /* remember the type of header for later use by parser */
  	 goto copy_id;			/* copy the token into line */
  
        case sp_nparen:			/* got else, do */
  	 ps.in_stmt = false;
  	 if (*token == 'e')
  	 {
  	    if (e_code != s_code && (!cuddle_else || e_code[-1] != '}'))
  	    {
  	       if (verbose)
  		  diag(0, "Line broken");
  	       dump_line();		/* make sure this starts a line */
  	       ps.want_blank = false;
  	    }
  	    force_nl = true;		/* also, following stuff must
  					   go onto new line */
  	    last_else = 1;
  	    parse(elselit);
  	 } else
  	 {
  	    if (e_code != s_code)
  	    {				/* make sure this starts a line */
  	       if (verbose)
  		  diag(0, "Line broken");
  	       dump_line();
  	       ps.want_blank = false;
  	    }
  	    force_nl = true;		/* also, following stuff must
  					   go onto new line */
  	    last_else = 0;
  	    parse(dolit);
  	 }
  	 goto copy_id;			/* move the token into line */
  
        case decl:			/* we have a declaration type
  					   (int, register, etc.) */
  	 parse(decl);			/* let parser worry about
  					   indentation */
  	 if (ps.last_token == rparen && ps.tos <= 1)
  	 {
  	    ps.in_par_decl = 1;
  	    if (s_code != e_code)
  	    {
  	       dump_line();
  	       ps.want_blank = 0;
  	    }
  	 }
  	 if (ps.in_par_decl && ps.indent_parameters && ps.dec_nest == 0)
  	 {
  	    ps.ind_level = ps.i_l_follow = 1;
  	    ps.ind_stmt = 0;
  	 }
  	 ps.in_or_st = true;		/* this might be a structure or
  					   initialization declaration */
  	 ps.in_decl = ps.decl_on_line = true;
  	 if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
  	    ps.just_saw_decl = 2;
  	 prefix_blankline_requested = 0;
  	 for (i = 0; token[i++];);	/* get length of token */
  
  	 /* dec_ind = e_code - s_code + (ps.decl_indent>i ?
  	    ps.decl_indent : i); */
  	 dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
  	 goto copy_id;
  
        case ident:			/* got an identifier or
  					   constant */
  	 if (ps.in_decl)
  	 {				/* if we are in a declaration,
  					   we must indent identifier */
  	    if (ps.want_blank)
  	       *e_code++ = ' ';
  	    ps.want_blank = false;
  	    if (is_procname == 0 || !proc_str_line)
  	    {
  	       if (!ps.block_init)
  		  if (troff && !ps.dumped_decl_indent)
  		  {
  		     sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
  		     ps.dumped_decl_indent = 1;
  		     e_code += strlen(e_code);
  		  } else
  		     while ((e_code - s_code) < dec_ind)
  		     {
  			if (e_code >= l_code)
  			{
  			   register        nsize = l_code - s_code + 400;
  			   codebuf = (char *) realloc(codebuf, nsize);
  			   e_code = codebuf + (e_code - s_code) + 1;
  			   l_code = codebuf + nsize - 5;
  			   s_code = codebuf + 1;
  			}
  			*e_code++ = ' ';
  		     }
  	    } else
  	    {
  	       if (dec_ind && s_code != e_code)
  		  dump_line();
  	       dec_ind = 0;
  	       ps.want_blank = false;
  	    }
  	 } else if (sp_sw && ps.p_l_follow == 0)
  	 {
  	    sp_sw = false;
  	    force_nl = true;
  	    ps.last_u_d = true;
  	    ps.in_stmt = false;
  	    parse(hd_type);
  	 }
     copy_id:
  	 if (ps.want_blank)
  	    *e_code++ = ' ';
  	 if (troff && ps.its_a_keyword)
  	 {
  	    e_code = chfont(&bodyf, &keywordf, e_code);
  	    for (t_ptr = token; *t_ptr; ++t_ptr)
  	    {
  	       if (e_code >= l_code)
  	       {
  		  register        nsize = l_code - s_code + 400;
  		  codebuf = (char *) realloc(codebuf, nsize);
  		  e_code = codebuf + (e_code - s_code) + 1;
  		  l_code = codebuf + nsize - 5;
  		  s_code = codebuf + 1;
  	       }
  	       *e_code++ = keywordf.allcaps && islower(*t_ptr)
  		  ? toupper(*t_ptr) : *t_ptr;
  	    }
  	    e_code = chfont(&keywordf, &bodyf, e_code);
  	 } else
  	    for (t_ptr = token; *t_ptr; ++t_ptr)
  	    {
  	       if (e_code >= l_code)
  	       {
  		  register        nsize = l_code - s_code + 400;
  		  codebuf = (char *) realloc(codebuf, nsize);
  		  e_code = codebuf + (e_code - s_code) + 1;
  		  l_code = codebuf + nsize - 5;
  		  s_code = codebuf + 1;
  	       }
  	       *e_code++ = *t_ptr;
  	    }
  	 ps.want_blank = true;
  	 break;
  
        case period:			/* treat a period kind of like
  					   a binary operation */
  	 *e_code++ = '.';		/* move the period into line */
  	 ps.want_blank = false;		/* dont put a blank after a
  					   period */
  	 break;
  
        case comma:
  	 ps.want_blank = (s_code != e_code);	/* only put blank after
  						   comma if comma does
  						   not start the line */
  	 if (ps.in_decl && is_procname == 0 && !ps.block_init)
  	    while ((e_code - s_code) < (dec_ind - 1))
  	    {
  	       if (e_code >= l_code)
  	       {
  		  register        nsize = l_code - s_code + 400;
  		  codebuf = (char *) realloc(codebuf, nsize);
  		  e_code = codebuf + (e_code - s_code) + 1;
  		  l_code = codebuf + nsize - 5;
  		  s_code = codebuf + 1;
  	       }
  	       *e_code++ = ' ';
  	    }
  
  	 *e_code++ = ',';
  	 if (ps.p_l_follow == 0)
  	 {
  	    if (ps.block_init_level <= 0)
  	       ps.block_init = 0;
  	    if (break_comma && !ps.leave_comma)
  	       force_nl = true;
  	 }
  	 break;
  
        case preesc:			/* got the character '#' */
  	 if ((s_com != e_com) ||
  	     (s_lab != e_lab) ||
  	     (s_code != e_code))
  	    dump_line();
  	 *e_lab++ = '#';		/* move whole line to 'label'
  					   buffer */
  	 {
  	    int             in_comment = 0;
  	    int             com_start = 0;
  	    char            quote = 0;
  	    int             com_end = 0;
  
  	    while (*buf_ptr != '\n' || in_comment)
  	    {
  	       if (e_lab >= l_lab)
  	       {
  		  register        nsize = l_lab - s_lab + 400;
  		  labbuf = (char *) realloc(labbuf, nsize);
  		  e_lab = labbuf + (e_lab - s_lab) + 1;
  		  l_lab = labbuf + nsize - 5;
  		  s_lab = labbuf + 1;
  	       }
  	       *e_lab = *buf_ptr++;
  	       if (buf_ptr >= buf_end)
  		  fill_buffer();
  	       switch (*e_lab++)
  	       {
  	       case BACKSLASH:
  		  if (troff)
  		     *e_lab++ = BACKSLASH;
  		  if (!in_comment)
  		  {
  		     *e_lab++ = *buf_ptr++;
  		     if (buf_ptr >= buf_end)
  			fill_buffer();
  		  }
  		  break;
  	       case '/':
  		  if (*buf_ptr == '*' && !in_comment && !quote)
  		  {
  		     in_comment = 1;
  		     *e_lab++ = *buf_ptr++;
  		     com_start = e_lab - s_lab - 2;
  		  }
  		  break;
  	       case '"':
  		  if (quote == '"')
  		     quote = 0;
  		  break;
  	       case '\'':
  		  if (quote == '\'')
  		     quote = 0;
  		  break;
  	       case '*':
  		  if (*buf_ptr == '/' && in_comment)
  		  {
  		     in_comment = 0;
  		     *e_lab++ = *buf_ptr++;
  		     com_end = e_lab - s_lab;
  		  }
  		  break;
  	       }
  	    }
  
  	    while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  	       e_lab--;
  	    if (e_lab - s_lab == com_end && bp_save == 0)
  	    {				/* comment on preprocessor line */
  	       if (sc_end == 0)		/* if this is the first
  					   comment, we must set up the
  					   buffer */
  		  sc_end = &(save_com[0]);
  	       else
  	       {
  		  *sc_end++ = '\n';	/* add newline between comments */
  		  *sc_end++ = ' ';
  		  --line_no;
  	       }
  	       memcpy(sc_end, s_lab + com_start, com_end - com_start);
  	       sc_end += com_end - com_start;
  	       if (sc_end >= &save_com[sc_size])
  		  abort();
  	       e_lab = s_lab + com_start;
  	       while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  		  e_lab--;
  	       bp_save = buf_ptr;	/* save current input buffer */
  	       be_save = buf_end;
  	       buf_ptr = save_com;	/* fix so that subsequent calls
  					   to lexi will take tokens out
  					   of save_com */
  	       *sc_end++ = ' ';		/* add trailing blank, just in
  					   case */
  	       buf_end = sc_end;
  	       sc_end = 0;
  	    }
  	    *e_lab = '\0';		/* null terminate line */
  	    ps.pcase = false;
  	 }
  
  	 if (strncmp(s_lab, "#if", 3) == 0)
  	 {
  	    if (bl_around)
  	    {
  	       register        c;
  	       prefix_blankline_requested++;
  	       while ((c = getc(input)) == '\n');
  	       ungetc(c, input);
  	    }
  	    if (ifdef_level < sizeof state_stack / sizeof state_stack[0])
  	    {
  	       match_state[ifdef_level].tos = -1;
  	       state_stack[ifdef_level++] = ps;
  	    } else
  	       diag(1, "#if stack overflow");
  	 } else if (strncmp(s_lab, "#else", 5) == 0)
  	    if (ifdef_level <= 0)
  	       diag(1, "Unmatched #else");
  	    else
  	    {
  	       match_state[ifdef_level - 1] = ps;
  	       ps = state_stack[ifdef_level - 1];
  	    }
  	 else if (strncmp(s_lab, "#endif", 6) == 0)
  	 {
  	    if (ifdef_level <= 0)
  	       diag(1, "Unmatched #endif");
  	    else
  	    {
  	       ifdef_level--;
  
  #ifdef undef
  	       /* This match needs to be more intelligent before the
  	          message is useful */
  	       if (match_state[ifdef_level].tos >= 0
  		   && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
  		  diag(0, "Syntactically inconsistant #ifdef alternatives.");
  #endif
  	    }
  	    if (bl_around)
  	    {
  	       postfix_blankline_requested++;
  	       n_real_blanklines = 0;
  	    }
  	 }
  	 break;				/* subsequent processing of the
  					   newline character will cause
  					   the line to be printed */
  
        case comment:			/* we have gotten a / *  this is
  					   a biggie */
  	 if (flushed_nl)
  	 {				/* we should force a broken
  					   line here */
  	    flushed_nl = false;
  	    dump_line();
  	    ps.want_blank = false;	/* dont insert blank at line
  					   start */
  	    force_nl = false;
  	 }
  	 pr_comment();
  	 break;
        }					/* end of big switch stmt */
  
        *e_code = '\0';			/* make sure code section is
  					   null terminated */
        if (type_code != comment && type_code != newline && type_code != preesc)
  	 ps.last_token = type_code;
     }					/* end of main while (1) loop */
  }
  
  /*
   * copy input file to backup file if in_name is /blah/blah/blah/file, then
   * backup file will be ".Bfile" then make the backup file the input and
   * original input file the output
   */
  void bakcopy()
  {
     int             n, bakchn;
     char            buff[8 * 1024];
     register char  *p;
  
     /* construct file name .Bfile */
     for (p = in_name; *p; p++);		/* skip to end of string */
     while (p > in_name && *p != '/')	/* find last '/' */
        p--;
     if (*p == '/')
        p++;
     sprintf(bakfile, "%s.BAK", p);
     if (strlen(p) >= NAME_SIZE) *bakfile ^= 040;	/* toggle char */
  
     /* copy in_name to backup file */
     bakchn = creat(bakfile, 0600);
     if (bakchn < 0)
     {
        fprintf(stderr, "indent: can't create backup file \"%s\"\n", bakfile);
        exit(1);
     }
     while (n = read(fileno(input), buff, sizeof buff))
        if (write(bakchn, buff, n) != n)
        {
  	 fprintf(stderr, "indent: error writing backup file \"%s\"\n",
  		 bakfile);
  	 exit(1);
        }
     if (n < 0)
     {
        fprintf(stderr, "indent: error reading input file \"%s\"\n", in_name);
        exit(1);
     }
     close(bakchn);
     fclose(input);
  
     /* re-open backup file as the input file */
     input = fopen(bakfile, "r");
     if (input == 0)
     {
        fprintf(stderr, "indent: can't re-open backup file\n");
        exit(1);
     }
     /* now the original input file will be the output */
     output = fopen(in_name, "w");
     if (output == 0)
     {
        fprintf(stderr, "indent: can't create %s\n", in_name);
        unlink(bakfile);
        exit(1);
     }
  }
  