home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / awk / awk320sr.zip / AWK.C next >
C/C++ Source or Header  |  1991-05-22  |  18KB  |  485 lines

  1. /*
  2.  * awk main programme
  3.  *
  4.  * Copyright (C) 1988, 1989, 1990, 1991 by Rob Duff
  5.  * All rights reserved
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <stdarg.h>
  11. #include <mem.h>
  12. #include <alloc.h>
  13. #include <string.h>
  14. #include <setjmp.h>
  15. #include <signal.h>
  16.  
  17. #include "awk.h"
  18.  
  19. IDENT *ident;                       /* list of all identifiers */
  20.  
  21. ITEM *nextvar;                      /* pointer to next unused variable */
  22. ITEM vartab[MAXNAME];               /* table to hold variables */
  23.  
  24. ITEM *stackptr, *stacktop;          /* stack pointer and top limit */
  25. ITEM stackbot[MAXSTACK];            /* the stack */
  26. ITEM fieldtab[MAXFIELD];            /* table to hold fields 0..MAXFIELD-1 */
  27. RULE *rules, *rulep;                /* awk code pointers */
  28. FYLE files[MAXFILE];                /* table to hold files */
  29. FYLE *nextfile;                     /* pointer to unused file */
  30.  
  31. LINK *beginact;                     /* list of BEGIN actions */
  32. LINK *beginend;                     /* pointer to last BEGIN action */
  33. LINK *endact;                       /* list of END actions */
  34. LINK *endend;                       /* pointer to last END action */
  35.  
  36. FILE *awkfile;                      /* AWK program input file */
  37.  
  38. char *yyname;                       /* program file name */
  39. char *awkfre;                       /* RE for field separator */
  40. char *awkname;                      /* data file name */
  41. char *blankre;                      /* RE for " " field separator */
  42.  
  43. char fmtstr[66];                    /* format string */
  44. char ofmtstr[66] = "\377%.6g";      /* output format string */
  45. char namebuf[66];                   /* internal form for file name */
  46. char code[MAXCODE];                 /* code generation buffer */
  47. char buffer[MAXCODE];               /* string buffer */
  48. char linebuf[MAXLINE] = "";         /* program input buffer */
  49.  
  50. NAME *varlist;                      /* list of var=text options */
  51. NAME *varlast;                      /* last var in list */
  52. NAME *awklist;                      /* list of program file names */
  53. NAME *awklast;                      /* last name in list */
  54. char *awkstdin = "<stdin>";
  55.  
  56. FSTR awkfs;                         /* current field separator */
  57. FSTR lineptr;                       /* program line pointer */
  58. FSTR nullstr = "\377";              /* standard null string */
  59. FSTR blankfs = "\377[ \\t\\n]+";    /* " " field separator */
  60. FSTR fieldbuf;                      /* field string storage */
  61.  
  62. short trace;                        /* trace execution */
  63. short awkline;                      /* include line information */
  64. short builtin;                      /* number of builtin variables */
  65. short status, awkeof;               /* exit status and EOF status */
  66.  
  67. ITEM  *ac, *av, *rl, *rst;          /* BUILTIN variables */
  68. ITEM  *nr, *fnr, *fs, *rs;          /* BUILTIN */
  69. ITEM  *ofs, *ors, *ofmt;            /* BUILTIN */
  70. ITEM  *nf, *fn, *nul, *subsep;      /* BUILTIN */
  71.  
  72. jmp_buf nextjmp, exitjmp;           /* next and exit long jump buffers */
  73.  
  74. void awkfpe();
  75. extern ELEMENT *allell(void);
  76.  
  77. static void usage(void);            /* error message */
  78. static void awkinit(void);          /* initialize AWK */
  79. static void execute(void);          /* execute an ACTION */
  80. static void addname(char *);        /* add -f program file */
  81. static void addvar(char *);         /* add -v var=text */
  82. static ITEM *buildin(char*, int, int, FSTR);
  83.  
  84. int main(int argc, char *argv[])
  85. {
  86.     int     found;                  /* found wildcard file */
  87.     char    *arg0;                  /* program name */
  88.     char    *argn;                  /* data file names */
  89.     LINK    *acts;                  /* pointer to next action */
  90.  
  91.     awkinit();                      /* initialize program */
  92.     arg0 = argv[0];                 /* get program name */
  93.     argc--; argv++;                 /* get next argument */
  94.     while (argc > 0 && argv[0][0] == '-') { /* parse options */
  95.         if (argv[0][1] == 'f') {    /* input file option */
  96.             if (argv[0][2] != '\0') /* is it a separate arg? */
  97.                 addname(argv[0]+2); /* no */
  98.             else if (argc > 0) {
  99.                 argc--; argv++;     /* yes */
  100.                 addname(argv[0]);   /* get next argument */
  101.             }
  102.             else {                  /* oops no more arguments */
  103.                 error("no file specified for -f", NULL);
  104.             }
  105.         }
  106.         else if (argv[0][1] == 'v') {    /* var=text option */
  107.             if (argv[0][2] != '\0') /* is it a separate arg? */
  108.                 addvar(argv[0]+2); /* no */
  109.             else if (argc > 0) {
  110.                 argc--; argv++;     /* yes */
  111.                 addvar(argv[0]);   /* get next argument */
  112.             }
  113.             else {                  /* oops no more arguments */
  114.                 error("no var=text specified for -v", NULL);
  115.             }
  116.         }
  117.         else if (argv[0][1] == 'F') {
  118.             argv[0][1] = LSTR;      /* field separator */
  119.             fs->sstr = argv[0] + 1; /* convert to internal form */
  120.             awkeof = 1;
  121.             setfs();                /* calculate RE for FS */
  122.             yyinit();
  123.         }
  124.         else if (argv[0][1] == 't') {
  125.             trace++;                /* trace execution */
  126.         }
  127.         else if (argv[0][1] == 't') {
  128.             awkline++;              /* include lines */
  129.         }
  130.         else if (argv[0][1] == '-') {
  131.             argc--; argv++;         /* "--" means end of options */
  132.             break;
  133.         }
  134.         else if (argv[0][1] == '\0') {
  135.             addname(awkstdin);      /* "-" means stdin */
  136.             argc--; argv++;
  137.             break;
  138.         }
  139.         else
  140.             usage();                /* messy option */
  141.         argc--; argv++;
  142.     }
  143.     if (awklist == NULL) {          /* don't have -f option */
  144.         if (argc > 0) {
  145.             if (strpbrk(*argv, " \",/[]|<>+=;") == NULL) {
  146.                 strcpy(buffer, *argv);      /* move to larger space */
  147.                 awkfile = fopen(buffer ,"r");
  148.                 if (awkfile != NULL) {
  149.                     awkeof = 0;
  150.                     yyname = *argv;
  151.                     lineptr = linebuf;
  152.                     *lineptr = '\0';
  153.                 }
  154.                 else {
  155.                     strcat(buffer, ".awk"); /* try .AWK */
  156.                     awkfile = fopen(buffer, "r");
  157.                     if (awkfile != NULL) {
  158.                         awkeof = 0;
  159.                         yyname = malloc(strlen(buffer)+1);
  160.                         strcpy(yyname, buffer);
  161.                         lineptr = linebuf;
  162.                         *lineptr = '\0';
  163.                     }
  164.                     else {
  165.                         awkeof = 1;         /* no input files */
  166.                         strcpy(linebuf, *argv);
  167.                         strcat(linebuf, "\n");
  168.                         lineptr = linebuf;
  169.                     }
  170.                 }
  171.             }
  172.             else {                  /* must be a program */
  173.                 awkeof = 1;         /* no input files */
  174.                 strcpy(linebuf, *argv);
  175.                 strcat(linebuf, "\n");
  176.                 lineptr = linebuf;
  177.             }
  178.             argc--; argv++;
  179.         }
  180.         else {
  181.             awkeof = 0;
  182.             addname(awkstdin);      /* no file name for stdin */
  183.         }
  184.     }
  185.     else
  186.         awkeof = 0;
  187.  
  188.     yyparse();                      /* compile AWK program */
  189.     awkeof = 1;                     /* end of awk program */
  190.     if (awkfile != stdin)           /* close if not stdin */
  191.         fclose(awkfile);
  192.     deparse();                      /* clean up input record */
  193.     setargv(argc, arg0, argv);      /* set ARGV and ARGC */
  194.     if (varlist != NULL)
  195.         getargs(varlist);
  196.     if (setjmp(exitjmp) == 0) {     /* EXIT() point */
  197.         if (beginact != NULL)       /* if we have BEGIN actions */
  198.             if (setjmp(nextjmp) == 0) { /* set NEXT() point */
  199.                 acts = beginact;
  200.                 while (acts != NULL) {  /* execute BEGIN actions */
  201.                     awkexec(acts->ccode);
  202.                     acts = acts->cnext; /* point to next action */
  203.                 }
  204.             }
  205.         found = 0;
  206.         argn = getargv();
  207.         if (rulep != NULL || endact != NULL) do {
  208.             if (argn != NULL) {
  209.                 if (*argn == '\0') {
  210.                     argn = getargv();   /* get the next input file */
  211.                     if (argn == NULL)
  212.                         break;          /* stop when no more */
  213.                 }
  214.                 if (argn[0] == '-' && argn[1] == '\0') {
  215.                     awkfile = stdin;    /* check for standard input */
  216.                     awkname = "";
  217.                     argn = "";
  218.                 }
  219.                 else {
  220.                     if (awkfind(buffer, argn, 0) == NULL) {
  221.                         if (found > 0) {    /* wildcard file */
  222.                             found = 0;      /* no more match */
  223.                             argn = "";
  224.                             continue;
  225.                         }
  226.                         error("can't find file %s", argn);
  227.                     }
  228.                     awkfile = fopen(buffer ,"r");
  229.                     if (awkfile == NULL)    /* can't open file */
  230.                         error("can't open data file", buffer);
  231.                     awkname = buffer;       /* set FILENAME */
  232.                     found++;
  233.                 }
  234.             }
  235.             else {
  236.                 awkname = "";               /* no FILENAME for stdin */
  237.                 awkfile = stdin;            /* file not specified */
  238.             }
  239.             namebuf[0] = TSTR;              /* mark FILENAME as temporary */
  240.             strcpy(namebuf+1, awkname);
  241.             setfile(namebuf);               /* set FILENAME and FNR */
  242.             files[1].ffyle = awkfile;
  243.             execute();                      /* execute program */
  244.             if (awkfile != stdin)
  245.                 fclose(awkfile);            /* close opened file */
  246.         } while (argn != NULL);             /* repeat for next file */
  247.     }
  248.     deparse();                              /* free FIELD temporaries */
  249.     setfile(nullstr);                       /* clear FILENAME and FNR */
  250.     if (setjmp(exitjmp) == 0) {             /* EXIT () point in END */
  251.         if (setjmp(nextjmp) == 0) {         /* some fool may try this */
  252.             for (acts = endact; acts != NULL; acts = acts->cnext)
  253.                 awkexec(acts->ccode);       /* execute end actions */
  254.         }
  255.     }
  256.     awkclose();                             /* close all the FILES */
  257.     return status;                          /* return exit code */
  258. }
  259.  
  260. static void execute()
  261. {
  262.     int     flag;
  263.  
  264.     while (getrecord() > 0) {               /* read a record (line) */
  265.         rulep = rules;                      /* start at the first pat/act */
  266.         if (setjmp(nextjmp) == 0) {         /* NEXT() point */
  267.             while (rulep != NULL) {
  268.                 if (rulep->start == NULL)
  269.                     rulep->seen = 1;        /* no rule means always */
  270.                 else if (rulep->seen == 0 && awkexec(rulep->start) != 0)
  271.                     rulep->seen = 1;        /* success means start */
  272.                 flag = rulep->seen;
  273.                 if (rulep->stop == NULL)
  274.                     rulep->seen = 0;        /* no rule means once */
  275.                 else if (rulep->seen != 0 && awkexec(rulep->stop) != 0)
  276.                     rulep->seen = 0;        /* success means stop */
  277.                 if (flag != 0)
  278.                     awkexec(rulep->action); /* execute action on start */
  279.                 rulep = rulep->next;        /* do next rule */
  280.             }
  281.         }
  282.         deparse();                          /* free FIELD assignments */
  283.     }
  284. }
  285.  
  286. /*
  287.  * create builtin variable
  288.  */
  289. static ITEM *buildin(char *name, int class, int type, FSTR ptr)
  290. {
  291.     IDENT *vp;
  292.  
  293.     nextvar->sclass = class;
  294.     nextvar->stype = type;
  295.     nextvar->sstr = ptr;
  296.     nextvar->svalue.dval = 0;
  297.  
  298.     vp = malloc(sizeof(IDENT));
  299.     vp->vitem = nextvar;
  300.     vp->vname = name;
  301.     vp->vfunc = NULL;
  302.     vp->vnext = ident;
  303.     ident = vp;
  304.     
  305.     builtin++;
  306.     return nextvar++;
  307. }
  308.  
  309. /*
  310.  * initialize all the structures used by AWK
  311.  */
  312. static void awkinit()
  313. {
  314.     int     i;
  315.     ELEMENT *ep;
  316.  
  317.     trace = 0;
  318.     status = 0;
  319.     ident = NULL;
  320.     rules = NULL;
  321.     rulep = NULL;
  322.     endact = NULL;
  323.     endend = NULL;
  324.     beginact = NULL;
  325.     beginend = NULL;
  326.     stackptr = stacktop = stackbot + MAXSTACK;
  327.  
  328.     fieldbuf = farmalloc(MAXLINE+MAXFIELD+MAXFIELD);
  329.     builtin = 0;
  330.     nextvar = vartab;
  331.     nul = buildin("\"\"", ACTUAL, S_NUMBER, nullstr);
  332.     fs = buildin("FS", ACTUAL, S_STRING, "\377 ");
  333.     ofs = buildin("OFS", ACTUAL, S_STRING, "\377 ");
  334.     nf = buildin("NF", ACTUAL, S_SHORT, 0);
  335.     ofmt = buildin("OFMT", ACTUAL, S_STRING, ofmtstr);
  336.  
  337.     rs = buildin("RS", ACTUAL, S_STRING, "\377\n");
  338.     ors = buildin("ORS", ACTUAL, S_STRING, "\377\n");
  339.     nr = buildin("NR", ACTUAL, S_SHORT, 0);
  340.     fnr = buildin("FNR", ACTUAL, S_SHORT, 0);
  341.     fn = buildin("FILENAME", ACTUAL, S_STRING, namebuf);
  342.  
  343.     av = buildin("ARGV", ACTUAL, S_STRING, nullstr);
  344.     ac = buildin("ARGC", ACTUAL, S_STRING, nullstr);
  345.  
  346.     rl = buildin("RLENGTH", ACTUAL, S_STRING, nullstr);
  347.     rst = buildin("RSTART", ACTUAL, S_STRING, nullstr);
  348.     subsep = buildin("SUBSEP", ACTUAL, S_STRING, "\377\034");
  349.  
  350.     for (i = builtin; i < MAXNAME; i++) {
  351.         ep = allell();                      /* this stuff allows undefined */
  352.         ep->aclass = ACTUAL;                /* variables to be passed to */
  353.         ep->atype = S_NUMBER;               /* functions as arrays */
  354.         ep->astr = nullstr;
  355.         ep->avalue.dval = 0;
  356.         ep->aindex = nullstr;
  357.         ep->anext = NULL;
  358.         vartab[i].sclass = ACTUAL;
  359.         vartab[i].stype = S_ARRAY;
  360.         vartab[i].sstr = nullstr;
  361.         vartab[i].svalue.aptr = ep;
  362.     }
  363.     for (i = 0; i < MAXFIELD; i++) {
  364.         fieldtab[i].sclass = ACTUAL;
  365.         fieldtab[i].stype = S_STRING;
  366.         fieldtab[i].sstr = nullstr;
  367.     }
  368.     nextfile = files + 2;
  369.     files[0].fname = "\377<stdout>";
  370.     files[0].fmode = "w";
  371.     files[0].ffyle = stdout;
  372.     files[1].fname = "\377<stdin>";
  373.     files[1].fmode = "r";
  374.     files[1].ffyle = stdin;
  375.     for (i = 2; i < MAXFILE; i++) {
  376.         files[i].fname = nullstr;
  377.         files[i].fmode = "";
  378.         files[i].ffyle = NULL;
  379.     }
  380.     awkeof = 1;
  381.     yyinit();
  382.     lineptr = blankfs+1;
  383.     blankre = regexp(2);
  384.     *lineptr = '\0';
  385.     yyinit();
  386.     awkfs = blankfs;
  387.     awkfre = blankre;
  388.     awkfile = stdin;
  389.     awkname = NULL;
  390.     awklist = NULL;
  391.     awklast = NULL;
  392.     varlist = NULL;
  393.     varlast = NULL;
  394.     lineptr = NULL;
  395.     yyname = NULL;
  396.     yyline = 0;
  397.  
  398.     signal(SIGFPE, awkfpe);
  399. }
  400.  
  401. /*
  402.  * display an error message and leave
  403.  */
  404. void
  405. error(char *fmt, ...)
  406. {
  407.     va_list ap;
  408.  
  409.     va_start(ap, fmt);
  410.     fprintf(stderr, "awk ERROR");
  411.     if (yyname)
  412.         fprintf(stderr, " %s", yyname);
  413.     if (yyline)
  414.         fprintf(stderr, " line %d", yyline);
  415.     fprintf(stderr, ": ");
  416.     vfprintf(stderr, fmt, ap);
  417.     fprintf(stderr, "\n");
  418.     va_end(ap)
  419.     exit(1);
  420. }
  421.  
  422. static void addname(char *name)
  423. {
  424.     NAME    *list;
  425.  
  426.     list = malloc(sizeof(NAME));
  427.     list->name = name;
  428.     list->next = NULL;
  429.     if (awklast == NULL)
  430.         awklist = list;
  431.     else
  432.         awklast->next = list;
  433.     awklast = list;
  434. }
  435.  
  436. static void addvar(char *name)
  437. {
  438.     NAME    *list;
  439.  
  440.     list = malloc(sizeof(NAME));
  441.     list->name = name;
  442.     list->next = NULL;
  443.     if (varlast == NULL)
  444.         varlist = list;
  445.     else
  446.         varlast->next = list;
  447.     varlast = list;
  448. }
  449.  
  450. void awkfpe()
  451. {
  452.     error("floating point exception", NULL);
  453. }
  454.  
  455. /*
  456.  * print a help message about how to use AWK and exit
  457.  */
  458. static void usage()
  459. {
  460.     fprintf(stderr, "   AWK version 3.20 (22-May-91)\n\n");
  461.     fprintf(stderr, "          Copyright (C) 1990, 91 by Rob Duff\n");
  462.     fprintf(stderr, "          Vancouver BC Canada V5N 1Y9\n\n");
  463.     fprintf(stderr, "usage: awk [-l] [-t] [-f name] [-v var=text] [-Ffs] [--] [prog] [data ... ]\n");
  464.     fprintf(stderr, "       -l      include line number tracing for debugging\n");
  465.     fprintf(stderr, "       -t      will trace execution of the program\n");
  466.     fprintf(stderr, "       -f      specify program file\n");
  467.     fprintf(stderr, "       name    is the name of a file containing an AWK program. You may\n");
  468.     fprintf(stderr, "               specify multiple program files with multiple -f options\n");
  469.     fprintf(stderr, "               A -f name and prog program definition may not be mixed\n");
  470.     fprintf(stderr, "       -v      assign var before any BEGIN blocks\n");
  471.     fprintf(stderr, "       -F      specify a pattern to match for field separation\n");
  472.     fprintf(stderr, "       fs      is the pattern to match for field separation\n");
  473.     fprintf(stderr, "       --      ends the option list.\n\n");
  474.     fprintf(stderr, "       prog    is a quoted program or a file name with optional [.AWK]\n");
  475.     fprintf(stderr, "               you may specify stdin with a dash (-). Not used with -f.\n");
  476.     fprintf(stderr, "       data    is any file name including wildcards.  If file is of the\n");
  477.     fprintf(stderr, "               form var=text then text is assigned to var in the program\n");
  478.     fprintf(stderr, "               instead of reading a file.\n");
  479.     fprintf(stderr, "       If no options are specified then the program and data are both\n");
  480.     fprintf(stderr, "       read from stdin.  You end the program with a line containing\n");
  481.     fprintf(stderr, "       only a single period (.) in the first column.\n\n");
  482.     exit(1);
  483. }
  484.  
  485.