home *** CD-ROM | disk | FTP | other *** search
/ ftp.uni-stuttgart.de/pub/systems/acorn/ / Acorn.tar / Acorn / acornet / dev / gawk.spk / gawk-2154 / c / builtin < prev    next >
Text File  |  1994-02-25  |  24KB  |  1,153 lines

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