home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / gems / gemsii / c_format.c next >
C/C++ Source or Header  |  1991-09-17  |  10KB  |  593 lines

  1. /************************************************************************
  2.   c_format -- a PostScript typesetting program for C source code (v0.6)
  3.  
  4.   Released into the public domain, November 1990 by Dale Schumacher
  5.   email: <dal@syntel.mn.org>  mail: 399 Beacon Ave., St. Paul MN 55104
  6. ************************************************************************/
  7.  
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11.  
  12. static char psPreamble[] = "\
  13. %!PS-Adobe-2.0\n\
  14. /inch { 72 mul } def\n\
  15. /pica { 12 mul } def\n\
  16. /xOrg 114 def\n\
  17. /xSize 32 pica def\n\
  18. /yOrg 684 def\n\
  19. /ySize 44 pica def\n\
  20. /yDelta 9 def\n\
  21. /Page 1 def\n\
  22. /Line 1 def\n\
  23. /FS {    % find and scale a font\n\
  24.     findfont exch scalefont\n\
  25. } bind def\n\
  26. /Fonts [    % create an array of prescaled fonts\n\
  27.     8 /Courier FS\n\
  28.     8 /Courier-Bold FS\n\
  29.     8 /Courier-Oblique FS\n\
  30. ] def\n\
  31. /SL {    % set line position\n\
  32.     /Line exch def\n\
  33.     xOrg yOrg Line yDelta mul sub moveto\n\
  34. } bind def\n\
  35. /NL {    % newline\n\
  36.     Line 1 add SL\n\
  37. } bind def\n\
  38. /R {    % use roman font\n\
  39.     Fonts 0 get setfont\n\
  40. } bind def\n\
  41. /B {    % use bold font\n\
  42.     Fonts 1 get setfont\n\
  43. } bind def\n\
  44. /I {    % use italic font\n\
  45.     Fonts 2 get setfont\n\
  46. } bind def\n\
  47. /S {    % show\n\
  48.     show\n\
  49. } bind def\n\
  50. ";
  51.  
  52. char psFinal[] = "\
  53. /BP {    % begin page\n\
  54.     1 SL R\n\
  55. } bind def\n\
  56. /EP {    % end page\n\
  57.     gsave\n\
  58.         newpath\n\
  59.             xOrg xSize add 0 moveto\n\
  60.             0 11 inch rlineto\n\
  61.             8.5 inch 11 inch lineto\n\
  62.             8.5 inch 0 lineto\n\
  63.         closepath 1 setgray fill    % mask right margin\n\
  64.     grestore\n\
  65.     showpage\n\
  66. } bind def\n\
  67. ";
  68.  
  69. char psDraft[] = "\
  70. /DraftFont 72 /Helvetica-Bold FS def\n\
  71. /BP {    % begin page\n\
  72.     gsave\n\
  73.         newpath\n\
  74.         184 452 moveto\n\
  75.         -30 rotate\n\
  76.         DraftFont setfont\n\
  77.         gsave \n\
  78.             0.82 setgray (DRAFT) show\n\
  79.         grestore \n\
  80.         (DRAFT) false charpath 0 setlinewidth stroke\n\
  81.     grestore\n\
  82.     1 SL R\n\
  83. } bind def\n\
  84. /EP {    % end page\n\
  85.     gsave\n\
  86.         newpath\n\
  87.             xOrg xSize add 0 moveto\n\
  88.             0 11 inch rlineto\n\
  89.             8.5 inch 11 inch lineto\n\
  90.             8.5 inch 0 lineto\n\
  91.         closepath 1 setgray fill    % mask right margin\n\
  92.         0 setgray\n\
  93.         newpath\n\
  94.             xOrg yOrg moveto\n\
  95.             xSize 0 rlineto\n\
  96.             0 ySize neg rlineto\n\
  97.             xSize neg 0 rlineto\n\
  98.         closepath 0 setlinewidth stroke    % nominal text box\n\
  99.     grestore\n\
  100.     showpage\n\
  101. } bind def\n\
  102. ";
  103.  
  104. #define    LPP    (60)        /* maximum allowable lines per page */
  105.  
  106. char        title[256] = "THE TITLE OF YOUR GEM";
  107. char        author[256] = "YOUR NAME (as it appears on your gem)";
  108. int        draft = 0;    /* draft output mode switch */
  109. int        tabsize = 4;    /* horizontal tab spacing */
  110. int        page = 1;    /* current page of listing (one based) */
  111. int        line = 1;    /* current line on page (one based) */
  112. int        firstline = 18;    /* first line of first page (one based) */
  113.  
  114. char *
  115. ps_string(s)
  116. char *s;
  117. {
  118.     static char ps_buf[512];
  119.     char *p = ps_buf;
  120.     int c;
  121.  
  122.     while(c = *s++) {
  123.         if((c == '(') || (c == ')') || (c == '\\')) {
  124.             *p++ = '\\';
  125.         }
  126.         if(isprint(c)) {
  127.             *p++ = c;
  128.         }
  129.     }
  130.     *p = '\0';
  131.     return(ps_buf);
  132. }
  133.  
  134. void
  135. start_listing(f)
  136. FILE *f;
  137. {
  138.     line = firstline;
  139.     fprintf(f, "%s%s\n", psPreamble, (draft ? psDraft : psFinal));
  140.     fprintf(f, "%% start of listing\n");
  141.     fprintf(f, "initgraphics\nBP\n");
  142.     fprintf(f, "(%s) S NL\n", ps_string(title));
  143.     fprintf(f, "(%s) S\n", ps_string(author));
  144.     fprintf(f, "%d SL\n", firstline);
  145. }
  146.  
  147. void
  148. page_eject(f)
  149. FILE *f;
  150. {
  151.     ++page;
  152.     line = 1;
  153.     fprintf(f, "EP\nBP\n");
  154. }
  155.  
  156. void
  157. new_line(f)
  158. FILE *f;
  159. {
  160.     ++line;
  161.     if(line > LPP) {
  162.         page_eject(f);
  163.     } else {
  164.         fprintf(f, "NL\n");
  165.     }
  166. }
  167.  
  168. void
  169. end_listing(f)
  170. FILE *f;
  171. {
  172.     fprintf(f, "EP\n\n%% end of listing\n");
  173. }
  174.  
  175. #define    TK_EMPTY    (-1)
  176. #define    TK_TEXT        (0)
  177. #define    TK_WORD        (1)
  178. #define    TK_KWORD    (2)
  179. #define    TK_CSTART    (3)
  180. #define    TK_CEMPTY    (4)
  181. #define    TK_CTEXT    (5)
  182. #define    TK_CEND        (6)
  183. #define    TK_SEMPTY    (7)
  184. #define    TK_STEXT    (8)
  185. #define    TK_NEWLINE    (9)
  186. #define    TK_FORMFEED    (10)
  187.  
  188. static char *keywords[] = {
  189.     "auto",        "break",    "case",        "char",
  190.     "const",    "continue",    "default",    "do",
  191.     "double",    "else",        "entry",    "enum",
  192.     "extern",    "float",    "for",        "goto",
  193.     "if",        "int",        "long",        "register",
  194.     "return",    "short",    "signed",    "sizeof",
  195.     "static",    "struct",    "switch",    "typedef",
  196.     "union",    "unsigned",    "void",        "volatile",
  197.     "while",
  198.     NULL
  199. };
  200.  
  201. int
  202. iskeyword(s)
  203. char *s;
  204. {
  205.     char **p;
  206.  
  207.     for(p = keywords; *p; ++p) {
  208.         if((**p == *s) && (strcmp((*p)+1, s+1) == 0)) {
  209.             return(1);
  210.         }
  211.     }
  212.     return(0);
  213. }
  214.  
  215. static int spaces = 0;
  216. static int pbchar = 0;
  217. static int pbflag = 0;
  218.  
  219. int
  220. push_back(f, c)
  221. FILE *f;
  222. int c;
  223. {
  224.     pbflag = 1;
  225.     return(pbchar = c);
  226. }
  227.  
  228. int
  229. next_char(f)
  230. FILE *f;
  231. {
  232.     static int col = 0;
  233.     int c;
  234.  
  235.     if(pbflag) {
  236.         pbflag = 0;
  237.         return(pbchar);
  238.     } else if(spaces > 0) {
  239.         --spaces;
  240.         ++col;
  241.         return(' ');
  242.     }
  243.     do {
  244.         c = getc(f);
  245.         if((c == EOF) || (c == '\f') || (c == '\n')) {
  246.             if(c == '\n') {
  247.                 col = 0;
  248.             }
  249.             return(c);
  250.         } else if(c == '\t') {
  251.             spaces = (tabsize - (col % tabsize)) - 1;
  252.             c = ' ';
  253.             break;
  254.         }
  255.     } while(iscntrl(c));
  256.     ++col;
  257.     return(c);
  258. }
  259.  
  260. char    token[256];
  261.  
  262. int
  263. next_token(f)
  264. FILE *f;
  265. {
  266.     static int state = TK_EMPTY;
  267.     static int qchar = '"';
  268.     int c;
  269.     char *tp;
  270.  
  271.     tp = token;
  272.     while((c = next_char(f)) != EOF) {
  273.         switch(state) {
  274.  
  275.         case TK_EMPTY:
  276.             switch(c) {
  277.             case '/':
  278.                 c = next_char(f);
  279.                 if(c == EOF) {
  280.                     *tp++ = '/';
  281.                     *tp = '\0';
  282.                     return(TK_TEXT);
  283.                 } else if(c == '*') {
  284.                     *tp++ = '/';
  285.                     state = TK_CSTART;
  286.                 } else {
  287.                     *tp++ = '/';
  288.                     state = TK_TEXT;
  289.                 }
  290.                 break;
  291.             case '\n':
  292.                 *tp++ = '\n';
  293.                 *tp = '\0';
  294.                 return(TK_NEWLINE);
  295.             case '\f':
  296.                 *tp++ = '\f';
  297.                 *tp = '\0';
  298.                 return(TK_FORMFEED);
  299.             case '\'':
  300.             case '"':
  301.                 qchar = c;
  302.                 state = TK_STEXT;
  303.                 break;
  304.             default:
  305.                 state = (isalpha(c) || (c=='_'))
  306.                     ? TK_WORD
  307.                     : TK_TEXT;
  308.                 break;
  309.             }
  310.             break;
  311.  
  312.         case TK_TEXT:
  313.             if(isalpha(c)
  314.             || (c=='_') || (c=='/')
  315.             || (c=='"') || (c=='\'') || iscntrl(c)) {
  316.                 push_back(f, c);
  317.                 *tp = '\0';
  318.                 state = TK_EMPTY;
  319.                 return(TK_TEXT);
  320.             }
  321.             break;
  322.  
  323.         case TK_WORD:
  324.             if(!(isalnum(c) || (c=='_'))
  325.             || (c=='/') || (c=='"') || (c=='\'')
  326.             || iscntrl(c)) {
  327.                 push_back(f, c);
  328.                 *tp = '\0';
  329.                 state = TK_EMPTY;
  330.                 return(iskeyword(token)
  331.                     ? TK_KWORD
  332.                     : TK_WORD);
  333.             }
  334.             break;
  335.  
  336.         case TK_CSTART:
  337.             if(c!='*') {
  338.                 push_back(f, c);
  339.                 *tp = '\0';
  340.                 state = (c == '/') ? TK_CEND : TK_CEMPTY;
  341.                 return(TK_CSTART);
  342.             }
  343.             break;
  344.  
  345.         case TK_CEMPTY:
  346.             switch(c) {
  347.             case '\n':
  348.                 *tp++ = '\n';
  349.                 *tp = '\0';
  350.                 return(TK_NEWLINE);
  351.             case '\f':
  352.                 *tp++ = '\f';
  353.                 *tp = '\0';
  354.                 return(TK_FORMFEED);
  355.             case '*':
  356.                 state = TK_CEND;
  357.                 break;
  358.             default:
  359.                 state = TK_CTEXT;
  360.                 break;
  361.             }
  362.             break;
  363.  
  364.         case TK_CTEXT:
  365.             if((c=='*') || iscntrl(c)) {
  366.                 push_back(f, c);
  367.                 *tp = '\0';
  368.                 state = (c == '*') ? TK_CEND : TK_CEMPTY;
  369.                 return(TK_CTEXT);
  370.             }
  371.             break;
  372.  
  373.         case TK_CEND:
  374.             if(c == '/') {
  375.                 *tp++ = '/';
  376.                 *tp = '\0';
  377.                 state = TK_EMPTY;
  378.                 return(TK_CEND);
  379.             } else if(c != '*') {
  380.                 push_back(f, c);
  381.                 *tp = '\0';
  382.                 state = TK_CTEXT;
  383.                 return(TK_CTEXT);
  384.             }
  385.             break;
  386.  
  387.         case TK_SEMPTY:
  388.             switch(c) {
  389.             case '\n':
  390.                 *tp++ = '\n';
  391.                 *tp = '\0';
  392.                 return(TK_NEWLINE);
  393.             case '\f':
  394.                 *tp++ = '\f';
  395.                 *tp = '\0';
  396.                 return(TK_FORMFEED);
  397.             default:
  398.                 if(c == qchar) {
  399.                     *tp++ = c;
  400.                     *tp = '\0';
  401.                     state = TK_EMPTY;
  402.                     return(TK_STEXT);
  403.                 }
  404.                 state = TK_STEXT;
  405.                 break;
  406.             }
  407.             break;
  408.  
  409.         case TK_STEXT:
  410.             if(c == qchar) {
  411.                 *tp++ = c;
  412.                 *tp = '\0';
  413.                 state = TK_EMPTY;
  414.                 return(TK_STEXT);
  415.             } else if(c == '\\') {
  416.                 *tp++ = '\\';
  417.                 c = next_char(f);
  418.                 if(c == EOF) {
  419.                     *tp = '\0';
  420.                     state = TK_EMPTY;
  421.                     return(TK_STEXT);
  422.                 }
  423.             }
  424.             if(iscntrl(c)) {
  425.                 push_back(f, c);
  426.                 *tp = '\0';
  427.                 state = TK_SEMPTY;
  428.                 return(TK_STEXT);
  429.             }
  430.             break;
  431.  
  432.         }
  433.         *tp++ = c;
  434.     }
  435.     *tp = '\0';
  436.     return(TK_EMPTY);
  437. }
  438.  
  439. #define    ROMAN_FONT    (0)
  440. #define    BOLD_FONT    (1)
  441. #define    ITALIC_FONT    (2)
  442.  
  443. void
  444. list(fi, fo)
  445. FILE *fi;
  446. FILE *fo;
  447. {
  448.     int tk, ptk;
  449.     int font = ROMAN_FONT;
  450.  
  451.     start_listing(fo);
  452.     ptk = TK_EMPTY;
  453.     while((tk = next_token(fi)) != TK_EMPTY) {
  454.         switch(tk) {
  455.         case TK_TEXT:
  456.         case TK_WORD:
  457.         case TK_STEXT:
  458.             if(font != ROMAN_FONT) {
  459.                 fprintf(fo, "R ");
  460.                 font = ROMAN_FONT;
  461.             }
  462.             fprintf(fo, "(%s) S\n", ps_string(token));
  463.             break;
  464.         case TK_KWORD:
  465.             if(font != BOLD_FONT) {
  466.                 fprintf(fo, "B ");
  467.                 font = BOLD_FONT;
  468.             }
  469.             fprintf(fo, "(%s) S\n", ps_string(token));
  470.             break;
  471.         case TK_CSTART:
  472.             if(font != ROMAN_FONT) {
  473.                 fprintf(fo, "R ");
  474.                 font = ROMAN_FONT;
  475.             }
  476.             fprintf(fo, "(%s) S\n", ps_string(token));
  477.             break;
  478.         case TK_CTEXT:
  479.             if(font != ITALIC_FONT) {
  480.                 fprintf(fo, "I ");
  481.                 font = ITALIC_FONT;
  482.             }
  483.             fprintf(fo, "(%s) S\n", ps_string(token));
  484.             break;
  485.         case TK_CEND:
  486.             font = ROMAN_FONT;
  487.             fprintf(fo, "R (%s) S\n", ps_string(token));
  488.             break;
  489.         case TK_NEWLINE:
  490.             if(((ptk == TK_NEWLINE) || (ptk == TK_FORMFEED))
  491.             && (line < 2)) {
  492.                 break;    /* ignore if at top of page */
  493.             }
  494.             if((ptk != TK_NEWLINE) || (line < (LPP - 6))) {
  495.                 new_line(fo);
  496.                 break;
  497.             }
  498.             /* FALL THRU */
  499.         case TK_FORMFEED:
  500.             if(line < 2) {
  501.                 break;    /* ignore if at top of page */
  502.             }
  503.             page_eject(fo);
  504.             break;
  505.         }
  506.         ptk = tk;
  507.     }
  508.     end_listing(fo);
  509. }
  510.  
  511. void
  512. usage()
  513. {
  514.     fprintf(stderr, "\
  515. usage: c_format [-options] [-] [file.c]\n\
  516. options:\n\
  517.     -d        draft output mode\n\
  518.     -t title    set listing title\n\
  519.     -a author    set listing author\n\
  520.     -x tabsize    set tab stops\n\
  521.     -o output.ps    write to output file (default to stdout)\n\
  522. ");
  523.     exit(1);
  524. }
  525.  
  526. main(argc, argv)
  527. int argc;
  528. char **argv;
  529. {
  530.     FILE *f;
  531.     register int c;
  532.     register char *p;
  533.     extern int optind;
  534.     extern char *optarg;
  535.  
  536.     while((c = getopt(argc, argv, "dt:a:x:o:f:")) != EOF) {
  537.         switch(c) {
  538.         case 'd':
  539.             draft = !draft;
  540.             break;
  541.         case 't':
  542.             strcpy(title, optarg);
  543.             break;
  544.         case 'a':
  545.             strcpy(author, optarg);
  546.             break;
  547.         case 'x':
  548.             tabsize = atoi(optarg);
  549.             break;
  550.         case 'o':
  551.             if(freopen(optarg, "w", stdout) == NULL) {
  552.                 perror(optarg);
  553.                 exit(1);
  554.             }
  555.             break;
  556.         case 'f':
  557.             c = atoi(optarg);
  558.             if((c > 0) && (c < LPP)) {
  559.                 firstline = c;
  560.             }
  561.             break;
  562.         case '?':
  563.         default:
  564.             usage();
  565.         }
  566.     }
  567.     c = argc - optind;
  568.     if(c < 1) {
  569.         if(isatty(fileno(stdin))) {
  570.             usage();
  571.         } else {
  572.             list(stdin, stdout);
  573.         }
  574.     } else if(c == 1) {
  575.         p = argv[optind];
  576.         if((p[0] == '-') && (p[1] == '\0')) {
  577.             list(stdin, stdout);
  578.         } else {
  579.             if(f = fopen(p, "r")) {
  580.                 list(f, stdout);
  581.                 fclose(f);
  582.             } else {
  583.                 perror(p);
  584.                 exit(1);
  585.             }
  586.         }
  587.     } else {
  588.         usage();
  589.     }
  590.     exit(0);
  591. }
  592.  
  593.