aboutsummaryrefslogtreecommitdiffstats
path: root/node.c
diff options
context:
space:
mode:
Diffstat (limited to 'node.c')
-rw-r--r--node.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/node.c b/node.c
new file mode 100644
index 00000000..3d006fe6
--- /dev/null
+++ b/node.c
@@ -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;
+}