/* CB3.C - C Beautifier - Jim Kyle (76703,762) - 05/06/86 * not mainstream rules, but I like 'em!! */ /* port to Apollo Domain by Jinfu Chen (72327,2434) - 03/07/87 */ /* port to Atari ST by Jinfu Chen - 03/08/87 */ /*#define CPM / remove for MSDOS, include for CPM */ /*#define APOLL O / remove for Apollo Domain version */ #define Megamax /* ------------ * * header files * * ------------ */ #ifdef CPM #include "libc.h" /* specifically, Aztec Cii V1.05c */ #include "ctype.h" #else #ifdef MSDOS #include "stdio.h" /* specifically, CI's C86 V1.33 */ #define ishex(x) isdigit(x) || ( toupper(x) < 'G' && toupper(x) >= 'A') #else #ifdef APOLLO /* specifically, Domain C Rev 4.16 */ #include #include #define ishex(x) isdigit(x) || ( toupper(x) < 'G' && toupper(x) >= 'A') #else #ifdef Megamax /* specifically, Megamax C Rev 1.1 */ #include #include #include #define ishex(x) isdigit(x) || ( toupper(x) < 'G' && toupper(x) >= 'A') #endif #endif /* ------------------ * * symbolic constants * * ------------------ */ #define LINEW 78 #define CMNTCOL 40 #define MTAB 8 #define LIND 2 #define YES 1 #define NO 0 /* ---------------- * * global variables * * ---------------- */ char bfr [ 128 ]; FILE * inf, * otf; int clvl = 0, plvl = 1, ilvl = 0, ppilv = 0, istk [ 64 ], istkp = 0, indf = 0, cflg = 0, dflg = 0, iflg = 0, tok = 0, oldtok = 0, mtabv = MTAB, lnwv = LINEW, lindv = LIND, ccv = CMNTCOL, nval = 0, ln = 1, col = 0; main ( argc, argv ) int argc ; char * argv []; { if ( argc == 1 || * argv [ 1 ] == '?' )/* help summary */ { msg ( "\nCommand syntax is: CB [[] []] \n" ); msg ( " where begins with '-' and is followed by\n" ); msg ( "\tCn - start comments at col n\n" ); msg ( "\tIn - each indent is n spaces\n" ); msg ( "\tNn - line number with increment n\n" ); msg ( "\tO - output to (must be last)\n" ); msg ( "\tTn - machine tabs are n cols apart\n" ); msg ( "\tWn - line length is n cols\n" ); msg ( "\tAny mix of args can follow the '-'; each one\n" ); msg ( "\t takes effect immediately.\n" ); msg ( " is a full filespec; is RETURN or ENTER.\n" ); msg ( " The [ and ] indicate options; don't type them.\n\n" ); msg ( "Default values of the settings are:\n" ); msg ( "\tC40 I2 N0 T8 W78\n" ); exit ( 0 ); } otf = stdout; while ( -- argc ) /* let parsearg() do most */ parsearg ( *++ argv ); } char * dmpdgt ( fn ) /* skip over digits */ char * fn; { if ( isdigit ( * fn )) { while ( isdigit ( * fn )) ++ fn; -- fn; } return ( fn ); } parsearg ( fn ) /* process one arg */ char * fn; { if ( * fn == '-' ) /* is an argument */ while ( *++ fn ) { switch ( toupper ( * fn )) { case 'C' : ccv = atoi ( ++ fn ); /* set comment column */ fn = dmpdgt ( fn ); break; case 'I' : lindv = atoi ( ++ fn ); /* set indent width */ if ( lindv < 1 ) lindv = 1; fn = dmpdgt ( fn ); break; case 'N' : nval = atoi ( ++ fn ); /* set line number increment */ fn = dmpdgt ( fn ); break; case 'O' : fclose ( otf ); /* write to file */ otf = fopen ( ++ fn, "w" ); msg ( "Writing output to: " ); msg ( fn ); tocrt ( '\n' ); lnwv = 32767; /* never wrap to a file */ return; case 'T' : mtabv = atoi ( ++ fn ); /* set mach tab spacing */ if ( mtabv < 1 ) mtabv = 1000; fn = dmpdgt ( fn ); break; case 'W' : lnwv = atoi ( ++ fn ); /* set line width */ fn = dmpdgt ( fn ); if ( lnwv < 1 ) lnwv = 32767; break; default : msg ( "Unknown arg: " ); tocrt ( * fn ); tocrt ( '\n' ); } } else /* treat as filename */ { if ( nval ) lnwv -= mtabv; dofil ( fn ); if ( nval ) lnwv += mtabv; } } dofil ( fn ) /* process one file */ char * fn; { int loop , svtok; if ( ! ( inf = fopen ( fn, "r" ))) /* open the file */ { msg ( "can't open " ); msg ( fn ); tocrt ( '\n' ); return; } col = clvl = oldtok = 0; /* initialize globals */ ln = 1; if ( nval ) /* output line number */ outf ( ln * nval ); outb ( '/' ); /* fake out C86 quirk */ outs ( "* " ); outs ( fn ); outs ( " as formatted by CB.C\t*" ); outb ( '/' ); nl (); for ( loop = 1; loop; oldtok = tok ) /* main loop */ { tok = gtok ( inf ); /* get next token */ if ( oldtok == ';' && tok != ' ' && col ) /* break after statement */ outb ( '\n' ); switch ( tok ) /* special processing */ { case 0 : /* newline or comment */ if ( clvl && ! iflg ) tok = oldtok; /* ignore it outside condx */ else if ( iflg || ! oldtok ) { nl (); if ( iflg ) ind ( ilvl + 2 ); tok = ' '; } continue; case ' ' : /* blank */ tok = oldtok; continue; case EOF : /* end of input */ loop = 0; continue; case '{' : /* begin compound */ if ( col ) nl (); ind ( ilvl ++ ); /* push ilvl in */ ++ clvl; outs ( bfr ); tok = ' '; continue; case '}' : /* end compound */ if ( col ) nl (); if ( ilvl ) -- ilvl; /* pop ilvl out for c.s. */ ind ( ilvl ); outs ( bfr ); nl (); if ( iflg ) iflg = 0; -- clvl; popilvl (); /* pop ilvl up if applicable */ tok = ';'; continue; case '(' : /* may be condition start */ ++ plvl; if ( isalnum ( oldtok ) || isop ( oldtok )) outb ( ' ' ); outs ( bfr ); tok = '('; continue; case ')' : /* may be condition end */ -- plvl; if ( isalnum ( oldtok )) outb ( ' ' ); outs ( bfr ); tok = ')'; if ( iflg && ( iflg == plvl )) { iflg = 0; /* end of condition */ tok = ';'; /* so fake statement end */ } continue; case ':' : /* may be end of label */ outb ( ' ' ); outs ( bfr ); tok = ':'; if ( cflg ) /* case or default label */ { tok = ';'; /* will force \n after comments */ ++ ilvl; cflg = 0; } continue; case ';' : /* may be end of statement */ ind ( ilvl ); outs ( bfr ); if ( iflg && ( plvl != iflg )) outb ( ' ' ); /* inside "for" condition */ else /* not in a "for" */ popilvl (); /* pop back up if ready */ dflg = 0; continue; case ',' : /* list separator */ outs ( bfr ); if ( dflg ) /* inside a declaration list */ outb ( '\n' ), ind ( 2 ); else /* elsewhere */ outb ( ' ' ); continue; case '#' : /* preprocessor flag */ /* if ( col ) /* shouldn't happen */ /* outs ( bfr ); */ /* else /* handle preprocessor line */ dopp ( inf ); continue; case 'A' : /* keyword or identifier */ if ( indf ) { nl (); tok = 'A'; indf = 0; } case '0' : /* numeric string */ case 'C' : /* char constant */ case 'S' : /* string constant */ svtok = tok; if (( tok == 'A' ) && kwd () && ( ! dflg ) && ( col > ( ppilv + ilvl ) * lindv )) nl (); if ( oldtok && ( oldtok != ' ' )) outb ( ' ' ); break; default : /* operators, etc. */ if ( tok & 128 ) { outb ( tok ); /* escaped chars ignored */ tok = svtok; continue; } svtok = tok; if ( isop ( svtok ) && ! isop ( oldtok )) outb ( ' ' ); break; } ind ( ilvl ); if ( indf ) /* push ilvl in */ { istk [ ++ istkp ] = (( ilvl ++ ) << 8 ) | ( clvl & 255 ); if ( iflg ) indf = 0; } if ( isalnum ( oldtok ) && ! ( isalnum ( svtok ) || isop ( svtok ))) outb ( ' ' ); outs ( bfr ); tok = svtok; if ( tok == oldtok ) outb ( ' ' ); } nl (); outb ( '/' ); /* trailer comment */ outs ( "* end of " ); outs ( fn ); outs ( " *" ); outb ( '/' ); nl (); } poll () /* break or pause */ #ifdef CPM { int c ; if (( c = bdos ( 6, 255 )) == 3 ) /* check for BREAK */ exit ( 7 ); if ( c ) /* check for PAUSE */ { msg ( "<>" ); while ( bdos ( 6, 255 ) != ' ' ) ; /* wait for SPACE */ msg ( "\b\b\b\b\b\b\b\b\b\b" ); } } #else { /* empty for MSDOS */ } #endif dopp ( fd ) /* handle preprocessor lines */ FILE * fd; { int asmflg; tok = gtok ( fd ); if ( tok == 'A' ) /* keyword at start of line */ { if ( ! strcmp ( bfr, "asm" )) { if ( col ) nl (); asmflg = 0; /* ind ( 0 ); */ outb ( '#' ); outs ( bfr ); do /* just echo until #endasm */ { tok = getc ( fd ); outb ( tok ); switch ( tok ) { case '#': if (asmflg == 0) ++asmflg; else asmflg = 0; break; case 'e': if (asmflg == 1) ++asmflg; else asmflg = 0; break; case 'n': if (asmflg == 2) ++asmflg; else asmflg = 0; break; case 'd': if (asmflg == 3) ++asmflg; else asmflg = 0; break; case 'a': if (asmflg == 4) ++asmflg; else asmflg = 0; break; case 's': if (asmflg == 5) ++asmflg; else asmflg = 0; break; case 'm': if (asmflg == 6) ++asmflg; else asmflg = 0; break; default: asmflg = 0; } } while ( asmflg != 7 ) ; } else if ( bfr [ 0 ] == 'i' && bfr [ 1 ] == 'f' ) { ppkw ( 0 ); ppilv ++ ; } else if ( ! strcmp ( bfr, "else" )) ppkw ( - 1 ); else if ( ! strcmp ( bfr, "endif" )) { -- ppilv; ppkw ( 0 ); } else /* all other keywords */ ppkw ( 0 ); } else /* no keyword after the '#' */ ppkw ( 0 ); while ( tok = gtok ( fd )) /* process rest of line here */ outs ( bfr ); /* output without change */ nl (); tok = 0; /* tell main scanner it was a newline */ } ppkw ( n ) /* indent preprocessor line */ int n ; { if ( col ) /* force newline if needed */ nl (); /* ind ( n ); /* only to preprocessor level */ outb ( '#' ); /* output the '#' */ outs ( bfr ); /* output the keyword */ } gtok ( fd ) /* input scanner */ FILE * fd; { int c ; char * p; poll (); /* check for pause or break */ p = bfr; * p ++ = c = esc ( fd ); /* save char in buffer */ * p = 0; if ( c == '\n' ) /* newline */ return ( 0 ); if ( isspace ( c ) || c == '\r' ) /* whitespace */ return ( ' ' ); if ( c < ' ' ) /* any other control char */ return ( EOF ); if ( c == '/' ) /* comment? */ { if (( c = esc ( fd )) != '*' ) { ungetc ( c, fd ); /* nope */ c = '/'; } else /* yep, echo it all */ { if ( col ) ind ( ccv / lindv ); outb ( '/' ); outb ( '*' ); while ( 1 ) { while (( c = esc ( fd )) != '*' ) outb ( c ); outb ( '*' ); if (( c = esc ( fd )) == '/' ) { outb ( '/' ); return ( oldtok != ';' ? 0 : ' ' ); } else outb ( c ); } } } if ( isalpha ( c ) || c == '_' ) /* keyword or identifier */ { while ( c = esc ( fd ), isalnum ( c ) || c == '_' ) * p ++ = c; * p = 0; ungetc ( c, fd ); return ( 'A' ); } if ( isdigit ( c )) /* numeric constant */ { if ( c == '0' ) /* octal or hex */ { c = esc ( fd ); /* check flag char */ if ( toupper ( c ) != 'X' ) /* then was not hex */ ungetc ( c, fd ); /* put it back */ else { * p ++ = c; /* save hex flag */ while ( c = esc ( fd ), ishex ( c )) * p ++ = c; * p = 0; ungetc ( c, fd ); return ( '0' ); /* and get out */ } } while ( c = esc ( fd ), isdigit ( c )) * p ++ = c; * p = 0; ungetc ( c, fd ); return ( '0' ); } if ( c == '\"' ) /* string constant */ { while ( c = esc ( fd ), c != '\"' ) * p ++ = c; * p ++ = c; * p = 0; return ( 'S' ); } if ( c == '\'' ) /* char constant */ { while ( c = esc ( fd ), c != '\'' ) * p ++ = c; * p ++ = c; * p = 0; return ( 'C' ); } * p = 0; /* anything else */ return ( c ); } outs ( s ) /* output string */ char * s; { if ( col + strlen ( s ) > lnwv ) outb ( 128 + '\n' ); while ( * s ) outb ( * s ++ ); } outb ( c ) /* output byte */ char c ; { if ( c & 128 ) /* ESC sequence */ { outb ( '\\' ); c &= 127; } switch ( c ) /* special treatment */ { case '\t' : /* machine tab */ col = nxtb ( col ); tok = ' '; out ( c ); c = 0; break; case '\n' : /* newline */ ln += 1; out ( c ); if ( nval ) /* line number */ outf ( ln * nval ); case '\r' : /* CR */ c = col = 0; break; case ' ' : /* blank */ tok = ' '; default : /* anything else */ if ( c >= ' ' ) /* printable */ { if ( ++ col > lnwv ) /* check for wrap */ { col = 0; outb ( 128 + '\n' ); /* force cont line */ } } else /* control, skip it */ c = 0; break; } if ( c ) out ( c ); /* send char out */ } out ( c ) /*byte output*/ char c ; { poll (); fprintf ( otf, "%c", c ); } outf ( n ) /*line number output*/ int n ; { fprintf ( otf, "%d\t", n ); } msg ( s ) /* output string to CRT */ char * s; { poll (); while ( * s ) tocrt ( * s ++ ); } tocrt ( c ) /* output char to CRT */ char c ; #ifdef CPM { if ( c == '\n' ) bdos ( 6, 13 ); bdos ( 6, c & 255 ); /* use BDOS for CPM */ } #else { fputc ( c, stderr ); /* use DOS for MSDOS */ } #endif nl () /* newline */ { outb ( '\n' ); tok = 0; } ind ( n ) /* do indenting */ int n ; { int svtok ; svtok = tok; /* save "tok" past the indent */ n += ppilv; /* include preprocessor indent */ n *= lindv; while ( nxtb ( col ) <= n ) /* machine tab if possible */ outb ( '\t' ); while ( col < n ) /* then fill with spaces */ outb ( ' ' ); tok = svtok; /* restore "tok" */ } nxtb ( n ) /* return next tabstop */ int n ; { return ( n + ( mtabv - n % mtabv )); } int inchr = '\n'; /* last input character */ esc ( fd ) /* handle ESC chars */ FILE * fd; { if ( inchr == '\n' ) /* if at start of line */ { inchr = getc ( fd ); if ( isdigit ( inchr )) { while ( inchr = getc ( fd ), isdigit ( inchr )) ; /* smash line numbers */ while ( isspace ( inchr )) inchr = getc ( fd ); /* and trailing whitespace */ } } else inchr = getc ( fd ); /* get next input char */ if ( inchr != '\\' ) return ( inchr ); /* normal char */ return ( inchr = ( getc ( fd ) | 128 ));/* ESC, flag next */ } popilvl () /* pop ilvl out */ { while ( clvl == ( istk [ istkp ] & 255 )) { ilvl = 255 & ( istk [ istkp -- ] >> 8 ); if ( istkp < 0 ) { istkp = 0; return; } } } kwd () /* check for keyword */ { if ( ! ( strcmp ( bfr, "break" )) || ! ( strcmp ( bfr, "continue" )) || ! ( strcmp ( bfr, "return" ))) return ( YES ); /* ordinary keywords */ if ( ! ( strcmp ( bfr, "case" )) || ! ( strcmp ( bfr, "default" ))) { outb ( '\n' ); ++ cflg; -- ilvl; return ( YES ); /* only inside switch() */ } if ( ! ( strcmp ( bfr, "char" )) || ! ( strcmp ( bfr, "double" )) || ! ( strcmp ( bfr, "extern" )) || ! ( strcmp ( bfr, "float" )) || ! ( strcmp ( bfr, "int" )) || ! ( strcmp ( bfr, "static" ))) { ++ dflg; return ( YES ); /* declarations */ } if ( ! ( strcmp ( bfr, "do" )) || ! ( strcmp ( bfr, "else" ))) { ++ indf; return ( YES ); /* indent but no parens */ } if ( ! ( strcmp ( bfr, "for" )) || ! ( strcmp ( bfr, "if" )) || ! ( strcmp ( bfr, "switch" )) || ! ( strcmp ( bfr, "while" ))) { iflg = plvl; ++ indf; return ( YES ); /* indent with parens */ } return ( NO ); /* not a keyword */ } isop ( t ) /* return YES if t is operator */ int t ; { if (( ! oldtok ) || oldtok == ' ' ) return ( NO ); /* force NO if first nonblank */ return ( index ( "+-/!*^?~=<>&|", t ) ? YES : NO ); } /* end of CB3.C */