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