home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 344_01 / pretty.c < prev    next >
Text File  |  1989-10-29  |  9KB  |  378 lines

  1.  
  2.  
  3. /*
  4.  *      HEADER:         ;
  5.  *      TITLE:          Pretty;
  6.  *      DATE:           10/29/89;
  7.  *      DESCRIPTION:    "Turbo Pascal source code indent utility";
  8.  *      VERSION:        1.0;
  9.  *      FILENAME:       PRETTY.C;
  10.  *      USAGE:          pretty filename.pas [tab width] [-s or /s];
  11.  *
  12.  *      OPTIONS:        tab width = indent increment ( 2 - 8 )
  13.  *                      -s = "use only spaces to indent";
  14.  *
  15.  *      AUTHORS:        Michael Kelly;
  16.  *
  17.  *      INPUT:          filename.pas  (Turbo Pascal source code);
  18.  *      OUTPUT:         filename.prt  (indented Turbo Pascal source code);
  19.  *
  20.  *      COMMENTS:       Tested using TurboC V 1.5 and TubroC V 2.0;
  21.  *
  22.  *      CAVEAT:         "This is not a true parser, for best results put
  23.  *                      reserved words that signify the start of a code
  24.  *                      block at the start of the line";
  25.  */
  26.  
  27.  
  28.  
  29. /*
  30.  *  ***  Pretty  ***
  31.  */
  32. #include <stdio.h>        /* Standard Header Files */
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <ctype.h>
  36. #define TOKENS 13        /* Array elements */
  37. #define MAXSTACK 40
  38. #define INBUFSIZE 6144
  39. #define OUTBUFSIZE 8198
  40. int push(void);            /* Function Prototypes */
  41. int pop(void);
  42. int write_spaces(void);
  43. int get_token(void);
  44.  
  45. enum TOKEN_TYPE {
  46.     BEGIN,REPEAT,CASE,WHILE,WITH,FOR,IF,END,UNTIL,ELSE,\
  47. PROCEDURE,FUNCTION,ENDD,NONE};
  48. enum TOKEN_TYPE z,tok;
  49. enum TOKEN_TYPE compare_tokens(void);
  50. void exit(int status);
  51. void clrscr(void);
  52. void gotoxy(int x,int y);
  53. void show_usage_and_quit(void);
  54. void writeln(void);
  55. void done(void);
  56. void do_switch(void);
  57.  
  58. int stack[MAXSTACK];        /* External Variables */
  59. int first = 1,use_tabs = 1;
  60. int ndx,nspaces;
  61. char buff[BUFSIZ];
  62. char newbuff[BUFSIZ];
  63. char out_line[BUFSIZ];
  64. char tokens[TOKENS][10] = {
  65.     "begin","repeat","case","while","with","for","if",\
  66. "end","until","else","procedure","function","end."};
  67.  
  68. FILE *fpin, *fpout;
  69. char *ibuf,*obuf;
  70. int i,x;
  71. char first_word[82] = "";
  72. char out_file[66] = "";
  73.  
  74. /*
  75.  *  Main
  76.  */
  77.  
  78. void main(int argc,char *argv[])
  79. {
  80.     char *p;
  81.  
  82.     /* get input filename and options from command line */
  83.  
  84.     if(argc > 1) {
  85.     strlwr(argv[1]);            /* convert file name to lower case */
  86.     if(! strstr(argv[1],".pas"))     /* ".pas" extension required */
  87.         show_usage_and_quit();
  88.     memccpy(out_file,argv[1],'.',64);
  89.     p = strrchr(out_file,'.');      /* extract file base name */
  90.     *p = '\0';
  91.     strcat(out_file,".prt");   /* tack ".prt" onto file base name */
  92.     }
  93.     else
  94.     show_usage_and_quit();    /* quit if no filename specified */
  95.  
  96.     if(argc > 2) {            /* check command line options */
  97.     p = strlwr(argv[2]);
  98.     if(!strcmp(p,"/s") || !strcmp(p,"-s")) {
  99.         use_tabs = 0;
  100.         nspaces = 4;    /* use spaces and default tab width */
  101.     }
  102.  
  103.     else {
  104.         nspaces = atoi(argv[2]);      /* valid tab width ? */
  105.         if((nspaces < 2) || (nspaces > 8))
  106.         show_usage_and_quit(); /* quit if not */
  107.     }
  108.     }
  109.  
  110.     if(argc > 3) {                 /* user tab width and no tabs */
  111.     p = strlwr(argv[3]);
  112.     if(!strcmp(p,"/s") || !strcmp(p,"-s"))
  113.         use_tabs = 0;
  114.     }
  115.  
  116.  
  117.     if(!nspaces) nspaces = 4;     /* if not set, use default tab width */
  118.  
  119.  
  120.     fpin = fopen(argv[1],"r");    /* get files ready */
  121.     if(! fpin) {
  122.     fprintf(stderr,"\n\tInput file not found\n");
  123.     exit(1);
  124.     }
  125.  
  126.     ibuf = (char *) malloc(INBUFSIZE);
  127.     if(!ibuf)  {
  128.     printf("\n\tBuffer allocation error!\n");
  129.     exit(1);
  130.     }
  131.  
  132.     fpout = fopen(out_file,"w");
  133.     if(! fpout) {
  134.     fprintf(stderr,"\n\tFile creation error\n");
  135.     exit(2);
  136.     }
  137.  
  138.     obuf = (char *) malloc(OUTBUFSIZE);
  139.     if(!obuf)  {
  140.     printf("\n\tBuffer allocation error!\n");
  141.     exit(1);
  142.     }
  143.  
  144.     if(setvbuf(fpin,ibuf,_IOFBF,INBUFSIZE))  {
  145.     printf("\n\tRead-file buffer allocation error!\n");
  146.     exit(1);
  147.     }
  148.  
  149.     if(setvbuf(fpout,obuf,_IOFBF,OUTBUFSIZE))  {
  150.     printf("\n\tWrite-file buffer allocation error!\n");
  151.     exit(1);
  152.     }
  153.  
  154.  
  155.     clrscr();
  156.     gotoxy(9,12);
  157.     fprintf(stderr,"Indenting: %s ...\n\n",argv[1]); /* program status */
  158.     fprintf(stderr,"   Output file is: %s\n\n",out_file);
  159.  
  160.  
  161.     /* ------------------  File processing Loop  ------------------------- */
  162.  
  163.     while(! feof(fpin)) {
  164.     if(!get_token()) done();    /* shut down if eof */
  165.     tok =  compare_tokens();
  166.     if(tok != NONE && tok != CASE  && tok != END)
  167.         first = 0;    /* if keyword, "var" section has passed */
  168.     if(first)
  169.         fputs(buff,fpout);
  170.     else
  171.         do_switch();            /* set indent */
  172.     }
  173.     done();        /* close files & quit */
  174. }
  175.  
  176.  
  177. /* ------------------  Subordinate Fuctions  --------------------------- */
  178.  
  179.  
  180. /*  ---  pad line with spaces or tabs/spaces combination to indent  -- */
  181.  
  182. int write_spaces()
  183. {
  184.     int i,j;
  185.     char temp[BUFSIZ] = "";
  186.  
  187.  
  188.     j = nspaces * x;
  189.     memset(out_line,' ',j);
  190.     out_line[j] = '\0';
  191.  
  192.     if(use_tabs) {
  193.     i = strlen(out_line) / 8;      /* number of tabs to use    */
  194.     if(!i) return(1);       /* if less than 8 spaces we're ok  */
  195.     memset(temp,'\t',i);    /* else insert leading tabs       */
  196.     temp[i] = '\0';          /* null terminate the string   */
  197.     j = strlen(out_line) % 8; /* pad remainder with spaces  */
  198.     memset(&temp[i],' ',j);
  199.     temp[i+j] = '\0';
  200.     strcpy(out_line,temp);    /* tabs/spaces combination complete */
  201.     }
  202.  
  203.     return(1);        /* done here */
  204.  
  205. }
  206.  
  207. /* -----------  save block start position  for alignment  ------------- */
  208.  
  209. int push()
  210. {
  211.     if(ndx < MAXSTACK) {        /* check for "stack" overflow */
  212.     stack[ndx++] = x;
  213.     return(1);
  214.     }
  215.     else
  216.         return(0);
  217.  
  218. }
  219.  
  220. /* --------  retrieve block start position for alignment  ---------- */
  221.  
  222. int pop()
  223. {
  224.     if((ndx > 0) && (ndx-1 < MAXSTACK)) { /* check "stack" array bounds */
  225.     x = stack[--ndx];
  226.     return(1);
  227.     }
  228.     else
  229.         return(0);
  230.  
  231. }
  232.  
  233.  
  234.  
  235. int get_token()
  236. {
  237.     char *q;
  238.  
  239.     out_line[0] = first_word[0] = buff[0] = newbuff[0] = '\0';
  240.     i = 0;
  241.     q = fgets(buff,BUFSIZ,fpin);    /* read a line from the file */
  242.     if(!q) return(0);
  243.  
  244.     while(isspace(buff[i++]))
  245.     ;                        /* strip leading white space */
  246.  
  247.     if(i) --i;
  248.  
  249.     if(!buff[i]) {
  250.     fputs("\n",fpout);       /* if empty line, copy and get the next */
  251.     if(!get_token()) done();    /* if eof then do exit routine */
  252.     return(2);
  253.     }
  254.     strcpy(newbuff,&buff[i]);  /* newbuff has stripped line */
  255.     sscanf(buff,"%s",first_word);
  256.     q = strtok(first_word,"({;:= ");/* first_word is first token in line */
  257.     strcpy(first_word,q);
  258.     return(1);
  259.  
  260. }
  261.  
  262.  
  263. enum TOKEN_TYPE compare_tokens()
  264. {
  265.  
  266.     for(z=0;z<TOKENS;z++)
  267.     if(!stricmp(first_word,tokens[z]))
  268.         return(z);                    /* return match */
  269.     return(z);                                      /* or no match */
  270.  
  271. }
  272.  
  273.  
  274. /* ------------ write indented line to file --------------- */
  275.  
  276. void writeln()
  277. {
  278.     write_spaces();
  279.     strcat(out_line,newbuff);
  280.     fputs(out_line,fpout);
  281. }
  282.  
  283. /* --------------------  Indent according to keyword  ---------------- */
  284.  
  285. void do_switch()
  286. {
  287.     int i;
  288.  
  289.     switch(tok) {
  290.     case IF:     /* determine if single or compound statement */
  291.  
  292.     case ELSE:
  293.  
  294.     case FOR:
  295.  
  296.     case WITH:
  297.     case WHILE:
  298.     writeln();
  299.     x++;
  300.     i = get_token();
  301.     if(!i) done();
  302.     if(i==2) break;
  303.     tok = compare_tokens();
  304.     if(tok == NONE) {
  305.         writeln();    /* indent single line */
  306.         x--;
  307.         break;
  308.     }
  309.     else if(tok == BEGIN || tok == REPEAT || tok == CASE){
  310.         x--;
  311.         do_switch();    /* or statement block */
  312.         break;
  313.     }
  314.     else
  315.         do_switch();
  316.     break;
  317.  
  318.     case REPEAT:
  319.     case CASE:
  320.     case BEGIN:
  321.     push();        /* save block start */
  322.     writeln();
  323.     ++x;        /* indent 1 tabwidth */
  324.     break;
  325.  
  326.     case UNTIL:
  327.     case END:
  328.     pop();         /* align to block start */
  329.     writeln();
  330.     break;
  331.  
  332.     case PROCEDURE:
  333.     case FUNCTION:
  334.     first = 1;  /*  signal "var" data area */
  335.  
  336.     x = 0;      /* & reset indent level to zero */
  337.     ndx = 0;
  338.     memset(stack,0,sizeof stack);
  339.     fputs(newbuff,fpout);
  340.     break;
  341.  
  342.     case ENDD:
  343.     fputs(newbuff,fpout);
  344.     done();   /* write "end." and shut down */
  345.  
  346.     case NONE:
  347.     writeln();  /* maintain indent level */
  348.     break;
  349.  
  350.     default:
  351.     break;    /* unknown condition ? */
  352.     }
  353. }
  354.  
  355. /* ------------  close files & exit  ------------- */
  356.  
  357. void done()
  358. {
  359.     fputc(0x1a,fpout);    /* write eof mark & close files */
  360.     fclose(fpout);
  361.     fclose(fpin);
  362.     exit(0);        /* all done */
  363. }
  364.  
  365. /* -------  identify the program, what it does, and it's usage  ------ */
  366.  
  367. void show_usage_and_quit()
  368. {
  369.     fprintf(stderr,"\n\t\t\t $$$  Pretty  $$$\n ");
  370.     fprintf(stderr,"\n\tAn auto-indent utility for Pascal Source files.\n");
  371.     fprintf(stderr,"\n\tUsage: pretty filename.pas [tab width] [/s or -s].\n");
  372.     fprintf(stderr,"\n\tAllowed values for tab width are 2 - 8 (default = 4).\n");
  373.     fprintf(stderr,"\n\tIf /s or -s, indent is composed of spaces only.\n");
  374.     fprintf(stderr,"\n\t\t(Default is optimal tabs/spaces).\n");
  375.     fprintf(stderr,"\n\t     Output file will have \".prt\" extension.\n");
  376.     exit(0);
  377. }
  378.