_A C++ BEAUTIFIER_ by Tim Maher [LISTING 1] 1 : 2 # @(#) c++cb,c++indent - driver program for C++ beautification 3 # Tim Maher, CONSULTIX, 11/9/91. (206) 781-UNIX 4 # 5 ENCODED=/tmp/c++encode_$$ BEAUT=/tmp/beaut_$$ # temp files 6 case "$0" in # use cb or indent, depending on invocation name 7 *c++cb) OUT="" # for cb, all arguments are optional 8 while test $# -gt 0 # separate options from filenames 9 do case "$1" in # "l" option takes argument 10 -[!l]) OPTS="$OPTS $1"; shift ;; 11 -l) OPTS="$OPTS $1 $2"; shift 2 ;; 12 *) break # end of options 13 esac 14 done # if no filename, copy stdin, and set filename arg 15 test -z "$*" && cat > /tmp/c++cb_$$ && set /tmp/c++cb_$$ 16 BEAUTIFY="cb $OPTS $ENCODED > $BEAUT"; INPUT=$* ;; 17 *c++indent) # not a filter; needs filename arg 18 INPUT=${1:?"Usage: $0 infile [outfile] [flags]"}; shift 19 case "$1" in # next arg would be output filename or flag 20 "") ;; # no second arg is okay too 21 [!-]*) OUT=$1; shift # set output filename 22 esac 23 OPTS="$*"; : ${OUT:=$INPUT} # if no outfile, use input name 24 BEAUTIFY="indent $ENCODED $BEAUT $OPTS -Tasm -Tbool -Tcatch 25 -Tclass -Tconst -Tdelete -Tdo -Tfriend -Tinline -Tnew 26 -Tprivate -Tprotected -Tpublic -Tsigned -Ttemplate -Tthrow 27 -Ttry -Tvirtual -Tvolatile" # -Toperator omitted 28 esac 29 : ${CppSYM:=_42}; export CppSYM; # set up disguising string 30 name=`grep -l "$CppSYM" $INPUT` && # exit if symbol in input 31 { echo Error- \"$CppSYM\" appears in $name >&2; exit 100; } 32 c++encode $INPUT > $ENCODED || exit 100 33 if eval $BEAUTIFY # beautify, leaving output in $BEAUT 34 then trap "" 2 3 15; # reconstruct C++ after beautification 35 sed -e 's+/\*-\(.*\) -\*/$+//\1+' -e "s/_${CppSYM}_/ : /g" \ 36 -e "s/$CppSYM/::/g" < $BEAUT > $OUT 37 else echo "$0: error code $? from $BEAUTIFY" >&2; exit 200 38 fi 39 rm -f /tmp/*_$$; # clean-up temp files [LISTING 2] 1 /* @(#) c++encode.c: Tim Maher, 11/9/91, tim@Timji.Celestial.Com 2 C++ syntax disguiser, allowing beautification via cb, indent */ 3 #include 4 #include /* Use this line for AT&T systems */ 5 /* #include /* Use this line for BSD systems */ 6 char *getenv(); 7 #define MAX 512 /* Maximum length for C++ input line */ 8 #define F 0 /* FALSE */ 9 #define T 1 /* TRUE */ 10 11 main (argc, argv) int argc; char *argv[]; { 12 int filenum, linenum, cnum, modes, exit(); 13 int sq, dq, cc, ic, ch, nx, max, knt; 14 char line[MAX], out[10], *sym; 15 FILE *handle; 16 17 if (argc < 2) { 18 fprintf(stderr, "Usage: %s file1 [file2 . . .]\n", 19 argv[0]); exit(1); 20 } 21 /* use default "sym" string if none supplied */ 22 if ((sym=getenv("CppSYM")) == (char *)0) sym="_42"; 23 for (filenum = 1; filenum < argc; filenum++) { 24 handle = (filenum == 1 ? fopen(argv[filenum], "r") : 25 freopen(argv[filenum], "r", handle)); 26 if (handle == (FILE *)0) { 27 fprintf(stderr, "%s: fopen() error\n",argv[0]); 28 exit (50); 29 } 30 linenum = 0; sq = dq = cc = ic = F; 31 while (fgets(line, MAX, handle) != (char *) 0) { 32 max=strlen(line)-2; /* ignore NL; 0-based index */ 33 if (max == MAX - 3) { 34 fprintf(stderr,"%s: increase MAX\n", argv[0]); 35 exit(100); 36 } 37 linenum++; 38 for (cnum = 0; cnum <= max; cnum++) { 39 ch = line[cnum]; 40 sprintf(out,"%c",ch); /* default out = ch */ 41 nx = (cnum == max) ? '\0' : line[cnum+1]; 42 if (cc) { /* in C comment mode */ 43 if ('*' == ch && nx == '/') { 44 /* C comment ends */ 45 cc = F; strcpy(out, "*/"); cnum++; 46 } 47 } else if ('/' == ch && nx == '*' && !(sq||dq)) { 48 /* C comment starts */ 49 cc = T; strcpy(out, "/*"); cnum++; 50 } else if (ic) ; /* in inline comment */ 51 else if ('/' == ch && nx == '/' && !sq && !dq) { 52 /* inline comment starts */ 53 ic = T; sprintf(out, "/*-"); cnum++; 54 } else if ('\\' == ch) { /* quote by BS */ 55 if (cnum != max) { /* next char is quoted */ 56 sprintf(out, "%c%c", ch, nx); cnum++; 57 } 58 } else if (dq) { /* in double-quotes */ 59 if ('"' == ch) dq = F; /* DQ string ends */ 60 } else if (sq) { /* in single-quotes */ 61 if (ch == '\'') sq = F; /* SQ string ends */ 62 } else if ('\'' == ch) sq = T; /* SQ starts */ 63 else if ('"' == ch) dq = T; /* DQ starts */ 64 else strcpy(out,""); /* no output created */ 65 /* OUTPUT OF QUOTED AND COMMENTED TEXT */ 66 if (strcmp(out,"") != 0) { /* non-null string */ 67 /* print and then process next char */ 68 printf("%s", out); continue; 69 } /* PROCESS UNQUOTED AND UNCOMMENTED TEXT */ 70 /* process scope qualifier; :: -> sym */ 71 if (ch == ':' && nx == ':') { 72 strcpy(out, sym); cnum++; 73 } else if (ch == ' ' && nx == ':') { 74 /* handle derivation; SP:SP OR SP:NL */ 75 if (cnum == max) { /* line ends with : */ 76 sprintf(out, "%s%s%s", "_", sym, "_"); 77 cnum += 1; /* SP:NL -> _sym_NL */ 78 } else if (line[cnum+2] == ' ') { 79 sprintf(out, "%s%s%s", "_", sym, "_"); 80 cnum += 2; /* SP:SP -> _sym_ */ 81 } 82 } /* FOLLOWING SECTION DOES ALL NORMAL OUTPUT */ 83 /* print prepared string, or literal input ch */ 84 if (strcmp(out, "") != 0) printf("%s", out); 85 else printf("%c", ch); 86 } /* END OF FOR-CNUM LOOP; FINISHED WITH LINE */ 87 if (ic) { /* inlines end with EOL, so turn off */ 88 ic = F; printf(" -*/\n"); 89 } else printf("\n"); /* NL to end this line */ 90 } /* END OF WHILE LOOP */ 91 if (sq || dq || ic || cc) { 92 fprintf(stderr,"%s: %s%s; sq=%d dq=%d ic=%d cc=%d\n", 93 argv[0], "ERROR- altered mode at EOF for file ", 94 argv[filenum], sq,dq,ic,cc); exit (200); 95 } 96 } /* END OF FOR FILENUM LOOP */ 97 exit (0); 98 } Example 1: (a) $ cat sample.cc 1 class C : virtual public F { public: 2 C(int x):F(x, 100u) { } // note; arg 2: unsigned 3 C func(double* = 0); /* defined below */ 4 }; 5 C C::func(double*x) { if (x) // commentary 6 { } // inline comment with funny stuff- // : :: 7 } (b) $ cb sample.cc 1 class C : 2 virtual public F { 3 public: 4 C(int x): 5 F(x, 100u) { 6 } 7 / / note; 8 arg 2: 9 unsigned 10 C func(double * = 0); /* defined below */ 11 }; 12 13 14 C C: 15 : 16 func(double*x) 17 { 18 if (x) 19 / / commentary 20 { 21 } 22 / / inline comment with funny stuff - / / : 23 : 24 : 25 } 26 27 (c) $ c++encode sample.cc 1 class C__42_virtual public F { public: 2 C(int x):F(x, 100u) { } /*- note; arg 2: unsigned -*/ 3 C func(double* = 0); /* defined below */ 4 }; 5 C C_42func(double*x) { if (x) /*- commentary -*/ 6 { } /*- inline comment with funny stuff- // : :: -*/ 7 } (d) $ c++cb sample.cc 1 class C : virtual public F { 2 public: 3 C(int x): 4 F(x, 100u) { 5 } // note; arg 2: unsigned 6 C func(double* = 0); /* defined below */ 7 }; 8 C C::func(double*x) { 9 if (x) // commentary 10 { 11 } // inline comment with funny stuff- // : :: 12 } (e) $ c++cb -s sample.cc 1 class C : virtual public F { 2 public: 3 C(int x): 4 F(x, 100u) { 5 } // note; arg 2: unsigned 6 C func(double * = 0); /* defined below */ 7 }; 8 9 10 C C::func(double*x) 11 { 12 if (x) /*- commentary -*/ { 13 } // inline comment with funny stuff- // : :: 14 } 15 16 (f) $ c++indent sample.cc; cat sample.cc 1 class C : virtual public F { 2 public: 3 C(int x):F(x, 100 u) { 4 } // note; arg 2: unsigned 5 C func(double *= 0); /* defined below */ 6 }; 7 C 8 C::func(double *x) 9 { 10 if (x) { // commentary 11 } // inline comment with funny stuff- // : :: 12 }