home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / unix / gawk.sit / source / node.c < prev    next >
Text File  |  1990-07-29  |  6KB  |  344 lines

  1. /*
  2.  * node.c -- routines for node management
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. extern double strtod();
  29.  
  30. /*
  31.  * We can't dereference a variable until after we've given it its new value.
  32.  * This variable points to the value we have to free up 
  33.  */
  34. NODE *deref;
  35.  
  36. AWKNUM
  37. r_force_number(n)
  38. NODE *n;
  39. {
  40.     char *ptr;
  41.  
  42. #ifdef DEBUG
  43.     if (n == NULL)
  44.         cant_happen();
  45.     if (n->type != Node_val)
  46.         cant_happen();
  47.     if(n->flags == 0)
  48.         cant_happen();
  49.     if (n->flags & NUM)
  50.         return n->numbr;
  51. #endif
  52.     if (n->stlen == 0)
  53.         n->numbr = 0.0;
  54.     else if (n->stlen == 1) {
  55.         if (isdigit(n->stptr[0])) {
  56.             n->numbr = n->stptr[0] - '0';
  57.             n->flags |= NUMERIC;
  58.         } else
  59.             n->numbr = 0.0;
  60.     } else {
  61.         errno = 0;
  62.         n->numbr = (AWKNUM) strtod(n->stptr, &ptr);
  63.         /* the following >= should be ==, but for SunOS 3.5 strtod() */
  64.         if (errno == 0 && ptr >= n->stptr + n->stlen)
  65.             n->flags |= NUMERIC;
  66.     }
  67.     n->flags |= NUM;
  68.     return n->numbr;
  69. }
  70.  
  71. /*
  72.  * the following lookup table is used as an optimization in force_string
  73.  * (more complicated) variations on this theme didn't seem to pay off, but 
  74.  * systematic testing might be in order at some point
  75.  */
  76. static char *values[] = {
  77.     "0",
  78.     "1",
  79.     "2",
  80.     "3",
  81.     "4",
  82.     "5",
  83.     "6",
  84.     "7",
  85.     "8",
  86.     "9",
  87. };
  88. #define    NVAL    (sizeof(values)/sizeof(values[0]))
  89.  
  90. NODE *
  91. r_force_string(s)
  92. NODE *s;
  93. {
  94.     char buf[128];
  95.     char *fmt;
  96.     long num;
  97.     char *sp = buf;
  98.  
  99. #ifdef DEBUG
  100.     if (s == NULL)
  101.         cant_happen();
  102.     if (s->type != Node_val)
  103.         cant_happen();
  104.     if (s->flags & STR)
  105.         return s;
  106.     if (!(s->flags & NUM))
  107.         cant_happen();
  108.     if (s->stref != 0)
  109.         cant_happen();
  110. #endif
  111.     s->flags |= STR;
  112.     /* should check validity of user supplied OFMT */
  113.     fmt = OFMT_node->var_value->stptr;
  114.     if ((num = s->numbr) == s->numbr) {
  115.         /* integral value */
  116.         if (num < NVAL && num >= 0) {
  117.             sp = values[num];
  118.             s->stlen = 1;
  119.         } else {
  120.             (void) sprintf(sp, "%ld", num);
  121.             s->stlen = strlen(sp);
  122.         }
  123.     } else {
  124.         (void) sprintf(sp, fmt, s->numbr);
  125.         s->stlen = strlen(sp);
  126.     }
  127.     s->stref = 1;
  128.     emalloc(s->stptr, char *, s->stlen + 1, "force_string");
  129.     memcpy(s->stptr, sp, s->stlen+1);
  130.     return s;
  131. }
  132.  
  133. /*
  134.  * Duplicate a node.  (For strings, "duplicate" means crank up the
  135.  * reference count.)
  136.  */
  137. NODE *
  138. dupnode(n)
  139. NODE *n;
  140. {
  141.     register NODE *r;
  142.  
  143.     if (n->flags & TEMP) {
  144.         n->flags &= ~TEMP;
  145.         n->flags |= MALLOC;
  146.         return n;
  147.     }
  148.     if ((n->flags & (MALLOC|STR)) == (MALLOC|STR)) {
  149.         if (n->stref < 255)
  150.             n->stref++;
  151.         return n;
  152.     }
  153.     r = newnode(Node_illegal);
  154.     *r = *n;
  155.     r->flags &= ~(PERM|TEMP);
  156.     r->flags |= MALLOC;
  157.     if (n->type == Node_val && (n->flags & STR)) {
  158.         r->stref = 1;
  159.         emalloc(r->stptr, char *, r->stlen + 1, "dupnode");
  160.         memcpy(r->stptr, n->stptr, r->stlen+1);
  161.     }
  162.     return r;
  163. }
  164.  
  165. /* this allocates a node with defined numbr */
  166. NODE *
  167. make_number(x)
  168. AWKNUM x;
  169. {
  170.     register NODE *r;
  171.  
  172.     r = newnode(Node_val);
  173.     r->numbr = x;
  174.     r->flags |= (NUM|NUMERIC);
  175.     r->stref = 0;
  176.     return r;
  177. }
  178.  
  179. /*
  180.  * This creates temporary nodes.  They go away quite quickly, so don't use
  181.  * them for anything important 
  182.  */
  183. NODE *
  184. tmp_number(x)
  185. AWKNUM x;
  186. {
  187.     NODE *r;
  188.  
  189.     r = make_number(x);
  190.     r->flags |= TEMP;
  191.     return r;
  192. }
  193.  
  194. /*
  195.  * Make a string node.
  196.  */
  197.  
  198. NODE *
  199. make_str_node(s, len, scan)
  200. char *s;
  201. int len;
  202. int scan;
  203. {
  204.     register NODE *r;
  205.     char *pf;
  206.     register char *pt;
  207.     register int c;
  208.     register char *end;
  209.  
  210.     r = newnode(Node_val);
  211.     emalloc(r->stptr, char *, len + 1, s);
  212.     memcpy(r->stptr, s, len);
  213.     r->stptr[len] = '\0';
  214.     end = &(r->stptr[len]);
  215.            
  216.     if (scan) {    /* scan for escape sequences */
  217.         for (pf = pt = r->stptr; pf < end;) {
  218.             c = *pf++;
  219.             if (c == '\\') {
  220.                 c = parse_escape(&pf);
  221.                 if (c < 0)
  222.                     cant_happen();
  223.                 *pt++ = c;
  224.             } else
  225.                 *pt++ = c;
  226.         }
  227.         len = pt - r->stptr;
  228.         erealloc(r->stptr, char *, len + 1, "make_str_node");
  229.         r->stptr[len] = '\0';
  230.         r->flags |= PERM;
  231.     }
  232.     r->stlen = len;
  233.     r->stref = 1;
  234.     r->flags |= (STR|MALLOC);
  235.  
  236.     return r;
  237. }
  238.  
  239. /* Read the warning under tmp_number */
  240. NODE *
  241. tmp_string(s, len)
  242. char *s;
  243. int len;
  244. {
  245.     register NODE *r;
  246.  
  247.     r = make_string(s, len);
  248.     r->flags |= TEMP;
  249.     return r;
  250. }
  251.  
  252.  
  253. #define NODECHUNK    100
  254.  
  255. static NODE *nextfree = NULL;
  256.  
  257. NODE *
  258. newnode(ty)
  259. NODETYPE ty;
  260. {
  261.     NODE *it;
  262.     NODE *np;
  263.  
  264. #ifdef MPROF
  265.     emalloc(it, NODE *, sizeof(NODE), "newnode");
  266. #else
  267.     if (nextfree == NULL) {
  268.         /* get more nodes and initialize list */
  269.         emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode");
  270.         for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++)
  271.             np->nextp = np + 1;
  272.         np->nextp = NULL;
  273.     }
  274.     /* get head of freelist */
  275.     it = nextfree;
  276.     nextfree = nextfree->nextp;
  277. #endif
  278.     it->type = ty;
  279.     it->flags = MALLOC;
  280. #ifdef MEMDEBUG
  281.     fprintf(stderr, "node: new: %0x\n", it);
  282. #endif
  283.     return it;
  284. }
  285.  
  286. void
  287. freenode(it)
  288. NODE *it;
  289. {
  290. #ifdef DEBUG
  291.     NODE *nf;
  292. #endif
  293. #ifdef MEMDEBUG
  294.     fprintf(stderr, "node: free: %0x\n", it);
  295. #endif
  296. #ifdef MPROF
  297.     free((char *) it);
  298. #else
  299. #ifdef DEBUG
  300.     for (nf = nextfree; nf; nf = nf->nextp)
  301.         if (nf == it)
  302.             fatal("attempt to free free node");
  303. #endif
  304.     /* add it to head of freelist */
  305.     it->nextp = nextfree;
  306.     nextfree = it;
  307. #endif
  308. }
  309.  
  310. #ifdef DEBUG
  311. pf()
  312. {
  313.     NODE *nf = nextfree;
  314.     while (nf != NULL) {
  315.         fprintf(stderr, "%0x ", nf);
  316.         nf = nf->nextp;
  317.     }
  318. }
  319. #endif
  320.  
  321. void
  322. do_deref()
  323. {
  324.     if (deref == NULL)
  325.         return;
  326.     if (deref->flags & PERM) {
  327.         deref = 0;
  328.         return;
  329.     }
  330.     if ((deref->flags & MALLOC) || (deref->flags & TEMP)) {
  331.         deref->flags &= ~TEMP;
  332.         if (deref->flags & STR) {
  333.             if (deref->stref > 1 && deref->stref != 255) {
  334.                 deref->stref--;
  335.                 deref = 0;
  336.                 return;
  337.             }
  338.             free(deref->stptr);
  339.         }
  340.         freenode(deref);
  341.     }
  342.     deref = 0;
  343. }
  344.