home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / gawk213s.lzh / GAWK213S / NODE.C < prev    next >
C/C++ Source or Header  |  1993-07-29  |  8KB  |  430 lines

  1. /*
  2.  * node.c -- routines for node management
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991 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. AWKNUM
  29. r_force_number(n)
  30. register NODE *n;
  31. {
  32.     register char *cp;
  33.     register char *cpend;
  34.     char save;
  35.     char *ptr;
  36.     unsigned int newflags = NUMERIC;
  37.  
  38. #ifdef DEBUG
  39.     if (n == NULL)
  40.         cant_happen();
  41.     if (n->type != Node_val)
  42.         cant_happen();
  43.     if(n->flags == 0)
  44.         cant_happen();
  45.     if (n->flags & NUM)
  46.         return n->numbr;
  47. #endif
  48.  
  49.     /* all the conditionals are an attempt to avoid the expensive strtod */
  50.  
  51.     n->numbr = 0.0;
  52.     n->flags |= NUM;
  53.  
  54.     if (n->stlen == 0)
  55.         return 0.0;
  56.  
  57.     cp = n->stptr;
  58.     if (isalpha(*cp))
  59.         return 0.0;
  60.  
  61.     cpend = cp + n->stlen;
  62.     while (cp < cpend && isspace(*cp))
  63.         cp++;
  64.     if (cp == cpend || isalpha(*cp))
  65.         return 0.0;
  66.  
  67.     if (n->flags & MAYBE_NUM) {
  68.         newflags |= NUMBER;
  69.         n->flags &= ~MAYBE_NUM;
  70.     }
  71.     if (cpend - cp == 1) {
  72.         if (isdigit(*cp)) {
  73.             n->numbr = *cp - '0';
  74.             n->flags |= newflags;
  75.         }
  76.         return n->numbr;
  77.     }
  78.  
  79.     errno = 0;
  80.     save = *cpend;
  81.     *cpend = '\0';
  82.     n->numbr = (AWKNUM) strtod((const char *)cp, &ptr);
  83.  
  84.     /* POSIX says trailing space is OK for NUMERIC */
  85.     while (isspace(*ptr))
  86.         ptr++;
  87.     *cpend = save;
  88.     /* the >= should be ==, but for SunOS 3.5 strtod() */
  89.     if (errno == 0 && ptr >= cpend)
  90.         n->flags |= newflags;
  91.     else
  92.         errno = 0;
  93.  
  94.     return n->numbr;
  95. }
  96.  
  97. /*
  98.  * the following lookup table is used as an optimization in force_string
  99.  * (more complicated) variations on this theme didn't seem to pay off, but 
  100.  * systematic testing might be in order at some point
  101.  */
  102. static char *values[] = {
  103.     "0",
  104.     "1",
  105.     "2",
  106.     "3",
  107.     "4",
  108.     "5",
  109.     "6",
  110.     "7",
  111.     "8",
  112.     "9",
  113. };
  114. #define    NVAL    (sizeof(values)/sizeof(values[0]))
  115.  
  116. NODE *
  117. r_force_string(s)
  118. register NODE *s;
  119. {
  120.     char buf[128];
  121.     register long num;
  122.     register char *sp = buf;
  123.  
  124. #ifdef DEBUG
  125.     if (s == NULL)
  126.         cant_happen();
  127.     if (s->type != Node_val)
  128.         cant_happen();
  129.     if (s->flags & STR)
  130.         return s;
  131.     if (!(s->flags & NUM))
  132.         cant_happen();
  133.     if (s->stref != 0)
  134.         ; /*cant_happen();*/
  135. #endif
  136.     if ((num = s->numbr) == s->numbr) {
  137.         /* integral value */
  138.         if (num < NVAL && num >= 0) {
  139.             sp = values[num];
  140.             s->stlen = 1;
  141.         } else {
  142.             (void) sprintf(sp, "%ld", num);
  143.             s->stlen = strlen(sp);
  144.         }
  145.         s->stfmt = -1;
  146.     } else {
  147.         (void) sprintf(sp, CONVFMT, s->numbr);
  148.         s->stlen = strlen(sp);
  149.         s->stfmt = CONVFMTidx;
  150.     }
  151.     s->stref = 1;
  152.     emalloc(s->stptr, char *, s->stlen + 2, "force_string");
  153.     memcpy(s->stptr, sp, s->stlen+1);
  154.     s->flags |= STR;
  155.     return s;
  156. }
  157.  
  158. /*
  159.  * Duplicate a node.  (For strings, "duplicate" means crank up the
  160.  * reference count.)
  161.  */
  162. NODE *
  163. dupnode(n)
  164. NODE *n;
  165. {
  166.     register NODE *r;
  167.  
  168.     if (n->flags & TEMP) {
  169.         n->flags &= ~TEMP;
  170.         n->flags |= MALLOC;
  171.         return n;
  172.     }
  173.     if ((n->flags & (MALLOC|STR)) == (MALLOC|STR)) {
  174.         if (n->stref < 255)
  175.             n->stref++;
  176.         return n;
  177.     }
  178.     getnode(r);
  179.     *r = *n;
  180.     r->flags &= ~(PERM|TEMP);
  181.     r->flags |= MALLOC;
  182.     if (n->type == Node_val && (n->flags & STR)) {
  183.         r->stref = 1;
  184.         emalloc(r->stptr, char *, r->stlen + 2, "dupnode");
  185.         memcpy(r->stptr, n->stptr, r->stlen+1);
  186.     }
  187.     return r;
  188. }
  189.  
  190. /* this allocates a node with defined numbr */
  191. NODE *
  192. mk_number(x, flags)
  193. AWKNUM x;
  194. unsigned int flags;
  195. {
  196.     register NODE *r;
  197.  
  198.     getnode(r);
  199.     r->type = Node_val;
  200.     r->numbr = x;
  201.     r->flags = flags;
  202. #ifdef DEBUG
  203.     r->stref = 1;
  204.     r->stptr = 0;
  205.     r->stlen = 0;
  206. #endif
  207.     return r;
  208. }
  209.  
  210. /*
  211.  * Make a string node.
  212.  */
  213. NODE *
  214. make_str_node(s, len, flags)
  215. char *s;
  216. size_t len;
  217. int flags;
  218. {
  219.     register NODE *r;
  220.  
  221.     getnode(r);
  222.     r->type = Node_val;
  223.     r->flags = (STRING|STR|MALLOC);
  224.     if (flags & ALREADY_MALLOCED)
  225.         r->stptr = s;
  226.     else {
  227.         emalloc(r->stptr, char *, len + 2, s);
  228.         memcpy(r->stptr, s, len);
  229.     }
  230.     r->stptr[len] = '\0';
  231.            
  232.     if (flags & SCAN) {    /* scan for escape sequences */
  233.         char *pf;
  234.         register char *pt;
  235.         register int c;
  236.         register char *end;
  237.  
  238.         end = &(r->stptr[len]);
  239.         for (pf = pt = r->stptr; pf < end;) {
  240.             c = *pf++;
  241.             if (c == '\\') {
  242.                 c = parse_escape(&pf);
  243.                 if (c < 0)
  244.                     cant_happen();
  245.                 *pt++ = c;
  246.             } else
  247.                 *pt++ = c;
  248.         }
  249.         len = pt - r->stptr;
  250.         erealloc(r->stptr, char *, len + 1, "make_str_node");
  251.         r->stptr[len] = '\0';
  252.         r->flags |= PERM;
  253.     }
  254.     r->stlen = len;
  255.     r->stref = 1;
  256.     r->stfmt = -1;
  257.  
  258.     return r;
  259. }
  260.  
  261. NODE *
  262. tmp_string(s, len)
  263. char *s;
  264. size_t len;
  265. {
  266.     register NODE *r;
  267.  
  268.     r = make_string(s, len);
  269.     r->flags |= TEMP;
  270.     return r;
  271. }
  272.  
  273.  
  274. #define NODECHUNK    100
  275.  
  276. NODE *nextfree = NULL;
  277.  
  278. NODE *
  279. more_nodes()
  280. {
  281.     register NODE *np;
  282.  
  283.     /* get more nodes and initialize list */
  284.     emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode");
  285.     for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++)
  286.         np->nextp = np + 1;
  287.     np->nextp = NULL;
  288.     np = nextfree;
  289.     nextfree = nextfree->nextp;
  290.     return np;
  291. }
  292.  
  293. #ifdef DEBUG
  294. void
  295. freenode(it)
  296. NODE *it;
  297. {
  298. #ifdef MPROF
  299.     it->stref = 0;
  300.     free((char *) it);
  301. #else
  302. #ifdef MALLOCDEBUG
  303.     memset(it, '\04', sizeof(*it));
  304. #endif
  305.     /* add it to head of freelist */
  306.     it->nextp = nextfree;
  307.     nextfree = it;
  308. #endif
  309. }
  310. #endif
  311.  
  312. void
  313. unref(tmp)
  314. register NODE *tmp;
  315. {
  316.     if (tmp == NULL)
  317.         return;
  318.     if (tmp->flags & PERM)
  319.         return;
  320.     if (tmp->flags & (MALLOC|TEMP)) {
  321.         tmp->flags &= ~TEMP;
  322.         if (tmp->flags & STR) {
  323.             if (tmp->stref > 1) {
  324.                 if (tmp->stref != 255)
  325.                     tmp->stref--;
  326.                 return;
  327.             }
  328.             free(tmp->stptr);
  329.         }
  330.         freenode(tmp);
  331.     }
  332. }
  333.  
  334. /*
  335.  * Parse a C escape sequence.  STRING_PTR points to a variable containing a
  336.  * pointer to the string to parse.  That pointer is updated past the
  337.  * characters we use.  The value of the escape sequence is returned. 
  338.  *
  339.  * A negative value means the sequence \ newline was seen, which is supposed to
  340.  * be equivalent to nothing at all. 
  341.  *
  342.  * If \ is followed by a null character, we return a negative value and leave
  343.  * the string pointer pointing at the null character. 
  344.  *
  345.  * If \ is followed by 000, we return 0 and leave the string pointer after the
  346.  * zeros.  A value of 0 does not mean end of string.  
  347.  *
  348.  * Posix doesn't allow \x.
  349.  */
  350.  
  351. int
  352. parse_escape(string_ptr)
  353. char **string_ptr;
  354. {
  355.     register int c = *(*string_ptr)++;
  356.     register int i;
  357.     register int count;
  358.  
  359.     switch (c) {
  360.     case 'a':
  361.         return BELL;
  362.     case 'b':
  363.         return '\b';
  364.     case 'f':
  365.         return '\f';
  366.     case 'n':
  367.         return '\n';
  368.     case 'r':
  369.         return '\r';
  370.     case 't':
  371.         return '\t';
  372.     case 'v':
  373.         return '\v';
  374.     case '\n':
  375.         return -2;
  376.     case 0:
  377.         (*string_ptr)--;
  378.         return -1;
  379.     case '0':
  380.     case '1':
  381.     case '2':
  382.     case '3':
  383.     case '4':
  384.     case '5':
  385.     case '6':
  386.     case '7':
  387.         i = c - '0';
  388.         count = 0;
  389.         while (++count < 3) {
  390.             if ((c = *(*string_ptr)++) >= '0' && c <= '7') {
  391.                 i *= 8;
  392.                 i += c - '0';
  393.             } else {
  394.                 (*string_ptr)--;
  395.                 break;
  396.             }
  397.         }
  398.         return i;
  399.     case 'x':
  400.         if (do_lint) {
  401.             static int didwarn;
  402.  
  403.             if (! didwarn) {
  404.                 didwarn = 1;
  405.                 warning("Posix does not allow \"\\x\" escapes");
  406.             }
  407.         }
  408.         if (do_posix)
  409.             return ('x');
  410.         i = 0;
  411.         while (1) {
  412.             if (isxdigit((c = *(*string_ptr)++))) {
  413.                 i *= 16;
  414.                 if (isdigit(c))
  415.                     i += c - '0';
  416.                 else if (isupper(c))
  417.                     i += c - 'A' + 10;
  418.                 else
  419.                     i += c - 'a' + 10;
  420.             } else {
  421.                 (*string_ptr)--;
  422.                 break;
  423.             }
  424.         }
  425.         return i;
  426.     default:
  427.         return c;
  428.     }
  429. }
  430.