home *** CD-ROM | disk | FTP | other *** search
- /*
- * Awk file and command line processing
- *
- * Copyright (C) 1988, 1989, 1990, 1991 by Rob Duff
- * All rights reserved
- */
-
- #include <stdio.h>
- #include <conio.h>
- #include <ctype.h>
- #include <string.h>
- #include <stdlib.h>
-
- #include "awkfstr.h"
- #include "awk.h"
-
- extern long fatol(FSTR);
- ELEMENT *allell(void);
-
- short modfield = 0;
- short modrecord = 0;
-
- static ITEM argn[1] = { { ACTUAL, S_SHORT } };
- static ITEM argp[1] = { { FORMAL, S_SIMPLE } };
-
- static char argvbuf[66]; /* string form of getargv */
-
- static void set_element(int, char*, ITEM*);
-
- /*
- * set an element of the ARGV array
- */
- static void set_element(int argc, char *arg, ITEM *vp)
- {
- FSTR sp;
- ELEMENT *ep;
- ITEM ip[1];
-
- ip->stype = S_SHORT;
- ip->sclass = ACTUAL;
- ip->svalue.ival = argc;
- sp = getstr(tostring(ip));
- buffer[0] = ZSTR;
- fstrncpy(buffer+1, arg, MAXCODE-2);
- ep = allell();
- ep->aclass = ACTUAL;
- ep->atype = S_STRING;
- ep->astr = getstr(buffer);
- ep->aindex = sp;
- ep->anext = NULL;
- add_element(ep, vp);
- if (isnumber(arg)) {
- ep->avalue.dval = todouble((ITEM*)ep);
- ep->atype = S_NUMBER;
- }
- }
-
- /*
- * copy argv into ARGV
- */
- void setargv(int n, char *arg0, char *argv[])
- {
- int argc;
-
- clear_array(av);
- set_element(0, arg0, av);
- argc = 1;
- while (n) {
- set_element(argc, *argv, av);
- n--; argc++; argv++;
- }
- free_item((ITEM*)ac);
- ac->stype = S_SHORT;
- ac->svalue.ival = argc;
- argn->svalue.ival = 0;
- argp->svalue.sptr = av;
- }
-
- /*
- * check to see whether an argument is a
- * command line assignment.
- * returns pointer to string after "="
- */
- FSTR isname(FSTR sp)
- {
- if (*sp > ' ' && (isalpha(*sp) || *sp == '_'))
- sp++;
- while (*sp > ' ' && (isalnum(*sp) || *sp == '_'))
- sp++;
- if (*sp != '=')
- sp = NULL;
- return sp;
- }
-
- /*
- * check to see if a field can be fully
- * represented as a number.
- */
- int isnumber(FSTR sp)
- {
- int lag, lead, len, power, digit;
- FSTR exp;
-
- if (*sp == '\0')
- return 0;
- exp = "0"; len = 1;
- lead = lag = digit = 0;
- if (*sp == '+' || *sp == '-')
- *sp++;
- if (*sp > ' ' && isdigit(*sp))
- digit++;
- while (*sp == '0')
- sp++;
- while (*sp > ' ' && isdigit(*sp)) {
- lead++;
- sp++;
- }
- if (*sp == '.') {
- sp++;
- if (*sp > ' ' && isdigit(*sp))
- digit++;
- while (*sp == '0') {
- lag++;
- sp++;
- }
- while (*sp > ' ' && isdigit(*sp))
- sp++;
- }
- if (*sp == 'e' || *sp == 'E') {
- sp++;
- exp = sp;
- len = 0;
- if (*sp == '+' || *sp == '-')
- *sp++;
- if (*sp < ' ' || !isdigit(*sp))
- return 0;
- while (*sp == '0')
- sp++;
- while (*sp > ' ' && isdigit(*sp)) {
- len++;
- sp++;
- }
- }
- if (digit == 0)
- return 0;
- if (*sp != '\0')
- return 0;
- if (len > 3)
- return 0;
- power = (int)fatol(exp);
- if (lead > 0)
- power += lead;
- else
- power -= lag;
- if (power > 307 || power < -305)
- return 0;
- return 1;
- }
-
- /*
- * get next non null element of ARGV less than ARGC
- * the user program may delete some of the arguments
- * or set them to null to erase them.
- */
- char *getargv()
- {
- int argc, n;
- FSTR argv, argq;
- IDENT *vp;
- ITEM *sp;
- ITEM item[1];
-
- argc = tointeger(ac);
- while (++(argn->svalue.ival) < argc) {
- index(argp, argn, item);
- argv = tostring(item);
- argq = isname(argv + 1);
- if (argq != NULL) {
- n = (int)(argq - argv) - 1;
- if (n > MAXCODE-1)
- n = MAXCODE-1;
- fstrncpy(buffer, argv + 1, n);
- buffer[n] = '\0';
- for (vp = ident; vp != NULL; vp = vp->vnext) {
- if (fstrcmp(buffer, vp->vname) == 0) {
- sp = vp->vitem;
- if (sp != nul) {
- buffer[0] = ZSTR;
- fstrncpy(buffer + 1, argq + 1, MAXCODE-2);
- free_item(sp);
- sp->stype = S_STRING;
- sp->sstr = getstr(buffer);
- if (isnumber(buffer+1)) {
- sp->svalue.dval = todouble(sp);
- sp->stype = S_NUMBER;
- }
- }
- break;
- }
- }
- }
- else if (argv[1] != '\0') {
- fstrncpy(argvbuf, argv+1, 64);
- return argvbuf;
- }
- }
- return NULL;
- }
-
- /*
- * get a list of var=text elements and process them
- */
- void getargs(NAME *list)
- {
- int n;
- FSTR var, text;
- IDENT *vp;
- ITEM *sp;
-
- while (list != NULL) {
- var = list->name;
- text = isname(var);
- if (text != NULL) {
- n = (int)(text - var);
- if (n > MAXCODE-1)
- n = MAXCODE-1;
- fstrncpy(buffer, var, n);
- buffer[n] = '\0';
- for (vp = ident; vp != NULL; vp = vp->vnext) {
- if (strcmp(buffer, vp->vname) == 0) {
- sp = vp->vitem;
- if (sp != nul) {
- buffer[0] = ZSTR;
- fstrncpy(buffer + 1, text + 1, MAXCODE-2);
- free_item(sp);
- sp->stype = S_STRING;
- sp->sstr = getstr(buffer);
- if (isnumber(buffer+1)) {
- sp->svalue.dval = todouble(sp);
- sp->stype = S_NUMBER;
- }
- }
- break;
- }
- }
- }
- else
- error("invalid -v var=text syntax %s", list->name);
- list = list->next;
- }
- }
-
- /*
- * set the filename variable to name
- * and clear FNR to 0
- */
- void setfile(FSTR name)
- {
- free_item(fn);
- fn->stype = S_STRING;
- fn->sstr = name;
- free_item(fnr);
- fnr->stype = S_SHORT;
- fnr->svalue.ival = 0;
- }
-
- /*
- * read the next input record to $0
- */
- int getrecord()
- {
- kbhit();
- return getline(files + 1, (ITEM*)fieldtab);
- }
-
- /*
- * read the input until an end of record character
- * is read or until the end of input.
- */
- int getline(FYLE *fp, ITEM *ip)
- {
- int ch, och, lrs;
- char *lp, *ep;
- FSTR dp;
- double lnr;
-
- if (fp->ffyle == NULL) {
- return -1;
- }
- if (ip == (ITEM*)fieldtab) {
- lp = linebuf;
- ep = linebuf + sizeof(linebuf) - 1;
- *lp++ = TSTR;
- }
- else {
- lp = buffer;
- ep = buffer + sizeof(buffer) - 1;
- *lp++ = ZSTR;
- }
- *lp = '\0';
- if (feof(fp->ffyle))
- return 0;
- dp = tostring(rs);
- lrs = dp[1];
- ch = fgetc(fp->ffyle);
- if (ch == EOF)
- return 0;
- if (lrs == 0) {
- och = '\0';
- while (ch != EOF && lp < ep) {
- if (ch == '\n' && och == '\n')
- break;
- *lp++ = och = ch;
- ch = fgetc(fp->ffyle);
- }
- }
- else {
- while (ch != EOF && ch != lrs && lp < ep) {
- *lp++ = ch;
- ch = fgetc(fp->ffyle);
- }
- }
- if (ch != EOF && lp == ep)
- ungetc(ch, fp->ffyle);
- *lp = '\0';
- if (ip == (ITEM*)fieldtab) {
- modrecord = 1;
- modfield = 0;
- free_item(ip);
- ip->stype = S_STRING;
- ip->sstr = linebuf;
- if (ch == EOF && lp == linebuf+1)
- return 0;
- }
- else {
- if (ip != (ITEM*)nul) {
- free_item(ip);
- ip->stype = S_STRING;
- ip->sstr = getstr(buffer);
- }
- if (ch == EOF && lp == buffer+1)
- return 0;
- }
- if (fp == (files + 1)) {
- lnr = todouble((ITEM*)fnr);
- if (fnr->stype != S_DOUBLE) {
- free_item((ITEM*)fnr);
- fnr->stype = S_DOUBLE;
- }
- fnr->svalue.dval = lnr + 1;
- lnr = todouble((ITEM*)nr);
- if (nr->stype != S_DOUBLE) {
- free_item((ITEM*)nr);
- nr->stype = S_DOUBLE;
- }
- nr->svalue.dval = lnr + 1;
- }
- return 1;
- }
-
- /*
- * free all the fields to prepare for the
- * next input record.
- */
- void deparse()
- {
- int i;
-
- for (i = 0; i < MAXFIELD; i++)
- free_item(fieldtab + i);
- fieldtab->stype = S_STRING;
- fieldtab->sstr = linebuf;
- linebuf[0] = TSTR;
- linebuf[1] = 0;
- free_item((ITEM*)nf);
- nf->stype = S_SHORT;
- nf->svalue.ival = 0;
- modfield = 0;
- modrecord = 0;
- }
-
- /*
- * parse the input record into fields
- */
- void parse()
- {
- FSTR dst, mat, beg, src;
- int lnf, i;
- ITEM *ip;
-
- if (modrecord) {
- for (i = 1; i < MAXFIELD; i++)
- free_item(fieldtab + i);
- lnf = 0;
- dst = fieldbuf;
- src = onestring(fieldtab)+1;
- beg = src;
- mat = NULL;
- ip = fieldtab+1;
- if (awkfre == blankre) {
- i = *src++;
- while (i != '\0' && lnf < MAXFIELD-1) {
- while (i > '\0' && isspace(i))
- i = *src++;
- if (i != '\0') {
- ip->stype = S_STRING;
- ip->sstr = dst;
- *dst++ = TSTR;
- while (i != '\0' && (i < 0 || !isspace(i))) {
- *dst++ = i;
- i = *src++;
- }
- *dst++ = '\0';
- if (isnumber(ip->sstr+1)) {
- ip->svalue.dval = todouble(ip);
- ip->stype = S_NUMBER;
- }
- lnf++;
- ip++;
- }
- }
- }
- else {
- while (*src != '\0' && lnf < MAXFIELD-1) {
- ip->stype = S_STRING;
- ip->sstr = dst;
- *dst++ = TSTR;
- while (*src != '\0' &&
- (mat = matchp(beg, src, awkfre)) == NULL && *src != '\n')
- *dst++ = *src++;
- if (src == mat)
- *dst++ = *mat++;
- if (mat != NULL) {
- if (*src != '\0') {
- if(mat > src)
- src = mat;
- else {
- mat = NULL;
- if (dst == fieldbuf + 1)
- *dst++ = *src++;
- }
- }
- }
- else if (*src == '\n') {
- src++;
- mat = NULL;
- }
- *dst++ = '\0';
- if (isnumber(ip->sstr+1)) {
- ip->svalue.dval = todouble(ip);
- ip->stype = S_NUMBER;
- }
- lnf++;
- ip++;
- }
- if (mat != NULL) {
- ip->stype = S_STRING;
- ip->sstr = nullstr;
- lnf++;
- }
- }
- free_item((ITEM*)nf);
- nf->stype = S_SHORT;
- nf->svalue.ival = lnf;
- modfield = 0;
- modrecord = 0;
- }
- }
-
- /*
- * convert the fields back into the input record
- * this is done whenever $0 is referenced after
- * any field is modified.
- */
- void unparse()
- {
- int i, lnf;
- char *dp;
- FSTR sp, fp;
-
- if (modfield) {
- free_item(fieldtab);
- fieldtab->stype = S_STRING;
- fieldtab->sstr = linebuf;
- dp = linebuf;
- *dp++ = TSTR;
- fp = tostring((ITEM*)ofs);
- lnf = tointeger((ITEM*)nf);
- for (i = 1; i <= lnf; i++) {
- if (i > 1) {
- sp = fp+1;
- while (*sp != '\0')
- *dp++ = *sp++;
- }
- sp = tostring(fieldtab + i)+1;
- while (*sp != '\0')
- *dp++ = *sp++;
- }
- *dp = '\0';
- for (i = lnf + 1; i < MAXFIELD; i++)
- free_item(fieldtab + i);
- modfield = 0;
- modrecord = 0;
- }
- }
-
- /*
- * convert an item into a file number
- * the item is converted to a string
- * and this string is used as the filename
- * mp is a pointer to a string that is the
- * open mode of the file "w" or "a"
- */
- FYLE *getfile(ITEM *a, int p)
- {
- FSTR sp;
- FYLE *fp;
-
- sp = tostring(a);
- for (fp = files + 2; fp < nextfile; fp++) {
- if (fstrcmp(fp->fname+1, sp+1) == 0)
- break;
- }
- if (p == P_CLOSE) {
- if (fp < nextfile && fp->ffyle != NULL) {
- fclose(fp->ffyle);
- fp->ffyle = NULL;
- }
- fp = NULL;
- }
- else {
- if (fp >= nextfile) {
- if (nextfile >= files + MAXFILE) {
- for (fp = files; fp < nextfile; fp++) {
- if (fp->ffyle == NULL)
- break;
- }
- }
- else
- fp = nextfile++;
- if (fp >= files + MAXFILE)
- error("too many files open \"%s\"", sp+1);
- }
- if (fp->ffyle == NULL) {
- switch (p) {
- case P_OPEN:
- fp->fmode = "r";
- break;
- case P_CREATE:
- fp->fmode = "w";
- break;
- case P_APPEND:
- fp->fmode = "a";
- break;
- }
- fp->fname = newstr(sp);
- fp->ffyle = NULL;
- }
- }
- return fp;
- }
-
- /*
- * close all of the files used by the AWK program
- */
- void awkclose()
- {
- FYLE *fp;
-
- for (fp = files + 2; fp < nextfile; fp++)
- if (fp->ffyle != NULL)
- fclose(fp->ffyle);
- }
-
-