home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / gawk2.11 / part12 / builtin.c next >
C/C++ Source or Header  |  1990-06-07  |  21KB  |  1,056 lines

  1. /*
  2.  * builtin.c - Builtin functions and various utility procedures 
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. extern void srandom();
  29. extern char *initstate();
  30. extern char *setstate();
  31. extern long random();
  32.  
  33. extern NODE **fields_arr;
  34.  
  35. static void get_one();
  36. static void get_two();
  37. static int get_three();
  38.  
  39. /* Builtin functions */
  40. NODE *
  41. do_exp(tree)
  42. NODE *tree;
  43. {
  44.     NODE *tmp;
  45.     double d, res;
  46.     double exp();
  47.  
  48.     get_one(tree, &tmp);
  49.     d = force_number(tmp);
  50.     free_temp(tmp);
  51.     errno = 0;
  52.     res = exp(d);
  53.     if (errno == ERANGE)
  54.         warning("exp argument %g is out of range", d);
  55.     return tmp_number((AWKNUM) res);
  56. }
  57.  
  58. NODE *
  59. do_index(tree)
  60. NODE *tree;
  61. {
  62.     NODE *s1, *s2;
  63.     register char *p1, *p2;
  64.     register int l1, l2;
  65.     long ret;
  66.  
  67.  
  68.     get_two(tree, &s1, &s2);
  69.     force_string(s1);
  70.     force_string(s2);
  71.     p1 = s1->stptr;
  72.     p2 = s2->stptr;
  73.     l1 = s1->stlen;
  74.     l2 = s2->stlen;
  75.     ret = 0;
  76.     if (! strict && IGNORECASE_node->var_value->numbr != 0.0) {
  77.         while (l1) {
  78.             if (casetable[*p1] == casetable[*p2]
  79.                 && strncasecmp(p1, p2, l2) == 0) {
  80.                 ret = 1 + s1->stlen - l1;
  81.                 break;
  82.             }
  83.             l1--;
  84.             p1++;
  85.         }
  86.     } else {
  87.         while (l1) {
  88.             if (STREQN(p1, p2, l2)) {
  89.                 ret = 1 + s1->stlen - l1;
  90.                 break;
  91.             }
  92.             l1--;
  93.             p1++;
  94.         }
  95.     }
  96.     free_temp(s1);
  97.     free_temp(s2);
  98.     return tmp_number((AWKNUM) ret);
  99. }
  100.  
  101. NODE *
  102. do_int(tree)
  103. NODE *tree;
  104. {
  105.     NODE *tmp;
  106.     double floor();
  107.     double d;
  108.  
  109.     get_one(tree, &tmp);
  110.     d = floor((double)force_number(tmp));
  111.     free_temp(tmp);
  112.     return tmp_number((AWKNUM) d);
  113. }
  114.  
  115. NODE *
  116. do_length(tree)
  117. NODE *tree;
  118. {
  119.     NODE *tmp;
  120.     int len;
  121.  
  122.     get_one(tree, &tmp);
  123.     len = force_string(tmp)->stlen;
  124.     free_temp(tmp);
  125.     return tmp_number((AWKNUM) len);
  126. }
  127.  
  128. NODE *
  129. do_log(tree)
  130. NODE *tree;
  131. {
  132.     NODE *tmp;
  133.     double log();
  134.     double d, arg;
  135.  
  136.     get_one(tree, &tmp);
  137.     arg = (double) force_number(tmp);
  138.     if (arg < 0.0)
  139.         warning("log called with negative argument %g", arg);
  140.     d = log(arg);
  141.     free_temp(tmp);
  142.     return tmp_number((AWKNUM) d);
  143. }
  144.  
  145. /*
  146.  * Note that the output buffer cannot be static because sprintf may get
  147.  * called recursively by force_string.  Hence the wasteful alloca calls 
  148.  */
  149.  
  150. /* %e and %f formats are not properly implemented.  Someone should fix them */
  151. NODE *
  152. do_sprintf(tree)
  153. NODE *tree;
  154. {
  155. #define bchunk(s,l) if(l) {\
  156.     while((l)>ofre) {\
  157.       char *tmp;\
  158.       tmp=(char *)alloca(osiz*2);\
  159.       memcpy(tmp,obuf,olen);\
  160.       obuf=tmp;\
  161.       ofre+=osiz;\
  162.       osiz*=2;\
  163.     }\
  164.     memcpy(obuf+olen,s,(l));\
  165.     olen+=(l);\
  166.     ofre-=(l);\
  167.   }
  168.  
  169.     /* Is there space for something L big in the buffer? */
  170. #define chksize(l)  if((l)>ofre) {\
  171.     char *tmp;\
  172.     tmp=(char *)alloca(osiz*2);\
  173.     memcpy(tmp,obuf,olen);\
  174.     obuf=tmp;\
  175.     ofre+=osiz;\
  176.     osiz*=2;\
  177.   }
  178.  
  179.     /*
  180.      * Get the next arg to be formatted.  If we've run out of args,
  181.      * return "" (Null string) 
  182.      */
  183. #define parse_next_arg() {\
  184.   if(!carg) arg= Nnull_string;\
  185.   else {\
  186.       get_one(carg,&arg);\
  187.     carg=carg->rnode;\
  188.   }\
  189.  }
  190.  
  191.     char *obuf;
  192.     int osiz, ofre, olen;
  193.     static char chbuf[] = "0123456789abcdef";
  194.     static char sp[] = " ";
  195.     char *s0, *s1;
  196.     int n0;
  197.     NODE *sfmt, *arg;
  198.     register NODE *carg;
  199.     long fw, prec, lj, alt, big;
  200.     long *cur;
  201.     long val;
  202. #ifdef sun386            /* Can't cast unsigned (int/long) from ptr->value */
  203.     long tmp_uval;        /* on 386i 4.0.1 C compiler -- it just hangs */
  204. #endif
  205.     unsigned long uval;
  206.     int sgn;
  207.     int base;
  208.     char cpbuf[30];        /* if we have numbers bigger than 30 */
  209.     char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
  210.     char *cp;
  211.     char *fill;
  212.     double tmpval;
  213.     char *pr_str;
  214.     int ucasehex = 0;
  215.     extern char *gcvt();
  216.  
  217.  
  218.     obuf = (char *) alloca(120);
  219.     osiz = 120;
  220.     ofre = osiz;
  221.     olen = 0;
  222.     get_one(tree, &sfmt);
  223.     sfmt = force_string(sfmt);
  224.     carg = tree->rnode;
  225.     for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) {
  226.         if (*s1 != '%') {
  227.             s1++;
  228.             continue;
  229.         }
  230.         bchunk(s0, s1 - s0);
  231.         s0 = s1;
  232.         cur = &fw;
  233.         fw = 0;
  234.         prec = 0;
  235.         lj = alt = big = 0;
  236.         fill = sp;
  237.         cp = cend;
  238.         s1++;
  239.  
  240. retry:
  241.         --n0;
  242.         switch (*s1++) {
  243.         case '%':
  244.             bchunk("%", 1);
  245.             s0 = s1;
  246.             break;
  247.  
  248.         case '0':
  249.             if (fill != sp || lj)
  250.                 goto lose;
  251.             if (cur == &fw)
  252.                 fill = "0";    /* FALL through */
  253.         case '1':
  254.         case '2':
  255.         case '3':
  256.         case '4':
  257.         case '5':
  258.         case '6':
  259.         case '7':
  260.         case '8':
  261.         case '9':
  262.             if (cur == 0)
  263.                 goto lose;
  264.             *cur = s1[-1] - '0';
  265.             while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
  266.                 --n0;
  267.                 *cur = *cur * 10 + *s1++ - '0';
  268.             }
  269.             goto retry;
  270. #ifdef not_yet
  271.         case ' ':        /* print ' ' or '-' */
  272.         case '+':        /* print '+' or '-' */
  273. #endif
  274.         case '-':
  275.             if (lj || fill != sp)
  276.                 goto lose;
  277.             lj++;
  278.             goto retry;
  279.         case '.':
  280.             if (cur != &fw)
  281.                 goto lose;
  282.             cur = ≺
  283.             goto retry;
  284.         case '#':
  285.             if (alt)
  286.                 goto lose;
  287.             alt++;
  288.             goto retry;
  289.         case 'l':
  290.             if (big)
  291.                 goto lose;
  292.             big++;
  293.             goto retry;
  294.         case 'c':
  295.             parse_next_arg();
  296.             if (arg->flags & NUMERIC) {
  297. #ifdef sun386
  298.                 tmp_uval = arg->numbr; 
  299.                 uval= (unsigned long) tmp_uval;
  300. #else
  301.                 uval = (unsigned long) arg->numbr;
  302. #endif
  303.                 cpbuf[0] = uval;
  304.                 prec = 1;
  305.                 pr_str = cpbuf;
  306.                 goto dopr_string;
  307.             }
  308.             if (! prec)
  309.                 prec = 1;
  310.             else if (prec > arg->stlen)
  311.                 prec = arg->stlen;
  312.             pr_str = arg->stptr;
  313.             goto dopr_string;
  314.         case 's':
  315.             parse_next_arg();
  316.             arg = force_string(arg);
  317.             if (!prec || prec > arg->stlen)
  318.                 prec = arg->stlen;
  319.             pr_str = arg->stptr;
  320.  
  321.     dopr_string:
  322.             if (fw > prec && !lj) {
  323.                 while (fw > prec) {
  324.                     bchunk(sp, 1);
  325.                     fw--;
  326.                 }
  327.             }
  328.             bchunk(pr_str, (int) prec);
  329.             if (fw > prec) {
  330.                 while (fw > prec) {
  331.                     bchunk(sp, 1);
  332.                     fw--;
  333.                 }
  334.             }
  335.             s0 = s1;
  336.             free_temp(arg);
  337.             break;
  338.         case 'd':
  339.         case 'i':
  340.             parse_next_arg();
  341.             val = (long) force_number(arg);
  342.             free_temp(arg);
  343.             if (val < 0) {
  344.                 sgn = 1;
  345.                 val = -val;
  346.             } else
  347.                 sgn = 0;
  348.             do {
  349.                 *--cp = '0' + val % 10;
  350.                 val /= 10;
  351.             } while (val);
  352.             if (sgn)
  353.                 *--cp = '-';
  354.             if (prec > fw)
  355.                 fw = prec;
  356.             prec = cend - cp;
  357.             if (fw > prec && !lj) {
  358.                 if (fill != sp && *cp == '-') {
  359.                     bchunk(cp, 1);
  360.                     cp++;
  361.                     prec--;
  362.                     fw--;
  363.                 }
  364.                 while (fw > prec) {
  365.                     bchunk(fill, 1);
  366.                     fw--;
  367.                 }
  368.             }
  369.             bchunk(cp, (int) prec);
  370.             if (fw > prec) {
  371.                 while (fw > prec) {
  372.                     bchunk(fill, 1);
  373.                     fw--;
  374.                 }
  375.             }
  376.             s0 = s1;
  377.             break;
  378.         case 'u':
  379.             base = 10;
  380.             goto pr_unsigned;
  381.         case 'o':
  382.             base = 8;
  383.             goto pr_unsigned;
  384.         case 'X':
  385.             ucasehex = 1;
  386.         case 'x':
  387.             base = 16;
  388.             goto pr_unsigned;
  389.     pr_unsigned:
  390.             parse_next_arg();
  391.             uval = (unsigned long) force_number(arg);
  392.             free_temp(arg);
  393.             do {
  394.                 *--cp = chbuf[uval % base];
  395.                 if (ucasehex && isalpha(*cp))
  396.                     *cp = toupper(*cp);
  397.                 uval /= base;
  398.             } while (uval);
  399.             if (alt && (base == 8 || base == 16)) {
  400.                 if (base == 16) {
  401.                     if (ucasehex)
  402.                         *--cp = 'X';
  403.                     else
  404.                         *--cp = 'x';
  405.                 }
  406.                 *--cp = '0';
  407.             }
  408.             prec = cend - cp;
  409.             if (fw > prec && !lj) {
  410.                 while (fw > prec) {
  411.                     bchunk(fill, 1);
  412.                     fw--;
  413.                 }
  414.             }
  415.             bchunk(cp, (int) prec);
  416.             if (fw > prec) {
  417.                 while (fw > prec) {
  418.                     bchunk(fill, 1);
  419.                     fw--;
  420.                 }
  421.             }
  422.             s0 = s1;
  423.             break;
  424.         case 'g':
  425.             parse_next_arg();
  426.             tmpval = force_number(arg);
  427.             free_temp(arg);
  428.             if (prec == 0)
  429.                 prec = 13;
  430.             (void) gcvt(tmpval, (int) prec, cpbuf);
  431.             prec = strlen(cpbuf);
  432.             cp = cpbuf;
  433.             if (fw > prec && !lj) {
  434.                 if (fill != sp && *cp == '-') {
  435.                     bchunk(cp, 1);
  436.                     cp++;
  437.                     prec--;
  438.                 }    /* Deal with .5 as 0.5 */
  439.                 if (fill == sp && *cp == '.') {
  440.                     --fw;
  441.                     while (--fw >= prec) {
  442.                         bchunk(fill, 1);
  443.                     }
  444.                     bchunk("0", 1);
  445.                 } else
  446.                     while (fw-- > prec)
  447.                         bchunk(fill, 1);
  448.             } else {/* Turn .5 into 0.5 */
  449.                 /* FOO */
  450.                 if (*cp == '.' && fill == sp) {
  451.                     bchunk("0", 1);
  452.                     --fw;
  453.                 }
  454.             }
  455.             bchunk(cp, (int) prec);
  456.             if (fw > prec)
  457.                 while (fw-- > prec)
  458.                     bchunk(fill, 1);
  459.             s0 = s1;
  460.             break;
  461.         case 'f':
  462.             parse_next_arg();
  463.             tmpval = force_number(arg);
  464.             free_temp(arg);
  465.             chksize(fw + prec + 5);    /* 5==slop */
  466.  
  467.             cp = cpbuf;
  468.             *cp++ = '%';
  469.             if (lj)
  470.                 *cp++ = '-';
  471.             if (fill != sp)
  472.                 *cp++ = '0';
  473.             if (cur != &fw) {
  474.                 (void) strcpy(cp, "*.*f");
  475.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
  476.             } else {
  477.                 (void) strcpy(cp, "*f");
  478.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
  479.             }
  480.             ofre -= strlen(obuf + olen);
  481.             olen += strlen(obuf + olen);    /* There may be nulls */
  482.             s0 = s1;
  483.             break;
  484.         case 'e':
  485.             parse_next_arg();
  486.             tmpval = force_number(arg);
  487.             free_temp(arg);
  488.             chksize(fw + prec + 5);    /* 5==slop */
  489.             cp = cpbuf;
  490.             *cp++ = '%';
  491.             if (lj)
  492.                 *cp++ = '-';
  493.             if (fill != sp)
  494.                 *cp++ = '0';
  495.             if (cur != &fw) {
  496.                 (void) strcpy(cp, "*.*e");
  497.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
  498.             } else {
  499.                 (void) strcpy(cp, "*e");
  500.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
  501.             }
  502.             ofre -= strlen(obuf + olen);
  503.             olen += strlen(obuf + olen);    /* There may be nulls */
  504.             s0 = s1;
  505.             break;
  506.  
  507.         default:
  508.     lose:
  509.             break;
  510.         }
  511.     }
  512.     bchunk(s0, s1 - s0);
  513.     free_temp(sfmt);
  514.     return tmp_string(obuf, olen);
  515. }
  516.  
  517. void
  518. do_printf(tree)
  519. NODE *tree;
  520. {
  521.     struct redirect *rp = NULL;
  522.     register FILE *fp = stdout;
  523.     int errflg = 0;        /* not used, sigh */
  524.  
  525.     if (tree->rnode) {
  526.         rp = redirect(tree->rnode, &errflg);
  527.         if (rp)
  528.             fp = rp->fp;
  529.     }
  530.     if (fp)
  531.         print_simple(do_sprintf(tree->lnode), fp);
  532.     if (rp && (rp->flag & RED_NOBUF))
  533.         fflush(fp);
  534. }
  535.  
  536. NODE *
  537. do_sqrt(tree)
  538. NODE *tree;
  539. {
  540.     NODE *tmp;
  541.     double sqrt();
  542.     double d, arg;
  543.  
  544.     get_one(tree, &tmp);
  545.     arg = (double) force_number(tmp);
  546.     if (arg < 0.0)
  547.         warning("sqrt called with negative argument %g", arg);
  548.     d = sqrt(arg);
  549.     free_temp(tmp);
  550.     return tmp_number((AWKNUM) d);
  551. }
  552.  
  553. NODE *
  554. do_substr(tree)
  555. NODE *tree;
  556. {
  557.     NODE *t1, *t2, *t3;
  558.     NODE *r;
  559.     register int indx, length;
  560.  
  561.     t1 = t2 = t3 = NULL;
  562.     length = -1;
  563.     if (get_three(tree, &t1, &t2, &t3) == 3)
  564.         length = (int) force_number(t3);
  565.     indx = (int) force_number(t2) - 1;
  566.     t1 = force_string(t1);
  567.     if (length == -1)
  568.         length = t1->stlen;
  569.     if (indx < 0)
  570.         indx = 0;
  571.     if (indx >= t1->stlen || length <= 0) {
  572.         if (t3)
  573.             free_temp(t3);
  574.         free_temp(t2);
  575.         free_temp(t1);
  576.         return Nnull_string;
  577.     }
  578.     if (indx + length > t1->stlen)
  579.         length = t1->stlen - indx;
  580.     if (t3)
  581.         free_temp(t3);
  582.     free_temp(t2);
  583.     r =  tmp_string(t1->stptr + indx, length);
  584.     free_temp(t1);
  585.     return r;
  586. }
  587.  
  588. NODE *
  589. do_system(tree)
  590. NODE *tree;
  591. {
  592. #if defined(unix) || defined(MSDOS) /* || defined(gnu) */
  593.     NODE *tmp;
  594.     int ret;
  595.  
  596.     (void) flush_io ();    /* so output is synchronous with gawk's */
  597.     get_one(tree, &tmp);
  598.     ret = system(force_string(tmp)->stptr);
  599.     ret = (ret >> 8) & 0xff;
  600.     free_temp(tmp);
  601.     return tmp_number((AWKNUM) ret);
  602. #else
  603.     fatal("the \"system\" function is not supported.");
  604.     /* NOTREACHED */
  605. #endif
  606. }
  607.  
  608. void 
  609. do_print(tree)
  610. register NODE *tree;
  611. {
  612.     struct redirect *rp = NULL;
  613.     register FILE *fp = stdout;
  614.     int errflg = 0;        /* not used, sigh */
  615.  
  616.     if (tree->rnode) {
  617.         rp = redirect(tree->rnode, &errflg);
  618.         if (rp)
  619.             fp = rp->fp;
  620.     }
  621.     if (!fp)
  622.         return;
  623.     tree = tree->lnode;
  624.     if (!tree)
  625.         tree = WHOLELINE;
  626.     if (tree->type != Node_expression_list) {
  627.         if (!(tree->flags & STR))
  628.             cant_happen();
  629.         print_simple(tree, fp);
  630.     } else {
  631.         while (tree) {
  632.             print_simple(force_string(tree_eval(tree->lnode)), fp);
  633.             tree = tree->rnode;
  634.             if (tree)
  635.                 print_simple(OFS_node->var_value, fp);
  636.         }
  637.     }
  638.     print_simple(ORS_node->var_value, fp);
  639.     if (rp && (rp->flag & RED_NOBUF))
  640.         fflush(fp);
  641. }
  642.  
  643. NODE *
  644. do_tolower(tree)
  645. NODE *tree;
  646. {
  647.     NODE *t1, *t2;
  648.     register char *cp, *cp2;
  649.  
  650.     get_one(tree, &t1);
  651.     t1 = force_string(t1);
  652.     t2 = tmp_string(t1->stptr, t1->stlen);
  653.     for (cp = t2->stptr, cp2 = t2->stptr + t2->stlen; cp < cp2; cp++)
  654.         if (isupper(*cp))
  655.             *cp = tolower(*cp);
  656.     free_temp(t1);
  657.     return t2;
  658. }
  659.  
  660. NODE *
  661. do_toupper(tree)
  662. NODE *tree;
  663. {
  664.     NODE *t1, *t2;
  665.     register char *cp;
  666.  
  667.     get_one(tree, &t1);
  668.     t1 = force_string(t1);
  669.     t2 = tmp_string(t1->stptr, t1->stlen);
  670.     for (cp = t2->stptr; cp < t2->stptr + t2->stlen; cp++)
  671.         if (islower(*cp))
  672.             *cp = toupper(*cp);
  673.     free_temp(t1);
  674.     return t2;
  675. }
  676.  
  677. /*
  678.  * Get the arguments to functions.  No function cares if you give it too many
  679.  * args (they're ignored).  Only a few fuctions complain about being given
  680.  * too few args.  The rest have defaults.
  681.  */
  682.  
  683. static void
  684. get_one(tree, res)
  685. NODE *tree, **res;
  686. {
  687.     if (!tree) {
  688.         *res = WHOLELINE;
  689.         return;
  690.     }
  691.     *res = tree_eval(tree->lnode);
  692. }
  693.  
  694. static void
  695. get_two(tree, res1, res2)
  696. NODE *tree, **res1, **res2;
  697. {
  698.     if (!tree) {
  699.         *res1 = WHOLELINE;
  700.         return;
  701.     }
  702.     *res1 = tree_eval(tree->lnode);
  703.     if (!tree->rnode)
  704.         return;
  705.     tree = tree->rnode;
  706.     *res2 = tree_eval(tree->lnode);
  707. }
  708.  
  709. static int
  710. get_three(tree, res1, res2, res3)
  711. NODE *tree, **res1, **res2, **res3;
  712. {
  713.     if (!tree) {
  714.         *res1 = WHOLELINE;
  715.         return 0;
  716.     }
  717.     *res1 = tree_eval(tree->lnode);
  718.     if (!tree->rnode)
  719.         return 1;
  720.     tree = tree->rnode;
  721.     *res2 = tree_eval(tree->lnode);
  722.     if (!tree->rnode)
  723.         return 2;
  724.     tree = tree->rnode;
  725.     *res3 = tree_eval(tree->lnode);
  726.     return 3;
  727. }
  728.  
  729. int
  730. a_get_three(tree, res1, res2, res3)
  731. NODE *tree, **res1, **res2, **res3;
  732. {
  733.     if (!tree) {
  734.         *res1 = WHOLELINE;
  735.         return 0;
  736.     }
  737.     *res1 = tree_eval(tree->lnode);
  738.     if (!tree->rnode)
  739.         return 1;
  740.     tree = tree->rnode;
  741.     *res2 = tree->lnode;
  742.     if (!tree->rnode)
  743.         return 2;
  744.     tree = tree->rnode;
  745.     *res3 = tree_eval(tree->lnode);
  746.     return 3;
  747. }
  748.  
  749. void
  750. print_simple(tree, fp)
  751. NODE *tree;
  752. FILE *fp;
  753. {
  754.     if (fwrite(tree->stptr, sizeof(char), tree->stlen, fp) != tree->stlen)
  755.         warning("fwrite: %s", strerror(errno));
  756.     free_temp(tree);
  757. }
  758.  
  759. NODE *
  760. do_atan2(tree)
  761. NODE *tree;
  762. {
  763.     NODE *t1, *t2;
  764.     extern double atan2();
  765.     double d1, d2;
  766.  
  767.     get_two(tree, &t1, &t2);
  768.     d1 = force_number(t1);
  769.     d2 = force_number(t2);
  770.     free_temp(t1);
  771.     free_temp(t2);
  772.     return tmp_number((AWKNUM) atan2(d1, d2));
  773. }
  774.  
  775. NODE *
  776. do_sin(tree)
  777. NODE *tree;
  778. {
  779.     NODE *tmp;
  780.     extern double sin();
  781.     double d;
  782.  
  783.     get_one(tree, &tmp);
  784.     d = sin((double)force_number(tmp));
  785.     free_temp(tmp);
  786.     return tmp_number((AWKNUM) d);
  787. }
  788.  
  789. NODE *
  790. do_cos(tree)
  791. NODE *tree;
  792. {
  793.     NODE *tmp;
  794.     extern double cos();
  795.     double d;
  796.  
  797.     get_one(tree, &tmp);
  798.     d = cos((double)force_number(tmp));
  799.     free_temp(tmp);
  800.     return tmp_number((AWKNUM) d);
  801. }
  802.  
  803. static int firstrand = 1;
  804. static char state[256];
  805.  
  806. #define    MAXLONG    2147483647    /* maximum value for long int */
  807.  
  808. /* ARGSUSED */
  809. NODE *
  810. do_rand(tree)
  811. NODE *tree;
  812. {
  813.     if (firstrand) {
  814.         (void) initstate((unsigned) 1, state, sizeof state);
  815.         srandom(1);
  816.         firstrand = 0;
  817.     }
  818.     return tmp_number((AWKNUM) random() / MAXLONG);
  819. }
  820.  
  821. NODE *
  822. do_srand(tree)
  823. NODE *tree;
  824. {
  825.     NODE *tmp;
  826.     static long save_seed = 1;
  827.     long ret = save_seed;    /* SVR4 awk srand returns previous seed */
  828.     extern long time();
  829.  
  830.     if (firstrand)
  831.         (void) initstate((unsigned) 1, state, sizeof state);
  832.     else
  833.         (void) setstate(state);
  834.  
  835.     if (!tree)
  836.         srandom((int) (save_seed = time((long *) 0)));
  837.     else {
  838.         get_one(tree, &tmp);
  839.         srandom((int) (save_seed = (long) force_number(tmp)));
  840.         free_temp(tmp);
  841.     }
  842.     firstrand = 0;
  843.     return tmp_number((AWKNUM) ret);
  844. }
  845.  
  846. NODE *
  847. do_match(tree)
  848. NODE *tree;
  849. {
  850.     NODE *t1;
  851.     int rstart;
  852.     struct re_registers reregs;
  853.     struct re_pattern_buffer *rp;
  854.     int need_to_free = 0;
  855.  
  856.     t1 = force_string(tree_eval(tree->lnode));
  857.     tree = tree->rnode;
  858.     if (tree == NULL || tree->lnode == NULL)
  859.         fatal("match called with only one argument");
  860.     tree = tree->lnode;
  861.     if (tree->type == Node_regex) {
  862.         rp = tree->rereg;
  863.         if (!strict && ((IGNORECASE_node->var_value->numbr != 0)
  864.             ^ (tree->re_case != 0))) {
  865.             /* recompile since case sensitivity differs */
  866.             rp = tree->rereg =
  867.                 mk_re_parse(tree->re_text,
  868.                 (IGNORECASE_node->var_value->numbr != 0));
  869.             tree->re_case =
  870.                 (IGNORECASE_node->var_value->numbr != 0);
  871.         }
  872.     } else {
  873.         need_to_free = 1;
  874.         rp = make_regexp(force_string(tree_eval(tree)),
  875.                 (IGNORECASE_node->var_value->numbr != 0));
  876.         if (rp == NULL)
  877.             cant_happen();
  878.     }
  879.     rstart = re_search(rp, t1->stptr, t1->stlen, 0, t1->stlen, &reregs);
  880.     free_temp(t1);
  881.     if (rstart >= 0) {
  882.         rstart++;    /* 1-based indexing */
  883.         /* RSTART set to rstart below */
  884.         RLENGTH_node->var_value->numbr =
  885.             (AWKNUM) (reregs.end[0] - reregs.start[0]);
  886.     } else {
  887.         /*
  888.          * Match failed. Set RSTART to 0, RLENGTH to -1.
  889.          * Return the value of RSTART.
  890.          */
  891.         rstart = 0;    /* used as return value */
  892.         RLENGTH_node->var_value->numbr = -1.0;
  893.     }
  894.     RSTART_node->var_value->numbr = (AWKNUM) rstart;
  895.     if (need_to_free) {
  896.         free(rp->buffer);
  897.         free(rp->fastmap);
  898.         free((char *) rp);
  899.     }
  900.     return tmp_number((AWKNUM) rstart);
  901. }
  902.  
  903. static NODE *
  904. sub_common(tree, global)
  905. NODE *tree;
  906. int global;
  907. {
  908.     register int len;
  909.     register char *scan;
  910.     register char *bp, *cp;
  911.     int search_start = 0;
  912.     int match_length;
  913.     int matches = 0;
  914.     char *buf;
  915.     struct re_pattern_buffer *rp;
  916.     NODE *s;        /* subst. pattern */
  917.     NODE *t;        /* string to make sub. in; $0 if none given */
  918.     struct re_registers reregs;
  919.     unsigned int saveflags;
  920.     NODE *tmp;
  921.     NODE **lhs;
  922.     char *lastbuf;
  923.     int need_to_free = 0;
  924.  
  925.     if (tree == NULL)
  926.         fatal("sub or gsub called with 0 arguments");
  927.     tmp = tree->lnode;
  928.     if (tmp->type == Node_regex) {
  929.         rp = tmp->rereg;
  930.         if (! strict && ((IGNORECASE_node->var_value->numbr != 0)
  931.             ^ (tmp->re_case != 0))) {
  932.             /* recompile since case sensitivity differs */
  933.             rp = tmp->rereg =
  934.                 mk_re_parse(tmp->re_text,
  935.                 (IGNORECASE_node->var_value->numbr != 0));
  936.             tmp->re_case = (IGNORECASE_node->var_value->numbr != 0);
  937.         }
  938.     } else {
  939.         need_to_free = 1;
  940.         rp = make_regexp(force_string(tree_eval(tmp)),
  941.                 (IGNORECASE_node->var_value->numbr != 0));
  942.         if (rp == NULL)
  943.             cant_happen();
  944.     }
  945.     tree = tree->rnode;
  946.     if (tree == NULL)
  947.         fatal("sub or gsub called with only 1 argument");
  948.     s = force_string(tree_eval(tree->lnode));
  949.     tree = tree->rnode;
  950.     deref = 0;
  951.     field_num = -1;
  952.     if (tree == NULL) {
  953.         t = node0_valid ? fields_arr[0] : *get_field(0, 0);
  954.         lhs = &fields_arr[0];
  955.         field_num = 0;
  956.         deref = t;
  957.     } else {
  958.         t = tree->lnode;
  959.         lhs = get_lhs(t, 1);
  960.         t = force_string(tree_eval(t));
  961.     }
  962.     /*
  963.      * create a private copy of the string
  964.      */
  965.     if (t->stref > 1 || (t->flags & PERM)) {
  966.         saveflags = t->flags;
  967.         t->flags &= ~MALLOC;
  968.         tmp = dupnode(t);
  969.         t->flags = saveflags;
  970.         do_deref();
  971.         t = tmp;
  972.         if (lhs)
  973.             *lhs = tmp;
  974.     }
  975.     lastbuf = t->stptr;
  976.     do {
  977.         if (re_search(rp, t->stptr, t->stlen, search_start,
  978.             t->stlen-search_start, &reregs) == -1
  979.             || reregs.start[0] == reregs.end[0])
  980.             break;
  981.         matches++;
  982.  
  983.         /*
  984.          * first, make a pass through the sub. pattern, to calculate
  985.          * the length of the string after substitution 
  986.          */
  987.         match_length = reregs.end[0] - reregs.start[0];
  988.         len = t->stlen - match_length;
  989.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  990.             if (*scan == '&')
  991.                 len += match_length;
  992.             else if (*scan == '\\' && *(scan+1) == '&') {
  993.                 scan++;
  994.                 len++;
  995.             } else
  996.                 len++;
  997.         emalloc(buf, char *, len + 1, "do_sub");
  998.         bp = buf;
  999.  
  1000.         /*
  1001.          * now, create the result, copying in parts of the original
  1002.          * string 
  1003.          */
  1004.         for (scan = t->stptr; scan < t->stptr + reregs.start[0]; scan++)
  1005.             *bp++ = *scan;
  1006.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  1007.             if (*scan == '&')
  1008.                 for (cp = t->stptr + reregs.start[0];
  1009.                      cp < t->stptr + reregs.end[0]; cp++)
  1010.                     *bp++ = *cp;
  1011.             else if (*scan == '\\' && *(scan+1) == '&') {
  1012.                 scan++;
  1013.                 *bp++ = *scan;
  1014.             } else
  1015.                 *bp++ = *scan;
  1016.         search_start = bp - buf;
  1017.         for (scan = t->stptr + reregs.end[0];
  1018.              scan < t->stptr + t->stlen; scan++)
  1019.             *bp++ = *scan;
  1020.         *bp = '\0';
  1021.         free(lastbuf);
  1022.         t->stptr = buf;
  1023.         lastbuf = buf;
  1024.         t->stlen = len;
  1025.     } while (global && search_start < t->stlen);
  1026.  
  1027.     free_temp(s);
  1028.     if (need_to_free) {
  1029.         free(rp->buffer);
  1030.         free(rp->fastmap);
  1031.         free((char *) rp);
  1032.     }
  1033.     if (matches > 0) {
  1034.         if (field_num == 0)
  1035.             set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
  1036.         t->flags &= ~(NUM|NUMERIC);
  1037.     }
  1038.     field_num = -1;
  1039.     return tmp_number((AWKNUM) matches);
  1040. }
  1041.  
  1042. NODE *
  1043. do_gsub(tree)
  1044. NODE *tree;
  1045. {
  1046.     return sub_common(tree, 1);
  1047. }
  1048.  
  1049. NODE *
  1050. do_sub(tree)
  1051. NODE *tree;
  1052. {
  1053.     return sub_common(tree, 0);
  1054. }
  1055.  
  1056.