[comp.os.minix] INDENT

hall@cod.NOSC.MIL (Robert R. Hall) (03/25/89)

Some time back I saw a request to the net, asking for a prettyprint
formating program.  A reply stated that INDENT source code existed
in comp.unix.source and the requestor could port it to MINIX.  Well
here is the INDENT port to MINIX.

Rename the file 'indent.pro' to '.indent.pro' and put it in the
directory refecenced by $HOME.  On the MINIX distrubtion disks
this directory was /usr/ast but on my system I rename it.  '.indent.pro'
maybe edited to set you preferences. As for documentation I am reading
the man pages from a UNIX system to learn this myself :-)

---------------------   cut here ---------------
echo x - manifest
sed '/^X/s///' > manifest << '/'
X49235   8176 indent/args.c
X38365   1688 indent/codes.h
X33572  13083 indent/comment.c
X60203  11917 indent/globs.h
X19811  26348 indent/indent
X41777  38309 indent/indent.c
X21387     46 indent/indent.pro
X47849  15307 indent/io.c
X29448  14398 indent/lexi.c
X09668    175 indent/makefile
X58464   8670 indent/parse.c
/
echo x - makefile
sed '/^X/s///' > makefile << '/'
X#	makefile for the 'indent' command
X
XCFLAGS = -i -F
X
XOBJS = indent.s io.s lexi.s parse.s comment.s args.s
X
Xindent: ${OBJS}
X	$(CC) -o indent ${OBJS}
X
X$(OBJS): globs.h codes.h
X
/
echo x - indent.pro
sed '/^X/s///' > indent.pro << '/'
X-bl -c41 -cd41 -l72 -i3 -bap -ncdb -nfc1 -nsc
/
echo x - codes.h
sed '/^X/s///' > codes.h << '/'
X/*
X * Copyright (c) 1985 Sun Microsystems, Inc.
X * Copyright (c) 1980 The Regents of the University of California.
X * Copyright (c) 1976 Board of Trustees of the University of Illinois.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley, the University of Illinois,
X * Urbana, and Sun Microsystems, Inc.  The name of either University
X * or Sun Microsystems may not be used to endorse or promote products
X * derived from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	@(#)indent_codes.h	5.6 (Berkeley) 9/15/88
X */
X
X#define newline		1
X#define lparen		2
X#define rparen		3
X#define unary_op	4
X#define binary_op	5
X#define postop		6
X#define question	7
X#define casestmt	8
X#define colon		9
X#define semicolon	10
X#define lbrace		11
X#define rbrace		12
X#define ident		13
X#define comma		14
X#define comment		15
X#define swstmt		16
X#define preesc		17
X#define form_feed	18
X#define decl		19
X#define sp_paren	20
X#define sp_nparen	21
X#define ifstmt		22
X#define whilestmt	23
X#define forstmt		24
X#define stmt		25
X#define stmtl		26
X#define elselit		27
X#define dolit		28
X#define dohead		29
X#define ifhead		30
X#define elsehead	31
X#define period		32
/
echo x - globs.h
sed '/^X/s///' > globs.h << '/'
X/*
X * Copyright (c) 1985 Sun Microsystems, Inc.
X * Copyright (c) 1980 The Regents of the University of California.
X * Copyright (c) 1976 Board of Trustees of the University of Illinois.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley, the University of Illinois,
X * Urbana, and Sun Microsystems, Inc.  The name of either University
X * or Sun Microsystems may not be used to endorse or promote products
X * derived from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	@(#)indent_globs.h	5.7 (Berkeley) 9/15/88
X */
X
X#include <stdio.h>
X
X#define BACKSLASH '\\'
X#define bufsize 200			/* size of internal buffers */
X#define inp_bufs 600			/* size of input buffer */
X#define sc_size 5000			/* size of save_com buffer */
X#define label_offset 2			/* number of levels a label is
X					   placed to left of code */
X
X#define tabsize 8			/* the size of a tab */
X#define tabmask 0177770			/* mask used when figuring
X					   length of lines with tabs */
X
X
X#define false 0
X#define true  !false
X
X
XPUBLIC FILE    *input;			/* the fid for the input file */
XPUBLIC FILE    *output;			/* the output file */
X
XPUBLIC char    *labbuf;			/* buffer for label */
XPUBLIC char    *s_lab;			/* start ... */
XPUBLIC char    *e_lab;			/* .. and end of stored label */
XPUBLIC char    *l_lab;			/* limit of label buffer */
X
XPUBLIC char    *codebuf;		/* buffer for code section */
XPUBLIC char    *s_code;			/* start ... */
XPUBLIC char    *e_code;			/* .. and end of stored code */
XPUBLIC char    *l_code;			/* limit of code section */
X
XPUBLIC char    *combuf;			/* buffer for comments */
XPUBLIC char    *s_com;			/* start ... */
XPUBLIC char    *e_com;			/* ... and end of stored
X					   comments */
XPUBLIC char    *l_com;			/* limit of comment buffer */
X
XPUBLIC char     in_buffer[inp_bufs];	/* input buffer */
XPUBLIC char    *buf_ptr;		/* ptr to next character to be
X					   taken from in_buffer */
XPUBLIC char    *buf_end;		/* ptr to first after last char
X					   in in_buffer */
X
XPUBLIC char     save_com[sc_size];	/* input text is saved here
X					   when looking for the brace
X					   after an if, while, etc */
XPUBLIC char    *sc_end;			/* pointer into save_com buffer */
X
XPUBLIC char    *bp_save;		/* saved value of buf_ptr when
X					   taking input from save_com */
XPUBLIC char    *be_save;		/* similarly saved value of
X					   buf_end */
X
XPUBLIC char     token[bufsize];		/* the last token scanned */
X
X
XPUBLIC int      ptr_binop;		/* pointer as binop */
XPUBLIC int      bl_aft_decl;		/* blanklines after
X					   declarations */
XPUBLIC int      bl_bef_bk;		/* blanklines before
X					   blockcomments */
XPUBLIC int      bl_a_procs;		/* blanklines after procs */
XPUBLIC int      bl_around;		/* blanklines around
X					   conditional compilation */
XPUBLIC int      swallow_opt_bl;		/* swallow optional blanklines */
XPUBLIC int      n_real_blanklines;
XPUBLIC int      prefix_blankline_requested;
XPUBLIC int      postfix_blankline_requested;
XPUBLIC int      break_comma;		/* when true and not in parens,
X					   break after a comma */
XPUBLIC int      btype_2;		/* when true, brace should be
X					   on same line as if, while,
X					   etc */
XPUBLIC long     case_ind;		/* indentation level to be used
X					   for a "case n:" */
XPUBLIC int      code_lines;		/* count of lines with code */
XPUBLIC int      had_eof;		/* set to true when input is
X					   exhausted */
XPUBLIC int      line_no;		/* the current line number. */
XPUBLIC int      max_col;		/* the maximum allowable line
X					   length */
XPUBLIC int      verbose;		/* when true, non-essential
X					   error messages are printed */
XPUBLIC int      cuddle_else;		/* true if else should cuddle
X					   up to '}' */
XPUBLIC int      star_comment_cont;	/* true iff comment
X					   continuation lines should
X					   have stars at the beginning
X					   of each line. */
XPUBLIC int      del_on_bl;		/* comment_delimiter_on_blanklin
X					   e */
XPUBLIC int      troff;			/* true iff were generating
X					   troff input */
XPUBLIC int      proc_str_line;		/* if true, the names of
X					   procedures being defined get
X					   placed in column 1 (ie. a
X					   newline is placed between
X					   the type of the procedure
X					   and its name) */
XPUBLIC int      proc_calls_space;	/* If true, procedure calls
X					   look like: foo(bar) rather
X					   than foo (bar) */
XPUBLIC int      format_col1_comments;	/* If comments which start in
X					   column 1 are to be magically
X					   reformatted (just like
X					   comments that begin in later
X					   columns) */
XPUBLIC int      inhibit_formatting;	/* true if INDENT OFF is in
X					   effect */
XPUBLIC int      suppress_blanklines;	/* set iff following blanklines
X					   should be suppressed */
XPUBLIC int      continuation_indent;	/* set to the indentation
X					   between the edge of code and
X					   continuation lines */
XPUBLIC int      lineup_to_parens;	/* if true, continued code
X					   within parens will be lined
X					   up to the open paren */
XPUBLIC int      Bill_Shannon;		/* true iff a blank should
X					   always be inserted after
X					   sizeof */
XPUBLIC int      bl_at_proctop;		/* This is vaguely similar to
X					   blanklines_after_declarations
X					   except that it only applies
X					   to the first set of
X					   declarations in a procedure
X					   (just after the first '{')
X					   and it causes a blank line
X					   to be generated even if
X					   there are no declarations */
XPUBLIC int      bk_max_col;
XPUBLIC int      ex_expr_indent;		/* True if continuation lines
X					   from the expression part of
X					   "if(e)", "while(e)",
X					   "for(e;e;e)" should be
X					   indented an extra tab stop
X					   so that they don't conflict
X					   with the code that follows */
X
X/* -troff font state information */
X
Xstruct fstate
X{
X   char            font[4];
X   char            size;
X   int             allcaps;
X};
Xchar           *chfont();
X
XPUBLIC struct fstate
X                keywordf,		/* keyword font */
X                stringf,		/* string font */
X                boxcomf,		/* Box comment font */
X                blkcomf,		/* Block comment font */
X                scomf,			/* Same line comment font */
X                bodyf;			/* major body font */
X
X
X#define STACKSIZE 150
X
XPUBLIC struct parser_state
X{
X   int             last_token;
X   struct fstate   cfont;		/* Current font */
X   int             p_stack[STACKSIZE];	/* this is the parsers stack */
X   int             il[STACKSIZE];	/* this stack stores
X					   indentation levels */
X   long            cstk[STACKSIZE];	/* used to store case stmt
X					   indentation levels */
X   int             box_com;		/* set to true when we are in a
X					   "boxed" comment. In that
X					   case, the first non-blank
X					   char should be lined up with
X					   the / in /* */
X   int             comment_delta, n_comment_delta;
X   int             cast_mask;		/* indicates which close parens
X					   close off casts */
X   int             sizeof_mask;		/* indicates which close parens
X					   close off sizeof''s */
X   int             block_init;		/* true iff inside a block
X					   initialization */
X   int             block_init_level;	/* The level of brace nesting
X					   in an initialization */
X   int             last_nl;		/* this is true if the last
X					   thing scanned was a newline */
X   int             in_or_st;		/* Will be true iff there has
X					   been a declarator (e.g. int
X					   or char) and no left paren
X					   since the last semicolon.
X					   When true, a '{' is starting
X					   a structure definition or an
X					   initialization list */
X   int             bl_line;		/* set to 1 by dump_line if the
X					   line is blank */
X   int             col_1;		/* set to true if the last
X					   token started in column 1 */
X   int             com_col;		/* this is the column in which
X					   the current coment should
X					   start */
X   int             com_ind;		/* the column in which comments
X					   to the right of code should
X					   start */
X   int             com_lines;		/* the number of lines with
X					   comments, set by dump_line */
X   int             dec_nest;		/* current nesting level for
X					   structure or init */
X   int             decl_com_ind;	/* the column in which comments
X					   after declarations should be
X					   put */
X   int             decl_on_line;	/* set to true if this line of
X					   code has part of a
X					   declaration on it */
X   int             i_l_follow;		/* the level to which ind_level
X					   should be set after the
X					   current line is printed */
X   int             in_decl;		/* set to true when we are in a
X					   declaration stmt.  The
X					   processing of braces is then
X					   slightly different */
X   int             in_stmt;		/* set to 1 while in a stmt */
X   int             ind_level;		/* the current indentation
X					   level */
X   int             ind_size;		/* the size of one indentation
X					   level */
X   int             ind_stmt;		/* set to 1 if next line should
X					   have an extra indentation
X					   level because we are in the
X					   middle of a stmt */
X   int             last_u_d;		/* set to true after scanning a
X					   token which forces a
X					   following operator to be
X					   unary */
X   int             leave_comma;		/* if true, never break
X					   declarations after commas */
X   int             ljust_decl;		/* true if declarations should
X					   be left justified */
X   int             out_coms;		/* the number of comments
X					   processed, set by pr_comment */
X   int             out_lines;		/* the number of lines written,
X					   set by dump_line */
X   int             p_l_follow;		/* used to remember how to
X					   indent following statement */
X   int             paren_level;		/* parenthesization level. used
X					   to indent within stmts */
X   short           paren_indents[20];	/* column positions of each
X					   paren */
X   int             pcase;		/* set to 1 if the current line
X					   label is a case.  It is
X					   printed differently from a
X					   regular label */
X   int             search_brace;	/* set to true by parse when it
X					   is necessary to buffer up
X					   all info up to the start of
X					   a stmt after an if, while,
X					   etc */
X   int             unindent_displace;	/* comments not to the right of
X					   code will be placed this
X					   many indentation levels to
X					   the left of code */
X   int             use_ff;		/* set to one if the current
X					   line should be terminated
X					   with a form feed */
X   int             want_blank;		/* set to true when the
X					   following token should be
X					   prefixed by a blank. (Said
X					   prefixing is ignored in some
X					   cases.) */
X   int             else_if;		/* True iff else if pairs
X					   should be handled specially */
X   int             decl_indent;		/* column to indent declared
X					   identifiers to */
X   int             its_a_keyword;
X   int             sizeof_keyword;
X   int             dumped_decl_indent;
X   long            case_indent;		/* The distance to indent case
X					   labels from the switch
X					   statement */
X   int             in_par_decl;
X   int             indent_parameters;
X   int             tos;			/* pointer to top of stack */
X   char            procname[100];	/* The name of the current
X					   procedure */
X   int             just_saw_decl;
X}               ps;
X
XPUBLIC int      ifdef_level;
XPUBLIC struct parser_state state_stack[5];
XPUBLIC struct parser_state match_state[5];
/
echo x - indent.c
sed '/^X/s///' > indent.c << '/'
X/*
X * Copyright (c) 1985 Sun Microsystems, Inc.
X * Copyright (c) 1980 The Regents of the University of California.
X * Copyright (c) 1976 Board of Trustees of the University of Illinois.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley, the University of Illinois,
X * Urbana, and Sun Microsystems, Inc.  The name of either University
X * or Sun Microsystems may not be used to endorse or promote products
X * derived from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xchar            copyright[] =
X"@(#) Copyright (c) 1985 Sun Microsystems, Inc.\n\
X @(#) Copyright (c) 1980 The Regents of the University of California.\n\
X @(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\
XAll rights reserved.\ n ";
X#endif					/* not lint */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)indent.c	5.11 (Berkeley) 9/15/88";
X#endif					/* not lint */
X
X#define	PUBLIC
X#include "globs.h"
X#include "codes.h"
X#include <ctype.h>
X
Xchar           *in_name = "Standard Input";	/* will always point to
X						   name of input file */
Xchar           *out_name = "Standard Output";	/* will always point to
X						   name of output file */
Xchar            bakfile[60] = "";
X
Xmain(argc, argv)
X   int             argc;
X   char          **argv;
X{
X
X   extern int      found_err;		/* flag set in diag() on error */
X   int             dec_ind;		/* current indentation for
X					   declarations */
X   int             di_stack[20];	/* a stack of structure
X					   indentation levels */
X   int             flushed_nl;		/* used when buffering up
X					   comments to remember that a
X					   newline was passed over */
X   int             force_nl;		/* when true, code must be
X					   broken */
X   int             hd_type;		/* used to store type of stmt
X					   for if (...), for (...), etc */
X   register int    i;			/* local loop counter */
X   int             scase;		/* set to true when we see a
X					   case, so we will know what
X					   to do with the following
X					   colon */
X   int             sp_sw;		/* when true, we are in the
X					   expressin of if(...),
X					   while(...), etc. */
X   int             squest;		/* when this is positive, we
X					   have seen a ? without the
X					   matching : in a <c>?<s>:<s>
X					   construct */
X   register char  *t_ptr;		/* used for copying tokens */
X   int             type_code;		/* the type of token, returned
X					   by lexi */
X
X   int             last_else = 0;	/* true iff last keyword was an
X					   else */
X
X
X   /*-----------------------------------------------*\
X    |		      INITIALIZATION		      |
X    \*-----------------------------------------------*/
X
X
X   ps.p_stack[0] = stmt;		/* this is the parser's stack */
X   ps.last_nl = true;			/* this is true if the last
X					   thing scanned was a newline */
X   ps.last_token = semicolon;
X   combuf = (char *) malloc(bufsize);
X   labbuf = (char *) malloc(bufsize);
X   codebuf = (char *) malloc(bufsize);
X   l_com = combuf + bufsize - 5;
X   l_lab = labbuf + bufsize - 5;
X   l_code = codebuf + bufsize - 5;
X   combuf[0] = codebuf[0] = labbuf[0] = ' ';	/* set up code, label,
X						   and comment buffers */
X   combuf[1] = codebuf[1] = labbuf[1] = '\0';
X   ps.else_if = 1;			/* Default else-if special
X					   processing to on */
X   s_lab = e_lab = labbuf + 1;
X   s_code = e_code = codebuf + 1;
X   s_com = e_com = combuf + 1;
X
X   buf_ptr = buf_end = in_buffer;
X   line_no = 1;
X   had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
X   sp_sw = force_nl = false;
X   ps.in_or_st = false;
X   ps.bl_line = true;
X   dec_ind = 0;
X   di_stack[ps.dec_nest = 0] = 0;
X   ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
X
X
X   scase = ps.pcase = false;
X   squest = 0;
X   sc_end = 0;
X   bp_save = 0;
X   be_save = 0;
X
X   output = 0;
X
X
X
X   /*--------------------------------------------------*\
X    |   		COMMAND LINE SCAN		 |
X    \*--------------------------------------------------*/
X
X#ifdef undef
X   max_col = 78;			/* -l78 */
X   lineup_to_parens = 1;		/* -lp */
X   ps.ljust_decl = 0;			/* -ndj */
X   ps.com_ind = 33;			/* -c33 */
X   star_comment_cont = 1;		/* -sc */
X   ps.ind_size = 8;			/* -i8 */
X   verbose = 0;
X   ps.decl_indent = 16;			/* -di16 */
X   ps.indent_parameters = 1;		/* -ip */
X   ps.decl_com_ind = 0;			/* if this is not set to some
X					   positive value by an arg, we
X					   will set this equal to
X					   ps.com_ind */
X   btype_2 = 1;				/* -br */
X   cuddle_else = 1;			/* -ce */
X   ps.unindent_displace = 0;		/* -d0 */
X   ps.case_indent = 0;			/* -cli0 */
X   format_col1_comments = 1;		/* -fc1 */
X   procnames_start_line = 1;		/* -psl */
X   proc_calls_space = 0;		/* -npcs */
X   comment_delimiter_on_blankline = 1;	/* -cdb */
X   ps.leave_comma = 1;			/* -nbc */
X#endif
X
X   for (i = 1; i < argc; ++i)
X      if (strcmp(argv[i], "-npro") == 0)
X	 break;
X   set_defaults();
X   if (i >= argc)
X      set_profile();
X
X   for (i = 1; i < argc; ++i)
X   {
X
X      /* look thru args (if any) for changes to defaults */
X      if (argv[i][0] != '-')
X      {					/* no flag on parameter */
X	 if (input == 0)
X	 {				/* we must have the input file */
X	    in_name = argv[i];		/* remember name of input file */
X	    input = fopen(in_name, "r");
X	    if (input == 0)
X	    {				/* check for open error */
X	       fprintf(stderr, "indent: can't open %s\n", argv[i]);
X	       exit(1);
X	    }
X	    continue;
X	 } else if (output == 0)
X	 {				/* we have the output file */
X	    out_name = argv[i];		/* remember name of output file */
X	    if (strcmp(in_name, out_name) == 0)
X	    {				/* attempt to overwrite the
X					   file */
X	       fprintf(stderr, "indent: input and output files must be different\n");
X	       exit(1);
X	    }
X	    output = fopen(out_name, "w");
X	    if (output == 0)
X	    {				/* check for create error */
X	       fprintf(stderr, "indent: can't create %s\n", argv[i]);
X	       exit(1);
X	    }
X	    continue;
X	 }
X	 fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
X	 exit(1);
X      } else
X	 set_option(argv[i]);
X   }					/* end of for */
X   if (input == 0)
X   {
X      fprintf(stderr, "indent: usage: indent file [ outfile ] [ options ]\n");
X      exit(1);
X   }
X   if (output == 0)
X      if (troff)
X	 output = stdout;
X      else
X      {
X	 out_name = in_name;
X	 bakcopy();
X      }
X   if (ps.com_ind <= 1)
X      ps.com_ind = 2;			/* dont put normal comments
X					   before column 2 */
X   if (troff)
X   {
X      if (bodyf.font[0] == 0)
X	 parsefont(&bodyf, "R");
X      if (scomf.font[0] == 0)
X	 parsefont(&scomf, "I");
X      if (blkcomf.font[0] == 0)
X	 blkcomf = scomf, blkcomf.size += 2;
X      if (boxcomf.font[0] == 0)
X	 boxcomf = blkcomf;
X      if (stringf.font[0] == 0)
X	 parsefont(&stringf, "L");
X      if (keywordf.font[0] == 0)
X	 parsefont(&keywordf, "B");
X      writefdef(&bodyf, 'B');
X      writefdef(&scomf, 'C');
X      writefdef(&blkcomf, 'L');
X      writefdef(&boxcomf, 'X');
X      writefdef(&stringf, 'S');
X      writefdef(&keywordf, 'K');
X   }
X   if (bk_max_col <= 0)
X      bk_max_col = max_col;
X   if (ps.decl_com_ind <= 0)		/* if not specified by user,
X					   set this */
X      ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
X   if (continuation_indent == 0)
X      continuation_indent = ps.ind_size;
X   fill_buffer();			/* get first batch of stuff
X					   into input buffer */
X
X   parse(semicolon);
X   {
X      register char  *p = buf_ptr;
X      register        col = 1;
X
X      while (1)
X      {
X	 if (*p == ' ')
X	    col++;
X	 else if (*p == '\t')
X	    col = ((col - 1) & ~7) + 9;
X	 else
X	    break;
X	 p++;
X      };
X      if (col > ps.ind_size)
X	 ps.ind_level = ps.i_l_follow = col / ps.ind_size;
X   }
X   if (troff)
X   {
X      register char  *p = in_name, *beg = in_name;
X
X      while (*p)
X	 if (*p++ == '/')
X	    beg = p;
X      fprintf(output, ".Fn \"%s\"\n", beg);
X   }
X   /* START OF MAIN LOOP */
X
X   while (1)
X   {					/* this is the main loop.  it
X					   will go until we reach eof */
X      int             is_procname;
X
X      type_code = lexi();		/* lexi reads one token.  The
X					   actual characters read are
X					   stored in "token". lexi
X					   returns a code indicating
X					   the type of token */
X      is_procname = ps.procname[0];
X
X      /* The following code moves everything following an if (), while
X         (), else, etc. up to the start of the following stmt to a
X         buffer. This allows proper handling of both kinds of brace
X         placement. */
X
X      flushed_nl = false;
X      while (ps.search_brace)
X      {					/* if we scanned an if(),
X					   while(), etc., we might need
X					   to copy stuff into a buffer
X					   we must loop, copying stuff
X					   into save_com, until we find
X					   the start of the stmt which
X					   follows the if, or whatever */
X	 switch (type_code)
X	 {
X	 case newline:
X	    ++line_no;
X	    flushed_nl = true;
X	 case form_feed:
X	    break;			/* form feeds and newlines
X					   found here will be ignored */
X
X	 case lbrace:			/* this is a brace that starts
X					   the compound stmt */
X	    if (sc_end == 0)
X	    {				/* ignore buffering if a
X					   comment wasnt stored up */
X	       ps.search_brace = false;
X	       goto check_type;
X	    }
X	    if (btype_2)
X	    {
X	       save_com[0] = '{';	/* we either want to put the
X					   brace right after the if */
X	       goto sw_buffer;		/* go to common code to get out
X					   of this loop */
X	    }
X	 case comment:			/* we have a comment, so we
X					   must copy it into the buffer */
X	    if (!flushed_nl || sc_end != 0)
X	    {
X	       if (sc_end == 0)
X	       {			/* if this is the first
X					   comment, we must set up the
X					   buffer */
X		  save_com[0] = save_com[1] = ' ';
X		  sc_end = &(save_com[2]);
X	       } else
X	       {
X		  *sc_end++ = '\n';	/* add newline between comments */
X		  *sc_end++ = ' ';
X		  --line_no;
X	       }
X	       *sc_end++ = '/';		/* copy in start of comment */
X	       *sc_end++ = '*';
X
X	       for (;;)
X	       {			/* loop until we get to the end
X					   of the comment */
X		  *sc_end = *buf_ptr++;
X		  if (buf_ptr >= buf_end)
X		     fill_buffer();
X
X		  if (*sc_end++ == '*' && *buf_ptr == '/')
X		     break;		/* we are at end of comment */
X
X		  if (sc_end >= &(save_com[sc_size]))
X		  {			/* check for temp buffer
X					   overflow */
X		     diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
X		     fflush(output);
X		     exit(1);
X		  }
X	       }
X	       *sc_end++ = '/';		/* add ending slash */
X	       if (++buf_ptr >= buf_end)/* get past / in buffer */
X		  fill_buffer();
X	       break;
X	    }
X	 default:			/* it is the start of a normal
X					   statment */
X	    if (flushed_nl)		/* if we flushed a newline,
X					   make sure it is put back */
X	       force_nl = true;
X	    if (type_code == sp_paren && *token == 'i'
X		&& last_else && ps.else_if
X		|| type_code == sp_nparen && *token == 'e'
X		&& e_code != s_code && e_code[-1] == '}')
X	       force_nl = false;
X
X	    if (sc_end == 0)
X	    {				/* ignore buffering if comment
X					   wasnt saved up */
X	       ps.search_brace = false;
X	       goto check_type;
X	    }
X	    if (force_nl)
X	    {				/* if we should insert a nl
X					   here, put it into the buffer */
X	       force_nl = false;
X	       --line_no;		/* this will be re-increased
X					   when the nl is read from the
X					   buffer */
X	       *sc_end++ = '\n';
X	       *sc_end++ = ' ';
X	       if (verbose && !flushed_nl)	/* print error msg if
X						   the line was not
X						   already broken */
X		  diag(0, "Line broken");
X	       flushed_nl = false;
X	    }
X	    for (t_ptr = token; *t_ptr; ++t_ptr)
X	       *sc_end++ = *t_ptr;	/* copy token into temp buffer */
X	    ps.procname[0] = 0;
X
X      sw_buffer:
X	    ps.search_brace = false;	/* stop looking for start of
X					   stmt */
X	    bp_save = buf_ptr;		/* save current input buffer */
X	    be_save = buf_end;
X	    buf_ptr = save_com;		/* fix so that subsequent calls
X					   to lexi will take tokens out
X					   of save_com */
X	    *sc_end++ = ' ';		/* add trailing blank, just in
X					   case */
X	    buf_end = sc_end;
X	    sc_end = 0;
X	    break;
X	 }				/* end of switch */
X	 if (type_code != 0)		/* we must make this check,
X					   just in case there was an
X					   unexpected EOF */
X	    type_code = lexi();		/* read another token */
X	 /* if (ps.search_brace) ps.procname[0] = 0; */
X	 if ((is_procname = ps.procname[0]) && flushed_nl
X	     && !proc_str_line && ps.in_decl
X	     && type_code == ident)
X	    flushed_nl = 0;
X      }					/* end of while (search_brace) */
X      last_else = 0;
Xcheck_type:
X      if (type_code == 0)
X      {					/* we got eof */
X	 if (s_lab != e_lab || s_code != e_code
X	     || s_com != e_com)		/* must dump end of line */
X	    dump_line();
X	 if (ps.tos > 1)		/* check for balanced braces */
X	    diag(1, "Stuff missing from end of file.");
X
X	 if (verbose)
X	 {
X	    printf("There were %d output lines and %d comments\n",
X		   ps.out_lines, ps.out_coms);
X	    printf("(Lines with comments)/(Lines with code): %6d\n",
X		   ps.com_lines / code_lines);
X	 }
X	 fflush(output);
X	 exit(found_err);
X      }
X      if (
X	  (type_code != comment) &&
X	  (type_code != newline) &&
X	  (type_code != preesc) &&
X	  (type_code != form_feed))
X      {
X	 if (force_nl &&
X	     (type_code != semicolon) &&
X	     (type_code != lbrace || !btype_2))
X	 {
X	    /* we should force a broken line here */
X	    if (verbose && !flushed_nl)
X	       diag(0, "Line broken");
X	    flushed_nl = false;
X	    dump_line();
X	    ps.want_blank = false;	/* dont insert blank at line
X					   start */
X	    force_nl = false;
X	 }
X	 ps.in_stmt = true;		/* turn on flag which causes an
X					   extra level of indentation.
X					   this is turned off by a ; or
X					   '}' */
X	 if (s_com != e_com)
X	 {				/* the turkey has embedded a
X					   comment in a line. fix it */
X	    *e_code++ = ' ';
X	    for (t_ptr = s_com; *t_ptr; ++t_ptr)
X	    {
X	       if (e_code >= l_code)
X	       {
X		  register        nsize = l_code - s_code + 400;
X		  codebuf = (char *) realloc(codebuf, nsize);
X		  e_code = codebuf + (e_code - s_code) + 1;
X		  l_code = codebuf + nsize - 5;
X		  s_code = codebuf + 1;
X	       }
X	       *e_code++ = *t_ptr;
X	    }
X	    *e_code++ = ' ';
X	    *e_code = '\0';		/* null terminate code sect */
X	    ps.want_blank = false;
X	    e_com = s_com;
X	 }
X      } else if (type_code != comment)	/* preserve force_nl thru a
X					   comment */
X	 force_nl = false;		/* cancel forced newline after
X					   newline, form feed, etc */
X
X
X
X      /*-----------------------------------------------------*\
X	|	   do switch on type of token scanned		|
X	\*-----------------------------------------------------*/
X      if (e_code >= l_code)
X      {
X	 register        nsize = l_code - s_code + 400;
X	 codebuf = (char *) realloc(codebuf, nsize);
X	 e_code = codebuf + (e_code - s_code) + 1;
X	 l_code = codebuf + nsize - 5;
X	 s_code = codebuf + 1;
X      }
X      switch (type_code)
X      {					/* now, decide what to do with
X					   the token */
X
X      case form_feed:			/* found a form feed in line */
X	 ps.use_ff = true;		/* a form feed is treated much
X					   like a newline */
X	 dump_line();
X	 ps.want_blank = false;
X	 break;
X
X      case newline:
X	 if (ps.last_token != comma || ps.p_l_follow > 0
X	     || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com)
X	 {
X	    dump_line();
X	    ps.want_blank = false;
X	 }
X	 ++line_no;			/* keep track of input line
X					   number */
X	 break;
X
X      case lparen:			/* got a '(' or '[' */
X	 ++ps.p_l_follow;		/* count parens to make Healy
X					   happy */
X	 if (ps.want_blank && *token != '[' &&
X	     (ps.last_token != ident || proc_calls_space
X	      || (ps.its_a_keyword && (!ps.sizeof_keyword || Bill_Shannon))))
X	    *e_code++ = ' ';
X	 if (ps.in_decl && !ps.block_init)
X	    if (troff && !ps.dumped_decl_indent && !is_procname && ps.last_token == decl)
X	    {
X	       ps.dumped_decl_indent = 1;
X	       sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
X	       e_code += strlen(e_code);
X	    } else
X	    {
X	       while ((e_code - s_code) < dec_ind)
X	       {
X		  if (e_code >= l_code)
X		  {
X		     register        nsize = l_code - s_code + 400;
X		     codebuf = (char *) realloc(codebuf, nsize);
X		     e_code = codebuf + (e_code - s_code) + 1;
X		     l_code = codebuf + nsize - 5;
X		     s_code = codebuf + 1;
X		  }
X		  *e_code++ = ' ';
X	       }
X	       *e_code++ = token[0];
X	    }
X	 else
X	    *e_code++ = token[0];
X	 ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code;
X	 if (sp_sw && ps.p_l_follow == 1 && ex_expr_indent
X	     && ps.paren_indents[0] < 2 * ps.ind_size)
X	    ps.paren_indents[0] = 2 * ps.ind_size;
X	 ps.want_blank = false;
X	 if (ps.in_or_st && *token == '(' && ps.tos <= 2)
X	 {
X	    /* this is a kluge to make sure that declarations will be
X	       aligned right if proc decl has an explicit type on it,
X	       i.e. "int a(x) {..." */
X	    parse(semicolon);		/* I said this was a kluge... */
X	    ps.in_or_st = false;	/* turn off flag for structure
X					   decl or initialization */
X	 }
X	 if (ps.sizeof_keyword)
X	    ps.sizeof_mask |= 1 << ps.p_l_follow;
X	 break;
X
X      case rparen:			/* got a ')' or ']' */
X	 if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask)
X	 {
X	    ps.last_u_d = true;
X	    ps.cast_mask &= (1 << ps.p_l_follow) - 1;
X	 }
X	 ps.sizeof_mask &= (1 << ps.p_l_follow) - 1;
X	 if (--ps.p_l_follow < 0)
X	 {
X	    ps.p_l_follow = 0;
X	    diag(0, "Extra %c", *token);
X	 }
X	 if (e_code == s_code)		/* if the paren starts the line */
X	    ps.paren_level = ps.p_l_follow;	/* then indent it */
X
X	 *e_code++ = token[0];
X	 ps.want_blank = true;
X
X	 if (sp_sw && (ps.p_l_follow == 0))
X	 {				/* check for end of if (...),
X					   or some such */
X	    sp_sw = false;
X	    force_nl = true;		/* must force newline after if */
X	    ps.last_u_d = true;		/* inform lexi that a following
X					   operator is unary */
X	    ps.in_stmt = false;		/* dont use stmt continuation
X					   indentation */
X
X	    parse(hd_type);		/* let parser worry about if,
X					   or whatever */
X	 }
X	 ps.search_brace = btype_2;	/* this should insure that
X					   constructs such as
X					   main(){...} and int[]{...}
X					   have their braces put in the
X					   right place */
X	 break;
X
X      case unary_op:			/* this could be any unary
X					   operation */
X	 if (ps.want_blank)
X	    *e_code++ = ' ';
X
X	 if (troff && !ps.dumped_decl_indent && ps.in_decl && !is_procname)
X	 {
X	    sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
X	    ps.dumped_decl_indent = 1;
X	    e_code += strlen(e_code);
X	 } else
X	 {
X	    char           *res = token;
X
X	    if (ps.in_decl && !ps.block_init)
X	    {				/* if this is a unary op in a
X					   declaration, we should
X					   indent this token */
X	       for (i = 0; token[i]; ++i);	/* find length of token */
X	       while ((e_code - s_code) < (dec_ind - i))
X	       {
X		  if (e_code >= l_code)
X		  {
X		     register        nsize = l_code - s_code + 400;
X		     codebuf = (char *) realloc(codebuf, nsize);
X		     e_code = codebuf + (e_code - s_code) + 1;
X		     l_code = codebuf + nsize - 5;
X		     s_code = codebuf + 1;
X		  }
X		  *e_code++ = ' ';	/* pad it */
X	       }
X	    }
X	    if (troff && token[0] == '-' && token[1] == '>')
X	       res = "\\(->";
X	    for (t_ptr = res; *t_ptr; ++t_ptr)
X	    {
X	       if (e_code >= l_code)
X	       {
X		  register        nsize = l_code - s_code + 400;
X		  codebuf = (char *) realloc(codebuf, nsize);
X		  e_code = codebuf + (e_code - s_code) + 1;
X		  l_code = codebuf + nsize - 5;
X		  s_code = codebuf + 1;
X	       }
X	       *e_code++ = *t_ptr;
X	    }
X	 }
X	 ps.want_blank = false;
X	 break;
X
X      case binary_op:			/* any binary operation */
X   do_binary:
X	 if (ps.want_blank)
X	    *e_code++ = ' ';
X	 {
X	    char           *res = token;
X
X	    if (troff)
X	       switch (token[0])
X	       {
X	       case '<':
X		  if (token[1] == '=')
X		     res = "\\(<=";
X		  break;
X	       case '>':
X		  if (token[1] == '=')
X		     res = "\\(>=";
X		  break;
X	       case '!':
X		  if (token[1] == '=')
X		     res = "\\(!=";
X		  break;
X	       case '|':
X		  if (token[1] == '|')
X		     res = "\\(br\\(br";
X		  else if (token[1] == 0)
X		     res = "\\(br";
X		  break;
X	       }
X	    for (t_ptr = res; *t_ptr; ++t_ptr)
X	    {
X	       if (e_code >= l_code)
X	       {
X		  register        nsize = l_code - s_code + 400;
X		  codebuf = (char *) realloc(codebuf, nsize);
X		  e_code = codebuf + (e_code - s_code) + 1;
X		  l_code = codebuf + nsize - 5;
X		  s_code = codebuf + 1;
X	       }
X	       *e_code++ = *t_ptr;	/* move the operator */
X	    }
X	 }
X	 ps.want_blank = true;
X	 break;
X
X      case postop:			/* got a trailing ++ or -- */
X	 *e_code++ = token[0];
X	 *e_code++ = token[1];
X	 ps.want_blank = true;
X	 break;
X
X      case question:			/* got a ? */
X	 squest++;			/* this will be used when a
X					   later colon appears so we
X					   can distinguish the
X					   <c>?<n>:<n> construct */
X	 if (ps.want_blank)
X	    *e_code++ = ' ';
X	 *e_code++ = '?';
X	 ps.want_blank = true;
X	 break;
X
X      case casestmt:			/* got word 'case' or 'default' */
X	 scase = true;			/* so we can process the later
X					   colon properly */
X	 goto copy_id;
X
X      case colon:			/* got a ':' */
X	 if (squest > 0)
X	 {				/* it is part of the <c>?<n>:
X					   <n> construct */
X	    --squest;
X	    if (ps.want_blank)
X	       *e_code++ = ' ';
X	    *e_code++ = ':';
X	    ps.want_blank = true;
X	    break;
X	 }
X	 if (ps.in_decl)
X	 {
X	    *e_code++ = ':';
X	    ps.want_blank = false;
X	    break;
X	 }
X	 ps.in_stmt = false;		/* seeing a label does not
X					   imply we are in a stmt */
X	 for (t_ptr = s_code; *t_ptr; ++t_ptr)
X	    *e_lab++ = *t_ptr;		/* turn everything so far into
X					   a label */
X	 e_code = s_code;
X	 *e_lab++ = ':';
X	 *e_lab++ = ' ';
X	 *e_lab = '\0';
X
X	 force_nl = ps.pcase = scase;	/* ps.pcase will be used by
X					   dump_line to decide how to
X					   indent the label. force_nl
X					   will force a case n: to be
X					   on a line by itself */
X	 scase = false;
X	 ps.want_blank = false;
X	 break;
X
X      case semicolon:			/* got a ';' */
X	 ps.in_or_st = false;		/* we are not in an
X					   initialization or structure
X					   declaration */
X	 scase = false;			/* these will only need
X					   resetting in a error */
X	 squest = 0;
X	 if (ps.last_token == rparen)
X	    ps.in_par_decl = 0;
X	 ps.cast_mask = 0;
X	 ps.sizeof_mask = 0;
X	 ps.block_init = 0;
X	 ps.block_init_level = 0;
X	 ps.just_saw_decl--;
X
X	 if (ps.in_decl && s_code == e_code && !ps.block_init)
X	    while ((e_code - s_code) < (dec_ind - 1))
X	    {
X	       if (e_code >= l_code)
X	       {
X		  register        nsize = l_code - s_code + 400;
X		  codebuf = (char *) realloc(codebuf, nsize);
X		  e_code = codebuf + (e_code - s_code) + 1;
X		  l_code = codebuf + nsize - 5;
X		  s_code = codebuf + 1;
X	       }
X	       *e_code++ = ' ';
X	    }
X
X	 ps.in_decl = (ps.dec_nest > 0);/* if we were in a first level
X					   structure declaration, we
X					   arent any more */
X
X	 if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0)
X	 {
X
X	    /* This should be true iff there were unbalanced parens in
X	       the stmt.  It is a bit complicated, because the
X	       semicolon might be in a for stmt */
X	    diag(1, "Unbalanced parens");
X	    ps.p_l_follow = 0;
X	    if (sp_sw)
X	    {				/* this is a check for a if,
X					   while, etc. with unbalanced
X					   parens */
X	       sp_sw = false;
X	       parse(hd_type);		/* dont lose the if, or
X					   whatever */
X	    }
X	 }
X	 *e_code++ = ';';
X	 ps.want_blank = true;
X	 ps.in_stmt = (ps.p_l_follow > 0);	/* we are no longer in
X						   the middle of a stmt */
X
X	 if (!sp_sw)
X	 {				/* if not if for (;;) */
X	    parse(semicolon);		/* let parser know about end of
X					   stmt */
X	    force_nl = true;		/* force newline after a end of
X					   stmt */
X	 }
X	 break;
X
X      case lbrace:			/* got a '{' */
X	 ps.in_stmt = false;		/* dont indent the {} */
X	 if (!ps.block_init)
X	    force_nl = true;		/* force other stuff on same
X					   line as '{' onto new line */
X	 else if (ps.block_init_level <= 0)
X	    ps.block_init_level = 1;
X	 else
X	    ps.block_init_level++;
X
X	 if (s_code != e_code && !ps.block_init)
X	 {
X	    if (!btype_2)
X	    {
X	       dump_line();
X	       ps.want_blank = false;
X	    } else if (ps.in_par_decl && !ps.in_or_st)
X	    {
X	       ps.i_l_follow = 0;
X	       dump_line();
X	       ps.want_blank = false;
X	    }
X	 }
X	 if (ps.in_par_decl)
X	    prefix_blankline_requested = 0;
X
X	 if (ps.p_l_follow > 0)
X	 {				/* check for preceeding
X					   unbalanced parens */
X	    diag(1, "Unbalanced parens");
X	    ps.p_l_follow = 0;
X	    if (sp_sw)
X	    {				/* check for unclosed if, for,
X					   etc. */
X	       sp_sw = false;
X	       parse(hd_type);
X	       ps.ind_level = ps.i_l_follow;
X	    }
X	 }
X	 if (s_code == e_code)
X	    ps.ind_stmt = false;	/* dont put extra indentation
X					   on line with '{' */
X	 if (ps.in_decl && ps.in_or_st)
X	 {				/* this is either a structure
X					   declaration or an init */
X	    di_stack[ps.dec_nest++] = dec_ind;
X	    /* ?		dec_ind = 0; */
X	 } else
X	 {
X	    ps.decl_on_line = false;	/* we cant be in the middle of
X					   a declaration, so dont do
X					   special indentation of
X					   comments */
X	    if (bl_at_proctop
X		&& ps.in_par_decl)
X	       postfix_blankline_requested = 1;
X	    ps.in_par_decl = 0;
X	 }
X	 dec_ind = 0;
X	 parse(lbrace);			/* let parser know about this */
X	 if (ps.want_blank)		/* put a blank before '{' if
X					   '{' is not at start of line */
X	    *e_code++ = ' ';
X	 ps.want_blank = false;
X	 *e_code++ = '{';
X	 ps.just_saw_decl = 0;
X	 break;
X
X      case rbrace:			/* got a '}' */
X	 if (ps.p_stack[ps.tos] == decl && !ps.block_init)	/* semicolons can be
X								   omitted in
X								   declarations */
X	    parse(semicolon);
X	 if (ps.p_l_follow)
X	 {				/* check for unclosed if, for,
X					   else. */
X	    diag(1, "Unbalanced parens");
X	    ps.p_l_follow = 0;
X	    sp_sw = false;
X	 }
X	 ps.just_saw_decl = 0;
X	 ps.block_init_level--;
X	 if (s_code != e_code && !ps.block_init)
X	 {				/* '}' must be first on line */
X	    if (verbose)
X	       diag(0, "Line broken");
X	    dump_line();
X	 }
X	 *e_code++ = '}';
X	 ps.want_blank = true;
X	 ps.in_stmt = ps.ind_stmt = false;
X	 if (ps.dec_nest > 0)
X	 {				/* we are in multi-level
X					   structure declaration */
X	    dec_ind = di_stack[--ps.dec_nest];
X	    if (ps.dec_nest == 0 && !ps.in_par_decl)
X	       ps.just_saw_decl = 2;
X	    ps.in_decl = true;
X	 }
X	 prefix_blankline_requested = 0;
X	 parse(rbrace);			/* let parser know about this */
X	 ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead
X	    && ps.il[ps.tos] >= ps.ind_level;
X	 if (ps.tos <= 1 && bl_a_procs && ps.dec_nest <= 0)
X	    postfix_blankline_requested = 1;
X	 break;
X
X      case swstmt:			/* got keyword "switch" */
X	 sp_sw = true;
X	 hd_type = swstmt;		/* keep this for when we have
X					   seen the expression */
X	 goto copy_id;			/* go move the token into
X					   buffer */
X
X      case sp_paren:			/* token is if, while, for */
X	 sp_sw = true;			/* the interesting stuff is
X					   done after the expression is
X					   scanned */
X	 hd_type = (*token == 'i' ? ifstmt :
X		    (*token == 'w' ? whilestmt : forstmt));
X
X	 /* remember the type of header for later use by parser */
X	 goto copy_id;			/* copy the token into line */
X
X      case sp_nparen:			/* got else, do */
X	 ps.in_stmt = false;
X	 if (*token == 'e')
X	 {
X	    if (e_code != s_code && (!cuddle_else || e_code[-1] != '}'))
X	    {
X	       if (verbose)
X		  diag(0, "Line broken");
X	       dump_line();		/* make sure this starts a line */
X	       ps.want_blank = false;
X	    }
X	    force_nl = true;		/* also, following stuff must
X					   go onto new line */
X	    last_else = 1;
X	    parse(elselit);
X	 } else
X	 {
X	    if (e_code != s_code)
X	    {				/* make sure this starts a line */
X	       if (verbose)
X		  diag(0, "Line broken");
X	       dump_line();
X	       ps.want_blank = false;
X	    }
X	    force_nl = true;		/* also, following stuff must
X					   go onto new line */
X	    last_else = 0;
X	    parse(dolit);
X	 }
X	 goto copy_id;			/* move the token into line */
X
X      case decl:			/* we have a declaration type
X					   (int, register, etc.) */
X	 parse(decl);			/* let parser worry about
X					   indentation */
X	 if (ps.last_token == rparen && ps.tos <= 1)
X	 {
X	    ps.in_par_decl = 1;
X	    if (s_code != e_code)
X	    {
X	       dump_line();
X	       ps.want_blank = 0;
X	    }
X	 }
X	 if (ps.in_par_decl && ps.indent_parameters && ps.dec_nest == 0)
X	 {
X	    ps.ind_level = ps.i_l_follow = 1;
X	    ps.ind_stmt = 0;
X	 }
X	 ps.in_or_st = true;		/* this might be a structure or
X					   initialization declaration */
X	 ps.in_decl = ps.decl_on_line = true;
X	 if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
X	    ps.just_saw_decl = 2;
X	 prefix_blankline_requested = 0;
X	 for (i = 0; token[i++];);	/* get length of token */
X
X	 /* dec_ind = e_code - s_code + (ps.decl_indent>i ?
X	    ps.decl_indent : i); */
X	 dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
X	 goto copy_id;
X
X      case ident:			/* got an identifier or
X					   constant */
X	 if (ps.in_decl)
X	 {				/* if we are in a declaration,
X					   we must indent identifier */
X	    if (ps.want_blank)
X	       *e_code++ = ' ';
X	    ps.want_blank = false;
X	    if (is_procname == 0 || !proc_str_line)
X	    {
X	       if (!ps.block_init)
X		  if (troff && !ps.dumped_decl_indent)
X		  {
X		     sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
X		     ps.dumped_decl_indent = 1;
X		     e_code += strlen(e_code);
X		  } else
X		     while ((e_code - s_code) < dec_ind)
X		     {
X			if (e_code >= l_code)
X			{
X			   register        nsize = l_code - s_code + 400;
X			   codebuf = (char *) realloc(codebuf, nsize);
X			   e_code = codebuf + (e_code - s_code) + 1;
X			   l_code = codebuf + nsize - 5;
X			   s_code = codebuf + 1;
X			}
X			*e_code++ = ' ';
X		     }
X	    } else
X	    {
X	       if (dec_ind && s_code != e_code)
X		  dump_line();
X	       dec_ind = 0;
X	       ps.want_blank = false;
X	    }
X	 } else if (sp_sw && ps.p_l_follow == 0)
X	 {
X	    sp_sw = false;
X	    force_nl = true;
X	    ps.last_u_d = true;
X	    ps.in_stmt = false;
X	    parse(hd_type);
X	 }
X   copy_id:
X	 if (ps.want_blank)
X	    *e_code++ = ' ';
X	 if (troff && ps.its_a_keyword)
X	 {
X	    e_code = chfont(&bodyf, &keywordf, e_code);
X	    for (t_ptr = token; *t_ptr; ++t_ptr)
X	    {
X	       if (e_code >= l_code)
X	       {
X		  register        nsize = l_code - s_code + 400;
X		  codebuf = (char *) realloc(codebuf, nsize);
X		  e_code = codebuf + (e_code - s_code) + 1;
X		  l_code = codebuf + nsize - 5;
X		  s_code = codebuf + 1;
X	       }
X	       *e_code++ = keywordf.allcaps && islower(*t_ptr)
X		  ? toupper(*t_ptr) : *t_ptr;
X	    }
X	    e_code = chfont(&keywordf, &bodyf, e_code);
X	 } else
X	    for (t_ptr = token; *t_ptr; ++t_ptr)
X	    {
X	       if (e_code >= l_code)
X	       {
X		  register        nsize = l_code - s_code + 400;
X		  codebuf = (char *) realloc(codebuf, nsize);
X		  e_code = codebuf + (e_code - s_code) + 1;
X		  l_code = codebuf + nsize - 5;
X		  s_code = codebuf + 1;
X	       }
X	       *e_code++ = *t_ptr;
X	    }
X	 ps.want_blank = true;
X	 break;
X
X      case period:			/* treat a period kind of like
X					   a binary operation */
X	 *e_code++ = '.';		/* move the period into line */
X	 ps.want_blank = false;		/* dont put a blank after a
X					   period */
X	 break;
X
X      case comma:
X	 ps.want_blank = (s_code != e_code);	/* only put blank after
X						   comma if comma does
X						   not start the line */
X	 if (ps.in_decl && is_procname == 0 && !ps.block_init)
X	    while ((e_code - s_code) < (dec_ind - 1))
X	    {
X	       if (e_code >= l_code)
X	       {
X		  register        nsize = l_code - s_code + 400;
X		  codebuf = (char *) realloc(codebuf, nsize);
X		  e_code = codebuf + (e_code - s_code) + 1;
X		  l_code = codebuf + nsize - 5;
X		  s_code = codebuf + 1;
X	       }
X	       *e_code++ = ' ';
X	    }
X
X	 *e_code++ = ',';
X	 if (ps.p_l_follow == 0)
X	 {
X	    if (ps.block_init_level <= 0)
X	       ps.block_init = 0;
X	    if (break_comma && !ps.leave_comma)
X	       force_nl = true;
X	 }
X	 break;
X
X      case preesc:			/* got the character '#' */
X	 if ((s_com != e_com) ||
X	     (s_lab != e_lab) ||
X	     (s_code != e_code))
X	    dump_line();
X	 *e_lab++ = '#';		/* move whole line to 'label'
X					   buffer */
X	 {
X	    int             in_comment = 0;
X	    int             com_start = 0;
X	    char            quote = 0;
X	    int             com_end = 0;
X
X	    while (*buf_ptr != '\n' || in_comment)
X	    {
X	       if (e_lab >= l_lab)
X	       {
X		  register        nsize = l_lab - s_lab + 400;
X		  labbuf = (char *) realloc(labbuf, nsize);
X		  e_lab = labbuf + (e_lab - s_lab) + 1;
X		  l_lab = labbuf + nsize - 5;
X		  s_lab = labbuf + 1;
X	       }
X	       *e_lab = *buf_ptr++;
X	       if (buf_ptr >= buf_end)
X		  fill_buffer();
X	       switch (*e_lab++)
X	       {
X	       case BACKSLASH:
X		  if (troff)
X		     *e_lab++ = BACKSLASH;
X		  if (!in_comment)
X		  {
X		     *e_lab++ = *buf_ptr++;
X		     if (buf_ptr >= buf_end)
X			fill_buffer();
X		  }
X		  break;
X	       case '/':
X		  if (*buf_ptr == '*' && !in_comment && !quote)
X		  {
X		     in_comment = 1;
X		     *e_lab++ = *buf_ptr++;
X		     com_start = e_lab - s_lab - 2;
X		  }
X		  break;
X	       case '"':
X		  if (quote == '"')
X		     quote = 0;
X		  break;
X	       case '\'':
X		  if (quote == '\'')
X		     quote = 0;
X		  break;
X	       case '*':
X		  if (*buf_ptr == '/' && in_comment)
X		  {
X		     in_comment = 0;
X		     *e_lab++ = *buf_ptr++;
X		     com_end = e_lab - s_lab;
X		  }
X		  break;
X	       }
X	    }
X
X	    while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
X	       e_lab--;
X	    if (e_lab - s_lab == com_end && bp_save == 0)
X	    {				/* comment on preprocessor line */
X	       if (sc_end == 0)		/* if this is the first
X					   comment, we must set up the
X					   buffer */
X		  sc_end = &(save_com[0]);
X	       else
X	       {
X		  *sc_end++ = '\n';	/* add newline between comments */
X		  *sc_end++ = ' ';
X		  --line_no;
X	       }
X	       bcopy(s_lab + com_start, sc_end, com_end - com_start);
X	       sc_end += com_end - com_start;
X	       if (sc_end >= &save_com[sc_size])
X		  abort();
X	       e_lab = s_lab + com_start;
X	       while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
X		  e_lab--;
X	       bp_save = buf_ptr;	/* save current input buffer */
X	       be_save = buf_end;
X	       buf_ptr = save_com;	/* fix so that subsequent calls
X					   to lexi will take tokens out
X					   of save_com */
X	       *sc_end++ = ' ';		/* add trailing blank, just in
X					   case */
X	       buf_end = sc_end;
X	       sc_end = 0;
X	    }
X	    *e_lab = '\0';		/* null terminate line */
X	    ps.pcase = false;
X	 }
X
X	 if (strncmp(s_lab, "#if", 3) == 0)
X	 {
X	    if (bl_around)
X	    {
X	       register        c;
X	       prefix_blankline_requested++;
X	       while ((c = getc(input)) == '\n');
X	       ungetc(c, input);
X	    }
X	    if (ifdef_level < sizeof state_stack / sizeof state_stack[0])
X	    {
X	       match_state[ifdef_level].tos = -1;
X	       state_stack[ifdef_level++] = ps;
X	    } else
X	       diag(1, "#if stack overflow");
X	 } else if (strncmp(s_lab, "#else", 5) == 0)
X	    if (ifdef_level <= 0)
X	       diag(1, "Unmatched #else");
X	    else
X	    {
X	       match_state[ifdef_level - 1] = ps;
X	       ps = state_stack[ifdef_level - 1];
X	    }
X	 else if (strncmp(s_lab, "#endif", 6) == 0)
X	 {
X	    if (ifdef_level <= 0)
X	       diag(1, "Unmatched #endif");
X	    else
X	    {
X	       ifdef_level--;
X
X#ifdef undef
X	       /* This match needs to be more intelligent before the
X	          message is useful */
X	       if (match_state[ifdef_level].tos >= 0
X		   && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
X		  diag(0, "Syntactically inconsistant #ifdef alternatives.");
X#endif
X	    }
X	    if (bl_around)
X	    {
X	       postfix_blankline_requested++;
X	       n_real_blanklines = 0;
X	    }
X	 }
X	 break;				/* subsequent processing of the
X					   newline character will cause
X					   the line to be printed */
X
X      case comment:			/* we have gotten a /*  this is
X					   a biggie */
X   proc_comment:
X	 if (flushed_nl)
X	 {				/* we should force a broken
X					   line here */
X	    flushed_nl = false;
X	    dump_line();
X	    ps.want_blank = false;	/* dont insert blank at line
X					   start */
X	    force_nl = false;
X	 }
X	 pr_comment();
X	 break;
X      }					/* end of big switch stmt */
X
X      *e_code = '\0';			/* make sure code section is
X					   null terminated */
X      if (type_code != comment && type_code != newline && type_code != preesc)
X	 ps.last_token = type_code;
X   }					/* end of main while (1) loop */
X};
X
X/*
X * copy input file to backup file if in_name is /blah/blah/blah/file, then
X * backup file will be ".Bfile" then make the backup file the input and
X * original input file the output
X */
Xbakcopy()
X{
X   int             n, bakchn;
X   char            buff[8 * 1024];
X   register char  *p;
X
X   /* construct file name .Bfile */
X   for (p = in_name; *p; p++);		/* skip to end of string */
X   while (p > in_name && *p != '/')	/* find last '/' */
X      p--;
X   if (*p == '/')
X      p++;
X   sprintf(bakfile, "%s.BAK", p);
X
X   /* copy in_name to backup file */
X   bakchn = creat(bakfile, 0600);
X   if (bakchn < 0)
X   {
X      fprintf(stderr, "indent: can't create backup file \"%s\"\n", bakfile);
X      exit(1);
X   }
X   while (n = read(fileno(input), buff, sizeof buff))
X      if (write(bakchn, buff, n) != n)
X      {
X	 fprintf(stderr, "indent: error writing backup file \"%s\"\n",
X		 bakfile);
X	 exit(1);
X      }
X   if (n < 0)
X   {
X      fprintf(stderr, "indent: error reading input file \"%s\"\n", in_name);
X      exit(1);
X   }
X   close(bakchn);
X   fclose(input);
X
X   /* re-open backup file as the input file */
X   input = fopen(bakfile, "r");
X   if (input == 0)
X   {
X      fprintf(stderr, "indent: can't re-open backup file\n");
X      exit(1);
X   }
X   /* now the original input file will be the output */
X   output = fopen(in_name, "w");
X   if (output == 0)
X   {
X      fprintf(stderr, "indent: can't create %s\n", in_name);
X      unlink(bakfile);
X      exit(1);
X   }
X}
/

hall@cod.NOSC.MIL (Robert R. Hall) (03/25/89)

I tested indent out by formating the code presented here.
I recomment you avoid using it on MINIX version 1.3
stuff for fear of making patch fail when on updates are
released.

-------------------   cut here  ----------------------
echo x - args.c
sed '/^X/s///' > args.c << '/'
X/*
X * Copyright (c) 1985 Sun Microsystems, Inc.
X * Copyright (c) 1980 The Regents of the University of California.
X * Copyright (c) 1976 Board of Trustees of the University of Illinois.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley, the University of Illinois,
X * Urbana, and Sun Microsystems, Inc.  The name of either University
X * or Sun Microsystems may not be used to endorse or promote products
X * derived from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xstatic char     sccsid[] = "@(#)args.c	5.6 (Berkeley) 9/15/88";
X#endif					/* not lint */
X
X/*
X * Argument scanning and profile reading code.  Default parameters are set
X * here as well.
X */
X
X#define PUBLIC extern
X#include "globs.h"
X#include <sys/types.h>
X#include <ctype.h>
X
Xchar           *
X                getenv(), *index();
X
X/* profile types */
X#define	PRO_SPECIAL	1		/* special case */
X#define	PRO_BOOL	2		/* boolean */
X#define	PRO_INT		3		/* integer */
X#define PRO_FONT	4		/* troff font */
X
X/* profile specials for booleans */
X#define	ON		1		/* turn it on */
X#define	OFF		0		/* turn it off */
X
X/* profile specials for specials */
X#define	IGN		1		/* ignore it */
X#define	CLI		2		/* case label indent (float) */
X#define	STDIN		3		/* use stdin */
X#define	KEY		4		/* type (keyword) */
X
X/*
X * N.B.: because of the way the table here is scanned, options whose names are
X * substrings of other options must occur later; that is, with -lp vs -l, -lp
X * must be first.  Also, while (most) booleans occur more than once, the last
X * default value is the one actually assigned.
X */
Xstruct pro
X{
X   char           *p_name;		/* name, eg -bl, -cli */
X   int             p_type;		/* type (int, bool, special) */
X   int             p_default;		/* the default value (if int) */
X   int             p_special;		/* depends on type */
X   int            *p_obj;		/* the associated variable */
X}               pro[] =
X
X{
X
X   "T", PRO_SPECIAL, 0, KEY, 0,
X   "bacc", PRO_BOOL, false, ON, &bl_around,
X   "badp", PRO_BOOL, false, ON, &bl_at_proctop,
X   "bad", PRO_BOOL, false, ON, &bl_aft_decl,
X   "bap", PRO_BOOL, false, ON, &bl_a_procs,
X   "bbb", PRO_BOOL, false, ON, &bl_bef_bk,
X   "bc", PRO_BOOL, true, OFF, &ps.leave_comma,
X   "bl", PRO_BOOL, true, OFF, &btype_2,
X   "br", PRO_BOOL, true, ON, &btype_2,
X   "bs", PRO_BOOL, false, ON, &Bill_Shannon,
X   "cdb", PRO_BOOL, true, ON, &del_on_bl,
X   "cd", PRO_INT, 0, 0, &ps.decl_com_ind,
X   "ce", PRO_BOOL, true, ON, &cuddle_else,
X   "ci", PRO_INT, 0, 0, &continuation_indent,
X   "cli", PRO_SPECIAL, 0, CLI, 0,
X   "c", PRO_INT, 33, 0, &ps.com_ind,
X   "di", PRO_INT, 16, 0, &ps.decl_indent,
X   "dj", PRO_BOOL, false, ON, &ps.ljust_decl,
X   "d", PRO_INT, 0, 0, &ps.unindent_displace,
X   "eei", PRO_BOOL, false, ON, &ex_expr_indent,
X   "ei", PRO_BOOL, true, ON, &ps.else_if,
X   "fbc", PRO_FONT, 0, 0, (int *) &blkcomf,
X   "fbx", PRO_FONT, 0, 0, (int *) &boxcomf,
X   "fb", PRO_FONT, 0, 0, (int *) &bodyf,
X   "fc1", PRO_BOOL, true, ON, &format_col1_comments,
X   "fc", PRO_FONT, 0, 0, (int *) &scomf,
X   "fk", PRO_FONT, 0, 0, (int *) &keywordf,
X   "fs", PRO_FONT, 0, 0, (int *) &stringf,
X   "ip", PRO_BOOL, true, ON, &ps.indent_parameters,
X   "i", PRO_INT, 8, 0, &ps.ind_size,
X   "lc", PRO_INT, 0, 0, &bk_max_col,
X   "lp", PRO_BOOL, true, ON, &lineup_to_parens,
X   "l", PRO_INT, 78, 0, &max_col,
X   "nbacc", PRO_BOOL, false, OFF, &bl_around,
X   "nbadp", PRO_BOOL, false, OFF, &bl_at_proctop,
X   "nbad", PRO_BOOL, false, OFF, &bl_aft_decl,
X   "nbap", PRO_BOOL, false, OFF, &bl_a_procs,
X   "nbbb", PRO_BOOL, false, OFF, &bl_bef_bk,
X   "nbc", PRO_BOOL, true, ON, &ps.leave_comma,
X   "nbs", PRO_BOOL, false, OFF, &Bill_Shannon,
X   "ncdb", PRO_BOOL, true, OFF, &del_on_bl,
X   "nce", PRO_BOOL, true, OFF, &cuddle_else,
X   "ndj", PRO_BOOL, false, OFF, &ps.ljust_decl,
X   "neei", PRO_BOOL, false, OFF, &ex_expr_indent,
X   "nei", PRO_BOOL, true, OFF, &ps.else_if,
X   "nfc1", PRO_BOOL, true, OFF, &format_col1_comments,
X   "nip", PRO_BOOL, true, OFF, &ps.indent_parameters,
X   "nlp", PRO_BOOL, true, OFF, &lineup_to_parens,
X   "npcs", PRO_BOOL, false, OFF, &proc_calls_space,
X   "npro", PRO_SPECIAL, 0, IGN, 0,
X   "npsl", PRO_BOOL, true, OFF, &proc_str_line,
X   "nps", PRO_BOOL, false, OFF, &ptr_binop,
X   "nsc", PRO_BOOL, true, OFF, &star_comment_cont,
X   "nsob", PRO_BOOL, false, OFF, &swallow_opt_bl,
X   "nv", PRO_BOOL, false, OFF, &verbose,
X   "pcs", PRO_BOOL, false, ON, &proc_calls_space,
X   "psl", PRO_BOOL, true, ON, &proc_str_line,
X   "ps", PRO_BOOL, false, ON, &ptr_binop,
X   "sc", PRO_BOOL, true, ON, &star_comment_cont,
X   "sob", PRO_BOOL, false, ON, &swallow_opt_bl,
X   "st", PRO_SPECIAL, 0, STDIN, 0,
X   "troff", PRO_BOOL, false, ON, &troff,
X   "v", PRO_BOOL, false, ON, &verbose,
X   /* whew! */
X   0, 0, 0, 0, 0
X};
X
X/*
X * set_profile reads $HOME/.indent.pro and ./.indent.pro and handles arguments
X * given in these files.
X */
Xset_profile()
X{
X   register FILE  *f;
X   char            fname[BUFSIZ];
X   static char     prof[] = ".indent.pro";
X
X   sprintf(fname, "%s/%s", getenv("HOME"), prof);
X   if ((f = fopen(fname, "r")) != NULL)
X   {
X      scan_profile(f);
X      (void) fclose(f);
X   }
X   if ((f = fopen(prof, "r")) != NULL)
X   {
X      scan_profile(f);
X      (void) fclose(f);
X   }
X}
X
Xscan_profile(f)
X   register FILE  *f;
X{
X   register int    i;
X   register char  *p;
X   char            buf[BUFSIZ];
X
X   while (1)
X   {
X      for (p = buf; (i = getc(f)) != EOF && (*p = i) > ' '; ++p);
X      if (p != buf)
X      {
X	 *p++ = 0;
X	 if (verbose)
X	    printf("profile: %s\n", buf);
X	 set_option(buf);
X      } else if (i == EOF)
X	 return;
X   }
X}
X
Xchar           *param_start;
X
Xeqin(s1, s2)
X   register char  *s1;
X   register char  *s2;
X{
X   while (*s1)
X   {
X      if (*s1++ != *s2++)
X	 return (false);
X   }
X   param_start = s2;
X   return (true);
X}
X
X/*
X * Set the defaults.
X */
Xset_defaults()
X{
X   register struct pro *p;
X
X   /* Because ps.case_indent is a float, we can't initialize it from
X      the table: */
X   ps.case_indent = 0;			/* -cli0.0 */
X   for (p = pro; p->p_name; p++)
X      if (p->p_type != PRO_SPECIAL && p->p_type != PRO_FONT)
X	 *p->p_obj = p->p_default;
X}
X
Xset_option(arg)
X   register char  *arg;
X{
X   register struct pro *p;
X   extern int      atoi();
X
X   arg++;				/* ignore leading "-" */
X   for (p = pro; p->p_name; p++)
X      if (*p->p_name == *arg && eqin(p->p_name, arg))
X	 goto found;
X   fprintf(stderr, "indent: unknown parameter \"%s\"\n", arg - 1);
X   exit(1);
Xfound:
X   switch (p->p_type)
X   {
X
X   case PRO_SPECIAL:
X      switch (p->p_special)
X      {
X
X      case IGN:
X	 break;
X
X      case CLI:
X	 if (*param_start == 0)
X	    goto need_param;
X	 ps.case_indent = atoi(param_start);
X	 break;
X
X      case STDIN:
X	 if (input == 0)
X	    input = stdin;
X	 if (output == 0)
X	    output = stdout;
X	 break;
X
X      case KEY:
X	 if (*param_start == 0)
X	    goto need_param;
X	 {
X	    register char  *str = (char *) malloc(strlen(param_start) + 1);
X	    strcpy(str, param_start);
X	    addkey(str, 4);
X	 }
X	 break;
X
X      default:
X	 fprintf(stderr, "\
Xindent: set_option: internal error: p_special %d\n", p->p_special);
X	 exit(1);
X      }
X      break;
X
X   case PRO_BOOL:
X      if (p->p_special == OFF)
X	 *p->p_obj = false;
X      else
X	 *p->p_obj = true;
X      break;
X
X   case PRO_INT:
X      if (*param_start == 0)
X      {
X   need_param:
X	 fprintf(stderr, "indent: ``%s'' requires a parameter\n",
X		 arg - 1);
X	 exit(1);
X      }
X      *p->p_obj = atoi(param_start);
X      break;
X
X   case PRO_FONT:
X      parsefont((struct fstate *) p->p_obj, param_start);
X      break;
X
X   default:
X      fprintf(stderr, "indent: set_option: internal error: p_type %d\n",
X	      p->p_type);
X      exit(1);
X   }
X}
/
echo x - comment.c
sed '/^X/s///' > comment.c << '/'
X/*
X * Copyright (c) 1985 Sun Microsystems, Inc.
X * Copyright (c) 1980 The Regents of the University of California.
X * Copyright (c) 1976 Board of Trustees of the University of Illinois.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley, the University of Illinois,
X * Urbana, and Sun Microsystems, Inc.  The name of either University
X * or Sun Microsystems may not be used to endorse or promote products
X * derived from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xstatic char     sccsid[] = "@(#)pr_comment.c	5.9 (Berkeley) 9/15/88";
X#endif					/* not lint */
X
X/*
X * NAME:
X *	pr_comment
X *
X * FUNCTION:
X *	This routine takes care of scanning and printing comments.
X *
X * ALGORITHM:
X *	1) Decide where the comment should be aligned, and if lines should
X *	   be broken.
X *	2) If lines should not be broken and filled, just copy up to end of
X *	   comment.
X *	3) If lines should be filled, then scan thru input_buffer copying
X *	   characters to com_buf.  Remember where the last blank, tab, or
X *	   newline was.  When line is filled, print up to last blank and
X *	   continue copying.
X *
X * HISTORY:
X *	November 1976	D A Willcox of CAC	Initial coding
X *	12/6/76		D A Willcox of CAC	Modification to handle
X *						UNIX-style comments
X *
X */
X
X/*
X * this routine processes comments.  It makes an attempt to keep comments from
X * going over the max line length.  If a line is too long, it moves everything
X * from the last blank to the next comment line.  Blanks and tabs from the
X * beginning of the input line are removed
X */
X
X
X#define PUBLIC extern
X#include "globs.h"
X
X
Xpr_comment()
X{
X   int             now_col;		/* column we are in now */
X   int             adj_max_col;		/* Adjusted max_col for when we
X					   decide to spill comments
X					   over the right margin */
X   char           *last_bl;		/* points to the last blank in
X					   the output buffer */
X   char           *t_ptr;		/* used for moving string */
X   int             unix_comment;	/* tri-state variable used to
X					   decide if it is a unix-style
X					   comment. 0 means only blanks
X					   since /*, 1 means regular
X					   style comment, 2 means unix
X					   style comment */
X   int             break_delim = del_on_bl;
X   int             l_just_saw_decl = ps.just_saw_decl;
X   /* int         ps.last_nl = 0;	/* true iff the last
X      significant thing weve seen is a newline */
X   int             one_liner = 1;	/* true iff this comment is a
X					   one-liner */
X   adj_max_col = max_col;
X   ps.just_saw_decl = 0;
X   last_bl = 0;				/* no blanks found so far */
X   ps.box_com = false;			/* at first, assume that we are
X					   not in a boxed comment or
X					   some other comment that
X					   should not be touched */
X   ++ps.out_coms;			/* keep track of number of
X					   comments */
X   unix_comment = 1;			/* set flag to let us figure
X					   out if there is a unix-style
X					   comment ** DISABLED: use 0
X					   to reenable this hack! */
X
X   /* Figure where to align and how to treat the comment */
X
X   if (ps.col_1 && !format_col1_comments)
X   {					/* if comment starts in column
X					   1 it should not be touched */
X      ps.box_com = true;
X      ps.com_col = 1;
X   } else
X   {
X      if (*buf_ptr == '-' || *buf_ptr == '*')
X      {
X	 ps.box_com = true;		/* a comment with a '-' or '*'
X					   immediately after the /* is
X					   assumed to be a boxed
X					   comment */
X	 break_delim = 0;
X      }
X      if ( /* ps.bl_line && */ (s_lab == e_lab) && (s_code == e_code))
X      {
X	 /* klg: check only if this line is blank */
X	 /* If this (*and previous lines are*) blank, dont put comment
X	    way out at left */
X	 ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1;
X	 adj_max_col = bk_max_col;
X	 if (ps.com_col <= 1)
X	    ps.com_col = 1 + !format_col1_comments;
X      } else
X      {
X	 register        target_col;
X	 break_delim = 0;
X	 if (s_code != e_code)
X	    target_col = count_spaces(code_target(), s_code);
X	 else
X	 {
X	    target_col = 1;
X	    if (s_lab != e_lab)
X	       target_col = count_spaces(label_target(), s_lab);
X	 }
X	 ps.com_col = ps.decl_on_line || ps.ind_level == 0 ? ps.decl_com_ind : ps.com_ind;
X	 if (ps.com_col < target_col)
X	    ps.com_col = ((target_col + 7) & ~7) + 1;
X	 if (ps.com_col + 24 > adj_max_col)
X	    adj_max_col = ps.com_col + 24;
X      }
X   }
X   if (ps.box_com)
X   {
X      buf_ptr[-2] = 0;
X      ps.n_comment_delta = 1 - count_spaces(1, in_buffer);
X      buf_ptr[-2] = '/';
X   } else
X   {
X      ps.n_comment_delta = 0;
X      while (*buf_ptr == ' ' || *buf_ptr == '\t')
X	 buf_ptr++;
X   }
X   ps.comment_delta = 0;
X   *e_com++ = '/';			/* put '/*' into buffer */
X   *e_com++ = '*';
X   if (*buf_ptr != ' ' && !ps.box_com)
X      *e_com++ = ' ';
X
X   *e_com = '\0';
X   if (troff)
X   {
X      now_col = 1;
X      adj_max_col = 80;
X   } else
X      now_col = count_spaces(ps.com_col, s_com);	/* figure what column we
X							   would be in if we
X							   printed the comment
X							   now */
X
X   /* Start to copy the comment */
X
X   while (1)
X   {					/* this loop will go until the
X					   comment is copied */
X      if (*buf_ptr > 040 && *buf_ptr != '*')
X	 ps.last_nl = 0;
X      if (e_com >= l_com)
X      {
X	 register        nsize = l_com - s_com + 400;
X	 combuf = (char *) realloc(combuf, nsize);
X	 e_com = combuf + (e_com - s_com) + 1;
X	 l_com = combuf + nsize - 5;
X	 s_com = combuf + 1;
X      }
X      switch (*buf_ptr)
X      {					/* this checks for various spcl
X					   cases */
X      case 014:			/* check for a form feed */
X	 if (!ps.box_com)
X	 {				/* in a text comment, break the
X					   line here */
X	    ps.use_ff = true;
X	    /* fix so dump_line uses a form feed */
X	    dump_line();
X	    last_bl = 0;
X	    *e_com++ = ' ';
X	    *e_com++ = '*';
X	    *e_com++ = ' ';
X	    while (*++buf_ptr == ' ' || *buf_ptr == '\t');
X	 } else
X	 {
X	    if (++buf_ptr >= buf_end)
X	       fill_buffer();
X	    *e_com++ = 014;
X	 }
X	 break;
X
X      case '\n':
X	 if (had_eof)
X	 {				/* check for unexpected eof */
X	    printf("Unterminated comment\n");
X	    *e_com = '\0';
X	    dump_line();
X	    return;
X	 }
X	 one_liner = 0;
X	 if (ps.box_com || ps.last_nl)
X	 {				/* if this is a boxed comment,
X					   we dont ignore the newline */
X	    if (s_com == e_com)
X	    {
X	       *e_com++ = ' ';
X	       *e_com++ = ' ';
X	    }
X	    *e_com = '\0';
X	    if (!ps.box_com && e_com - s_com > 3)
X	    {
X	       if (break_delim == 1 && s_com[0] == '/'
X		   && s_com[1] == '*' && s_com[2] == ' ')
X	       {
X		  char           *t = e_com;
X		  break_delim = 2;
X		  e_com = s_com + 2;
X		  *e_com = 0;
X		  if (bl_bef_bk)
X		     prefix_blankline_requested = 1;
X		  dump_line();
X		  e_com = t;
X		  s_com[0] = s_com[1] = s_com[2] = ' ';
X	       }
X	       dump_line();
X	       if (e_com >= l_com)
X	       {
X		  register        nsize = l_com - s_com + 400;
X		  combuf = (char *) realloc(combuf, nsize);
X		  e_com = combuf + (e_com - s_com) + 1;
X		  l_com = combuf + nsize - 5;
X		  s_com = combuf + 1;
X	       }
X	       *e_com++ = ' ';
X	       *e_com++ = ' ';
X	    }
X	    dump_line();
X	    now_col = ps.com_col;
X	 } else
X	 {
X	    ps.last_nl = 1;
X	    if (unix_comment != 1)
X	    {				/* we not are in unix_style
X					   comment */
X	       if (unix_comment == 0 && s_code == e_code)
X	       {
X		  /* if it is a UNIX-style comment, ignore the
X		     requirement that previous line be blank for
X		     unindention */
X		  ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1;
X		  if (ps.com_col <= 1)
X		     ps.com_col = 2;
X	       }
X	       unix_comment = 2;	/* permanently remember that we
X					   are in this type of comment */
X	       dump_line();
X	       ++line_no;
X	       now_col = ps.com_col;
X	       *e_com++ = ' ';
X	       /* fix so that the star at the start of the line will
X	          line up */
X	       do			/* flush leading white space */
X		  if (++buf_ptr >= buf_end)
X		     fill_buffer();
X	       while (*buf_ptr == ' ' || *buf_ptr == '\t');
X	       break;
X	    }
X	    if (*(e_com - 1) == ' ' || *(e_com - 1) == '\t')
X	       last_bl = e_com - 1;
X	    /* if there was a space at the end of the last line,
X	       remember where it was */
X	    else
X	    {				/* otherwise, insert one */
X	       last_bl = e_com;
X	       *e_com++ = ' ';
X	       if (e_com >= l_com)
X	       {
X		  register        nsize = l_com - s_com + 400;
X		  combuf = (char *) realloc(combuf, nsize);
X		  e_com = combuf + (e_com - s_com) + 1;
X		  l_com = combuf + nsize - 5;
X		  s_com = combuf + 1;
X	       }
X	       ++now_col;
X	    }
X	 }
X	 ++line_no;			/* keep track of input line
X					   number */
X	 if (!ps.box_com)
X	 {
X	    int             nstar = 1;
X	    do
X	    {				/* flush any blanks and/or tabs
X					   at start of next line */
X	       if (++buf_ptr >= buf_end)
X		  fill_buffer();
X	       if (*buf_ptr == '*' && --nstar >= 0)
X	       {
X		  if (++buf_ptr >= buf_end)
X		     fill_buffer();
X		  if (*buf_ptr == '/')
X		     goto end_of_comment;
X	       }
X	    } while (*buf_ptr == ' ' || *buf_ptr == '\t');
X	 } else if (++buf_ptr >= buf_end)
X	    fill_buffer();
X	 break;				/* end of case for newline */
X
X      case '*':			/* must check for possibility
X					   of being at end of comment */
X	 if (++buf_ptr >= buf_end)	/* get to next char after * */
X	    fill_buffer();
X
X	 if (unix_comment == 0)		/* set flag to show we are not
X					   in unix-style comment */
X	    unix_comment = 1;
X
X	 if (*buf_ptr == '/')
X	 {				/* it is the end!!! */
X      end_of_comment:
X	    if (++buf_ptr >= buf_end)
X	       fill_buffer();
X
X	    if (*(e_com - 1) != ' ' && !ps.box_com)
X	    {				/* insure blank before end */
X	       *e_com++ = ' ';
X	       ++now_col;
X	    }
X	    if (break_delim == 1 && !one_liner && s_com[0] == '/'
X		&& s_com[1] == '*' && s_com[2] == ' ')
X	    {
X	       char           *t = e_com;
X	       break_delim = 2;
X	       e_com = s_com + 2;
X	       *e_com = 0;
X	       if (bl_bef_bk)
X		  prefix_blankline_requested = 1;
X	       dump_line();
X	       e_com = t;
X	       s_com[0] = s_com[1] = s_com[2] = ' ';
X	    }
X	    if (break_delim == 2 && e_com > s_com + 3
X		 /* now_col > adj_max_col - 2 && !ps.box_com */ )
X	    {
X	       *e_com = '\0';
X	       dump_line();
X	       now_col = ps.com_col;
X	    }
X	    if (e_com >= l_com)
X	    {
X	       register        nsize = l_com - s_com + 400;
X	       combuf = (char *) realloc(combuf, nsize);
X	       e_com = combuf + (e_com - s_com) + 1;
X	       l_com = combuf + nsize - 5;
X	       s_com = combuf + 1;
X	    }
X	    *e_com++ = '*';
X	    *e_com++ = '/';
X	    *e_com = '\0';
X	    ps.just_saw_decl = l_just_saw_decl;
X	    return;
X	 } else
X	 {				/* handle isolated '*' */
X	    *e_com++ = '*';
X	    ++now_col;
X	 }
X	 break;
X      default:				/* we have a random char */
X	 if (unix_comment == 0 && *buf_ptr != ' ' && *buf_ptr != '\t')
X	    unix_comment = 1;		/* we are not in unix-style
X					   comment */
X
X	 *e_com = *buf_ptr++;
X	 if (buf_ptr >= buf_end)
X	    fill_buffer();
X
X	 if (*e_com == '\t')		/* keep track of column */
X	    now_col = ((now_col - 1) & tabmask) + tabsize + 1;
X	 else if (*e_com == '\b')	/* this is a backspace */
X	    --now_col;
X	 else
X	    ++now_col;
X
X	 if (*e_com == ' ' || *e_com == '\t')
X	    last_bl = e_com;
X	 /* remember we saw a blank */
X
X	 ++e_com;
X	 if (now_col > adj_max_col && !ps.box_com && unix_comment == 1 && e_com[-1] > ' ')
X	 {
X	    /* the comment is too long, it must be broken up */
X	    if (break_delim == 1 && s_com[0] == '/'
X		&& s_com[1] == '*' && s_com[2] == ' ')
X	    {
X	       char           *t = e_com;
X	       break_delim = 2;
X	       e_com = s_com + 2;
X	       *e_com = 0;
X	       if (bl_bef_bk)
X		  prefix_blankline_requested = 1;
X	       dump_line();
X	       e_com = t;
X	       s_com[0] = s_com[1] = s_com[2] = ' ';
X	    }
X	    if (last_bl == 0)
X	    {				/* we have seen no blanks */
X	       last_bl = e_com;		/* fake it */
X	       *e_com++ = ' ';
X	    }
X	    *e_com = '\0';		/* print what we have */
X	    *last_bl = '\0';
X	    while (last_bl > s_com && last_bl[-1] < 040)
X	       *--last_bl = 0;
X	    e_com = last_bl;
X	    dump_line();
X
X	    *e_com++ = ' ';		/* add blanks for continuation */
X	    *e_com++ = ' ';
X	    *e_com++ = ' ';
X
X	    t_ptr = last_bl + 1;
X	    last_bl = 0;
X	    if (t_ptr >= e_com)
X	    {
X	       while (*t_ptr == ' ' || *t_ptr == '\t')
X		  t_ptr++;
X	       while (*t_ptr != '\0')
X	       {			/* move unprinted part of
X					   comment down in buffer */
X		  if (*t_ptr == ' ' || *t_ptr == '\t')
X		     last_bl = e_com;
X		  *e_com++ = *t_ptr++;
X	       }
X	    }
X	    *e_com = '\0';
X	    now_col = count_spaces(ps.com_col, s_com);	/* recompute current
X							   position */
X	 }
X	 break;
X      }
X   }
X}
/
echo x - io.c
sed '/^X/s///' > io.c << '/'
X/*
X * Copyright (c) 1985 Sun Microsystems, Inc.
X * Copyright (c) 1980 The Regents of the University of California.
X * Copyright (c) 1976 Board of Trustees of the University of Illinois.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley, the University of Illinois,
X * Urbana, and Sun Microsystems, Inc.  The name of either University
X * or Sun Microsystems may not be used to endorse or promote products
X * derived from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xstatic char     sccsid[] = "@(#)io.c	5.10 (Berkeley) 9/15/88";
X#endif					/* not lint */
X
X#define PUBLIC extern
X#include "globs.h"
X#include <ctype.h>
X
X
Xint             comment_open;
Xstatic          paren_target;
X
Xdump_line()
X{					/* dump_line is the routine
X					   that actually effects the
X					   printing of the new source.
X					   It prints the label section,
X					   followed by the code section
X					   with the appropriate nesting
X					   level, followed by any
X					   comments */
X   register int    cur_col, target_col;
X   static          not_first_line;
X
X   if (ps.procname[0])
X   {
X      if (troff)
X      {
X	 if (comment_open)
X	 {
X	    comment_open = 0;
X	    fprintf(output, ".*/\n");
X	 }
X	 fprintf(output, ".Pr \"%s\"\n", ps.procname);
X      }
X      ps.ind_level = 0;
X      ps.procname[0] = 0;
X   }
X   if (s_code == e_code && s_lab == e_lab && s_com == e_com)
X   {
X      if (suppress_blanklines > 0)
X	 suppress_blanklines--;
X      else
X      {
X	 ps.bl_line = true;
X	 n_real_blanklines++;
X      }
X   } else if (!inhibit_formatting)
X   {
X      suppress_blanklines = 0;
X      ps.bl_line = false;
X      if (prefix_blankline_requested && not_first_line)
X	 if (swallow_opt_bl)
X	 {
X	    if (n_real_blanklines == 1)
X	       n_real_blanklines = 0;
X	 } else
X	 {
X	    if (n_real_blanklines == 0)
X	       n_real_blanklines = 1;
X	 }
X      while (--n_real_blanklines >= 0)
X	 putc('\n', output);
X      n_real_blanklines = 0;
X      if (ps.ind_level == 0)
X	 ps.ind_stmt = 0;		/* this is a class A kludge.
X					   dont do additional statement
X					   indentation if we are at
X					   bracket level 0 */
X
X      if (e_lab != s_lab || e_code != s_code)
X	 ++code_lines;			/* keep count of lines with
X					   code */
X
X
X      if (e_lab != s_lab)
X      {					/* print lab, if any */
X	 if (comment_open)
X	 {
X	    comment_open = 0;
X	    fprintf(output, ".*/\n");
X	 }
X	 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
X	    e_lab--;
X	 cur_col = pad_output(1, label_target());
X	 fprintf(output, "%.*s", e_lab - s_lab, s_lab);
X	 cur_col = count_spaces(cur_col, s_lab);
X      } else
X	 cur_col = 1;			/* there is no label section */
X
X      ps.pcase = false;
X
X      if (s_code != e_code)
X      {					/* print code section, if any */
X	 register char  *p;
X
X	 if (comment_open)
X	 {
X	    comment_open = 0;
X	    fprintf(output, ".*/\n");
X	 }
X	 target_col = code_target();
X	 {
X	    register        i;
X
X	    for (i = 0; i < ps.p_l_follow; i++)
X	       if (ps.paren_indents[i] >= 0)
X		  ps.paren_indents[i] = -(ps.paren_indents[i] + target_col);
X	 }
X	 cur_col = pad_output(cur_col, target_col);
X	 for (p = s_code; p < e_code; p++)
X	    if (*p == (char) 0200)
X	       fprintf(output, "%d", target_col * 7);
X	    else
X	       putc(*p, output);
X	 cur_col = count_spaces(cur_col, s_code);
X      }
X      if (s_com != e_com)
X	 if (troff)
X	 {
X	    int             all_here = 0;
X	    register char  *p;
X
X	    if (e_com[-1] == '/' && e_com[-2] == '*')
X	       e_com -= 2, all_here++;
X	    while (e_com > s_com && e_com[-1] == ' ')
X	       e_com--;
X	    *e_com = 0;
X	    p = s_com;
X	    while (*p == ' ')
X	       p++;
X	    if (p[0] == '/' && p[1] == '*')
X	       p += 2, all_here++;
X	    else if (p[0] == '*')
X	       p += p[1] == '/' ? 2 : 1;
X	    while (*p == ' ')
X	       p++;
X	    if (*p == 0)
X	       goto inhibit_newline;
X	    if (comment_open < 2 && ps.box_com)
X	    {
X	       comment_open = 0;
X	       fprintf(output, ".*/\n");
X	    }
X	    if (comment_open == 0)
X	    {
X	       if ('a' <= *p && *p <= 'z')
X		  *p = *p + 'A' - 'a';
X	       if (e_com - p < 50 && all_here == 2)
X	       {
X		  register char  *follow = p;
X		  fprintf(output, "\n.nr C! \\w\1");
X		  while (follow < e_com)
X		  {
X		     switch (*follow)
X		     {
X		     case '\n':
X			putc(' ', output);
X		     case 1:
X			break;
X		     case '\\':
X			putc('\\', output);
X		     default:
X			putc(*follow, output);
X		     }
X		     follow++;
X		  }
X		  putc(1, output);
X	       }
X	       fprintf(output, "\n./* %dp %d %dp\n",
X		       ps.com_col * 7,
X		    (s_code != e_code || s_lab != e_lab) - ps.box_com,
X		       target_col * 7);
X	    }
X	    comment_open = 1 + ps.box_com;
X	    while (*p)
X	    {
X	       if (*p == BACKSLASH)
X		  putc(BACKSLASH, output);
X	       putc(*p++, output);
X	    }
X	 } else
X	 {				/* print comment, if any */
X	    register        target = ps.com_col;
X	    register char  *com_st = s_com;
X
X	    target += ps.comment_delta;
X	    while (*com_st == '\t')
X	       com_st++, target += 8;	/* ? */
X	    while (target <= 0)
X	       if (*com_st == ' ')
X		  target++, com_st++;
X	       else if (*com_st == '\t')
X		  target = ((target - 1) & ~7) + 9, com_st++;
X	       else
X		  target = 1;
X	    if (cur_col > target)
X	    {				/* if comment cant fit on this
X					   line, put it on next line */
X	       putc('\n', output);
X	       cur_col = 1;
X	       ++ps.out_lines;
X	    }
X	    while (e_com > com_st && isspace(e_com[-1]))
X	       e_com--;
X	    cur_col = pad_output(cur_col, target);
X	    if (!ps.box_com)
X	    {
X	       if (star_comment_cont && (com_st[1] != '*' || e_com <= com_st + 1))
X		  if (com_st[1] == ' ' && com_st[0] == ' ' && e_com > com_st + 1)
X		     com_st[1] = '*';
X		  else
X		     fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output);
X	    }
X	    fwrite(com_st, e_com - com_st, 1, output);
X	    ps.comment_delta = ps.n_comment_delta;
X	    cur_col = count_spaces(cur_col, com_st);
X	    ++ps.com_lines;		/* count lines with comments */
X	 }
X      if (ps.use_ff)
X	 putc('\014', output);
X      else
X	 putc('\n', output);
Xinhibit_newline:
X      ++ps.out_lines;
X      if (ps.just_saw_decl == 1 && bl_aft_decl)
X      {
X	 prefix_blankline_requested = 1;
X	 ps.just_saw_decl = 0;
X      } else
X	 prefix_blankline_requested = postfix_blankline_requested;
X      postfix_blankline_requested = 0;
X   }
X   ps.decl_on_line = ps.in_decl;	/* if we are in the middle of a
X					   declaration, remember that
X					   fact for proper comment
X					   indentation */
X   ps.ind_stmt = ps.in_stmt & ~ps.in_decl;	/* next line should be
X						   indented if we have
X						   not completed this
X						   stmt and if we are
X						   not in the middle of
X						   a declaration */
X   ps.use_ff = false;
X   ps.dumped_decl_indent = 0;
X   *(e_lab = s_lab) = '\0';		/* reset buffers */
X   *(e_code = s_code) = '\0';
X   *(e_com = s_com) = '\0';
X   ps.ind_level = ps.i_l_follow;
X   ps.paren_level = ps.p_l_follow;
X   paren_target = -ps.paren_indents[ps.paren_level - 1];
X   not_first_line = 1;
X   return;
X};
X
Xcode_target()
X{
X   register        target_col = ps.ind_size * ps.ind_level + 1;
X
X   if (ps.paren_level)
X      if (!lineup_to_parens)
X	 target_col += continuation_indent * ps.paren_level;
X      else
X      {
X	 register        w;
X	 register        t = paren_target;
X
X	 if ((w = count_spaces(t, s_code) - max_col) > 0
X	     && count_spaces(target_col, s_code) <= max_col)
X	 {
X	    t -= w + 1;
X	    if (t > target_col)
X	       target_col = t;
X	 } else
X	    target_col = t;
X      }
X   else if (ps.ind_stmt)
X      target_col += continuation_indent;
X   return target_col;
X}
X
Xlabel_target()
X{
X   return
X      ps.pcase ? (int) (case_ind * ps.ind_size) + 1
X      : *s_lab == '#' ? 1
X      : ps.ind_size * (ps.ind_level - label_offset) + 1;
X}
X
X
X/*
X * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
X *
X * All rights reserved
X *
X *
X * NAME: fill_buffer
X *
X * FUNCTION: Reads one block of input into input_buffer
X *
X * HISTORY: initial coding 	November 1976	D A Willcox of CAC 1/7/77 A
X * Willcox of CAC	Added check for switch back to partly full input
X * buffer from temporary buffer
X *
X */
Xint
Xfill_buffer()
X{					/* this routine reads stuff
X					   from the input */
X   register char  *p;
X   register int    i;
X   register FILE  *f = input;
X
X   if (bp_save != 0)
X   {					/* there is a partly filled
X					   input buffer left */
X      buf_ptr = bp_save;		/* dont read anything, just
X					   switch buffers */
X      buf_end = be_save;
X      bp_save = be_save = 0;
X      if (buf_ptr < buf_end)
X	 return;			/* only return if there is
X					   really something in this
X					   buffer */
X   }
X   for (p = buf_ptr = in_buffer;;)
X   {
X      if ((i = getc(f)) == EOF)
X      {
X	 *p++ = ' ';
X	 *p++ = '\n';
X	 had_eof = true;
X	 break;
X      }
X      *p++ = i;
X      if (i == '\n')
X	 break;
X   }
X   buf_end = p;
X   if (p[-2] == '/' && p[-3] == '*')
X   {
X      if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0)
X	 fill_buffer();			/* flush indent error message */
X      else
X      {
X	 int             com = 0;
X
X	 p = in_buffer;
X	 while (*p == ' ' || *p == '\t')
X	    p++;
X	 if (*p == '/' && p[1] == '*')
X	 {
X	    p += 2;
X	    while (*p == ' ' || *p == '\t')
X	       p++;
X	    if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
X		&& p[4] == 'N' && p[5] == 'T')
X	    {
X	       p += 6;
X	       while (*p == ' ' || *p == '\t')
X		  p++;
X	       if (*p == '*')
X		  com = 1;
X	       else if (*p == 'O')
X		  if (*++p == 'N')
X		     p++, com = 1;
X		  else if (*p == 'F' && *++p == 'F')
X		     p++, com = 2;
X	       while (*p == ' ' || *p == '\t')
X		  p++;
X	       if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com)
X	       {
X		  if (s_com != e_com || s_lab != e_lab || s_code != e_code)
X		     dump_line();
X		  if (!(inhibit_formatting = com - 1))
X		  {
X		     n_real_blanklines = 0;
X		     postfix_blankline_requested = 0;
X		     prefix_blankline_requested = 0;
X		     suppress_blanklines = 1;
X		  }
X	       }
X	    }
X	 }
X      }
X   }
X   if (inhibit_formatting)
X   {
X      p = in_buffer;
X      do
X	 putc(*p, output);
X      while (*p++ != '\n');
X   }
X   return;
X};
X
X/*
X * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
X *
X * All rights reserved
X *
X *
X * NAME: pad_output
X *
X * FUNCTION: Writes tabs and spaces to move the current column up to the desired
X * position.
X *
X * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
X *
X * PARAMETERS: current		integer		The current column target
X * nteger		The desired column
X *
X * RETURNS: Integer value of the new column.  (If current >= target, no action is
X * taken, and current is returned.
X *
X * GLOBALS: None
X *
X * CALLS: write (sys)
X *
X * CALLED BY: dump_line
X *
X * HISTORY: initial coding 	November 1976	D A Willcox of CAC
X *
X */
Xpad_output(current, target)		/* writes tabs and blanks (if
X					   necessary) to get the
X					   current output position up
X					   to the target column */
X   int             current;		/* the current column value */
X   int             target;		/* position we want it at */
X{
X   register int    curr;		/* internal column pointer */
X   register int    tcur;
X
X   if (troff)
X      fprintf(output, "\\h'|%dp'", (target - 1) * 7);
X   else
X   {
X      if (current >= target)
X	 return (current);		/* line is already long enough */
X      curr = current;
X      while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target)
X      {
X	 putc('\t', output);
X	 curr = tcur;
X      }
X      while (curr++ < target)
X	 putc(' ', output);		/* pad with final blanks */
X   }
X   return (target);
X};
X
X/*
X * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
X *
X * All rights reserved
X *
X *
X * NAME: count_spaces
X *
X * FUNCTION: Find out where printing of a given string will leave the current
X * character position on output.
X *
X * ALGORITHM: Run thru input string and add appropriate values to current
X * position.
X *
X * RETURNS: Integer value of position after printing "buffer" starting in column
X * "current".
X *
X * HISTORY: initial coding 	November 1976	D A Willcox of CAC
X *
X */
Xint
Xcount_spaces(current, buffer)
X/*
X * this routine figures out where the character position will be after
X * printing the text in buffer starting at column "current"
X */
X   int             current;
X   char           *buffer;
X{
X   register char  *buf;			/* used to look thru buffer */
X   register int    cur;			/* current character counter */
X
X   cur = current;
X
X   for (buf = buffer; *buf != '\0'; ++buf)
X   {
X      switch (*buf)
X      {
X
X      case '\n':
X      case 014:			/* form feed */
X	 cur = 1;
X	 break;
X
X      case '\t':
X	 cur = ((cur - 1) & tabmask) + tabsize + 1;
X	 break;
X
X      case '':				/* this is a backspace */
X	 --cur;
X	 break;
X
X      default:
X	 ++cur;
X	 break;
X      }					/* end of switch */
X   }					/* end of for loop */
X   return (cur);
X};
X
Xint             found_err;
Xdiag(level, msg, a, b)
X{
X   if (level)
X      found_err = 1;
X   if (output == stdout)
X   {
X      fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
X      fprintf(stdout, msg, a, b);
X      fprintf(stdout, " */\n");
X   } else
X   {
X      fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
X      fprintf(stderr, msg, a, b);
X      fprintf(stderr, "\n");
X   }
X}
X
Xwritefdef(f, nm)
X   register struct fstate *f;
X{
X   fprintf(output, ".ds f%c %s\n.nr s%c %d\n",
X	   nm, f->font, nm, f->size);
X}
X
Xchar           *
Xchfont(of, nf, s)
X   register struct fstate *of, *nf;
X   char           *s;
X{
X   if (of->font[0] != nf->font[0]
X       || of->font[1] != nf->font[1])
X   {
X      *s++ = '\\';
X      *s++ = 'f';
X      if (nf->font[1])
X      {
X	 *s++ = '(';
X	 *s++ = nf->font[0];
X	 *s++ = nf->font[1];
X      } else
X	 *s++ = nf->font[0];
X   }
X   if (nf->size != of->size)
X   {
X      *s++ = '\\';
X      *s++ = 's';
X      if (nf->size < of->size)
X      {
X	 *s++ = '-';
X	 *s++ = '0' + of->size - nf->size;
X      } else
X      {
X	 *s++ = '+';
X	 *s++ = '0' + nf->size - of->size;
X      }
X   }
X   return s;
X}
X
X
Xparsefont(f, s0)
X   register struct fstate *f;
X   char           *s0;
X{
X   register char  *s = s0;
X   int             sizedelta = 0;
X   bzero(f, sizeof *f);
X   while (*s)
X   {
X      if (isdigit(*s))
X	 f->size = f->size * 10 + *s - '0';
X      else if (isupper(*s))
X	 if (f->font[0])
X	    f->font[1] = *s;
X	 else
X	    f->font[0] = *s;
X      else if (*s == 'c')
X	 f->allcaps = 1;
X      else if (*s == '+')
X	 sizedelta++;
X      else if (*s == '-')
X	 sizedelta--;
X      else
X      {
X	 fprintf(stderr, "indent: bad font specification: %s\n", s0);
X	 exit(1);
X      }
X      s++;
X   }
X   if (f->font[0] == 0)
X      f->font[0] = 'R';
X   if (bodyf.size == 0)
X      bodyf.size = 11;
X   if (f->size == 0)
X      f->size = bodyf.size + sizedelta;
X   else if (sizedelta > 0)
X      f->size += bodyf.size;
X   else
X      f->size = bodyf.size - f->size;
X}
/
echo x - lexi.c
sed '/^X/s///' > lexi.c << '/'
X/*
X * Copyright (c) 1985 Sun Microsystems, Inc.
X * Copyright (c) 1980 The Regents of the University of California.
X * Copyright (c) 1976 Board of Trustees of the University of Illinois.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley, the University of Illinois,
X * Urbana, and Sun Microsystems, Inc.  The name of either University
X * or Sun Microsystems may not be used to endorse or promote products
X * derived from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xstatic char     sccsid[] = "@(#)lexi.c	5.11 (Berkeley) 9/15/88";
X#endif					/* not lint */
X
X/*
X * Here we have the token scanner for indent.  It scans off one token and puts
X * it in the global variable "token".  It returns a code, indicating the type
X * of token scanned.
X */
X
X#define PUBLIC extern
X#include "globs.h"
X#include "codes.h"
X#include "ctype.h"
X
X#define alphanum 1
X#define opchar 3
X
Xstruct templ
X{
X   char           *rwd;
X   int             rwcode;
X};
X
Xstruct templ    specials[100] =
X{
X   "switch", 1,
X   "case", 2,
X   "break", 0,
X   "struct", 3,
X   "union", 3,
X   "enum", 3,
X   "default", 2,
X   "int", 4,
X   "char", 4,
X   "float", 4,
X   "double", 4,
X   "long", 4,
X   "short", 4,
X   "typdef", 4,
X   "unsigned", 4,
X   "register", 4,
X   "static", 4,
X   "global", 4,
X   "extern", 4,
X   "void", 4,
X   "goto", 0,
X   "return", 0,
X   "if", 5,
X   "while", 5,
X   "for", 5,
X   "else", 6,
X   "do", 6,
X   "sizeof", 7,
X   0, 0
X};
X
Xchar            chartype[128] =
X{					/* this is used to facilitate
X					   the decision of what type
X					   (alphanumeric, operator)
X					   each character is */
X   0, 0, 0, 0, 0, 0, 0, 0,
X   0, 0, 0, 0, 0, 0, 0, 0,
X   0, 0, 0, 0, 0, 0, 0, 0,
X   0, 0, 0, 0, 0, 0, 0, 0,
X   0, 3, 0, 0, 1, 3, 3, 0,
X   0, 0, 3, 3, 0, 3, 0, 3,
X   1, 1, 1, 1, 1, 1, 1, 1,
X   1, 1, 0, 0, 3, 3, 3, 3,
X   0, 1, 1, 1, 1, 1, 1, 1,
X   1, 1, 1, 1, 1, 1, 1, 1,
X   1, 1, 1, 1, 1, 1, 1, 1,
X   1, 1, 1, 0, 0, 0, 3, 1,
X   0, 1, 1, 1, 1, 1, 1, 1,
X   1, 1, 1, 1, 1, 1, 1, 1,
X   1, 1, 1, 1, 1, 1, 1, 1,
X   1, 1, 1, 0, 3, 0, 3, 0
X};
X
X
X
X
Xint
Xlexi()
X{
X   register char  *tok;			/* local pointer to next char
X					   in token */
X   int             unary_delim;		/* this is set to 1 if the
X					   current token
X					
X					forces a following operator to
X					   be unary */
X   static int      last_code;		/* the last token type returned */
X   static int      l_struct;		/* set to 1 if the last token
X					   was 'struct' */
X   int             code;		/* internal code to be returned */
X   char            qchar;		/* the delimiter character for
X					   a string */
X
X   tok = token;				/* point to start of place to
X					   save token */
X   unary_delim = false;
X   ps.col_1 = ps.last_nl;		/* tell world that this token
X					   started in column 1 iff the
X					   last thing scanned was nl */
X   ps.last_nl = false;
X
X   while (*buf_ptr == ' ' || *buf_ptr == '\t')
X   {					/* get rid of blanks */
X      ps.col_1 = false;			/* leading blanks imply token
X					   is not in column 1 */
X      if (++buf_ptr >= buf_end)
X	 fill_buffer();
X   }
X
X   /* Scan an alphanumeric token */
X   if (chartype[*buf_ptr] == alphanum || buf_ptr[0] == '.' && isdigit(buf_ptr[1]))
X   {
X      /* we have a character or number */
X      register char  *j;		/* used for searching thru list
X					   of
X					
X					reserved words */
X      register struct templ *p;
X
X      if (isdigit(*buf_ptr) || buf_ptr[0] == '.' && isdigit(buf_ptr[1]))
X      {
X	 int             seendot = 0, seenexp = 0;
X	 if (*buf_ptr == '0' &&
X	     (buf_ptr[1] == 'x' || buf_ptr[1] == 'X'))
X	 {
X	    *tok++ = *buf_ptr++;
X	    *tok++ = *buf_ptr++;
X	    while (isxdigit(*buf_ptr))
X	       *tok++ = *buf_ptr++;
X	 } else
X	    while (1)
X	    {
X	       if (*buf_ptr == '.')
X		  if (seendot)
X		     break;
X		  else
X		     seendot++;
X	       *tok++ = *buf_ptr++;
X	       if (!isdigit(*buf_ptr) && *buf_ptr != '.')
X		  if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp)
X		     break;
X		  else
X		  {
X		     seenexp++;
X		     seendot++;
X		     *tok++ = *buf_ptr++;
X		     if (*buf_ptr == '+' || *buf_ptr == '-')
X			*tok++ = *buf_ptr++;
X		  }
X	    }
X	 if (*buf_ptr == 'L' || *buf_ptr == 'l')
X	    *tok++ = *buf_ptr++;
X      } else
X	 while (chartype[*buf_ptr] == alphanum)
X	 {				/* copy it over */
X	    *tok++ = *buf_ptr++;
X	    if (buf_ptr >= buf_end)
X	       fill_buffer();
X	 }
X      *tok++ = '\0';
X      while (*buf_ptr == ' ' || *buf_ptr == '\t')
X      {					/* get rid of blanks */
X	 if (++buf_ptr >= buf_end)
X	    fill_buffer();
X      }
X      ps.its_a_keyword = false;
X      ps.sizeof_keyword = false;
X      if (l_struct)
X      {					/* if last token was 'struct',
X					   then this token should be
X					   treated as a declaration */
X	 l_struct = false;
X	 last_code = ident;
X	 ps.last_u_d = true;
X	 return (decl);
X      }
X      ps.last_u_d = false;		/* Operator after indentifier
X					   is binary */
X      last_code = ident;		/* Remember that this is the
X					   code we will return */
X
X      /* This loop will check if the token is a keyword. */
X      for (p = specials; (j = p->rwd) != 0; p++)
X      {
X	 tok = token;			/* point at scanned token */
X	 if (*j++ != *tok++ || *j++ != *tok++)
X	    continue;			/* This test depends on the
X					   fact that identifiers are
X					   always at least 1 character
X					   long (ie. the first two
X					   bytes of the identifier are
X					   always meaningful) */
X	 if (tok[-1] == 0)
X	    break;			/* If its a one-character
X					   identifier */
X	 while (*tok++ == *j)
X	    if (*j++ == 0)
X	       goto found_keyword;	/* I wish that C had a
X					   multi-level break... */
X      }
X      if (p->rwd)
X      {					/* we have a keyword */
X   found_keyword:
X	 ps.its_a_keyword = true;
X	 ps.last_u_d = true;
X	 switch (p->rwcode)
X	 {
X	 case 1:			/* it is a switch */
X	    return (swstmt);
X	 case 2:			/* a case or default */
X	    return (casestmt);
X
X	 case 3:			/* a "struct" */
X	    if (ps.p_l_follow)
X	       break;			/* inside parens: cast */
X	    l_struct = true;
X
X	    /* Next time around, we will want to know that we have had
X	       a 'struct' */
X	 case 4:			/* one of the declaration
X					   keywords */
X	    if (ps.p_l_follow)
X	    {
X	       ps.cast_mask |= 1 << ps.p_l_follow;
X	       break;			/* inside parens: cast */
X	    }
X	    last_code = decl;
X	    return (decl);
X
X	 case 5:			/* if, while, for */
X	    return (sp_paren);
X
X	 case 6:			/* do, else */
X	    return (sp_nparen);
X
X	 case 7:
X	    ps.sizeof_keyword = true;
X	 default:			/* all others are treated like
X					   any other identifier */
X	    return (ident);
X	 }				/* end of switch */
X      }					/* end of if (found_it) */
X      if (*buf_ptr == '(' && ps.tos <= 1 && ps.ind_level == 0)
X      {
X	 register char  *tp = buf_ptr;
X	 while (tp < buf_end)
X	    if (*tp++ == ')' && *tp == ';')
X	       goto not_proc;
X	 strncpy(ps.procname, token, sizeof ps.procname - 1);
X	 ps.in_par_decl = 1;
X   not_proc:;
X      }
X      /* The following hack attempts to guess whether or not the
X         current token is in fact a declaration keyword -- one that has
X         been typedefd */
X      if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr) || *buf_ptr == '_')
X	  && !ps.p_l_follow
X	  && !ps.block_init
X	  && (ps.last_token == rparen || ps.last_token == semicolon ||
X	      ps.last_token == decl ||
X	      ps.last_token == lbrace || ps.last_token == rbrace))
X      {
X	 ps.its_a_keyword = true;
X	 ps.last_u_d = true;
X	 last_code = decl;
X	 return decl;
X      }
X      if (last_code == decl)		/* if this is a declared
X					   variable, then following
X					   sign is unary */
X	 ps.last_u_d = true;		/* will make "int a -1" work */
X      last_code = ident;
X      return (ident);			/* the ident is not in the list */
X   }					/* end of procesing for alpanum
X					   character */
X   /*    l l l Scan a non-alphanumeric token */
X   *tok++ = *buf_ptr;			/* if it is only a
X					   one-character token, it is
X					   moved here */
X   *tok = '\0';
X   if (++buf_ptr >= buf_end)
X      fill_buffer();
X
X   switch (*token)
X   {
X   case '\n':
X      unary_delim = ps.last_u_d;
X      ps.last_nl = true;		/* remember that we just had a
X					   newline */
X      code = (had_eof ? 0 : newline);
X
X      /* if data has been exausted, the newline is a dummy, and we
X         should return code to stop */
X      break;
X
X   case '\'':				/* start of quoted character */
X   case '"':				/* start of string */
X      qchar = *token;
X      if (troff)
X      {
X	 tok[-1] = '`';
X	 if (qchar == '"')
X	    *tok++ = '`';
X	 tok = chfont(&bodyf, &stringf, tok);
X      }
X      do
X      {					/* copy the string */
X	 while (1)
X	 {				/* move one character or
X					   [/<char>]<char> */
X	    if (*buf_ptr == '\n')
X	    {
X	       printf("%d: Unterminated literal\n", line_no);
X	       goto stop_lit;
X	    }
X	    *tok = *buf_ptr++;
X	    if (buf_ptr >= buf_end)
X	       fill_buffer();
X	    if (had_eof || ((tok - token) > (bufsize - 2)))
X	    {
X	       printf("Unterminated literal\n");
X	       ++tok;
X	       goto stop_lit;
X	       /* get outof literal copying loop */
X	    }
X	    if (*tok == BACKSLASH)
X	    {				/* if escape, copy extra char */
X	       if (*buf_ptr == '\n')	/* check for escaped newline */
X		  ++line_no;
X	       if (troff)
X	       {
X		  *++tok = BACKSLASH;
X		  if (*buf_ptr == BACKSLASH)
X		     *++tok = BACKSLASH;
X	       }
X	       *++tok = *buf_ptr++;
X	       ++tok;			/* we must increment this again
X					   because we copied two chars */
X	       if (buf_ptr >= buf_end)
X		  fill_buffer();
X	    } else
X	       break;			/* we copied one character */
X	 }				/* end of while (1) */
X      } while (*tok++ != qchar);
X      if (troff)
X      {
X	 tok = chfont(&stringf, &bodyf, tok - 1);
X	 if (qchar == '"')
X	    *tok++ = '\'';
X      }
Xstop_lit:
X      code = ident;
X      break;
X
X   case ('('):
X   case ('['):
X      unary_delim = true;
X      code = lparen;
X      break;
X
X   case (')'):
X   case (']'):
X      code = rparen;
X      break;
X
X   case '#':
X      unary_delim = ps.last_u_d;
X      code = preesc;
X      break;
X
X   case '?':
X      unary_delim = true;
X      code = question;
X      break;
X
X   case (':'):
X      code = colon;
X      unary_delim = true;
X      break;
X
X   case (';'):
X      unary_delim = true;
X      code = semicolon;
X      break;
X
X   case ('{'):
X      unary_delim = true;
X
X      /* if (ps.in_or_st) ps.block_init = 1; */
X      /* ?	code = ps.block_init ? lparen : lbrace; */
X      code = lbrace;
X      break;
X
X   case ('}'):
X      unary_delim = true;
X      /* ?	code = ps.block_init ? rparen : rbrace; */
X      code = rbrace;
X      break;
X
X   case 014:				/* a form feed */
X      unary_delim = ps.last_u_d;
X      ps.last_nl = true;		/* remember this so we can set
X					   'ps.col_1' right */
X      code = form_feed;
X      break;
X
X   case (','):
X      unary_delim = true;
X      code = comma;
X      break;
X
X   case '.':
X      unary_delim = false;
X      code = period;
X      break;
X
X   case '-':
X   case '+':				/* check for -, +, --, ++ */
X      code = (ps.last_u_d ? unary_op : binary_op);
X      unary_delim = true;
X
X      if (*buf_ptr == token[0])
X      {
X	 /* check for doubled character */
X	 *tok++ = *buf_ptr++;
X	 /* buffer overflow will be checked at end of loop */
X	 if (last_code == ident || last_code == rparen)
X	 {
X	    code = (ps.last_u_d ? unary_op : postop);
X	    /* check for following ++ or -- */
X	    unary_delim = false;
X	 }
X      } else if (*buf_ptr == '=')
X	 /* check for operator += */
X	 *tok++ = *buf_ptr++;
X      else if (*buf_ptr == '>')
X      {
X	 /* check for operator -> */
X	 *tok++ = *buf_ptr++;
X	 if (!ptr_binop)
X	 {
X	    unary_delim = false;
X	    code = unary_op;
X	    ps.want_blank = false;
X	 }
X      }
X      break;				/* buffer overflow will be
X					   checked at end of switch */
X
X   case '=':
X      if (ps.in_or_st)
X	 ps.block_init = 1;
X#ifdef undef
X      if (chartype[*buf_ptr] == opchar)
X      {					/* we have two char assignment */
X	 tok[-1] = *buf_ptr++;
X	 if ((tok[-1] == '<' || tok[-1] == '>') && tok[-1] == *buf_ptr)
X	    *tok++ = *buf_ptr++;
X	 *tok++ = '=';			/* Flip =+ to += */
X	 *tok = 0;
X      }
X#else
X      if (*buf_ptr == '=')
X      {					/* == */
X	 *tok++ = '=';			/* Flip =+ to += */
X	 buf_ptr++;
X	 *tok = 0;
X      }
X#endif
X      code = binary_op;
X      unary_delim = true;
X      break;
X      /* can drop thru!!! */
X
X   case '>':
X   case '<':
X   case '!':				/* ops like <, <<, <=, !=, etc */
X      if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=')
X      {
X	 *tok++ = *buf_ptr;
X	 if (++buf_ptr >= buf_end)
X	    fill_buffer();
X      }
X      if (*buf_ptr == '=')
X	 *tok++ = *buf_ptr++;
X      code = (ps.last_u_d ? unary_op : binary_op);
X      unary_delim = true;
X      break;
X
X   default:
X      if (token[0] == '/' && *buf_ptr == '*')
X      {
X	 /* it is start of comment */
X	 *tok++ = '*';
X
X	 if (++buf_ptr >= buf_end)
X	    fill_buffer();
X
X	 code = comment;
X	 unary_delim = ps.last_u_d;
X	 break;
X      }
X      while (*(tok - 1) == *buf_ptr || *buf_ptr == '=')
X      {
X	 /* handle ||, &&, etc, and also things as in int *****i */
X	 *tok++ = *buf_ptr;
X	 if (++buf_ptr >= buf_end)
X	    fill_buffer();
X      }
X      code = (ps.last_u_d ? unary_op : binary_op);
X      unary_delim = true;
X
X
X   }					/* end of switch */
X   if (code != newline)
X   {
X      l_struct = false;
X      last_code = code;
X   }
X   if (buf_ptr >= buf_end)		/* check for input buffer empty */
X      fill_buffer();
X   ps.last_u_d = unary_delim;
X   *tok = '\0';				/* null terminate the token */
X   return (code);
X};
X
X/*
X * Add the given keyword to the keyword table, using val as the keyword type
X */
Xaddkey(key, val)
X   char           *key;
X{
X   register struct templ *p = specials;
X   while (p->rwd)
X      if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0)
X	 return;
X      else
X	 p++;
X   if (p >= specials + sizeof specials / sizeof specials[0])
X      return;				/* For now, table overflows are
X					   silently ignored */
X   p->rwd = key;
X   p->rwcode = val;
X   p[1].rwd = 0;
X   p[1].rwcode = 0;
X   return;
X}
/
echo x - parse.c
sed '/^X/s///' > parse.c << '/'
X/*
X * Copyright (c) 1985 Sun Microsystems, Inc.
X * Copyright (c) 1980 The Regents of the University of California.
X * Copyright (c) 1976 Board of Trustees of the University of Illinois.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley, the University of Illinois,
X * Urbana, and Sun Microsystems, Inc.  The name of either University
X * or Sun Microsystems may not be used to endorse or promote products
X * derived from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xstatic char     sccsid[] = "@(#)parse.c	5.8 (Berkeley) 9/15/88";
X#endif					/* not lint */
X
X#define PUBLIC	extern
X#include "./globs.h"
X#include "./codes.h"
X
X
X
X
Xparse(tk)
X   int             tk;			/* the code for the construct
X					   scanned */
X{
X   int             i;
X
X#ifdef debug
X   printf("%2d - %s\n", tk, token);
X#endif
X
X   while (ps.p_stack[ps.tos] == ifhead && tk != elselit)
X   {
X      /* true if we have an if without an else */
X      ps.p_stack[ps.tos] = stmt;	/* apply the if(..) stmt ::=
X					   stmt reduction */
X      reduce();				/* see if this allows any
X					   reduction */
X   }
X
X
X   switch (tk)
X   {					/* go on and figure out what to
X					   do with the input */
X
X   case decl:				/* scanned a declaration word */
X      ps.search_brace = btype_2;
X      /* indicate that following brace should be on same line */
X      if (ps.p_stack[ps.tos] != decl)
X      {					/* only put one declaration
X					   onto stack */
X	 break_comma = true;		/* while in declaration,
X					   newline should be forced
X					   after comma */
X	 ps.p_stack[++ps.tos] = decl;
X	 ps.il[ps.tos] = ps.i_l_follow;
X
X	 if (ps.ljust_decl)
X	 {				/* only do if we want left
X					   justified declarations */
X	    ps.ind_level = 0;
X	    for (i = ps.tos - 1; i > 0; --i)
X	       if (ps.p_stack[i] == decl)
X		  ++ps.ind_level;	/* indentation is number of
X					   declaration levels deep we
X					   are */
X	    ps.i_l_follow = ps.ind_level;
X	 }
X      }
X      break;
X
X   case ifstmt:			/* scanned if (...) */
X      if (ps.p_stack[ps.tos] == elsehead && ps.else_if)	/* "else if ..." */
X	 ps.i_l_follow = ps.il[ps.tos];
X   case dolit:				/* 'do' */
X   case forstmt:			/* for (...) */
X      ps.p_stack[++ps.tos] = tk;
X      ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
X      ++ps.i_l_follow;			/* subsequent statements should
X					   be indented 1 */
X      ps.search_brace = btype_2;
X      break;
X
X   case lbrace:			/* scanned { */
X      break_comma = false;		/* don't break comma in an
X					   initial list */
X      if (ps.p_stack[ps.tos] == stmt || ps.p_stack[ps.tos] == decl
X	  || ps.p_stack[ps.tos] == stmtl)
X	 ++ps.i_l_follow;		/* it is a random, isolated
X					   stmt group or a declaration */
X      else
X      {
X	 if (s_code == e_code)
X	 {
X	    /* only do this if there is nothing on the line */
X	    --ps.ind_level;
X	    /* it is a group as part of a while, for, etc. */
X	    if (ps.p_stack[ps.tos] == swstmt && ps.case_indent >= 1)
X	       --ps.ind_level;
X	    /* for a switch, brace should be two levels out from the
X	       code */
X	 }
X      }
X
X      ps.p_stack[++ps.tos] = lbrace;
X      ps.il[ps.tos] = ps.ind_level;
X      ps.p_stack[++ps.tos] = stmt;
X      /* allow null stmt between braces */
X      ps.il[ps.tos] = ps.i_l_follow;
X      break;
X
X   case whilestmt:			/* scanned while (...) */
X      if (ps.p_stack[ps.tos] == dohead)
X      {
X	 /* it is matched with do stmt */
X	 ps.ind_level = ps.i_l_follow = ps.il[ps.tos];
X	 ps.p_stack[++ps.tos] = whilestmt;
X	 ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
X      } else
X      {					/* it is a while loop */
X	 ps.p_stack[++ps.tos] = whilestmt;
X	 ps.il[ps.tos] = ps.i_l_follow;
X	 ++ps.i_l_follow;
X	 ps.search_brace = btype_2;
X      }
X
X      break;
X
X   case elselit:			/* scanned an else */
X
X      if (ps.p_stack[ps.tos] != ifhead)
X	 diag(1, "Unmatched 'else'");
X      else
X      {
X	 ps.ind_level = ps.il[ps.tos];	/* indentation for else should
X					   be same as for if */
X	 ps.i_l_follow = ps.ind_level + 1;	/* everything following
X						   should be in 1 level */
X	 ps.p_stack[ps.tos] = elsehead;
X	 /* remember if with else */
X	 ps.search_brace = btype_2 | ps.else_if;
X      }
X      break;
X
X   case rbrace:			/* scanned a } */
X      /* stack should have <lbrace> <stmt> or <lbrace> <stmtl> */
X      if (ps.p_stack[ps.tos - 1] == lbrace)
X      {
X	 ps.ind_level = ps.i_l_follow = ps.il[--ps.tos];
X	 ps.p_stack[ps.tos] = stmt;
X      } else
X	 diag(1, "Stmt nesting error.");
X      break;
X
X   case swstmt:			/* had switch (...) */
X      ps.p_stack[++ps.tos] = swstmt;
X      ps.cstk[ps.tos] = case_ind;
X      /* save current case indent level */
X      ps.il[ps.tos] = ps.i_l_follow;
X      case_ind = ps.i_l_follow + ps.case_indent;	/* cases should be one
X							   level down from
X							   switch */
X      ps.i_l_follow += ps.case_indent + 1;	/* statements should be
X						   two levels in */
X      ps.search_brace = btype_2;
X      break;
X
X   case semicolon:			/* this indicates a simple stmt */
X      break_comma = false;		/* turn off flag to break after
X					   commas in a declaration */
X      ps.p_stack[++ps.tos] = stmt;
X      ps.il[ps.tos] = ps.ind_level;
X      break;
X
X   default:				/* this is an error */
X      diag(1, "Unknown code to parser");
X      return;
X
X
X   }					/* end of switch */
X
X   reduce();				/* see if any reduction can be
X					   done */
X
X#ifdef debug
X   for (i = 1; i <= ps.tos; ++i)
X      printf("(%d %d)", ps.p_stack[i], ps.il[i]);
X   printf("\n");
X#endif
X
X   return;
X}
X
X/*
X * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
X *
X * All rights reserved
X *
X *
X * NAME: reduce
X *
X * FUNCTION: Implements the reduce part of the parsing algorithm
X *
X * ALGORITHM: The following reductions are done.  Reductions are repeated until
X * no more are possible.
X *
X * Old TOS		New TOS <stmt> <stmt>	<stmtl> <stmtl> <stmt>	<stmtl> do
X * <stmt>	"dostmt" if <stmt>	"ifstmt" switch <stmt>	<stmt> decl
X * <stmt>	<stmt> "ifelse" <stmt>	<stmt> for <stmt>	<stmt> while
X * <stmt>	<stmt> "dostmt" while	<stmt>
X *
X * On each reduction, ps.i_l_follow (the indentation for the following line) is
X * set to the indentation level associated with the old TOS.
X *
X * PARAMETERS: None
X *
X * RETURNS: Nothing
X *
X * GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos =
X *
X * CALLS: None
X *
X * CALLED BY: parse
X *
X * HISTORY: initial coding 	November 1976	D A Willcox of CAC
X *
X */
X/*----------------------------------------------*\
X|   REDUCTION PHASE				    |
X\*----------------------------------------------*/
Xreduce()
X{
X
X   register int    i;
X
X   for (;;)
X   {					/* keep looping until there is
X					   nothing left to reduce */
X
X      switch (ps.p_stack[ps.tos])
X      {
X
X      case stmt:
X	 switch (ps.p_stack[ps.tos - 1])
X	 {
X
X	 case stmt:
X	 case stmtl:
X	    /* stmtl stmt or stmt stmt */
X	    ps.p_stack[--ps.tos] = stmtl;
X	    break;
X
X	 case dolit:			/* <do> <stmt> */
X	    ps.p_stack[--ps.tos] = dohead;
X	    ps.i_l_follow = ps.il[ps.tos];
X	    break;
X
X	 case ifstmt:
X	    /* <if> <stmt> */
X	    ps.p_stack[--ps.tos] = ifhead;
X	    for (i = ps.tos - 1;
X		 (
X		  ps.p_stack[i] != stmt
X		  &&
X		  ps.p_stack[i] != stmtl
X		  &&
X		  ps.p_stack[i] != lbrace
X		  );
X		 --i);
X	    ps.i_l_follow = ps.il[i];
X	    /* for the time being, we will assume that there is no else
X	       on this if, and set the indentation level accordingly.
X	       If an else is scanned, it will be fixed up later */
X	    break;
X
X	 case swstmt:
X	    /* <switch> <stmt> */
X	    case_ind = ps.cstk[ps.tos - 1];
X
X	 case decl:			/* finish of a declaration */
X	 case elsehead:
X	    /* <<if> <stmt> else> <stmt> */
X	 case forstmt:
X	    /* <for> <stmt> */
X	 case whilestmt:
X	    /* <while> <stmt> */
X	    ps.p_stack[--ps.tos] = stmt;
X	    ps.i_l_follow = ps.il[ps.tos];
X	    break;
X
X	 default:			/* <anything else> <stmt> */
X	    return;
X
X	 }				/* end of section for <stmt> on
X					   top of stack */
X	 break;
X
X      case whilestmt:			/* while (...) on top */
X	 if (ps.p_stack[ps.tos - 1] == dohead)
X	 {
X	    /* it is termination of a do while */
X	    ps.p_stack[--ps.tos] = stmt;
X	    break;
X	 } else
X	    return;
X
X      default:				/* anything else on top */
X	 return;
X
X      }
X   }
X}
/