/************    DOCUMENTATION

cb [-jnst] [-l length] [ file ...]    --- C program beautifier ---
    j: split lines are put back together
    l: split lines that are longer than length
    n: tab = n spaces (default = 2)
    s: K & R style
    t: tab = real tabs

    cb temp>file.c		Beautifies temp and places result in file.c
    cb temp1 temp2>>file.c	Beautifies temp1 & temp2 and adds to file.c

                                           ********************************/


#include <stdio.h>
/* character type flags */
#define _U  01
#define _L  02
#define _N  04
#define _S  010
#define _P  020
#define _C  040
#define _X  0100
#define _O  0200

#define isop(c)     ((_chartype_+1)[c]&_O)
#define isalpha(c)  ((_chartype_+1)[c]&(_U|_L))
#define isupper(c)  ((_chartype_+1)[c]&_U)
#define islower(c)  ((_chartype_+1)[c]&_L)
#define isdigit(c)  ((_chartype_+1)[c]&_N)
#define isxdigit(c) ((_chartype_+1)[c]&(_N|_X))
#define isspace(c)  ((_chartype_+1)[c]&_S)
#define ispunct(c)  ((_chartype_+1)[c]&_P)
#define isalnum(c)  ((_chartype_+1)[c]&(_U|_L|_N))
#define isprint(c)  ((_chartype_+1)[c]&(_P|_U|_L|_N))
#define iscntrl(c)  ((_chartype_+1)[c]&_C)
#define isascii(c)  ((unsigned)(c)<=0177)
#define toupper(c)  ((c)-'a'+'A')
#define tolower(c)  ((c)-'A'+'a')
#define toascii(c)  ((c)&0177)
char _chartype_[] = {
  0,
  _C,  _C,     _C,     _C,     _C,     _C,     _C,     _C,
  _C,  _C|_S,  _C|_S,  _C|_S,  _C|_S,  _C|_S,  _C,     _C,
  _C,  _C,     _C,     _C,     _C,     _C,     _C,     _C,
  _C,  _C,     _C,     _C,     _C,     _C,     _C,     _C,
  _S,  _P|_O,  _P,     _P,     _P,     _P|_O,  _P|_O,  _P,
  _P,  _P,     _P|_O,  _P|_O,  _P,     _P|_O,  _P,     _P|_O,
  _N,  _N,     _N,     _N,     _N,     _N,     _N,     _N,
  _N,  _N,     _P,     _P,     _P|_O,  _P|_O,  _P|_O,  _P,
  _P,  _U|_X,  _U|_X,  _U|_X,  _U|_X,  _U|_X,  _U|_X,  _U,
  _U,  _U,     _U,     _U,     _U,     _U,     _U,     _U,
  _U,  _U,     _U,     _U,     _U,     _U,     _U,     _U,
  _U,  _U,     _U,     _P,     _P,     _P,     _P|_O,  _P|_L,
  _P,  _L|_X,  _L|_X,  _L|_X,  _L|_X,  _L|_X,  _L|_X,  _L,
  _L,  _L,     _L,     _L,     _L,     _L,     _L,     _L,
  _L,  _L,     _L,     _L,     _L,     _L,     _L,     _L,
  _L,  _L,     _L,     _P,     _P|_O,  _P,     _P,     _C
};

#define IF     1
#define ELSE   2
#define CASE   3
#define TYPE   4
#define DO     5
#define STRUCT 6
#define OTHER  7

#define ALWAYS    01
#define NEVER     02
#define SOMETIMES 04

#define YES 1
#define NO  0

#define KEYWORD 1
#define DATADEF 2
#define SINIT   3

#define CLEVEL   20
#define IFLEVEL  10
#define DOLEVEL  10
#define OPLENGTH 10
#define LINE     256
#define LINELENG 120
#define MAXTABS  20
#define TABLENG  8
#define TEMP     1024

#define OUT    outs(clev->tabs); putchar('\n');opflag = lbegin = 1; count = 0
#define OUTK   OUT; keyflag = 0;
#define BUMP   clev->tabs++; clev->pdepth++
#define UNBUMP clev->tabs -= clev->pdepth; clev->pdepth = 0
#define eatspace() while((cc=getch())==' '||cc=='\t'); unget(cc)
#define eatallsp() while((cc=getch())==' '||cc=='\t'||cc=='\n'); unget(cc)

struct indent {    /* one for each level of { } */
  int tabs;
  int pdepth;
  int iflev;
  int ifc[IFLEVEL];
  int spdepth[IFLEVEL];
} ind[CLEVEL];
struct indent *clev = ind;
struct keyw {
  char  *name;
  char  punc;
  char  type;
} key[] = {
  "switch", ' ', OTHER,
  "do", ' ', DO,
  "while", ' ', OTHER,
  "if", ' ', IF,
  "for", ' ', OTHER,
  "else", ' ', ELSE,
  "case", ' ', CASE,
  "default", ' ', CASE,
  "char", '\t', TYPE,
  "int", '\t', TYPE,
  "short", '\t', TYPE,
  "long", '\t', TYPE,
  "unsigned", '\t', TYPE,
  "float", '\t', TYPE,
  "double", '\t', TYPE,
  "struct", ' ', STRUCT,
  "union", ' ', STRUCT,
  "extern", ' ', TYPE,
  "register", ' ', TYPE,
  "static", ' ', TYPE,
  "typedef", ' ', TYPE,
  0, 0, 0
};
struct keyw *lookup();
struct op {
  char  *name;
  char  blanks;
  char  setop;
} op[] = {
  "+=", ALWAYS, YES,
  "-=", ALWAYS, YES,
  "*=", ALWAYS, YES,
  "/=", ALWAYS, YES,
  "%=", ALWAYS, YES,
  ">>=",ALWAYS, YES,
  "<<=",ALWAYS, YES,
  "&=", ALWAYS, YES,
  "^=", ALWAYS, YES,
  "|=", ALWAYS, YES,
  ">>", ALWAYS, YES,
  "<<", ALWAYS, YES,
  "<=", ALWAYS, YES,
  ">=", ALWAYS, YES,
  "==", ALWAYS, YES,
  "!=", ALWAYS, YES,
  "=",  ALWAYS, YES,
  "&&", ALWAYS, YES,
  "||", ALWAYS, YES,
  "++", NEVER,  NO,
  "--", NEVER,  NO,
  "->", NEVER,  NO,
  "<",  ALWAYS, YES,
  ">",  ALWAYS, YES,
  "+",  ALWAYS, YES,
  "/",  ALWAYS, YES,
  "%",  ALWAYS, YES,
  "^",  ALWAYS, YES,
  "|",  ALWAYS, YES,
  "!",  NEVER,  YES,
  "~",  NEVER,  YES,
  "*",  SOMETIMES, YES,
  "&",  SOMETIMES, YES,
  "-",  SOMETIMES, YES,
  "?",  ALWAYS, YES,
  ":",  ALWAYS, YES,
  0,0,0
};
FILE *input = stdin;
char *getnext();
char puttmp();
int opflag=1;
int strict=0,join=0,keyflag=0,paren=0,split=0,folded=0,dolevel=0;
int dotabs[DOLEVEL];
int docurly[DOLEVEL];
int dopdepth[DOLEVEL];
int structlev=0,err=0,question=0,count=0,inswitch=0;
char string[LINE];
char *lastlook;
char *p = string;
char temp[TEMP];
char *tp;
char *lastplace = temp;
char *tptr = temp;
int maxleng = LINELENG;
int maxtabs = MAXTABS;
char next = '\0';
int tab,z,i=1,lbegin=1,space=2;

main(argc,argv)
char **argv;
{
  if(argc == 1)
      help();

  while(--argc>0)
  {
    if(*argv[i]=='-')
      while(*++argv[i])
        switch (*argv[i])
        {
        case '0':  case '1':  case '2':  case '3':  case '4':
        case '5':  case '6':  case '7':  case '8':  case '9':
          space=*argv[i]-'0';
          break;
        case 's':
          strict = 1;
          break;
        case 't':
          ++tab;
          break;
        case 'j':
          join = 1;
          break;
        case 'l':
          ++i;
          maxleng = atoi(argv[i]);
          maxtabs = maxleng/TABLENG - 2;
          maxleng -= .1 * maxleng;
          argc--;
          break;
        default:
          fprintf(stderr,"Usage: cb [-jnst] [-l length] [ file ...]\n");
          fprintf(stderr,"    j: split lines are put back together\n");
          fprintf(stderr,"    l: split lines that are longer than length\n");
          fprintf(stderr,"    n: tab = n spaces (default = 2)\n");
          fprintf(stderr,"    s: K & R style\n");
          fprintf(stderr,"    t: tab = real tabs\n");
          exit(2);
        }
    else
    {
      if ((input = fopen( argv[i], "r")) == NULL)
      {
        fprintf(stderr, "cb: cannot open input file %s\n", argv[i]);
        exit(1);
      }
    }
    ++i;
  }
  work();
  exit(0);
}

work(){
  register int c;
  register struct keyw *lptr;
  char *pt;
  char cc;
  int ct;

  while ((c = getch()) != EOF){
    switch (c){
    case '{':
      if ((lptr = lookup(lastlook,p)) != 0){
        if (lptr->type == ELSE)gotelse();
        else if(lptr->type == DO)gotdo();
        else if(lptr->type == STRUCT)structlev++;
      }
      if(++clev >= &ind[CLEVEL-1]){
        fprintf(stderr,"too many levels of curly brackets\n");
        clev = &ind[CLEVEL-1];
      }
      clev->pdepth = 0;
      clev->tabs = (clev-1)->tabs;
      clearif(clev);
      if(strict && clev->tabs > 0)
        putspace(' ',NO);
      putch(c,NO);
      getnl();
      if(keyflag == DATADEF){
        OUT;
      }
      else {
        OUTK;
      }
      clev->tabs++;
      pt = getnext(0);      /* to handle initialized structures */
      if(*pt == '{'){    /* hide one level of {} */
        while((c=getch()) != '{');
        putch(c,NO);
        if(strict){
          putch(' ',NO);
          eatspace();
        }
        keyflag = SINIT;
      }
      continue;
    case '}':
      pt = getnext(0);      /* to handle initialized structures */
      if(*pt == ','){
        if(strict){
          putspace(' ',NO);
          eatspace();
        }
        putch(c,NO);
        putch(*pt,NO);
        *pt = '\0';
        ct = getnl();
        pt = getnext(0);
        if(*pt == '{'){
          OUT;
          while((cc = getch()) != '{');
          putch(cc,NO);
          if(strict){
            putch(' ',NO);
            eatspace();
          }
          pt = getnext(0);
          continue;
        }
        else if(strict || ct){
          OUT;
        }
        continue;
      }
      else if(keyflag == SINIT && *pt == '}'){
        if(strict)
          putspace(' ',NO);
        putch(c,NO);
        getnl();
        OUT;
        keyflag = DATADEF;
        *pt = '\0';
        pt = getnext(0);
      }
      outs(clev->tabs);
      if(--clev < ind)clev = ind;
      ptabs(clev->tabs);
      putch(c,NO);
      lbegin = 0;
      lptr=lookup(pt,lastplace+1);
      c = *pt;
      if(*pt == ';' || *pt == ','){
        putch(*pt,NO);
        *pt = '\0';
        lastplace=pt;
      }
      ct = getnl();
      if((dolevel && clev->tabs <= dotabs[dolevel]) || (structlev )
          || (lptr != 0 &&lptr->type == ELSE&& clev->pdepth == 0)){
        if(c == ';'){
          OUTK;
        }
        else if(strict || (lptr != 0 && lptr->type == ELSE && ct == 0)){
          putspace(' ',NO);
          eatspace();
        }
        else if(lptr != 0 && lptr->type == ELSE){
          OUTK;
        }
        if(structlev){
          structlev--;
          keyflag = DATADEF;
        }
      }
      else {
        OUTK;
        if(strict && clev->tabs == 0){
          if((c=getch()) != '\n'){
            putchar('\n');
            putchar('\n');
            unget(c);
          }
          else {
            putchar('\n');
            if((c=getch()) != '\n')unget(c);
            putchar('\n');
          }
        }
      }
      if(lptr != 0 && lptr->type == ELSE && clev->pdepth != 0){
        UNBUMP;
      }
      if(lptr == 0 || lptr->type != ELSE){
        clev->iflev = 0;
        if(dolevel&&docurly[dolevel]==NO&&clev->tabs==dotabs[dolevel]+1)
          clev->tabs--;
        else if(clev->pdepth != 0){
          UNBUMP;
        }
      }
      continue;
    case '(':
      paren++;
      if ((lptr = lookup(lastlook,p)) != 0){
        if(!(lptr->type == TYPE || lptr->type == STRUCT))keyflag=KEYWORD;
        if (strict){
          putspace(lptr->punc,NO);
          opflag = 1;
        }
        putch(c,NO);
        if (lptr->type == IF)gotif();
      }
      else {
        putch(c,NO);
        lastlook = p;
        opflag = 1;
      }
      continue;
    case ')':
      if(--paren < 0)paren = 0;
      putch(c,NO);
      if((lptr = lookup(lastlook,p)) != 0){
        if(lptr->type == TYPE || lptr->type == STRUCT)
          opflag = 1;
      }
      else if(keyflag == DATADEF)opflag = 1;
      else opflag = 0;
      outs(clev->tabs);
      pt = getnext(1);
      if ((ct = getnl()) == 1 && !strict){
        if(dolevel && clev->tabs <= dotabs[dolevel])
          resetdo();
        if(clev->tabs > 0 && (paren != 0 || keyflag == 0)){
          if(join){
            eatspace();
            putch(' ',YES);
            continue;
          } else {
            OUT;
            split = 1;
            continue;
          }
        }
        else if(clev->tabs > 0 && *pt != '{'){
          BUMP;
        }
        OUTK;
      }
      else if(strict){
        if(clev->tabs == 0){
          if(*pt != ';' && *pt != ',' && *pt != '(' && *pt != '['){
            OUTK;
          }
        }
        else {
          if(keyflag == KEYWORD && paren == 0){
            if(dolevel && clev->tabs <= dotabs[dolevel]){
              resetdo();
              eatspace();
              continue;
            }
            if(*pt != '{'){
              BUMP;
              OUTK;
            }
            else {
              *pt='\0';
              eatspace();
              unget('{');
            }
          }
          else if(ct){
            if(paren){
              if(join){
                eatspace();
              } else {
                split = 1;
                OUT;
              }
            }
            else {
              OUTK;
            }
          }
        }
      }
      else if(dolevel && clev->tabs <= dotabs[dolevel])
        resetdo();
      continue;
    case ' ':
    case '\t':
      if ((lptr = lookup(lastlook,p)) != 0){
        if(!(lptr->type==TYPE||lptr->type==STRUCT))
          keyflag = KEYWORD;
        else if(paren == 0)keyflag = DATADEF;
        if(strict){
          if(lptr->type != ELSE){
            if(lptr->type == TYPE){
              if(paren != 0)putch(' ',YES);
            }
            else
              putch(lptr->punc,NO);
            eatspace();
          }
        }
        else putch(c,YES);
        switch(lptr->type){
        case CASE:
          outs(clev->tabs-1);
          continue;
        case ELSE:
          pt = getnext(1);
          eatspace();
          if((cc = getch()) == '\n' && !strict){
            unget(cc);
          }
          else {
            unget(cc);
            if(checkif(pt))continue;
          }
          gotelse();
          if(strict) unget(c);
          if(getnl() == 1 && !strict){
            OUTK;
            if(*pt != '{'){
              BUMP;
            }
          }
          else if(strict){
            if(*pt != '{'){
              OUTK;
              BUMP;
            }
          }
          continue;
        case IF:
          gotif();
          continue;
        case DO:
          gotdo();
          pt = getnext(1);
          if(*pt != '{'){
            eatallsp();
            OUTK;
            docurly[dolevel] = NO;
            dopdepth[dolevel] = clev->pdepth;
            clev->pdepth = 0;
            clev->tabs++;
          }
          continue;
        case TYPE:
          if(paren)continue;
          if(!strict)continue;
          gottype(lptr);
          continue;
        case STRUCT:
          gotstruct();
          continue;
        }
      }
      else if (lbegin == 0 || p > string)
        if(strict)
          putch(c,NO);
        else putch(c,YES);
      continue;
    case ';':
      putch(c,NO);
      if(paren != 0){
        if(strict){
          putch(' ',YES);
          eatspace();
        }
        opflag = 1;
        continue;
      }
      outs(clev->tabs);
      pt = getnext(0);
      lptr=lookup(pt,lastplace+1);
      if(lptr == 0 || lptr->type != ELSE){
        clev->iflev = 0;
        if(clev->pdepth != 0){
          UNBUMP;
        }
        if(dolevel&&docurly[dolevel]==NO&&clev->tabs<=dotabs[dolevel]+1)
          clev->tabs--;
        /*
            else if(clev->pdepth != 0){
               UNBUMP;
            }
*/
      }
      getnl();
      OUTK;
      continue;
    case '\n':
      if ((lptr = lookup(lastlook,p)) != 0){
        pt = getnext(1);
        if (lptr->type == ELSE){
          if(strict)
            if(checkif(pt))continue;
          gotelse();
          OUTK;
          if(*pt != '{'){
            BUMP;
          }
        }
        else if(lptr->type == DO){
          OUTK;
          gotdo();
          if(*pt != '{'){
            docurly[dolevel] = NO;
            dopdepth[dolevel] = clev->pdepth;
            clev->pdepth = 0;
            clev->tabs++;
          }
        }
        else {
          OUTK;
          if(lptr->type == STRUCT)gotstruct();
        }
      }
      else if(p == string)putchar('\n');
      else {
        if(clev->tabs > 0 &&(paren != 0 || keyflag == 0)){
          if(join){
            putch(' ',YES);
            eatspace();
            continue;
          } else {
            OUT;
            split = 1;
            continue;
          }
        }
        else if(keyflag == KEYWORD){
          OUTK;
          continue;
        }
        OUT;
      }
      continue;
    case '"':
    case '\'':
      putch(c,NO);
      while ((cc = getch()) != c){
        putch(cc,NO);
        if (cc == '\\'){
          putch(getch(),NO);
        }
        if (cc == '\n'){
          outs(clev->tabs);
          lbegin = 1;
          count = 0;
        }
      }
      putch(cc,NO);
      opflag=0;
      if (getnl() == 1){
        unget('\n');
      }
      continue;
    case '\\':
      putch(c,NO);
      putch(getch(),NO);
      continue;
    case '?':
      question = 1;
      gotop(c);
      continue;
    case ':':
      if (question == 1){
        question = 0;
        gotop(c);
        continue;
      }
      putch(c,NO);
      if(structlev)continue;
      if ((lptr = lookup(lastlook,p)) != 0){
        if (lptr->type == CASE)outs(clev->tabs - 1);
      }
      else {
        lbegin = 0;
        outs(clev->tabs);
      }
      getnl();
      OUTK;
      continue;
    case '/':
      if ((cc = getch()) != '*'){
        unget(cc);
        gotop(c);
        continue;
      }
      putch(c,NO);
      putch(cc,NO);
      cc = comment(YES);
      if(getnl() == 1){
        if(cc == 0){
          OUT;
        }
        else {
          outs(0);
          putchar('\n');
          lbegin = 1;
          count = 0;
        }
        lastlook = 0;
      }
      continue;
    case '[':
      putch(c,NO);
      ct = 0;
      while((c = getch()) != ']' || ct > 0){
        putch(c,NO);
        if(c == '[')ct++;
        if(c == ']')ct--;
      }
      putch(c,NO);
      continue;
    case '#':
      putch(c,NO);
      while ((cc = getch()) != '\n'){
        if (cc == '\\'){
          putch(cc,NO);
          cc = getch();
        }
        putch(cc,NO);
      }
      putch(cc,NO);
      lbegin = 0;
      outs(clev->tabs);
      lbegin = 1;
      count = 0;
      continue;
    default:
      if (c == ','){
        opflag = 1;
        putch(c,YES);
        if (strict){
          if ((cc = getch()) != ' ')unget(cc);
          if(cc != '\n')putch(' ',YES);
        }
      }
      else if(isop(c))gotop(c);
      else {
        if(isalnum(c) && lastlook == 0)lastlook = p;
        putch(c,NO);
        if(keyflag != DATADEF)opflag = 0;
      }
    }
  }
}

gotif(){
  outs(clev->tabs);
  if(++clev->iflev >= IFLEVEL-1){
    fprintf(stderr,"too many levels of if\n");
    clev->iflev = IFLEVEL-1;
  }
  clev->ifc[clev->iflev] = clev->tabs;
  clev->spdepth[clev->iflev] = clev->pdepth;
}

gotelse(){
  clev->tabs = clev->ifc[clev->iflev];
  clev->pdepth = clev->spdepth[clev->iflev];
  if(--(clev->iflev) < 0)clev->iflev = 0;
}

checkif(pt)
char *pt;
{
  register struct keyw *lptr;
  int cc;
  if((lptr=lookup(pt,lastplace+1))!= 0){
    if(lptr->type == IF){
      if(strict)putch(' ',YES);
      copy(lptr->name);
      *pt='\0';
      lastplace = pt;
      if(strict){
        putch(lptr->punc,NO);
        eatallsp();
      }
      clev->tabs = clev->ifc[clev->iflev];
      clev->pdepth = clev->spdepth[clev->iflev];
      keyflag = KEYWORD;
      return(1);
    }
  }
  return(0);
}
gotdo(){
  if(++dolevel >= DOLEVEL-1){
    fprintf(stderr,"too many levels of do\n");
    dolevel = DOLEVEL-1;
  }
  dotabs[dolevel] = clev->tabs;
  docurly[dolevel] = YES;
}
resetdo(){
  if(docurly[dolevel] == NO)
    clev->pdepth = dopdepth[dolevel];
  if(--dolevel < 0)dolevel = 0;
}
gottype(lptr)
struct keyw *lptr;
{
  char *pt;
  struct keyw *tlptr;
  int c;
  while(1){
    pt = getnext(1);
    if((tlptr=lookup(pt,lastplace+1))!=0){
      putch(' ',YES);
      copy(tlptr->name);
      *pt='\0';
      lastplace = pt;
      if(tlptr->type == STRUCT){
        putch(tlptr->punc,YES);
        gotstruct();
        break;
      }
      lptr=tlptr;
      continue;
    }
    else{
      putch(lptr->punc,NO);
      while((c=getch())== ' ' || c == '\t');
      unget(c);
      break;
    }
  }
}
gotstruct(){
  int c;
  int cc;
  char *pt;
  while((c=getch()) == ' ' || c == '\t')
    if(!strict)putch(c,NO);
  if(c == '{'){
    structlev++;
    unget(c);
    return;
  }
  if(isalpha(c)){
    putch(c,NO);
    while(isalnum(c=getch()))putch(c,NO);
  }
  unget(c);
  pt = getnext(1);
  if(*pt == '{')structlev++;
  if(strict){
    eatallsp();
    putch(' ',NO);
  }
}
gotop(c)
{
  char optmp[OPLENGTH];
  char *op_ptr;
  struct op *s_op;
  char *a, *b;
  op_ptr = optmp;
  *op_ptr++ = c;
  while (isop(( *op_ptr = getch())))op_ptr++;
  if(!strict)unget(*op_ptr);
  else if (*op_ptr != ' ')unget( *op_ptr);
  *op_ptr = '\0';
  s_op = op;
  b = optmp;
  while ((a = s_op->name) != 0){
    op_ptr = b;
    while ((*op_ptr == *a) && (*op_ptr != '\0')){
      a++;
      op_ptr++;
    }
    if (*a == '\0'){
      keep(s_op);
      opflag = s_op->setop;
      if (*op_ptr != '\0'){
        b = op_ptr;
        s_op = op;
        continue;
      }
      else break;
    }
    else s_op++;
  }
}


keep(o)
struct op *o;
{
  char    *s;
  int ok;
  ok = !strict;
  if (strict && ((o->blanks & ALWAYS)
      || ((opflag == 0 && o->blanks & SOMETIMES) && clev->tabs != 0)))
    putspace(' ',YES);
  for(s=o->name; *s != '\0'; s++){
    putch(*s,ok);
    ok = NO;
  }
  if (strict && ((o->blanks & ALWAYS)
      || ((opflag == 0 && o->blanks & SOMETIMES) && clev->tabs != 0)))
    putch(' ',YES);
}
getnl(){
  register int ch;
  char *savp;
  int gotcmt;
  gotcmt = 0;
  savp = p;
  while ((ch = getch()) == '\t' || ch == ' ')putch(ch,NO);
  if (ch == '/'){
    if ((ch = getch()) == '*'){
      putch('/',NO);
      putch('*',NO);
      comment(NO);
      ch = getch();
      gotcmt=1;
    }
    else {
      if(inswitch)*(++lastplace) = ch;
      else {
        inswitch = 1;
        *lastplace = ch;
      }
      unget('/');
      return(0);
    }
  }
  if(ch == '\n'){
    if(gotcmt == 0)p=savp;
    return(1);
  }
  unget(ch);
  return(0);
}
ptabs(n){
  int     i;
  int num;
  if(n > maxtabs){
    if(!folded){
      printf("/* code folded from here */\n");
      folded = 1;
    }
    num = n-maxtabs;
  }
  else {
    num = n;
    if(folded){
      folded = 0;
      printf("/* unfolding */\n");
    }
  }
  if(tab)
    for (i = 0; i < num; i++)printf("\t");    /* tab = real tabs */
  else
    for (i = 0; i < num; i++)
      for(z=0;z<space;z++)printf(" ");     /* tab = "space" spaces */
}
outs(n){
  if (p > string){
    if (lbegin){
      ptabs(n);
      lbegin = 0;
      if (split == 1){
        split = 0;
        if (clev->tabs > 0)printf("    ");
      }
    }
    *p = '\0';
    printf("%s", string);
    lastlook = p = string;
  }
  else {
    if (lbegin != 0){
      lbegin = 0;
      split = 0;
    }
  }
}
putch(c,ok)
char c;
{
  register int cc;
  if(p < &string[LINE-1]){
    if(count+TABLENG*clev->tabs >= maxleng && ok && !folded){
      if(c != ' ')*p++ = c;
      OUT;
      split = 1;
      if((cc=getch()) != '\n')unget(cc);
    }
    else {
      *p++ = c;
      count++;
    }
  }
  else {
    outs(clev->tabs);
    *p++ = c;
    count = 0;
  }
}
struct keyw *
lookup(first, last)
char *first, *last;
{
  struct keyw *ptr;
  char    *cptr, *ckey, *k;

  if(first == last || first == 0)return(0);
  cptr = first;
  while (*cptr == ' ' || *cptr == '\t')cptr++;
  if(cptr >= last)return(0);
  ptr = key;
  while ((ckey = ptr->name) != 0){
    for (k = cptr; (*ckey == *k && *ckey != '\0'); k++, ckey++);
    if(*ckey=='\0' && (k==last|| (k<last && !isalnum(*k)))){
      opflag = 1;
      lastlook = 0;
      return(ptr);
    }
    ptr++;
  }
  return(0);
}
comment(ok)
{
  register int ch;
  int hitnl;

  hitnl = 0;
  while ((ch  = getch()) != EOF){
    putch(ch, NO);
    if (ch == '*'){
gotstar:
      if ((ch  = getch()) == '/'){
        putch(ch,NO);
        return(hitnl);
      }
      putch(ch,NO);
      if (ch == '*')goto gotstar;
    }
    if (ch == '\n'){
      if(ok && !hitnl){
        outs(clev->tabs);
      }
      else {
        outs(0);
      }
      lbegin = 1;
      count = 0;
      hitnl = 1;
    }
  }
  return(hitnl);
}
putspace(ch,ok)
char    ch;
{
  if(p == string)putch(ch,ok);
  else if (*(p - 1) != ch) putch(ch,ok);
}
getch(){
  register char c;
  if(inswitch){
    if(next != '\0'){
      c=next;
      next = '\0';
      return(c);
    }
    if(tptr <= lastplace){
      if(*tptr != '\0')return(*tptr++);
      else if(++tptr <= lastplace)return(*tptr++);
    }
    inswitch=0;
    lastplace = tptr = temp;
  }
  return(getc(input));
}
unget(c)
{
  if(inswitch){
    if(tptr != temp)
      *(--tptr) = c;
    else next = c;
  }
  else ungetc(c,input);
}
char *
getnext(must){
  int c;
  char *beg;
  int prect,nlct;
  prect = nlct = 0;
  if(tptr > lastplace){
    tptr = lastplace = temp;
    err = 0;
    inswitch = 0;
  }
  tp = beg = lastplace;
  if(inswitch && tptr <= lastplace)
    if (isalnum(*lastplace)||ispunct(*lastplace)||isop(*lastplace))
      return(lastplace);
space:
  while(isspace(c=getc(input)))puttmp(c,1);
  beg = tp;
  puttmp(c,1);
  if(c == '/'){
    if(puttmp((c=getc(input)),1) == '*'){
cont:
      while((c=getc(input)) != '*'){
        puttmp(c,0);
        if(must == 0 && c == '\n')
          if(nlct++ > 2)goto done;
      }
      puttmp(c,1);
star:
      if(puttmp((c=getc(input)),1) == '/'){
        beg = tp;
        puttmp((c=getc(input)),1);
      }
      else if(c == '*')goto star;
      else goto cont;
    }
    else goto done;
  }
  if(isspace(c))goto space;
  if(c == '#' && tp > temp+1 && *(tp-2) == '\n'){
    if(prect++ > 2)goto done;
    while(puttmp((c=getc(input)),1) != '\n')
      if(c == '\\')puttmp(getc(input),1);
    goto space;
  }
  if(isalnum(c)){
    while(isalnum(c = getc(input)))puttmp(c,1);
    ungetc(c,input);
  }
done:
  puttmp('\0',1);
  lastplace = tp-1;
  inswitch = 1;
  return(beg);
}
copy(s)
char *s;
{
  while(*s != '\0')putch(*s++,NO);
}
clearif(cl)
struct indent *cl;
{
  int i;
  for(i=0;i<IFLEVEL-1;i++)cl->ifc[i] = 0;
}
char puttmp(c,keep)
char c;
{
  if(tp < &temp[TEMP-120])
    *tp++ = c;
  else {
    if(keep){
      if(tp >= &temp[TEMP-1]){
        fprintf(stderr,"can't look past huge comment - quitting\n");
        exit(3);
      }
      *tp++ = c;
    }
    else if(err == 0){
      err++;
      fprintf(stderr,"truncating long comment\n");
    }
  }
  return(c);
}


help()
{
puts("cb [-jnst] [-l length] [ file ...]	/* C program beautifier */");
puts("j: split lines are put back together");
puts("l: split lines that are longer than length");
puts("n: tab = n spaces (default = 2)");
puts("s: K & R style");
puts("t: tab = real tabs");
puts(" ");
puts("cb temp>file.c		Beautifies temp and places result in file.c");
puts("cb temp1 temp2>>file.c	Beautifies temp1 & temp2 and adds to file.c");
exit(0);
}