home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast2.iso
/
awk
/
awk320sr.zip
/
AWK.C
next >
Wrap
C/C++ Source or Header
|
1991-05-22
|
18KB
|
485 lines
/*
* awk main programme
*
* Copyright (C) 1988, 1989, 1990, 1991 by Rob Duff
* All rights reserved
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <mem.h>
#include <alloc.h>
#include <string.h>
#include <setjmp.h>
#include <signal.h>
#include "awk.h"
IDENT *ident; /* list of all identifiers */
ITEM *nextvar; /* pointer to next unused variable */
ITEM vartab[MAXNAME]; /* table to hold variables */
ITEM *stackptr, *stacktop; /* stack pointer and top limit */
ITEM stackbot[MAXSTACK]; /* the stack */
ITEM fieldtab[MAXFIELD]; /* table to hold fields 0..MAXFIELD-1 */
RULE *rules, *rulep; /* awk code pointers */
FYLE files[MAXFILE]; /* table to hold files */
FYLE *nextfile; /* pointer to unused file */
LINK *beginact; /* list of BEGIN actions */
LINK *beginend; /* pointer to last BEGIN action */
LINK *endact; /* list of END actions */
LINK *endend; /* pointer to last END action */
FILE *awkfile; /* AWK program input file */
char *yyname; /* program file name */
char *awkfre; /* RE for field separator */
char *awkname; /* data file name */
char *blankre; /* RE for " " field separator */
char fmtstr[66]; /* format string */
char ofmtstr[66] = "\377%.6g"; /* output format string */
char namebuf[66]; /* internal form for file name */
char code[MAXCODE]; /* code generation buffer */
char buffer[MAXCODE]; /* string buffer */
char linebuf[MAXLINE] = ""; /* program input buffer */
NAME *varlist; /* list of var=text options */
NAME *varlast; /* last var in list */
NAME *awklist; /* list of program file names */
NAME *awklast; /* last name in list */
char *awkstdin = "<stdin>";
FSTR awkfs; /* current field separator */
FSTR lineptr; /* program line pointer */
FSTR nullstr = "\377"; /* standard null string */
FSTR blankfs = "\377[ \\t\\n]+"; /* " " field separator */
FSTR fieldbuf; /* field string storage */
short trace; /* trace execution */
short awkline; /* include line information */
short builtin; /* number of builtin variables */
short status, awkeof; /* exit status and EOF status */
ITEM *ac, *av, *rl, *rst; /* BUILTIN variables */
ITEM *nr, *fnr, *fs, *rs; /* BUILTIN */
ITEM *ofs, *ors, *ofmt; /* BUILTIN */
ITEM *nf, *fn, *nul, *subsep; /* BUILTIN */
jmp_buf nextjmp, exitjmp; /* next and exit long jump buffers */
void awkfpe();
extern ELEMENT *allell(void);
static void usage(void); /* error message */
static void awkinit(void); /* initialize AWK */
static void execute(void); /* execute an ACTION */
static void addname(char *); /* add -f program file */
static void addvar(char *); /* add -v var=text */
static ITEM *buildin(char*, int, int, FSTR);
int main(int argc, char *argv[])
{
int found; /* found wildcard file */
char *arg0; /* program name */
char *argn; /* data file names */
LINK *acts; /* pointer to next action */
awkinit(); /* initialize program */
arg0 = argv[0]; /* get program name */
argc--; argv++; /* get next argument */
while (argc > 0 && argv[0][0] == '-') { /* parse options */
if (argv[0][1] == 'f') { /* input file option */
if (argv[0][2] != '\0') /* is it a separate arg? */
addname(argv[0]+2); /* no */
else if (argc > 0) {
argc--; argv++; /* yes */
addname(argv[0]); /* get next argument */
}
else { /* oops no more arguments */
error("no file specified for -f", NULL);
}
}
else if (argv[0][1] == 'v') { /* var=text option */
if (argv[0][2] != '\0') /* is it a separate arg? */
addvar(argv[0]+2); /* no */
else if (argc > 0) {
argc--; argv++; /* yes */
addvar(argv[0]); /* get next argument */
}
else { /* oops no more arguments */
error("no var=text specified for -v", NULL);
}
}
else if (argv[0][1] == 'F') {
argv[0][1] = LSTR; /* field separator */
fs->sstr = argv[0] + 1; /* convert to internal form */
awkeof = 1;
setfs(); /* calculate RE for FS */
yyinit();
}
else if (argv[0][1] == 't') {
trace++; /* trace execution */
}
else if (argv[0][1] == 't') {
awkline++; /* include lines */
}
else if (argv[0][1] == '-') {
argc--; argv++; /* "--" means end of options */
break;
}
else if (argv[0][1] == '\0') {
addname(awkstdin); /* "-" means stdin */
argc--; argv++;
break;
}
else
usage(); /* messy option */
argc--; argv++;
}
if (awklist == NULL) { /* don't have -f option */
if (argc > 0) {
if (strpbrk(*argv, " \",/[]|<>+=;") == NULL) {
strcpy(buffer, *argv); /* move to larger space */
awkfile = fopen(buffer ,"r");
if (awkfile != NULL) {
awkeof = 0;
yyname = *argv;
lineptr = linebuf;
*lineptr = '\0';
}
else {
strcat(buffer, ".awk"); /* try .AWK */
awkfile = fopen(buffer, "r");
if (awkfile != NULL) {
awkeof = 0;
yyname = malloc(strlen(buffer)+1);
strcpy(yyname, buffer);
lineptr = linebuf;
*lineptr = '\0';
}
else {
awkeof = 1; /* no input files */
strcpy(linebuf, *argv);
strcat(linebuf, "\n");
lineptr = linebuf;
}
}
}
else { /* must be a program */
awkeof = 1; /* no input files */
strcpy(linebuf, *argv);
strcat(linebuf, "\n");
lineptr = linebuf;
}
argc--; argv++;
}
else {
awkeof = 0;
addname(awkstdin); /* no file name for stdin */
}
}
else
awkeof = 0;
yyparse(); /* compile AWK program */
awkeof = 1; /* end of awk program */
if (awkfile != stdin) /* close if not stdin */
fclose(awkfile);
deparse(); /* clean up input record */
setargv(argc, arg0, argv); /* set ARGV and ARGC */
if (varlist != NULL)
getargs(varlist);
if (setjmp(exitjmp) == 0) { /* EXIT() point */
if (beginact != NULL) /* if we have BEGIN actions */
if (setjmp(nextjmp) == 0) { /* set NEXT() point */
acts = beginact;
while (acts != NULL) { /* execute BEGIN actions */
awkexec(acts->ccode);
acts = acts->cnext; /* point to next action */
}
}
found = 0;
argn = getargv();
if (rulep != NULL || endact != NULL) do {
if (argn != NULL) {
if (*argn == '\0') {
argn = getargv(); /* get the next input file */
if (argn == NULL)
break; /* stop when no more */
}
if (argn[0] == '-' && argn[1] == '\0') {
awkfile = stdin; /* check for standard input */
awkname = "";
argn = "";
}
else {
if (awkfind(buffer, argn, 0) == NULL) {
if (found > 0) { /* wildcard file */
found = 0; /* no more match */
argn = "";
continue;
}
error("can't find file %s", argn);
}
awkfile = fopen(buffer ,"r");
if (awkfile == NULL) /* can't open file */
error("can't open data file", buffer);
awkname = buffer; /* set FILENAME */
found++;
}
}
else {
awkname = ""; /* no FILENAME for stdin */
awkfile = stdin; /* file not specified */
}
namebuf[0] = TSTR; /* mark FILENAME as temporary */
strcpy(namebuf+1, awkname);
setfile(namebuf); /* set FILENAME and FNR */
files[1].ffyle = awkfile;
execute(); /* execute program */
if (awkfile != stdin)
fclose(awkfile); /* close opened file */
} while (argn != NULL); /* repeat for next file */
}
deparse(); /* free FIELD temporaries */
setfile(nullstr); /* clear FILENAME and FNR */
if (setjmp(exitjmp) == 0) { /* EXIT () point in END */
if (setjmp(nextjmp) == 0) { /* some fool may try this */
for (acts = endact; acts != NULL; acts = acts->cnext)
awkexec(acts->ccode); /* execute end actions */
}
}
awkclose(); /* close all the FILES */
return status; /* return exit code */
}
static void execute()
{
int flag;
while (getrecord() > 0) { /* read a record (line) */
rulep = rules; /* start at the first pat/act */
if (setjmp(nextjmp) == 0) { /* NEXT() point */
while (rulep != NULL) {
if (rulep->start == NULL)
rulep->seen = 1; /* no rule means always */
else if (rulep->seen == 0 && awkexec(rulep->start) != 0)
rulep->seen = 1; /* success means start */
flag = rulep->seen;
if (rulep->stop == NULL)
rulep->seen = 0; /* no rule means once */
else if (rulep->seen != 0 && awkexec(rulep->stop) != 0)
rulep->seen = 0; /* success means stop */
if (flag != 0)
awkexec(rulep->action); /* execute action on start */
rulep = rulep->next; /* do next rule */
}
}
deparse(); /* free FIELD assignments */
}
}
/*
* create builtin variable
*/
static ITEM *buildin(char *name, int class, int type, FSTR ptr)
{
IDENT *vp;
nextvar->sclass = class;
nextvar->stype = type;
nextvar->sstr = ptr;
nextvar->svalue.dval = 0;
vp = malloc(sizeof(IDENT));
vp->vitem = nextvar;
vp->vname = name;
vp->vfunc = NULL;
vp->vnext = ident;
ident = vp;
builtin++;
return nextvar++;
}
/*
* initialize all the structures used by AWK
*/
static void awkinit()
{
int i;
ELEMENT *ep;
trace = 0;
status = 0;
ident = NULL;
rules = NULL;
rulep = NULL;
endact = NULL;
endend = NULL;
beginact = NULL;
beginend = NULL;
stackptr = stacktop = stackbot + MAXSTACK;
fieldbuf = farmalloc(MAXLINE+MAXFIELD+MAXFIELD);
builtin = 0;
nextvar = vartab;
nul = buildin("\"\"", ACTUAL, S_NUMBER, nullstr);
fs = buildin("FS", ACTUAL, S_STRING, "\377 ");
ofs = buildin("OFS", ACTUAL, S_STRING, "\377 ");
nf = buildin("NF", ACTUAL, S_SHORT, 0);
ofmt = buildin("OFMT", ACTUAL, S_STRING, ofmtstr);
rs = buildin("RS", ACTUAL, S_STRING, "\377\n");
ors = buildin("ORS", ACTUAL, S_STRING, "\377\n");
nr = buildin("NR", ACTUAL, S_SHORT, 0);
fnr = buildin("FNR", ACTUAL, S_SHORT, 0);
fn = buildin("FILENAME", ACTUAL, S_STRING, namebuf);
av = buildin("ARGV", ACTUAL, S_STRING, nullstr);
ac = buildin("ARGC", ACTUAL, S_STRING, nullstr);
rl = buildin("RLENGTH", ACTUAL, S_STRING, nullstr);
rst = buildin("RSTART", ACTUAL, S_STRING, nullstr);
subsep = buildin("SUBSEP", ACTUAL, S_STRING, "\377\034");
for (i = builtin; i < MAXNAME; i++) {
ep = allell(); /* this stuff allows undefined */
ep->aclass = ACTUAL; /* variables to be passed to */
ep->atype = S_NUMBER; /* functions as arrays */
ep->astr = nullstr;
ep->avalue.dval = 0;
ep->aindex = nullstr;
ep->anext = NULL;
vartab[i].sclass = ACTUAL;
vartab[i].stype = S_ARRAY;
vartab[i].sstr = nullstr;
vartab[i].svalue.aptr = ep;
}
for (i = 0; i < MAXFIELD; i++) {
fieldtab[i].sclass = ACTUAL;
fieldtab[i].stype = S_STRING;
fieldtab[i].sstr = nullstr;
}
nextfile = files + 2;
files[0].fname = "\377<stdout>";
files[0].fmode = "w";
files[0].ffyle = stdout;
files[1].fname = "\377<stdin>";
files[1].fmode = "r";
files[1].ffyle = stdin;
for (i = 2; i < MAXFILE; i++) {
files[i].fname = nullstr;
files[i].fmode = "";
files[i].ffyle = NULL;
}
awkeof = 1;
yyinit();
lineptr = blankfs+1;
blankre = regexp(2);
*lineptr = '\0';
yyinit();
awkfs = blankfs;
awkfre = blankre;
awkfile = stdin;
awkname = NULL;
awklist = NULL;
awklast = NULL;
varlist = NULL;
varlast = NULL;
lineptr = NULL;
yyname = NULL;
yyline = 0;
signal(SIGFPE, awkfpe);
}
/*
* display an error message and leave
*/
void
error(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "awk ERROR");
if (yyname)
fprintf(stderr, " %s", yyname);
if (yyline)
fprintf(stderr, " line %d", yyline);
fprintf(stderr, ": ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap)
exit(1);
}
static void addname(char *name)
{
NAME *list;
list = malloc(sizeof(NAME));
list->name = name;
list->next = NULL;
if (awklast == NULL)
awklist = list;
else
awklast->next = list;
awklast = list;
}
static void addvar(char *name)
{
NAME *list;
list = malloc(sizeof(NAME));
list->name = name;
list->next = NULL;
if (varlast == NULL)
varlist = list;
else
varlast->next = list;
varlast = list;
}
void awkfpe()
{
error("floating point exception", NULL);
}
/*
* print a help message about how to use AWK and exit
*/
static void usage()
{
fprintf(stderr, " AWK version 3.20 (22-May-91)\n\n");
fprintf(stderr, " Copyright (C) 1990, 91 by Rob Duff\n");
fprintf(stderr, " Vancouver BC Canada V5N 1Y9\n\n");
fprintf(stderr, "usage: awk [-l] [-t] [-f name] [-v var=text] [-Ffs] [--] [prog] [data ... ]\n");
fprintf(stderr, " -l include line number tracing for debugging\n");
fprintf(stderr, " -t will trace execution of the program\n");
fprintf(stderr, " -f specify program file\n");
fprintf(stderr, " name is the name of a file containing an AWK program. You may\n");
fprintf(stderr, " specify multiple program files with multiple -f options\n");
fprintf(stderr, " A -f name and prog program definition may not be mixed\n");
fprintf(stderr, " -v assign var before any BEGIN blocks\n");
fprintf(stderr, " -F specify a pattern to match for field separation\n");
fprintf(stderr, " fs is the pattern to match for field separation\n");
fprintf(stderr, " -- ends the option list.\n\n");
fprintf(stderr, " prog is a quoted program or a file name with optional [.AWK]\n");
fprintf(stderr, " you may specify stdin with a dash (-). Not used with -f.\n");
fprintf(stderr, " data is any file name including wildcards. If file is of the\n");
fprintf(stderr, " form var=text then text is assigned to var in the program\n");
fprintf(stderr, " instead of reading a file.\n");
fprintf(stderr, " If no options are specified then the program and data are both\n");
fprintf(stderr, " read from stdin. You end the program with a line containing\n");
fprintf(stderr, " only a single period (.) in the first column.\n\n");
exit(1);
}