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

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