home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gawk-2.15.6-base.tgz / gawk-2.15.6-base.tar / fsf / gawk / builtin.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  27KB  |  1,252 lines

  1. /*
  2.  * builtin.c - Builtin functions and various utility procedures 
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1995 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 2 of the License, or
  14.  * (at your option) 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26.  
  27. #include "awk.h"
  28.  
  29. #ifndef SRANDOM_PROTO
  30. extern void srandom P((unsigned int seed));
  31. #endif
  32. #if defined(RANDOM_MISSING)
  33. extern char *initstate P((unsigned seed, char *state, int n));
  34. extern char *setstate P((char *state));
  35. extern long random P((void));
  36. #endif
  37.  
  38. extern NODE **fields_arr;
  39. extern int output_is_tty;
  40.  
  41. static NODE *sub_common P((NODE *tree, int global));
  42. NODE *format_tree P((const char *, int, NODE *));
  43.  
  44. #ifdef _CRAY
  45. /* Work around a problem in conversion of doubles to exact integers. */
  46. #include <float.h>
  47. #define Floor(n) floor((n) * (1.0 + DBL_EPSILON))
  48. #define Ceil(n) ceil((n) * (1.0 + DBL_EPSILON))
  49.  
  50. /* Force the standard C compiler to use the library math functions. */
  51. extern double exp(double);
  52. double (*Exp)() = exp;
  53. #define exp(x) (*Exp)(x)
  54. extern double log(double);
  55. double (*Log)() = log;
  56. #define log(x) (*Log)(x)
  57. #else
  58. #define Floor(n) floor(n)
  59. #define Ceil(n) ceil(n)
  60. #endif
  61.  
  62. #define DEFAULT_G_PRECISION 6
  63.  
  64. #ifdef GFMT_WORKAROUND
  65. /* semi-temporary hack, mostly to gracefully handle VMS */
  66. static void sgfmt P((char *buf, const char *format, int alt,
  67.              int fwidth, int precision, double value));
  68. #endif /* GFMT_WORKAROUND */
  69.  
  70. /*
  71.  * On the alpha, LONG_MAX is too big for doing rand().
  72.  * On the Cray (Y-MP, anyway), ints and longs are 64 bits, but
  73.  * random() does things in terms of 32 bits. So we have to chop
  74.  * LONG_MAX down.
  75.  */
  76. #if (defined(__alpha) && defined(__osf__)) || defined(_CRAY)
  77. #define GAWK_RANDOM_MAX (LONG_MAX & 0x7fffffff)
  78. #else
  79. #define GAWK_RANDOM_MAX LONG_MAX
  80. #endif
  81.  
  82. static void efwrite P((const void *ptr, size_t size, size_t count, FILE *fp,
  83.                const char *from, struct redirect *rp,int flush));
  84.  
  85. static void
  86. efwrite(ptr, size, count, fp, from, rp, flush)
  87. const void *ptr;
  88. size_t size, count;
  89. FILE *fp;
  90. const char *from;
  91. struct redirect *rp;
  92. int flush;
  93. {
  94.     errno = 0;
  95.     if (fwrite(ptr, size, count, fp) != count)
  96.         goto wrerror;
  97.     if (flush
  98.       && ((fp == stdout && output_is_tty)
  99.        || (rp && (rp->flag & RED_NOBUF)))) {
  100.         fflush(fp);
  101.         if (ferror(fp))
  102.             goto wrerror;
  103.     }
  104.     return;
  105.  
  106.   wrerror:
  107.     fatal("%s to \"%s\" failed (%s)", from,
  108.         rp ? rp->value : "standard output",
  109.         errno ? strerror(errno) : "reason unknown");
  110. }
  111.  
  112. /* Builtin functions */
  113. NODE *
  114. do_exp(tree)
  115. NODE *tree;
  116. {
  117.     NODE *tmp;
  118.     double d, res;
  119. #ifndef exp
  120.     double exp P((double));
  121. #endif
  122.  
  123.     tmp= tree_eval(tree->lnode);
  124.     d = force_number(tmp);
  125.     free_temp(tmp);
  126.     errno = 0;
  127.     res = exp(d);
  128.     if (errno == ERANGE)
  129.         warning("exp argument %g is out of range", d);
  130.     return tmp_number((AWKNUM) res);
  131. }
  132.  
  133. NODE *
  134. do_index(tree)
  135. NODE *tree;
  136. {
  137.     NODE *s1, *s2;
  138.     register char *p1, *p2;
  139.     register size_t l1, l2;
  140.     long ret;
  141.  
  142.  
  143.     s1 = tree_eval(tree->lnode);
  144.     s2 = tree_eval(tree->rnode->lnode);
  145.     force_string(s1);
  146.     force_string(s2);
  147.     p1 = s1->stptr;
  148.     p2 = s2->stptr;
  149.     l1 = s1->stlen;
  150.     l2 = s2->stlen;
  151.     ret = 0;
  152.     if (IGNORECASE) {
  153.         while (l1) {
  154.             if (l2 > l1)
  155.                 break;
  156.             if (casetable[(int)*p1] == casetable[(int)*p2]
  157.                 && (l2 == 1 || strncasecmp(p1, p2, l2) == 0)) {
  158.                 ret = 1 + s1->stlen - l1;
  159.                 break;
  160.             }
  161.             l1--;
  162.             p1++;
  163.         }
  164.     } else {
  165.         while (l1) {
  166.             if (l2 > l1)
  167.                 break;
  168.             if (*p1 == *p2
  169.                 && (l2 == 1 || STREQN(p1, p2, l2))) {
  170.                 ret = 1 + s1->stlen - l1;
  171.                 break;
  172.             }
  173.             l1--;
  174.             p1++;
  175.         }
  176.     }
  177.     free_temp(s1);
  178.     free_temp(s2);
  179.     return tmp_number((AWKNUM) ret);
  180. }
  181.  
  182. double
  183. double_to_int(d)
  184. double d;
  185. {
  186.     double floor P((double));
  187.     double ceil P((double));
  188.  
  189.     if (d >= 0)
  190.         d = Floor(d);
  191.     else
  192.         d = Ceil(d);
  193.     return d;
  194. }
  195.  
  196. NODE *
  197. do_int(tree)
  198. NODE *tree;
  199. {
  200.     NODE *tmp;
  201.     double d;
  202.  
  203.     tmp = tree_eval(tree->lnode);
  204.     d = force_number(tmp);
  205.     d = double_to_int(d);
  206.     free_temp(tmp);
  207.     return tmp_number((AWKNUM) d);
  208. }
  209.  
  210. NODE *
  211. do_length(tree)
  212. NODE *tree;
  213. {
  214.     NODE *tmp;
  215.     size_t len;
  216.  
  217.     tmp = tree_eval(tree->lnode);
  218.     len = force_string(tmp)->stlen;
  219.     free_temp(tmp);
  220.     return tmp_number((AWKNUM) len);
  221. }
  222.  
  223. NODE *
  224. do_log(tree)
  225. NODE *tree;
  226. {
  227.     NODE *tmp;
  228. #ifndef log
  229.     double log P((double));
  230. #endif
  231.     double d, arg;
  232.  
  233.     tmp = tree_eval(tree->lnode);
  234.     arg = (double) force_number(tmp);
  235.     if (arg < 0.0)
  236.         warning("log called with negative argument %g", arg);
  237.     d = log(arg);
  238.     free_temp(tmp);
  239.     return tmp_number((AWKNUM) d);
  240. }
  241.  
  242. /*
  243.  * format_tree() formats nodes of a tree, starting with a left node,
  244.  * and accordingly to a fmt_string providing a format like in
  245.  * printf family from C library.  Returns a string node which value
  246.  * is a formatted string.  Called by  sprintf function.
  247.  *
  248.  * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
  249.  * for taming this beast and making it compatible with ANSI C.
  250.  */
  251.  
  252. NODE *
  253. format_tree(fmt_string, n0, carg)
  254. const char *fmt_string;
  255. int n0;
  256. register NODE *carg;
  257. {
  258. /* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
  259. /* difference of pointers should be of ptrdiff_t type, but let us be kind */
  260. #define bchunk(s,l) if(l) {\
  261.     while((l)>ofre) {\
  262.       long olen = obufout - obuf;\
  263.       erealloc(obuf, char *, osiz*2, "format_tree");\
  264.       ofre+=osiz;\
  265.       osiz*=2;\
  266.       obufout = obuf + olen;\
  267.     }\
  268.     memcpy(obufout,s,(size_t)(l));\
  269.     obufout+=(l);\
  270.     ofre-=(l);\
  271.   }
  272. /* copy one byte from 's' to 'obufout' checking for space in the process */
  273. #define bchunk_one(s) {\
  274.     if(ofre <= 0) {\
  275.       long olen = obufout - obuf;\
  276.       erealloc(obuf, char *, osiz*2, "format_tree");\
  277.       ofre+=osiz;\
  278.       osiz*=2;\
  279.       obufout = obuf + olen;\
  280.     }\
  281.     *obufout++ = *s;\
  282.     --ofre;\
  283.   }
  284.  
  285.     /* Is there space for something L big in the buffer? */
  286. #define chksize(l)  if((l)>ofre) {\
  287.     long olen = obufout - obuf;\
  288.     erealloc(obuf, char *, osiz*2, "format_tree");\
  289.     obufout = obuf + olen;\
  290.     ofre+=osiz;\
  291.     osiz*=2;\
  292.   }
  293.  
  294.     /*
  295.      * Get the next arg to be formatted.  If we've run out of args,
  296.      * return "" (Null string) 
  297.      */
  298. #define parse_next_arg() {\
  299.   if(!carg) { toofew = 1; break; }\
  300.   else {\
  301.     arg=tree_eval(carg->lnode);\
  302.     carg=carg->rnode;\
  303.   }\
  304.  }
  305.  
  306.     NODE *r;
  307.     int toofew = 0;
  308.     char *obuf, *obufout;
  309.     size_t osiz, ofre;
  310.     char *chbuf;
  311.     const char *s0, *s1;
  312.     int cs1;
  313.     NODE *arg;
  314.     long fw, prec;
  315.     int lj, alt, big, have_prec;
  316.     long *cur;
  317.     long val;
  318. #ifdef sun386        /* Can't cast unsigned (int/long) from ptr->value */
  319.     long tmp_uval;    /* on 386i 4.0.1 C compiler -- it just hangs */
  320. #endif
  321.     unsigned long uval;
  322.     int sgn;
  323.     int base = 0;
  324.     char cpbuf[30];        /* if we have numbers bigger than 30 */
  325.     char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
  326.     char *cp;
  327.     char *fill;
  328.     double tmpval;
  329.     char signchar = 0;
  330.     size_t len;
  331.     static char sp[] = " ";
  332.     static char zero_string[] = "0";
  333.     static char lchbuf[] = "0123456789abcdef";
  334.     static char Uchbuf[] = "0123456789ABCDEF";
  335.  
  336.     emalloc(obuf, char *, 120, "format_tree");
  337.     obufout = obuf;
  338.     osiz = 120;
  339.     ofre = osiz - 1;
  340.  
  341.     s0 = s1 = fmt_string;
  342.     while (n0-- > 0) {
  343.         if (*s1 != '%') {
  344.             s1++;
  345.             continue;
  346.         }
  347.         bchunk(s0, s1 - s0);
  348.         s0 = s1;
  349.         cur = &fw;
  350.         fw = 0;
  351.         prec = 0;
  352.         have_prec = 0;
  353.         lj = alt = big = 0;
  354.         fill = sp;
  355.         cp = cend;
  356.         chbuf = lchbuf;
  357.         s1++;
  358.  
  359. retry:
  360.         --n0;
  361.         switch (cs1 = *s1++) {
  362.         case (-1):    /* dummy case to allow for checking */
  363. check_pos:
  364.             if (cur != &fw)
  365.                 break;        /* reject as a valid format */
  366.             goto retry;
  367.         case '%':
  368.             bchunk_one("%");
  369.             s0 = s1;
  370.             break;
  371.  
  372.         case '0':
  373.             if (lj)
  374.                 goto retry;
  375.             if (cur == &fw)
  376.                 fill = zero_string;    /* FALL through */
  377.         case '1':
  378.         case '2':
  379.         case '3':
  380.         case '4':
  381.         case '5':
  382.         case '6':
  383.         case '7':
  384.         case '8':
  385.         case '9':
  386.             if (cur == 0)
  387.                 /* goto lose; */
  388.                 break;
  389.             if (prec >= 0)
  390.                 *cur = cs1 - '0';
  391.             /* with a negative precision *cur is already set  */
  392.             /* to -1, so it will remain negative, but we have */
  393.             /* to "eat" precision digits in any case          */
  394.             while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
  395.                 --n0;
  396.                 *cur = *cur * 10 + *s1++ - '0';
  397.             }
  398.             if (prec < 0)     /* negative precision is discarded */
  399.                 have_prec = 0;
  400.             if (cur == &prec)
  401.                 cur = 0;
  402.             goto retry;
  403.         case '*':
  404.             if (cur == 0)
  405.                 /* goto lose; */
  406.                 break;
  407.             parse_next_arg();
  408.             *cur = force_number(arg);
  409.             free_temp(arg);
  410.             if (cur == &prec)
  411.                 cur = 0;
  412.             goto retry;
  413.         case ' ':        /* print ' ' or '-' */
  414.                     /* 'space' flag is ignored */
  415.                     /* if '+' already present  */
  416.             if (signchar != 0) 
  417.                 goto check_pos;
  418.             /* FALL THROUGH */
  419.         case '+':        /* print '+' or '-' */
  420.             signchar = cs1;
  421.             goto check_pos;
  422.         case '-':
  423.             if (prec < 0)
  424.                 break;
  425.             if (cur == &prec) {
  426.                 prec = -1;
  427.                 goto retry;
  428.             }
  429.             fill = sp;      /* if left justified then other */
  430.             lj++;         /* filling is ignored */
  431.             goto check_pos;
  432.         case '.':
  433.             if (cur != &fw)
  434.                 break;
  435.             cur = ≺
  436.             have_prec++;
  437.             goto retry;
  438.         case '#':
  439.             alt++;
  440.             goto check_pos;
  441.         case 'l':
  442.             if (big)
  443.                 break;
  444.             else {
  445.                 static int warned = 0;
  446.                 
  447.                 if (do_lint && ! warned) {
  448.                     warning("`l' is meaningless in awk formats; ignored");
  449.                     warned++;
  450.                 }
  451.                 if (do_posix)
  452.                     fatal("'l' is not permitted in POSIX awk formats");
  453.             }
  454.             big++;
  455.             goto retry;
  456.         case 'c':
  457.             parse_next_arg();
  458.             if (arg->flags & NUMBER) {
  459. #ifdef sun386
  460.                 tmp_uval = arg->numbr; 
  461.                 uval= (unsigned long) tmp_uval;
  462. #else
  463.                 uval = (unsigned long) arg->numbr;
  464. #endif
  465.                 cpbuf[0] = uval;
  466.                 prec = 1;
  467.                 cp = cpbuf;
  468.                 goto pr_tail;
  469.             }
  470.             if (have_prec == 0)
  471.                 prec = 1;
  472.             else if (prec > arg->stlen)
  473.                 prec = arg->stlen;
  474.             cp = arg->stptr;
  475.             goto pr_tail;
  476.         case 's':
  477.             parse_next_arg();
  478.             arg = force_string(arg);
  479.             if (have_prec == 0 || prec > arg->stlen)
  480.                 prec = arg->stlen;
  481.             cp = arg->stptr;
  482.             goto pr_tail;
  483.         case 'd':
  484.         case 'i':
  485.             parse_next_arg();
  486.             tmpval = force_number(arg);
  487.             if (tmpval > LONG_MAX || tmpval < LONG_MIN) {
  488.                 /* out of range - emergency use of %g format */
  489.                 cs1 = 'g';
  490.                 goto format_float;
  491.             }
  492.             val = (long) tmpval;
  493.  
  494.             if (val < 0) {
  495.                 sgn = 1;
  496.                 if (val > LONG_MIN)
  497.                     uval = (unsigned long) -val;
  498.                 else
  499.                     uval = (unsigned long)(-(LONG_MIN + 1))
  500.                            + (unsigned long)1;
  501.             } else {
  502.                 sgn = 0;
  503.                 uval = (unsigned long) val;
  504.             }
  505.             do {
  506.                 *--cp = (char) ('0' + uval % 10);
  507.                 uval /= 10;
  508.             } while (uval);
  509.             if (sgn)
  510.                 *--cp = '-';
  511.             else if (signchar)
  512.                 *--cp = signchar;
  513.             if (have_prec != 0)    /* ignore '0' flag if */
  514.                 fill = sp;     /* precision given    */
  515.             if (prec > fw)
  516.                 fw = prec;
  517.             prec = cend - cp;
  518.             if (fw > prec && ! lj && fill != sp
  519.                 && (*cp == '-' || signchar)) {
  520.                 bchunk_one(cp);
  521.                 cp++;
  522.                 prec--;
  523.                 fw--;
  524.             }
  525.             goto pr_tail;
  526.         case 'X':
  527.             chbuf = Uchbuf;    /* FALL THROUGH */
  528.         case 'x':
  529.             base += 6;    /* FALL THROUGH */
  530.         case 'u':
  531.             base += 2;    /* FALL THROUGH */
  532.         case 'o':
  533.             base += 8;
  534.             parse_next_arg();
  535.             tmpval = force_number(arg);
  536.             if (tmpval > ULONG_MAX || tmpval < LONG_MIN) {
  537.                 /* out of range - emergency use of %g format */
  538.                 cs1 = 'g';
  539.                 goto format_float;
  540.             }
  541.             uval = (unsigned long)tmpval;
  542.             if (have_prec != 0)    /* ignore '0' flag if */
  543.                 fill = sp;     /* precision given    */
  544.             do {
  545.                 *--cp = chbuf[uval % base];
  546.                 uval /= base;
  547.             } while (uval);
  548.             if (alt) {
  549.                 if (base == 16) {
  550.                     *--cp = cs1;
  551.                     *--cp = '0';
  552.                     if (fill != sp) {
  553.                         bchunk(cp, 2);
  554.                         cp += 2;
  555.                         fw -= 2;
  556.                     }
  557.                 } else if (base == 8)
  558.                     *--cp = '0';
  559.             }
  560.             base = 0;
  561.             prec = cend - cp;
  562.     pr_tail:
  563.             if (! lj) {
  564.                 while (fw > prec) {
  565.                         bchunk_one(fill);
  566.                     fw--;
  567.                 }
  568.             }
  569.             bchunk(cp, (int) prec);
  570.             while (fw > prec) {
  571.                 bchunk_one(fill);
  572.                 fw--;
  573.             }
  574.             s0 = s1;
  575.             free_temp(arg);
  576.             break;
  577.         case 'g':
  578.         case 'G':
  579.         case 'e':
  580.         case 'f':
  581.         case 'E':
  582.             parse_next_arg();
  583.             tmpval = force_number(arg);
  584.      format_float:
  585.             free_temp(arg);
  586.             if (have_prec == 0)
  587.                 prec = DEFAULT_G_PRECISION;
  588.             chksize(fw + prec + 9);    /* 9==slop */
  589.  
  590.             cp = cpbuf;
  591.             *cp++ = '%';
  592.             if (lj)
  593.                 *cp++ = '-';
  594.             if (signchar)
  595.                 *cp++ = signchar;
  596.             if (alt)
  597.                 *cp++ = '#';
  598.             if (fill != sp)
  599.                 *cp++ = '0';
  600.             cp = strcpy(cp, "*.*") + 3;
  601.             *cp++ = cs1;
  602.             *cp   = '\0';
  603. #ifndef GFMT_WORKAROUND
  604.             (void) sprintf(obufout, cpbuf,
  605.                        (int) fw, (int) prec, (double) tmpval);
  606. #else    /* GFMT_WORKAROUND */
  607.             if (cs1 == 'g' || cs1 == 'G')
  608.                 sgfmt(obufout, cpbuf, (int) alt,
  609.                        (int) fw, (int) prec, (double) tmpval);
  610.             else
  611.                 (void) sprintf(obufout, cpbuf,
  612.                        (int) fw, (int) prec, (double) tmpval);
  613. #endif    /* GFMT_WORKAROUND */
  614.             len = strlen(obufout);
  615.             ofre -= len;
  616.             obufout += len;
  617.             s0 = s1;
  618.             break;
  619.         default:
  620.             break;
  621.         }
  622.         if (toofew)
  623.             fatal("%s\n\t%s\n\t%*s%s",
  624.             "not enough arguments to satisfy format string",
  625.             fmt_string, s1 - fmt_string - 2, "",
  626.             "^ ran out for this one"
  627.             );
  628.     }
  629.     if (do_lint && carg != NULL)
  630.         warning("too many arguments supplied for format string");
  631.     bchunk(s0, s1 - s0);
  632.     r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
  633.     r->flags |= TEMP;
  634.     return r;
  635. }
  636.  
  637. NODE *
  638. do_sprintf(tree)
  639. NODE *tree;
  640. {
  641.     NODE *r;
  642.     NODE *sfmt = force_string(tree_eval(tree->lnode));
  643.  
  644.     r = format_tree(sfmt->stptr, sfmt->stlen, tree->rnode);
  645.     free_temp(sfmt);
  646.     return r;
  647. }
  648.  
  649.  
  650. void
  651. do_printf(tree)
  652. register NODE *tree;
  653. {
  654.     struct redirect *rp = NULL;
  655.     register FILE *fp;
  656.  
  657.     if (tree->rnode) {
  658.         int errflg;    /* not used, sigh */
  659.  
  660.         rp = redirect(tree->rnode, &errflg);
  661.         if (rp) {
  662.             fp = rp->fp;
  663.             if (!fp)
  664.                 return;
  665.         } else
  666.             return;
  667.     } else
  668.         fp = stdout;
  669.     tree = do_sprintf(tree->lnode);
  670.     efwrite(tree->stptr, sizeof(char), tree->stlen, fp, "printf", rp , 1);
  671.     free_temp(tree);
  672. }
  673.  
  674. NODE *
  675. do_sqrt(tree)
  676. NODE *tree;
  677. {
  678.     NODE *tmp;
  679.     double arg;
  680.     extern double sqrt P((double));
  681.  
  682.     tmp = tree_eval(tree->lnode);
  683.     arg = (double) force_number(tmp);
  684.     free_temp(tmp);
  685.     if (arg < 0.0)
  686.         warning("sqrt called with negative argument %g", arg);
  687.     return tmp_number((AWKNUM) sqrt(arg));
  688. }
  689.  
  690. NODE *
  691. do_substr(tree)
  692. NODE *tree;
  693. {
  694.     NODE *t1, *t2, *t3;
  695.     NODE *r;
  696.     register int indx;
  697.     size_t length;
  698.     int is_long;
  699.  
  700.     t1 = tree_eval(tree->lnode);
  701.     t2 = tree_eval(tree->rnode->lnode);
  702.     if (tree->rnode->rnode == NULL)    /* third arg. missing */
  703.         length = t1->stlen;
  704.     else {
  705.         t3 = tree_eval(tree->rnode->rnode->lnode);
  706.         length = (size_t) force_number(t3);
  707.         free_temp(t3);
  708.     }
  709.     indx = (int) force_number(t2) - 1;
  710.     free_temp(t2);
  711.     t1 = force_string(t1);
  712.     if (indx < 0)
  713.         indx = 0;
  714.     if (indx >= t1->stlen || (long) length <= 0) {
  715.         free_temp(t1);
  716.         return Nnull_string;
  717.     }
  718.     if ((is_long = (indx + length > t1->stlen)) || LONG_MAX - indx < length) {
  719.         length = t1->stlen - indx;
  720.         if (do_lint && is_long)
  721.             warning("substr: length %d at position %d exceeds length of first argument",
  722.                 length, indx+1);
  723.     }
  724.     r =  tmp_string(t1->stptr + indx, length);
  725.     free_temp(t1);
  726.     return r;
  727. }
  728.  
  729. NODE *
  730. do_strftime(tree)
  731. NODE *tree;
  732. {
  733.     NODE *t1, *t2;
  734.     struct tm *tm;
  735.     time_t fclock;
  736.     char buf[100];
  737.  
  738.     t1 = force_string(tree_eval(tree->lnode));
  739.  
  740.     if (tree->rnode == NULL)    /* second arg. missing, default */
  741.         (void) time(&fclock);
  742.     else {
  743.         t2 = tree_eval(tree->rnode->lnode);
  744.         fclock = (time_t) force_number(t2);
  745.         free_temp(t2);
  746.     }
  747.     tm = localtime(&fclock);
  748.  
  749.     return tmp_string(buf, strftime(buf, 100, t1->stptr, tm));
  750. }
  751.  
  752. NODE *
  753. do_systime(tree)
  754. NODE *tree;
  755. {
  756.     time_t lclock;
  757.  
  758.     (void) time(&lclock);
  759.     return tmp_number((AWKNUM) lclock);
  760. }
  761.  
  762. NODE *
  763. do_system(tree)
  764. NODE *tree;
  765. {
  766.     NODE *tmp;
  767.     int ret = 0;
  768.     char *cmd;
  769.     char save;
  770.  
  771.     (void) flush_io ();     /* so output is synchronous with gawk's */
  772.     tmp = tree_eval(tree->lnode);
  773.     cmd = force_string(tmp)->stptr;
  774.  
  775.     if (cmd && *cmd) {
  776.         /* insure arg to system is zero-terminated */
  777.  
  778.         /*
  779.          * From: David Trueman <emory!cs.dal.ca!david>
  780.          * To: arnold@cc.gatech.edu (Arnold Robbins)
  781.          * Date:     Wed, 3 Nov 1993 12:49:41 -0400
  782.          * 
  783.          * It may not be necessary to save the character, but
  784.          * I'm not sure.  It would normally be the field
  785.          * separator.  If the parse has not yet gone beyond
  786.          * that, it could mess up (although I doubt it).  If
  787.          * FIELDWIDTHS is being used, it might be the first
  788.          * character of the next field.  Unless someone wants
  789.          * to check it out exhaustively, I suggest saving it
  790.          * for now...
  791.          */
  792.         save = cmd[tmp->stlen];
  793.         cmd[tmp->stlen] = '\0';
  794.  
  795.         ret = system(cmd);
  796.         ret = (ret >> 8) & 0xff;
  797.  
  798.         cmd[tmp->stlen] = save;
  799.     }
  800.     free_temp(tmp);
  801.     return tmp_number((AWKNUM) ret);
  802. }
  803.  
  804. extern NODE **fmt_list;  /* declared in eval.c */
  805.  
  806. void 
  807. do_print(tree)
  808. register NODE *tree;
  809. {
  810.     register NODE *t1;
  811.     struct redirect *rp = NULL;
  812.     register FILE *fp;
  813.     register char *s;
  814.  
  815.     if (tree->rnode) {
  816.         int errflg;        /* not used, sigh */
  817.  
  818.         rp = redirect(tree->rnode, &errflg);
  819.         if (rp) {
  820.             fp = rp->fp;
  821.             if (!fp)
  822.                 return;
  823.         } else
  824.             return;
  825.     } else
  826.         fp = stdout;
  827.     tree = tree->lnode;
  828.     while (tree) {
  829.         t1 = tree_eval(tree->lnode);
  830.         if (t1->flags & NUMBER) {
  831.             if (OFMTidx == CONVFMTidx)
  832.                 (void) force_string(t1);
  833.             else {
  834. #ifndef GFMT_WORKAROUND
  835.                 char buf[100];
  836.  
  837.                 (void) sprintf(buf, OFMT, t1->numbr);
  838.                 free_temp(t1);
  839.                 t1 = tmp_string(buf, strlen(buf));
  840. #else /* GFMT_WORKAROUND */
  841.                 free_temp(t1);
  842.                 t1 = format_tree(OFMT,
  843.                          fmt_list[OFMTidx]->stlen,
  844.                          tree);
  845. #endif /* GFMT_WORKAROUND */
  846.             }
  847.         }
  848.         efwrite(t1->stptr, sizeof(char), t1->stlen, fp, "print", rp, 0);
  849.         free_temp(t1);
  850.         tree = tree->rnode;
  851.         if (tree) {
  852.             s = OFS;
  853.             if (OFSlen)
  854.                 efwrite(s, sizeof(char), (size_t)OFSlen,
  855.                     fp, "print", rp, 0);
  856.         }
  857.     }
  858.     s = ORS;
  859.     if (ORSlen)
  860.         efwrite(s, sizeof(char), (size_t)ORSlen, fp, "print", rp, 1);
  861. }
  862.  
  863. NODE *
  864. do_tolower(tree)
  865. NODE *tree;
  866. {
  867.     NODE *t1, *t2;
  868.     register char *cp, *cp2;
  869.  
  870.     t1 = tree_eval(tree->lnode);
  871.     t1 = force_string(t1);
  872.     t2 = tmp_string(t1->stptr, t1->stlen);
  873.     for (cp = t2->stptr, cp2 = t2->stptr + t2->stlen; cp < cp2; cp++)
  874.         if (isupper(*cp))
  875.             *cp = tolower(*cp);
  876.     free_temp(t1);
  877.     return t2;
  878. }
  879.  
  880. NODE *
  881. do_toupper(tree)
  882. NODE *tree;
  883. {
  884.     NODE *t1, *t2;
  885.     register char *cp;
  886.  
  887.     t1 = tree_eval(tree->lnode);
  888.     t1 = force_string(t1);
  889.     t2 = tmp_string(t1->stptr, t1->stlen);
  890.     for (cp = t2->stptr; cp < t2->stptr + t2->stlen; cp++)
  891.         if (islower(*cp))
  892.             *cp = toupper(*cp);
  893.     free_temp(t1);
  894.     return t2;
  895. }
  896.  
  897. NODE *
  898. do_atan2(tree)
  899. NODE *tree;
  900. {
  901.     NODE *t1, *t2;
  902.     extern double atan2 P((double, double));
  903.     double d1, d2;
  904.  
  905.     t1 = tree_eval(tree->lnode);
  906.     t2 = tree_eval(tree->rnode->lnode);
  907.     d1 = force_number(t1);
  908.     d2 = force_number(t2);
  909.     free_temp(t1);
  910.     free_temp(t2);
  911.     return tmp_number((AWKNUM) atan2(d1, d2));
  912. }
  913.  
  914. NODE *
  915. do_sin(tree)
  916. NODE *tree;
  917. {
  918.     NODE *tmp;
  919.     extern double sin P((double));
  920.     double d;
  921.  
  922.     tmp = tree_eval(tree->lnode);
  923.     d = sin((double)force_number(tmp));
  924.     free_temp(tmp);
  925.     return tmp_number((AWKNUM) d);
  926. }
  927.  
  928. NODE *
  929. do_cos(tree)
  930. NODE *tree;
  931. {
  932.     NODE *tmp;
  933.     extern double cos P((double));
  934.     double d;
  935.  
  936.     tmp = tree_eval(tree->lnode);
  937.     d = cos((double)force_number(tmp));
  938.     free_temp(tmp);
  939.     return tmp_number((AWKNUM) d);
  940. }
  941.  
  942. static int firstrand = 1;
  943. static char state[512];
  944.  
  945. /* ARGSUSED */
  946. NODE *
  947. do_rand(tree)
  948. NODE *tree;
  949. {
  950.     if (firstrand) {
  951.         (void) initstate((unsigned) 1, state, sizeof state);
  952.         srandom(1);
  953.         firstrand = 0;
  954.     }
  955.     return tmp_number((AWKNUM) random() / GAWK_RANDOM_MAX);
  956. }
  957.  
  958. NODE *
  959. do_srand(tree)
  960. NODE *tree;
  961. {
  962.     NODE *tmp;
  963.     static long save_seed = 0;
  964.     long ret = save_seed;    /* SVR4 awk srand returns previous seed */
  965.  
  966.     if (firstrand)
  967.         (void) initstate((unsigned) 1, state, sizeof state);
  968.     else
  969.         (void) setstate(state);
  970.  
  971.     if (!tree)
  972.         srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
  973.     else {
  974.         tmp = tree_eval(tree->lnode);
  975.         srandom((unsigned int) (save_seed = (long) force_number(tmp)));
  976.         free_temp(tmp);
  977.     }
  978.     firstrand = 0;
  979.     return tmp_number((AWKNUM) ret);
  980. }
  981.  
  982. NODE *
  983. do_match(tree)
  984. NODE *tree;
  985. {
  986.     NODE *t1;
  987.     int rstart;
  988.     AWKNUM rlength;
  989.     Regexp *rp;
  990.  
  991.     t1 = force_string(tree_eval(tree->lnode));
  992.     tree = tree->rnode->lnode;
  993.     rp = re_update(tree);
  994.     rstart = research(rp, t1->stptr, 0, t1->stlen, 1);
  995.     if (rstart >= 0) {    /* match succeded */
  996.         rstart++;    /* 1-based indexing */
  997.         rlength = REEND(rp, t1->stptr) - RESTART(rp, t1->stptr);
  998.     } else {        /* match failed */
  999.         rstart = 0;
  1000.         rlength = -1.0;
  1001.     }
  1002.     free_temp(t1);
  1003.     unref(RSTART_node->var_value);
  1004.     RSTART_node->var_value = make_number((AWKNUM) rstart);
  1005.     unref(RLENGTH_node->var_value);
  1006.     RLENGTH_node->var_value = make_number(rlength);
  1007.     return tmp_number((AWKNUM) rstart);
  1008. }
  1009.  
  1010. static NODE *
  1011. sub_common(tree, global)
  1012. NODE *tree;
  1013. int global;
  1014. {
  1015.     register char *scan;
  1016.     register char *bp, *cp;
  1017.     char *buf;
  1018.     size_t buflen;
  1019.     register char *matchend;
  1020.     register size_t len;
  1021.     char *matchstart;
  1022.     char *text;
  1023.     size_t textlen;
  1024.     char *repl;
  1025.     char *replend;
  1026.     size_t repllen;
  1027.     int sofar;
  1028.     int ampersands;
  1029.     int matches = 0;
  1030.     Regexp *rp;
  1031.     NODE *s;        /* subst. pattern */
  1032.     NODE *t;        /* string to make sub. in; $0 if none given */
  1033.     NODE *tmp;
  1034.     NODE **lhs = &tree;    /* value not used -- just different from NULL */
  1035.     int priv = 0;
  1036.     Func_ptr after_assign = NULL;
  1037.  
  1038.     tmp = tree->lnode;
  1039.     rp = re_update(tmp);
  1040.  
  1041.     tree = tree->rnode;
  1042.     s = tree->lnode;
  1043.  
  1044.     tree = tree->rnode;
  1045.     tmp = tree->lnode;
  1046.     t = force_string(tree_eval(tmp));
  1047.  
  1048.     /* do the search early to avoid work on non-match */
  1049.     if (research(rp, t->stptr, 0, t->stlen, 1) == -1 ||
  1050.         RESTART(rp, t->stptr) > t->stlen) {
  1051.         free_temp(t);
  1052.         return tmp_number((AWKNUM) 0.0);
  1053.     }
  1054.  
  1055.     if (tmp->type == Node_val)
  1056.         lhs = NULL;
  1057.     else
  1058.         lhs = get_lhs(tmp, &after_assign);
  1059.     t->flags |= STRING;
  1060.     /*
  1061.      * create a private copy of the string
  1062.      */
  1063.     if (t->stref > 1 || (t->flags & PERM)) {
  1064.         unsigned int saveflags;
  1065.  
  1066.         saveflags = t->flags;
  1067.         t->flags &= ~MALLOC;
  1068.         tmp = dupnode(t);
  1069.         t->flags = saveflags;
  1070.         t = tmp;
  1071.         priv = 1;
  1072.     }
  1073.     text = t->stptr;
  1074.     textlen = t->stlen;
  1075.     buflen = textlen + 2;
  1076.  
  1077.     s = force_string(tree_eval(s));
  1078.     repl = s->stptr;
  1079.     replend = repl + s->stlen;
  1080.     repllen = replend - repl;
  1081.     emalloc(buf, char *, buflen + 2, "do_sub");
  1082.     buf[buflen] = '\0';
  1083.     buf[buflen + 1] = '\0';
  1084.     ampersands = 0;
  1085.     for (scan = repl; scan < replend; scan++) {
  1086.         if (*scan == '&') {
  1087.             repllen--;
  1088.             ampersands++;
  1089.         } else if (*scan == '\\'
  1090.                && (*(scan+1) == '&' || *(scan+1) == '\\')) {
  1091.             repllen--;
  1092.             scan++;
  1093.         }
  1094.     }
  1095.  
  1096.     bp = buf;
  1097.     for (;;) {
  1098.         matches++;
  1099.         matchstart = t->stptr + RESTART(rp, t->stptr);
  1100.         matchend = t->stptr + REEND(rp, t->stptr);
  1101.  
  1102.         /*
  1103.          * create the result, copying in parts of the original
  1104.          * string 
  1105.          */
  1106.         len = matchstart - text + repllen
  1107.               + ampersands * (matchend - matchstart);
  1108.         sofar = bp - buf;
  1109.         while (buflen < (sofar + len + 1)) {
  1110.             buflen *= 2;
  1111.             erealloc(buf, char *, buflen, "do_sub");
  1112.             bp = buf + sofar;
  1113.         }
  1114.         for (scan = text; scan < matchstart; scan++)
  1115.             *bp++ = *scan;
  1116.         for (scan = repl; scan < replend; scan++)
  1117.             if (*scan == '&')
  1118.                 for (cp = matchstart; cp < matchend; cp++)
  1119.                     *bp++ = *cp;
  1120.             else if (*scan == '\\'
  1121.                   && (*(scan+1) == '&' || *(scan+1) == '\\')) {
  1122.                 scan++;
  1123.                 *bp++ = *scan;
  1124.             } else
  1125.                 *bp++ = *scan;
  1126.  
  1127.         /* catch the case of gsub(//, "blah", whatever), i.e. empty regexp */
  1128.         if (global && matchstart == matchend && matchend < text + textlen) {
  1129.             *bp++ = *matchend;
  1130.             matchend++;
  1131.         }
  1132.         textlen = text + textlen - matchend;
  1133.         text = matchend;
  1134.         if (!global || (long)textlen <= 0 ||
  1135.             research(rp, t->stptr, text-t->stptr, textlen, 1) == -1)
  1136.             break;
  1137.     }
  1138.     sofar = bp - buf;
  1139.     if (buflen - sofar - textlen - 1) {
  1140.         buflen = sofar + textlen + 2;
  1141.         erealloc(buf, char *, buflen, "do_sub");
  1142.         bp = buf + sofar;
  1143.     }
  1144.     for (scan = matchend; scan < text + textlen; scan++)
  1145.         *bp++ = *scan;
  1146.     *bp = '\0';
  1147.     textlen = bp - buf;
  1148.     free(t->stptr);
  1149.     t->stptr = buf;
  1150.     t->stlen = textlen;
  1151.  
  1152.     free_temp(s);
  1153.     if (matches > 0 && lhs) {
  1154.         if (priv) {
  1155.             unref(*lhs);
  1156.             *lhs = t;
  1157.         }
  1158.         if (after_assign)
  1159.             (*after_assign)();
  1160.         t->flags &= ~(NUM|NUMBER);
  1161.     }
  1162.     return tmp_number((AWKNUM) matches);
  1163. }
  1164.  
  1165. NODE *
  1166. do_gsub(tree)
  1167. NODE *tree;
  1168. {
  1169.     return sub_common(tree, 1);
  1170. }
  1171.  
  1172. NODE *
  1173. do_sub(tree)
  1174. NODE *tree;
  1175. {
  1176.     return sub_common(tree, 0);
  1177. }
  1178.  
  1179. #ifdef GFMT_WORKAROUND
  1180. /*
  1181.  * printf's %g format [can't rely on gcvt()]
  1182.  *    caveat: don't use as argument to *printf()!
  1183.  * 'format' string HAS to be of "<flags>*.*g" kind, or we bomb!
  1184.  */
  1185. static void
  1186. sgfmt(buf, format, alt, fwidth, prec, g)
  1187. char *buf;    /* return buffer; assumed big enough to hold result */
  1188. const char *format;
  1189. int alt;    /* use alternate form flag */
  1190. int fwidth;    /* field width in a format */
  1191. int prec;    /* indicates desired significant digits, not decimal places */
  1192. double g;    /* value to format */
  1193. {
  1194.     char dform[40];
  1195.     register char *gpos;
  1196.     register char *d, *e, *p;
  1197.     int again = 0;
  1198.  
  1199.     strncpy(dform, format, sizeof dform - 1);
  1200.     dform[sizeof dform - 1] = '\0';
  1201.     gpos = strrchr(dform, '.');
  1202.  
  1203.     if (g == 0.0 && alt == 0) {    /* easy special case */
  1204.         *gpos++ = 'd';
  1205.         *gpos = '\0';
  1206.         (void) sprintf(buf, dform, fwidth, 0);
  1207.         return;
  1208.     }
  1209.     gpos += 2;  /* advance to location of 'g' in the format */
  1210.  
  1211.     if (prec <= 0)          /* negative precision is ignored */
  1212.         prec = (prec < 0 ?  DEFAULT_G_PRECISION : 1);
  1213.  
  1214.     if (*gpos == 'G')
  1215.         again = 1;
  1216.     /* start with 'e' format (it'll provide nice exponent) */
  1217.     *gpos = 'e';
  1218.     prec -= 1;
  1219.     (void) sprintf(buf, dform, fwidth, prec, g);
  1220.     if ((e = strrchr(buf, 'e')) != NULL) {    /* find exponent  */
  1221.         int exp = atoi(e+1);        /* fetch exponent */
  1222.         if (exp >= -4 && exp <= prec) {    /* per K&R2, B1.2 */
  1223.             /* switch to 'f' format and re-do */
  1224.             *gpos = 'f';
  1225.             prec -= exp;        /* decimal precision */
  1226.             (void) sprintf(buf, dform, fwidth, prec, g);
  1227.             e = buf + strlen(buf);
  1228.             while (*--e == ' ')
  1229.                 continue;
  1230.             e += 1;
  1231.         }
  1232.         else if (again != 0)
  1233.             *gpos = 'E';
  1234.  
  1235.         /* if 'alt' in force, then trailing zeros are not removed */
  1236.         if (alt == 0 && (d = strrchr(buf, '.')) != NULL) {
  1237.             /* throw away an excess of precision */
  1238.             for (p = e; p > d && *--p == '0'; )
  1239.                 prec -= 1;
  1240.             if (d == p)
  1241.                 prec -= 1;
  1242.             if (prec < 0)
  1243.                 prec = 0;
  1244.             /* and do that once again */
  1245.             again = 1;
  1246.         }
  1247.         if (again != 0)
  1248.             (void) sprintf(buf, dform, fwidth, prec, g);
  1249.     }
  1250. }
  1251. #endif    /* GFMT_WORKAROUND */
  1252.