9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

tran.c (11856B)


      1 /****************************************************************
      2 Copyright (C) Lucent Technologies 1997
      3 All Rights Reserved
      4 
      5 Permission to use, copy, modify, and distribute this software and
      6 its documentation for any purpose and without fee is hereby
      7 granted, provided that the above copyright notice appear in all
      8 copies and that both that the copyright notice and this
      9 permission notice and warranty disclaimer appear in supporting
     10 documentation, and that the name Lucent Technologies or any of
     11 its entities not be used in advertising or publicity pertaining
     12 to distribution of the software without specific, written prior
     13 permission.
     14 
     15 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
     17 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
     18 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
     20 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
     22 THIS SOFTWARE.
     23 ****************************************************************/
     24 
     25 #define	DEBUG
     26 #include <stdio.h>
     27 #include <math.h>
     28 #include <ctype.h>
     29 #include <string.h>
     30 #include <stdlib.h>
     31 #include "awk.h"
     32 #include "y.tab.h"
     33 
     34 #define	FULLTAB	2	/* rehash when table gets this x full */
     35 #define	GROWTAB 4	/* grow table by this factor */
     36 
     37 Array	*symtab;	/* main symbol table */
     38 
     39 char	**FS;		/* initial field sep */
     40 char	**RS;		/* initial record sep */
     41 char	**OFS;		/* output field sep */
     42 char	**ORS;		/* output record sep */
     43 char	**OFMT;		/* output format for numbers */
     44 char	**CONVFMT;	/* format for conversions in getsval */
     45 Awkfloat *NF;		/* number of fields in current record */
     46 Awkfloat *NR;		/* number of current record */
     47 Awkfloat *FNR;		/* number of current record in current file */
     48 char	**FILENAME;	/* current filename argument */
     49 Awkfloat *ARGC;		/* number of arguments from command line */
     50 char	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
     51 Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
     52 Awkfloat *RLENGTH;	/* length of same */
     53 
     54 Cell	*nrloc;		/* NR */
     55 Cell	*nfloc;		/* NF */
     56 Cell	*fnrloc;	/* FNR */
     57 Array	*ARGVtab;	/* symbol table containing ARGV[...] */
     58 Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
     59 Cell	*rstartloc;	/* RSTART */
     60 Cell	*rlengthloc;	/* RLENGTH */
     61 Cell	*symtabloc;	/* SYMTAB */
     62 
     63 Cell	*nullloc;	/* a guaranteed empty cell */
     64 Node	*nullnode;	/* zero&null, converted into a node for comparisons */
     65 Cell	*literal0;
     66 
     67 extern Cell **fldtab;
     68 
     69 void syminit(void)	/* initialize symbol table with builtin vars */
     70 {
     71 	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
     72 	/* this is used for if(x)... tests: */
     73 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
     74 	nullnode = celltonode(nullloc, CCON);
     75 
     76 	FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
     77 	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
     78 	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
     79 	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
     80 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
     81 	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
     82 	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
     83 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
     84 	NF = &nfloc->fval;
     85 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
     86 	NR = &nrloc->fval;
     87 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
     88 	FNR = &fnrloc->fval;
     89 	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
     90 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
     91 	RSTART = &rstartloc->fval;
     92 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
     93 	RLENGTH = &rlengthloc->fval;
     94 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
     95 	symtabloc->sval = (char *) symtab;
     96 }
     97 
     98 void arginit(int ac, char **av)	/* set up ARGV and ARGC */
     99 {
    100 	Cell *cp;
    101 	int i;
    102 	char temp[50];
    103 
    104 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
    105 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
    106 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
    107 	cp->sval = (char *) ARGVtab;
    108 	for (i = 0; i < ac; i++) {
    109 		sprintf(temp, "%d", i);
    110 		if (is_number(*av))
    111 			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
    112 		else
    113 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
    114 		av++;
    115 	}
    116 }
    117 
    118 void envinit(char **envp)	/* set up ENVIRON variable */
    119 {
    120 	Cell *cp;
    121 	char *p;
    122 
    123 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
    124 	ENVtab = makesymtab(NSYMTAB);
    125 	cp->sval = (char *) ENVtab;
    126 	for ( ; *envp; envp++) {
    127 		if ((p = strchr(*envp, '=')) == NULL)
    128 			continue;
    129 		*p++ = 0;	/* split into two strings at = */
    130 		if (is_number(p))
    131 			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
    132 		else
    133 			setsymtab(*envp, p, 0.0, STR, ENVtab);
    134 		p[-1] = '=';	/* restore in case env is passed down to a shell */
    135 	}
    136 }
    137 
    138 Array *makesymtab(int n)	/* make a new symbol table */
    139 {
    140 	Array *ap;
    141 	Cell **tp;
    142 
    143 	ap = (Array *) malloc(sizeof(Array));
    144 	tp = (Cell **) calloc(n, sizeof(Cell *));
    145 	if (ap == NULL || tp == NULL)
    146 		FATAL("out of space in makesymtab");
    147 	ap->nelem = 0;
    148 	ap->size = n;
    149 	ap->tab = tp;
    150 	return(ap);
    151 }
    152 
    153 void freesymtab(Cell *ap)	/* free a symbol table */
    154 {
    155 	Cell *cp, *temp;
    156 	Array *tp;
    157 	int i;
    158 
    159 	if (!isarr(ap))
    160 		return;
    161 	tp = (Array *) ap->sval;
    162 	if (tp == NULL)
    163 		return;
    164 	for (i = 0; i < tp->size; i++) {
    165 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
    166 			xfree(cp->nval);
    167 			if (freeable(cp))
    168 				xfree(cp->sval);
    169 			temp = cp->cnext;	/* avoids freeing then using */
    170 			free(cp); 
    171 		}
    172 		tp->tab[i] = 0;
    173 	}
    174 	free(tp->tab);
    175 	free(tp);
    176 }
    177 
    178 void freeelem(Cell *ap, char *s)	/* free elem s from ap (i.e., ap["s"] */
    179 {
    180 	Array *tp;
    181 	Cell *p, *prev = NULL;
    182 	int h;
    183 	
    184 	tp = (Array *) ap->sval;
    185 	h = hash(s, tp->size);
    186 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
    187 		if (strcmp(s, p->nval) == 0) {
    188 			if (prev == NULL)	/* 1st one */
    189 				tp->tab[h] = p->cnext;
    190 			else			/* middle somewhere */
    191 				prev->cnext = p->cnext;
    192 			if (freeable(p))
    193 				xfree(p->sval);
    194 			free(p->nval);
    195 			free(p);
    196 			tp->nelem--;
    197 			return;
    198 		}
    199 }
    200 
    201 Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
    202 {
    203 	int h;
    204 	Cell *p;
    205 
    206 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
    207 		   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
    208 			p, p->nval, p->sval, p->fval, p->tval) );
    209 		return(p);
    210 	}
    211 	p = (Cell *) malloc(sizeof(Cell));
    212 	if (p == NULL)
    213 		FATAL("out of space for symbol table at %s", n);
    214 	p->nval = tostring(n);
    215 	p->sval = s ? tostring(s) : tostring("");
    216 	p->fval = f;
    217 	p->tval = t;
    218 	p->csub = CUNK;
    219 	p->ctype = OCELL;
    220 	tp->nelem++;
    221 	if (tp->nelem > FULLTAB * tp->size)
    222 		rehash(tp);
    223 	h = hash(n, tp->size);
    224 	p->cnext = tp->tab[h];
    225 	tp->tab[h] = p;
    226 	   dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
    227 		p, p->nval, p->sval, p->fval, p->tval) );
    228 	return(p);
    229 }
    230 
    231 int hash(char *s, int n)	/* form hash value for string s */
    232 {
    233 	unsigned hashval;
    234 
    235 	for (hashval = 0; *s != '\0'; s++)
    236 		hashval = (*s + 31 * hashval);
    237 	return hashval % n;
    238 }
    239 
    240 void rehash(Array *tp)	/* rehash items in small table into big one */
    241 {
    242 	int i, nh, nsz;
    243 	Cell *cp, *op, **np;
    244 
    245 	nsz = GROWTAB * tp->size;
    246 	np = (Cell **) calloc(nsz, sizeof(Cell *));
    247 	if (np == NULL)		/* can't do it, but can keep running. */
    248 		return;		/* someone else will run out later. */
    249 	for (i = 0; i < tp->size; i++) {
    250 		for (cp = tp->tab[i]; cp; cp = op) {
    251 			op = cp->cnext;
    252 			nh = hash(cp->nval, nsz);
    253 			cp->cnext = np[nh];
    254 			np[nh] = cp;
    255 		}
    256 	}
    257 	free(tp->tab);
    258 	tp->tab = np;
    259 	tp->size = nsz;
    260 }
    261 
    262 Cell *lookup(char *s, Array *tp)	/* look for s in tp */
    263 {
    264 	Cell *p;
    265 	int h;
    266 
    267 	h = hash(s, tp->size);
    268 	for (p = tp->tab[h]; p != NULL; p = p->cnext)
    269 		if (strcmp(s, p->nval) == 0)
    270 			return(p);	/* found it */
    271 	return(NULL);			/* not found */
    272 }
    273 
    274 Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
    275 {
    276 	int fldno;
    277 
    278 	if ((vp->tval & (NUM | STR)) == 0) 
    279 		funnyvar(vp, "assign to");
    280 	if (isfld(vp)) {
    281 		donerec = 0;	/* mark $0 invalid */
    282 		fldno = atoi(vp->nval);
    283 		if (fldno > *NF)
    284 			newfld(fldno);
    285 		   dprintf( ("setting field %d to %g\n", fldno, f) );
    286 	} else if (isrec(vp)) {
    287 		donefld = 0;	/* mark $1... invalid */
    288 		donerec = 1;
    289 	}
    290 	if (freeable(vp))
    291 		xfree(vp->sval); /* free any previous string */
    292 	vp->tval &= ~STR;	/* mark string invalid */
    293 	vp->tval |= NUM;	/* mark number ok */
    294 	   dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
    295 	return vp->fval = f;
    296 }
    297 
    298 void funnyvar(Cell *vp, char *rw)
    299 {
    300 	if (isarr(vp))
    301 		FATAL("can't %s %s; it's an array name.", rw, vp->nval);
    302 	if (vp->tval & FCN)
    303 		FATAL("can't %s %s; it's a function.", rw, vp->nval);
    304 	WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
    305 		vp, vp->nval, vp->sval, vp->fval, vp->tval);
    306 }
    307 
    308 char *setsval(Cell *vp, char *s)	/* set string val of a Cell */
    309 {
    310 	char *t;
    311 	int fldno;
    312 
    313 	   dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
    314 	if ((vp->tval & (NUM | STR)) == 0)
    315 		funnyvar(vp, "assign to");
    316 	if (isfld(vp)) {
    317 		donerec = 0;	/* mark $0 invalid */
    318 		fldno = atoi(vp->nval);
    319 		if (fldno > *NF)
    320 			newfld(fldno);
    321 		   dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
    322 	} else if (isrec(vp)) {
    323 		donefld = 0;	/* mark $1... invalid */
    324 		donerec = 1;
    325 	}
    326 	t = tostring(s);	/* in case it's self-assign */
    327 	vp->tval &= ~NUM;
    328 	vp->tval |= STR;
    329 	if (freeable(vp))
    330 		xfree(vp->sval);
    331 	vp->tval &= ~DONTFREE;
    332 	   dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
    333 	return(vp->sval = t);
    334 }
    335 
    336 Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
    337 {
    338 	if ((vp->tval & (NUM | STR)) == 0)
    339 		funnyvar(vp, "read value of");
    340 	if (isfld(vp) && donefld == 0)
    341 		fldbld();
    342 	else if (isrec(vp) && donerec == 0)
    343 		recbld();
    344 	if (!isnum(vp)) {	/* not a number */
    345 		vp->fval = atof(vp->sval);	/* best guess */
    346 		if (is_number(vp->sval) && !(vp->tval&CON))
    347 			vp->tval |= NUM;	/* make NUM only sparingly */
    348 	}
    349 	   dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
    350 	return(vp->fval);
    351 }
    352 
    353 char *getsval(Cell *vp)	/* get string val of a Cell */
    354 {
    355 	char s[100];	/* BUG: unchecked */
    356 	double dtemp;
    357 
    358 	if ((vp->tval & (NUM | STR)) == 0)
    359 		funnyvar(vp, "read value of");
    360 	if (isfld(vp) && donefld == 0)
    361 		fldbld();
    362 	else if (isrec(vp) && donerec == 0)
    363 		recbld();
    364 	if (isstr(vp) == 0) {
    365 		if (freeable(vp))
    366 			xfree(vp->sval);
    367 		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
    368 			sprintf(s, "%.30g", vp->fval);
    369 		else
    370 			sprintf(s, *CONVFMT, vp->fval);
    371 		vp->sval = tostring(s);
    372 		vp->tval &= ~DONTFREE;
    373 		vp->tval |= STR;
    374 	}
    375 	   dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
    376 	return(vp->sval);
    377 }
    378 
    379 char *tostring(char *s)	/* make a copy of string s */
    380 {
    381 	char *p;
    382 
    383 	p = (char *) malloc(strlen(s)+1);
    384 	if (p == NULL)
    385 		FATAL("out of space in tostring on %s", s);
    386 	strcpy(p, s);
    387 	return(p);
    388 }
    389 
    390 char *qstring(char *s, int delim)	/* collect string up to next delim */
    391 {
    392 	char *os = s;
    393 	int c, n;
    394 	char *buf, *bp;
    395 
    396 	if ((buf = (char *) malloc(strlen(s)+3)) == NULL)
    397 		FATAL( "out of space in qstring(%s)", s);
    398 	for (bp = buf; (c = *s) != delim; s++) {
    399 		if (c == '\n')
    400 			SYNTAX( "newline in string %.20s...", os );
    401 		else if (c != '\\')
    402 			*bp++ = c;
    403 		else {	/* \something */
    404 			c = *++s;
    405 			if (c == 0) {	/* \ at end */
    406 				*bp++ = '\\';
    407 				break;	/* for loop */
    408 			}	
    409 			switch (c) {
    410 			case '\\':	*bp++ = '\\'; break;
    411 			case 'n':	*bp++ = '\n'; break;
    412 			case 't':	*bp++ = '\t'; break;
    413 			case 'b':	*bp++ = '\b'; break;
    414 			case 'f':	*bp++ = '\f'; break;
    415 			case 'r':	*bp++ = '\r'; break;
    416 			default:
    417 				if (!isdigit(c)) {
    418 					*bp++ = c;
    419 					break;
    420 				}
    421 				n = c - '0';
    422 				if (isdigit(s[1])) {
    423 					n = 8 * n + *++s - '0';
    424 					if (isdigit(s[1]))
    425 						n = 8 * n + *++s - '0';
    426 				}
    427 				*bp++ = n;
    428 				break;
    429 			}
    430 		}
    431 	}
    432 	*bp++ = 0;
    433 	return buf;
    434 }
    435