diff options
Diffstat (limited to 'node.c')
-rw-r--r-- | node.c | 342 |
1 files changed, 342 insertions, 0 deletions
@@ -0,0 +1,342 @@ +/* + * node.c -- routines for node management + */ + +/* + * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc. + * + * This file is part of GAWK, the GNU implementation of the + * AWK Progamming Language. + * + * GAWK is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * GAWK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GAWK; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "awk.h" + +extern double strtod(); + +/* + * We can't dereference a variable until after we've given it its new value. + * This variable points to the value we have to free up + */ +NODE *deref; + +AWKNUM +r_force_number(n) +NODE *n; +{ + char *ptr; + +#ifdef DEBUG + if (n == NULL) + cant_happen(); + if (n->type != Node_val) + cant_happen(); + if(n->flags == 0) + cant_happen(); + if (n->flags & NUM) + return n->numbr; +#endif + if (n->stlen == 0) + n->numbr = 0.0; + else if (n->stlen == 1) { + if (isdigit(n->stptr[0])) { + n->numbr = n->stptr[0] - '0'; + n->flags |= NUMERIC; + } else + n->numbr = 0.0; + } else { + errno = 0; + n->numbr = (AWKNUM) strtod(n->stptr, &ptr); + if (errno == 0 && ptr == n->stptr + n->stlen) + n->flags |= NUMERIC; + } + n->flags |= NUM; + return n->numbr; +} + +/* + * the following lookup table is used as an optimization in force_string + * (more complicated) variations on this theme didn't seem to pay off, but + * systematic testing might be in order at some point + */ +static char *values[] = { + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", +}; +#define NVAL (sizeof(values)/sizeof(values[0])) + +NODE * +r_force_string(s) +NODE *s; +{ + char buf[128]; + char *fmt; + long num; + char *sp = buf; + +#ifdef DEBUG + if (s == NULL) + cant_happen(); + if (s->type != Node_val) + cant_happen(); + if (s->flags & STR) + return s; + if (!(s->flags & NUM)) + cant_happen(); + if (s->stref != 0) + cant_happen(); +#endif + s->flags |= STR; + /* should check validity of user supplied OFMT */ + fmt = OFMT_node->var_value->stptr; + if ((num = s->numbr) == s->numbr) { + /* integral value */ + if (num < NVAL && num >= 0) { + sp = values[num]; + s->stlen = 1; + } else { + (void) sprintf(sp, "%ld", num); + s->stlen = strlen(sp); + } + } else { + (void) sprintf(sp, fmt, s->numbr); + s->stlen = strlen(sp); + } + s->stref = 1; + emalloc(s->stptr, char *, s->stlen + 1, "force_string"); + memcpy(s->stptr, sp, s->stlen+1); + return s; +} + +/* + * Duplicate a node. (For strings, "duplicate" means crank up the + * reference count.) + */ +NODE * +dupnode(n) +NODE *n; +{ + register NODE *r; + + if (n->flags & TEMP) { + n->flags &= ~TEMP; + n->flags |= MALLOC; + return n; + } + if ((n->flags & (MALLOC|STR)) == (MALLOC|STR)) { + if (n->stref < 255) + n->stref++; + return n; + } + r = newnode(Node_illegal); + *r = *n; + r->flags &= ~(PERM|TEMP); + r->flags |= MALLOC; + if (n->type == Node_val && (n->flags & STR)) { + r->stref = 1; + emalloc(r->stptr, char *, r->stlen + 1, "dupnode"); + memcpy(r->stptr, n->stptr, r->stlen+1); + } + return r; +} + +/* this allocates a node with defined numbr */ +NODE * +make_number(x) +AWKNUM x; +{ + register NODE *r; + + r = newnode(Node_val); + r->numbr = x; + r->flags |= (NUM|NUMERIC); + r->stref = 0; + return r; +} + +/* + * This creates temporary nodes. They go away quite quickly, so don't use + * them for anything important + */ +NODE * +tmp_number(x) +AWKNUM x; +{ + NODE *r; + + r = make_number(x); + r->flags |= TEMP; + return r; +} + +/* + * Make a string node. + */ + +NODE * +make_str_node(s, len, scan) +char *s; +int len; +int scan; +{ + register NODE *r; + char *pf; + register char *pt; + register int c; + register char *end; + + r = newnode(Node_val); + emalloc(r->stptr, char *, len + 1, s); + memcpy(r->stptr, s, len); + r->stptr[len] = '\0'; + end = &(r->stptr[len]); + + if (scan) { /* scan for escape sequences */ + for (pf = pt = r->stptr; pf < end;) { + c = *pf++; + if (c == '\\') { + c = parse_escape(&pf); + if (c < 0) + cant_happen(); + *pt++ = c; + } else + *pt++ = c; + } + len = pt - r->stptr; + erealloc(r->stptr, char *, len + 1, "make_str_node"); + r->stptr[len] = '\0'; + r->flags |= PERM; + } + r->stlen = len; + r->stref = 1; + r->flags |= (STR|MALLOC); + + return r; +} + +/* Read the warning under tmp_number */ +NODE * +tmp_string(s, len) +char *s; +int len; +{ + register NODE *r; + + r = make_string(s, len); + r->flags |= TEMP; + return r; +} + + +#define NODECHUNK 100 + +static NODE *nextfree = NULL; + +NODE * +newnode(ty) +NODETYPE ty; +{ + NODE *it; + NODE *np; + +#ifdef MPROF + emalloc(it, NODE *, sizeof(NODE), "newnode"); +#else + if (nextfree == NULL) { + /* get more nodes and initialize list */ + emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode"); + for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++) + np->nextp = np + 1; + np->nextp = NULL; + } + /* get head of freelist */ + it = nextfree; + nextfree = nextfree->nextp; +#endif + it->type = ty; + it->flags = MALLOC; +#ifdef MEMDEBUG + fprintf(stderr, "node: new: %0x\n", it); +#endif + return it; +} + +void +freenode(it) +NODE *it; +{ +#ifdef DEBUG + NODE *nf; +#endif +#ifdef MEMDEBUG + fprintf(stderr, "node: free: %0x\n", it); +#endif +#ifdef MPROF + free((char *) it); +#else +#ifdef DEBUG + for (nf = nextfree; nf; nf = nf->nextp) + if (nf == it) + fatal("attempt to free free node"); +#endif + /* add it to head of freelist */ + it->nextp = nextfree; + nextfree = it; +#endif +} + +#ifdef DEBUG +pf() +{ + NODE *nf = nextfree; + while (nf != NULL) { + fprintf(stderr, "%0x ", nf); + nf = nf->nextp; + } +} +#endif + +void +do_deref() +{ + if (deref == NULL) + return; + if (deref->flags & PERM) { + deref = 0; + return; + } + if ((deref->flags & MALLOC) || (deref->flags & TEMP)) { + deref->flags &= ~TEMP; + if (deref->flags & STR) { + if (deref->stref > 1 && deref->stref != 255) { + deref->stref--; + deref = 0; + return; + } + free(deref->stptr); + } + freenode(deref); + } + deref = 0; +} |