home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / CLIPPER / MISC / AWK.ZIP / AWK3.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-09-09  |  39.0 KB  |  1,675 lines

  1. /**
  2.  * $Revision:   1.1  $
  3.  * $Log:   C:/AWK/AWK3.C_V  $
  4.  * 
  5.  *    Rev 1.1   09 Sep 1988 18:29:58   vince
  6.  * MC 5.1 version
  7.  * 
  8.  *    Rev 1.0   09 Sep 1988 18:03:06   vince
  9.  * Original source
  10.  * 
  11.  * awk3.c -- Builtin functions and various utility procedures
  12.  *
  13.  *
  14.  * Copyright (C) 1986 Free Software Foundation
  15.  *    Written by Jay Fenlason, December 1986 
  16.  *
  17.  *    Modifications by Andrew D. Estes, July 1988 
  18.  */
  19.  
  20. /**
  21.  * GAWK is distributed in the hope that it will be useful, but WITHOUT ANY
  22.  * WARRANTY.  No author or distributor accepts responsibility to anyone
  23.  * for the consequences of using it or for whether it serves any
  24.  * particular purpose or works at all, unless he says so in writing.
  25.  * Refer to the GAWK General Public License for full details.
  26.  * 
  27.  * Everyone is granted permission to copy, modify and redistribute GAWK,
  28.  * but only under the conditions described in the GAWK General Public
  29.  * License.  A copy of this license is supposed to have been given to you
  30.  * along with GAWK so you can know your rights and responsibilities.  It
  31.  * should be in a file named COPYING.  Among other things, the copyright
  32.  * notice and this notice must be preserved on all copies.
  33.  * 
  34.  * In other words, go ahead and share GAWK, but don't try to stop
  35.  * anyone else from sharing it farther.  Help stamp out software hoarding!
  36.  */
  37.  
  38. #include <stdio.h>
  39. #include "obstack.h"
  40. #include "awk.h"
  41. #include "regex.h"
  42.  
  43. struct re_registers reregs;            /* ADE */
  44.  
  45. extern struct obstack temp_strings;
  46.  
  47. /* This node is the cannonical null string, used everywhere */
  48. extern NODE *Nnull_string;
  49.  
  50. /* These nodes store all the special variables gAWK uses */
  51. NODE *FS_node, *NF_node, *FNR_node, *RS_node, *NR_node;
  52. NODE *FILENAME_node, *OFS_node, *ORS_node, *OFMT_node;
  53. NODE *ARGC_node, *ARGV_node, *RSTART_node, *RLENGTH_node;
  54.  
  55. /*
  56.  * This dumb kludge is used by force_string to turn a floating point number into a string 
  57.  */
  58. NODE dumb[2];
  59.  
  60. NODE **get_lhs();
  61. FILE *deal_redirect();
  62.  
  63. struct redirect
  64. {
  65.    int flag;                           /* JF was NODETYPE */
  66.    NODE *value;
  67.    FILE *fp;
  68. };
  69. struct redirect reds[20];              /* An arbitrary limit, surely, but there's an arbitrary limit on open files, too.  So it
  70.                                         * doesn't make much difference, does it? */
  71.  
  72. static char *inrecbuf;                 /* input buffer for inrec & getline -ade- */
  73.  
  74. long NR;
  75. int NF;
  76. int FNR;                               /* new variables -ade- */
  77. int ARGV_index;
  78. int ARGC;
  79.  
  80. /* The next #define tells how you find $0.  Its a hack */
  81. extern NODE **fields_arr;
  82. #define WHOLELINE       fields_arr[0]
  83.  
  84. /*
  85.  * Set all the special variables to their initial values.  Also sets up the dumb[] array for force_string 
  86.  */
  87. init_vars()
  88. {
  89.    NODE *spc_var();
  90.    NODE *do_sprintf();
  91.  
  92.    FS_node = spc_var("FS", make_string(" ", 1));
  93.    NF_node = spc_var("NF", make_number(0.0));
  94.    RS_node = spc_var("RS", make_string("\n", 1));
  95.    NR_node = spc_var("NR", make_number(0.0));
  96.    FNR_node = spc_var("FNR", make_number(0.0)); /* File Number Records -ade- */
  97.    FILENAME_node = spc_var("FILENAME", Nnull_string);
  98.    OFS_node = spc_var("OFS", make_string(" ", 1));
  99.    ORS_node = spc_var("ORS", make_string("\n", 1));
  100.    OFMT_node = spc_var("OFMT", make_string("%.6g", 4));
  101.    RSTART_node = spc_var("RSTART", make_number(0.0));   /* for Match -ade- */
  102.    RLENGTH_node = spc_var("RLENGTH", make_number(0.0)); /* for Match -ade- */
  103.  
  104.    /*
  105.     * This ugly hack is used by force_string to fake a call to sprintf 
  106.     */
  107.    dumb[0].type = Node_expression_list;
  108.    dumb[0].lnode = OFMT_node;
  109.    dumb[0].rnode = &dumb[1];
  110.    dumb[1].type = Node_expression_list;
  111.    dumb[1].lnode = (NODE *) 0;         /* fill in the var here */
  112.    dumb[1].rnode = (NODE *) 0;
  113.    reds[0].flag = 0;                   /* Don't depend on uninit data being zero, although it should be */
  114. }
  115.  
  116. /* ADE */
  117.  
  118. init_args(argstart, argend, argv)
  119. int argstart;
  120. int argend;
  121. char **argv;
  122. {
  123.    NODE *tmp, *spc_var(), **assoc_lookup();
  124.    register int count;
  125.  
  126.    ARGC_node = spc_var("ARGC", make_number((float) (argend - argstart + 1)));
  127.    ARGC = argend - argstart;
  128.    ARGV_index = 1;
  129.    tmp = variable("ARGV");
  130.    assoc_clear(tmp);
  131.    *assoc_lookup(tmp, make_number((AWKNUM) (0))) =
  132.      make_string("awk", 3);
  133.    for (count = argstart; count < argend; count++)
  134.    {
  135.       *assoc_lookup(tmp, make_number((AWKNUM) (count - argstart + 1))) =
  136.         make_string(argv[count], strlen(argv[count]));
  137.    }
  138. }
  139.  
  140. /*
  141.  * argc and argv functions added so that gawk will be in sync with * ARGC and ARGV[] internal variables -ADE- 
  142.  */
  143.  
  144. int get_argc()
  145. {
  146.    return (ARGC);
  147. }
  148.  
  149. set_argc(val)
  150. int val;
  151. {
  152.    ARGC = val;
  153. }
  154.  
  155. int get_argc_dec()
  156. {
  157.    return (ARGC--);
  158. }
  159.  
  160. char *get_argv()
  161. {
  162.    register NODE *tmp, *tmp1;
  163.  
  164.    tmp = variable("ARGV");
  165.    tmp1 = *assoc_lookup(tmp, make_number((AWKNUM) ARGV_index));
  166.    if (tmp1->stlen == 0)
  167.       return 0;
  168.    return (tmp1->stptr);
  169. }
  170.  
  171. inc_argv()
  172. {
  173.    ARGV_index++;
  174. }
  175.  
  176. set_argv(str)
  177. char *str;
  178. {
  179.    NODE *tmp, *spc_var(), **assoc_lookup();
  180.  
  181.    tmp = variable("ARGV");
  182.    *assoc_lookup(tmp, make_number((AWKNUM) ARGV_index)) =
  183.      make_string(str, strlen(str));
  184. }
  185.  
  186. /*
  187.  * OFMT is special because we don't dare use force_string on it for fear of infinite loops.  Thus, if it isn't a string, we return
  188.  * the default "%.6g" This may or may not be the right thing to do, but its the easiest 
  189.  */
  190. /* This routine isn't used!  It should be.  */
  191. char *get_ofmt()
  192. {
  193.    register NODE *tmp;
  194.  
  195.    tmp = *get_lhs(OFMT_node);
  196.    if (tmp->type != Node_string || tmp->stlen == 0)
  197.       return "%.6g";
  198.    return tmp->stptr;
  199. }
  200.  
  201. /*
  202.  * this was int.  changed to allow regular expressions * as field seperators -ade- 
  203.  */
  204.  
  205. char *get_fs()
  206. {
  207.    register NODE *tmp;
  208.  
  209.    tmp = force_string(FS_node->var_value);
  210.    if (tmp->stlen == 0)
  211.       return NULL;                     /* ade */
  212.    return (tmp->stptr);                /* ade */
  213. }
  214.  
  215. set_fs(str)
  216. char *str;
  217. {
  218.    register NODE **tmp;
  219.  
  220.    tmp = get_lhs(FS_node);
  221.    do_deref();
  222.    /* stupid special case so -F\t works as documented in awk */
  223.    /* even though the shell hands us -Ft.  Bleah! (jfw) */
  224.    if (*str == 't')
  225.       *str == '\t';
  226.    *tmp = make_string(str, 1);
  227. }
  228.  
  229. set_rs(str)
  230. char *str;
  231. {
  232.    register NODE **tmp;
  233.  
  234.    tmp = get_lhs(RS_node);
  235.    do_deref();
  236.    /* stupid special case to be consistent with -F (jfw) */
  237.    if (*str == 't')
  238.       *str == '\t';
  239.    *tmp = make_string(str, 1);
  240. }
  241.  
  242.  
  243. int get_rs()
  244. {
  245.    register NODE *tmp;
  246.  
  247.    tmp = force_string(RS_node->var_value);
  248.    if (tmp->stlen == 0)
  249.       return 0;
  250.    return *(tmp->stptr);
  251. }
  252.  
  253. /* ADE */
  254. set_fnr(fnr)
  255. int fnr;
  256. {
  257.    FNR = fnr;
  258.    assign_number(&(FNR_node->var_value), (AWKNUM) fnr);
  259. }
  260.  
  261.  
  262.  
  263. /* Builtin functions */
  264. /*
  265.  * ADE - added do_atan2, do_close, do_cos, do_gsub, do_match, do_sub
  266.  *             do_srand, do_rand, do_sin and do_system 
  267.  */
  268. NODE *do_atan2(tree)
  269. NODE *tree;
  270. {
  271.    NODE *tmp1, *tmp2;
  272.    double atan2();
  273.  
  274.    get_two(tree, &tmp1, &tmp2);
  275.    return tmp_number((AWKNUM) atan2((double) force_number(tmp1),
  276.                                     (double) force_number(tmp2)));
  277. }
  278.  
  279. NODE *do_close(tree)
  280. NODE *tree;
  281. {
  282.    register NODE *tmp;
  283.    register struct redirect *rp;
  284.    register char *str;
  285.    register FILE *fp;
  286. #ifdef UNIX
  287.    /* %%% VANDYS: I guess you could run a prog to a file... */
  288.    FILE *popen();
  289. #endif
  290.    int tflag;
  291.  
  292.    tmp = tree_eval(tree->subnode);
  293.    for (rp = reds; rp->flag != 0 && rp < &reds[20]; rp++)
  294.    {                                   /* That limit again */
  295.       if (cmp_nodes(rp->value, tmp) == 0)
  296.          break;
  297.    }
  298.    if (rp == &reds[20])
  299.       return tmp_number(1.1);          /* ERROR not a redirect -ADE- */
  300.    if (rp->flag == 0)
  301.       return tmp_number(1.1);
  302.    rp->flag = 0;
  303.    fclose(rp->fp);
  304.    return tmp_number(0.0);
  305. }
  306.  
  307. NODE *do_cos(tree)
  308. NODE *tree;
  309. {
  310.    NODE *tmp;
  311.    double cos();
  312.  
  313.    get_one(tree, &tmp);
  314.    return tmp_number((AWKNUM) cos((double) force_number(tmp)));
  315. }
  316.  
  317. NODE *do_exp(tree)
  318. NODE *tree;
  319. {
  320.    NODE *tmp;
  321.    double exp();
  322.  
  323.    get_one(tree, &tmp);
  324.    return tmp_number((AWKNUM) exp((double) force_number(tmp)));
  325. }
  326.  
  327. /* JF: I don't know what this should return. */
  328. /* jfw: 1 if successful or by land, 0 if end of file or by sea */
  329. /*
  330.  * do_getline has been beefed up to allow assignment to variables
  331.  * and reading from a redirection. -ade- 
  332.  */
  333. /* ADE: 1 if record present, 0 if end of file, -1 error */
  334.  
  335. NODE *do_getline(tree)
  336. NODE *tree;
  337. {
  338.    NODE **tmp, *t1, *t2;
  339.    FILE *infp, *deal_redirect_in();
  340.    extern FILE *input_file;
  341.    int retval, parse_type;
  342.  
  343.    parse_type = 0;
  344.    t1 = tree->rnode;
  345.    tree = tree->lnode;
  346.    infp = deal_redirect_in(t1);
  347.    if (infp != input_file)
  348.    {
  349.       parse_type += 2;
  350.       FNR = 0;
  351.    }
  352.    if (tree == NULL)
  353.       retval = inrec(parse_type, infp);
  354.    else if (tree->type != Node_var)
  355.       retval = inrec(parse_type, infp);
  356.    else
  357.    {
  358.       parse_type++;
  359.       t1 = tree;
  360.       retval = inrec(parse_type, infp);
  361.       tmp = get_lhs(t1);
  362.       do_deref();
  363.       *tmp = make_string(inrecbuf, strlen(inrecbuf));
  364.    }
  365.    if (retval == 1)
  366.       return tmp_number(0.0);
  367.    else
  368.       return tmp_number(1.0);
  369. }
  370.  
  371. /* globally substitute function -ade- */
  372. NODE *do_gsub(tree)
  373. NODE *tree;
  374. {
  375.    NODE **tmp, *t1, *t2, *t3, *t4;
  376.    char *temp, *temp1, *regsub();
  377.    int new_len, redofields;
  378.  
  379.    switch (b_get_three(tree, &t1, &t2, &t3))
  380.    {
  381.    case 1:
  382.       printf("Error: gsub needs 2 or 3 parameters\n");
  383.       abort();
  384.       break;
  385.    case 2:
  386.       t3 = WHOLELINE;
  387.       redofields++;
  388.       break;
  389.    default:
  390.       redofields = 0;
  391.       break;
  392.    }
  393.    if (t3->type == Node_field_spec)
  394.       ++redofields;
  395.    t4 = tree_eval(t3);
  396.    if (re_search(t1->rereg, t4->stptr, t4->stlen, 0, t4->stlen, &reregs) != -1)
  397.    {
  398.       if ((temp = malloc(64)) == NULL)
  399.          panic("Memory exhausted");
  400.       new_len = 64;
  401.       temp = regsub(t4->stptr, temp, t2->stptr, &new_len);
  402.       while (re_search(t1->rereg, temp, new_len, 0, new_len, &reregs) != -1)
  403.       {
  404.          if ((temp1 = malloc(64)) == NULL)
  405.             panic("Memory exhausted");
  406.          new_len = 64;
  407.          temp1 = regsub(temp, temp1, t2->stptr, &new_len);
  408.          free(temp);
  409.          temp = temp1;
  410.       }
  411.       if ((t3->lnode->type == Node_field_spec) || redofields)
  412.       {
  413.          --FNR;
  414.          --NR;
  415.          parse_fields(temp, temp + strlen(temp), 0);
  416.          free(temp);
  417.          return (tmp_number(1.0));
  418.       }
  419.       tmp = get_lhs(t3);
  420.       do_deref();
  421.       *tmp = make_string(temp, strlen(temp));
  422.       free(temp);
  423.       free(temp1);
  424.       return (tmp_number(1.0));
  425.    }
  426.    return (tmp_number(0.0));
  427. }
  428.  
  429. NODE *do_index(tree)
  430. NODE *tree;
  431. {
  432.    NODE *s1, *s2;
  433.    register char *p1, *p2;
  434.    register int l1, l2;
  435.  
  436.    get_two(tree, &s1, &s2);
  437.    p1 = s1->stptr;
  438.    p2 = s2->stptr;
  439.    l1 = s1->stlen;
  440.    l2 = s2->stlen;
  441.    while (l1)
  442.    {
  443.       if (!strncmp(p1, p2, l2))
  444.          return tmp_number((AWKNUM) (1 + s1->stlen - l1));
  445.       l1--;
  446.       p1++;
  447.    }
  448.    return tmp_number(0.0);
  449. }
  450.  
  451. NODE *do_int(tree)
  452. NODE *tree;
  453. {
  454.    NODE *tmp;
  455.    double floor();
  456.  
  457.    get_one(tree, &tmp);
  458.    return tmp_number((AWKNUM) floor((double) force_number(tmp)));
  459. }
  460.  
  461. NODE *do_length(tree)
  462. NODE *tree;
  463. {
  464.    NODE *tmp;
  465.  
  466.    get_one(tree, &tmp);
  467.    return tmp_number((AWKNUM) (force_string(tmp)->stlen));
  468. }
  469.  
  470. NODE *do_log(tree)
  471. NODE *tree;
  472. {
  473.    NODE *tmp;
  474.    double log();
  475.  
  476.    get_one(tree, &tmp);
  477.    return tmp_number(log(force_number(tmp)));
  478. }
  479.  
  480. NODE *do_match(tree)
  481. NODE *tree;
  482. {
  483.    NODE **tmp, *tmp1, *tmp2;
  484.    int retval;
  485.  
  486.    get_two(tree, &tmp1, &tmp2);
  487.    retval = re_search(tmp2->rereg, tmp1->stptr, tmp1->stlen, 0, tmp1->stlen, &reregs);
  488.    retval++;
  489.    tmp = get_lhs(RSTART_node);
  490.    do_deref();
  491.    *tmp = make_number((AWKNUM) retval);
  492.    tmp = get_lhs(RLENGTH_node);
  493.    do_deref();
  494.    *tmp = make_number((AWKNUM) (reregs.end[0] - reregs.start[0]));
  495.    return (tmp_number((AWKNUM) retval));
  496. }
  497.  
  498. NODE *do_printf(tree)
  499. NODE *tree;
  500. {
  501.    register FILE *fp;
  502.    NODE *do_sprintf();
  503.  
  504.    fp = deal_redirect(tree->rnode);
  505.    print_simple(do_sprintf(tree->lnode), fp);
  506.    return Nnull_string;
  507. }
  508.  
  509. NODE *do_sin(tree)
  510. NODE *tree;
  511. {
  512.    NODE *tmp;
  513.    double sin();
  514.  
  515.    get_one(tree, &tmp);
  516.    return (tmp_number((AWKNUM) sin((double) force_number(tmp))));
  517. }
  518.  
  519. NODE *do_split(tree)
  520. NODE *tree;
  521. {
  522.    NODE *t1, *t2, *t3;
  523.    register char *splitc;
  524.    register int num, snum, olds;
  525.    register char *ptr, *oldp;
  526.    NODE **assoc_lookup();
  527.  
  528.    if (a_get_three(tree, &t1, &t2, &t3) < 3)
  529.       splitc = get_fs();
  530.    else
  531.       splitc = (force_string(t3)->stptr);
  532.    num = 0;
  533.    tree = force_string(t1);
  534.    olds = snum = tree->stlen;
  535.    oldp = ptr = tree->stptr;
  536.    assoc_clear(t2);
  537.    while (snum--)
  538.    {
  539.       if (*ptr++ == *splitc)
  540.       {
  541.          *assoc_lookup(t2, make_number((AWKNUM) (++num))) = make_string(oldp, (olds - snum) - 1);
  542.          oldp = ptr;
  543.          olds = snum;
  544.       }
  545.    }
  546.    *assoc_lookup(t2, make_number((AWKNUM) (++num))) = make_string(oldp, (olds - snum) - 1);
  547.    return tmp_number((AWKNUM) num);
  548. }
  549.  
  550. /*
  551.  * Note that the output buffer cannot be static because sprintf may get called recursively by force_string.  Hence the wasteful
  552.  * alloca calls 
  553.  */
  554.  
  555. /* %e and %f formats are not properly implemented.      Someone should fix them */
  556. /* %f format seems to be working now -ADE- */
  557.  
  558. NODE *do_sprintf(tree)
  559. NODE *tree;
  560. {
  561. #define bchunk(s,l) if(l) {\
  562.     if((l)>ofre) {\
  563.       char *tmp;\
  564.       tmp=(char *)alloca(osiz*2);\
  565.       bcopy(obuf,tmp,olen);\
  566.       obuf=tmp;\
  567.       ofre+=osiz;\
  568.       osiz*=2;\
  569.     }\
  570.     bcopy(s,obuf+olen,(l));\
  571.     olen+=(l);\
  572.     ofre-=(l);\
  573.   }
  574.  
  575.    /* Is there space for something L big in the buffer? */
  576. #define chksize(l)  if((l)>ofre) {\
  577.     char *tmp;\
  578.     tmp=(char *)alloca(osiz*2);\
  579.     bcopy(obuf,tmp,olen);\
  580.     obuf=tmp;\
  581.     ofre+=osiz;\
  582.     osiz*=2;\
  583.   }
  584.    /*
  585.     * Get the next arg to be formatted.  If we've run out of args, return "" (Null string) 
  586.     */
  587. #define parse_next_arg() {\
  588.   if(!carg) arg= Nnull_string;\
  589.   else {\
  590.         get_one(carg,&arg);\
  591.         carg=carg->rnode;\
  592.   }\
  593.  }
  594.  
  595.    char *obuf;
  596.    int osiz, ofre, olen, dec;
  597.    static char chbuf[] = "0123456789abcdef";
  598.    static char sp[] = " ";
  599.    char *s0, *s1;
  600.    int n0;
  601.    NODE *sfmt, *arg;
  602.    register NODE *carg;
  603.    long fw, prec, lj, alt, big;
  604.    long *cur;
  605.    long val;
  606.    unsigned long uval;
  607.    int sgn;
  608.    int base;
  609.    char cpbuf[30];                     /* if we have numbers bigger than 30 */
  610.    char *cend = &cpbuf[30];            /* chars, we lose, but seems unlikely */
  611.    char *cp;
  612.    char *fill;
  613.    double tmpval;
  614.    char *pr_str;
  615.  
  616.    obuf = (char *) alloca(120);
  617.    osiz = 120;
  618.    ofre = osiz;
  619.    olen = 0;
  620.    get_one(tree, &sfmt);
  621.    sfmt = force_string(sfmt);
  622.    carg = tree->rnode;
  623.    for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;)
  624.    {
  625.       if (*s1 != '%')
  626.       {
  627.          s1++;
  628.          continue;
  629.       }
  630.  
  631.       bchunk(s0, s1 - s0);
  632.       s0 = s1;
  633.       cur = &fw;
  634.       fw = 0;
  635.       prec = 0;
  636.       lj = alt = big = 0;
  637.       fill = sp;
  638.       cp = cend;
  639.       s1++;
  640.  
  641. retry:
  642.       --n0;
  643.       switch (*s1++)
  644.       {
  645.       case '%':
  646.          bchunk("%", 1);
  647.          s0 = s1;
  648.          break;
  649.  
  650.       case '0':
  651.          if (fill != sp || lj)
  652.             goto lose;
  653.          fill = "0";                   /* FALL through */
  654.       case '1':
  655.       case '2':
  656.       case '3':
  657.       case '4':
  658.       case '5':
  659.       case '6':
  660.       case '7':
  661.       case '8':
  662.       case '9':
  663.          if (cur == 0)
  664.             goto lose;
  665.          *cur = s1[-1] - '0';
  666.          while (n0 > 0 && *s1 >= '0' && *s1 <= '9')
  667.          {
  668.             --n0;
  669.             *cur = *cur * 10 + *s1++ - '0';
  670.          }
  671.          goto retry;
  672.       case '-':
  673.          if (lj || fill != sp)
  674.             goto lose;
  675.          lj++;
  676.          goto retry;
  677.       case '.':
  678.          if (cur != &fw)
  679.             goto lose;
  680.          cur = ≺
  681.          goto retry;
  682.       case '#':
  683.          if (alt)
  684.             goto lose;
  685.          alt++;
  686.          goto retry;
  687.       case 'l':
  688.          if (big)
  689.             goto lose;
  690.          big++;
  691.          goto retry;
  692.       case '*':
  693.          if (cur == 0)
  694.             goto lose;
  695.          parse_next_arg();
  696.          *cur = (int) arg;
  697.          goto retry;
  698.       case 'c':
  699.          parse_next_arg();
  700.          if (arg->type == Node_number)
  701.          {
  702.             uval = (unsigned long) arg->numbr;
  703.             cpbuf[0] = uval;
  704.             prec = 1;
  705.             pr_str = cpbuf;
  706.             goto dopr_string;
  707.          }
  708.          if (!prec || prec > arg->stlen)
  709.             prec = arg->stlen;
  710.          pr_str = cpbuf;
  711.          goto dopr_string;
  712.       case 's':
  713.          parse_next_arg();
  714.          arg = force_string(arg);
  715.          if (!prec || prec > arg->stlen)
  716.             prec = arg->stlen;
  717.          pr_str = arg->stptr;
  718.  
  719.    dopr_string:
  720.          if (fw > prec && !lj)
  721.          {
  722.             while (fw > prec)
  723.             {
  724.                bchunk(sp, 1);
  725.                fw--;
  726.             }
  727.          }
  728.          bchunk(pr_str, (int) prec);
  729.          if (fw > prec)
  730.          {
  731.             while (fw > prec)
  732.             {
  733.                bchunk(sp, 1);
  734.                fw--;
  735.             }
  736.          }
  737.          s0 = s1;
  738.          break;
  739.       case 'd':
  740.          parse_next_arg();
  741.          val = (long) force_number(arg);
  742.          if (val < 0)
  743.          {
  744.             sgn = 1;
  745.             val = -val;
  746.          }
  747.          else
  748.             sgn = 0;
  749.          do
  750.          {
  751.             *--cp = '0' + val % 10;
  752.             val /= 10;
  753.          } while (val);
  754.          if (sgn)
  755.             *--cp = '-';
  756.          prec = cend - cp;
  757.          if (fw > prec && !lj)
  758.          {
  759.             if (fill != sp && *cp == '-')
  760.             {
  761.                bchunk(cp, 1);
  762.                cp++;
  763.                prec--;
  764.                fw--;
  765.             }
  766.             while (fw > prec)
  767.             {
  768.                bchunk(fill, 1);
  769.                fw--;
  770.             }
  771.          }
  772.          bchunk(cp, (int) prec);
  773.          if (fw > prec)
  774.          {
  775.             while (fw > prec)
  776.             {
  777.                bchunk(fill, 1);
  778.                fw--;
  779.             }
  780.          }
  781.          s0 = s1;
  782.          break;
  783.       case 'u':
  784.          base = 10;
  785.          goto pr_unsigned;
  786.       case 'o':
  787.          base = 8;
  788.          goto pr_unsigned;
  789.       case 'x':
  790.          base = 16;
  791.          goto pr_unsigned;
  792.    pr_unsigned:
  793.          parse_next_arg();
  794.          uval = (unsigned long) force_number(arg);
  795.          do
  796.          {
  797.             *--cp = chbuf[uval % base];
  798.             uval /= base;
  799.          } while (uval);
  800.          prec = cend - cp;
  801.          if (fw > prec && !lj)
  802.          {
  803.             while (fw > prec)
  804.             {
  805.                bchunk(fill, 1);
  806.                fw--;
  807.             }
  808.          }
  809.          bchunk(cp, (int) prec);
  810.          if (fw > prec)
  811.          {
  812.             while (fw > prec)
  813.             {
  814.                bchunk(fill, 1);
  815.                fw--;
  816.             }
  817.          }
  818.          s0 = s1;
  819.          break;
  820.       case 'g':
  821.          parse_next_arg();
  822.          tmpval = force_number(arg);
  823.          if (prec == 0)
  824.             prec = 13;
  825.          gcvt(tmpval, prec, cpbuf);
  826.          prec = strlen(cpbuf);
  827.          cp = cpbuf;
  828.          if (cpbuf[prec - 1] == '.')   /* if last char is a '.' */
  829.             cpbuf[--prec] = '\0';      /* drop it -ADE- */
  830.          if (fw > prec && !lj)
  831.          {
  832.             if (fill != sp && *cp == '-')
  833.             {
  834.                bchunk(cp, 1);
  835.                cp++;
  836.                prec--;
  837.             }                          /* Deal with .5 as 0.5 */
  838.             if (fill == sp && *cp == '.')
  839.             {
  840.                --fw;
  841.                while (--fw >= prec)
  842.                {
  843.                   bchunk(fill, 1);
  844.                }
  845.                bchunk("0", 1);
  846.             }
  847.             else
  848.                while (fw-- > prec)
  849.                   bchunk(fill, 1);
  850.          }
  851.          else
  852.          {                             /* Turn .5 into 0.5 */
  853.             /* FOO */
  854.             if (*cp == '.' && fill == sp)
  855.             {
  856.                bchunk("0", 1);
  857.                --fw;
  858.             }
  859.          }
  860.          bchunk(cp, (int) prec);
  861.          if (fw > prec)
  862.             while (fw-- > prec)
  863.                bchunk(fill, 1);
  864.          s0 = s1;
  865.          break;
  866.          /* JF how to handle these!? */
  867.       case 'f':
  868.          parse_next_arg();
  869.          tmpval = force_number(arg);
  870.          if (prec == 0)
  871.             prec = 6;
  872.          cp = fcvt(tmpval, prec, &dec, &sgn);
  873.          prec = strlen(cp);
  874.          if (fw > prec && !lj)
  875.          {
  876.             if (fill != sp && *cp == '-')
  877.             {
  878.                bchunk(cp, 1);
  879.                cp++;
  880.                prec--;
  881.             }                          /* Deal with .5 as 0.5 */
  882.             if (fill == sp && *cp == '.')
  883.             {
  884.                --fw;
  885.                while (--fw >= prec)
  886.                {
  887.                   bchunk(fill, 1);
  888.                }
  889.                bchunk("0", 1);
  890.             }
  891.             else
  892.                while (fw-- > prec)
  893.                   bchunk(fill, 1);
  894.          }
  895.          else
  896.          {                             /* Turn .5 into 0.5 */
  897.             /* FOO */
  898.             if (*cp == '.' && fill == sp)
  899.             {
  900.                bchunk("0", 1);
  901.                --fw;
  902.             }
  903.          }
  904.          if (sgn)
  905.             bchunk("-", 1);
  906.          if (dec > 0)
  907.          {
  908.             bchunk(cp, dec);
  909.             bchunk(".", 1);
  910.             cp += dec;
  911.             bchunk(cp, (int) prec - dec);
  912.          }
  913.          else if (dec)
  914.          {
  915.             prec += dec;
  916.             bchunk("0", 1);
  917.             bchunk(".", 1);
  918.             while (dec++)
  919.                bchunk("0", 1);
  920.             bchunk(cp, (int) prec);
  921.          }
  922.          else
  923.          {
  924.             bchunk("0", 1);
  925.             bchunk(".", 1);
  926.             bchunk(cp, (int) prec);
  927.          }
  928.          if (fw > prec)
  929.             while (fw-- > prec)
  930.                bchunk(fill, 1);
  931.  
  932.          /*
  933.           * chksize(fw + prec + 5);
  934.           * *cp++ = '%';
  935.           * if (lj)
  936.           *    *cp++='-';                       
  937.           * if(fill != sp)
  938.           *    *cp++='0';
  939.           * if (prec != 0)
  940.           * {
  941.           *    strcpy(cp, "*.*f");
  942.           *    sprintf(obuf + olen, cpbuf, fw, prec, (double)tmpval);
  943.           *  }
  944.           *  else
  945.           *  {
  946.           *     strcpy(cp, "*f");
  947.           *     sprintf(obuf + olen, cpbuf, fw, (double)tmpval);
  948.           * }
  949.           * cp = obuf + olen;
  950.           * ofre -= strlen(obuf + olen);
  951.           * olen += strlen(obuf + olen);
  952.           */
  953.          s0 = s1;
  954.          break;
  955.       case 'e':
  956.          parse_next_arg();
  957.          tmpval = force_number(arg);
  958.          if (prec == 0)
  959.             prec = 13;
  960.          cp = ecvt(tmpval, prec, &dec, &sgn);
  961.          prec = strlen(cp);
  962.          if (sgn)
  963.             bchunk("-", 1);
  964.          if (dec > 0)
  965.          {
  966.             bchunk(cp, dec);
  967.             bchunk(".", 1);
  968.             cp += dec;
  969.             bchunk(cp, (int) prec - dec);
  970.          }
  971.          else if (dec)
  972.          {
  973.             bchunk("0", abs(dec));
  974.             bchunk(".", 1);
  975.             bchunk(cp, (int) prec + dec);
  976.          }
  977.          else
  978.          {
  979.             bchunk("0", 1);
  980.             bchunk(".", 1);
  981.             bchunk(cp, (int) prec);
  982.          }
  983.          if (fw > prec)
  984.             while (fw-- > prec)
  985.                bchunk(fill, 1);
  986.  
  987.          /*
  988.           * chksize(fw + prec + 5);
  989.           * cp = cpbuf;
  990.           * *cp++ = '%';
  991.           * if (lj)
  992.           *    *cp++='-';
  993.           * if (fill != sp)
  994.           *    *cp++ = '0';
  995.           * if (prec != 0)
  996.           * {                                
  997.           *    strcpy(cp, "*.*e");
  998.           *    sprintf(obuf + olen, cpbuf, fw, prec, (double)tmpval);
  999.           * }
  1000.           * else
  1001.           * {
  1002.           *    strcpy(cp, "*e");
  1003.           *    sprintf(obuf + olen, cpbuf, fw, (double)tmpval);
  1004.           * }
  1005.           * cp = obuf + olen;
  1006.           * ofre -= strlen(obuf + olen);
  1007.           * olen += strlen(obuf + olen);
  1008.           */
  1009.          s0 = s1;
  1010.          break;
  1011.          /*
  1012.           * case 'g':
  1013.           *    parse_next_arg();
  1014.           *    tmpval = force_number(arg);
  1015.           *    if (prec != 0)
  1016.           *       sprintf(obuf + osiz - ofre, "%*.*g", fw, prec, (double)tmpval);
  1017.           *    else
  1018.           *       sprintf(obuf + osiz - ofre, "%*g", fw, (double)tmpval);
  1019.           *    ofre -= strlen(obuf + osiz - ofre);
  1020.           *    s0 = s1;
  1021.           *    break;
  1022.           */
  1023.       default:
  1024.    lose:
  1025.          break;
  1026.       }
  1027.    }
  1028.    bchunk(s0, s1 - s0);
  1029.    return tmp_string(obuf, olen);
  1030. }
  1031.  
  1032. NODE *do_sqrt(tree)
  1033. NODE *tree;
  1034. {
  1035.    NODE *tmp;
  1036.    double sqrt();
  1037.  
  1038.    get_one(tree, &tmp);
  1039.    return tmp_number((AWKNUM) sqrt((double) force_number(tmp)));
  1040. }
  1041.  
  1042. /* set a seed for rand(). if no parameter, use time. -ade- */
  1043.  
  1044. NODE *do_srand(tree)
  1045. NODE *tree;
  1046. {
  1047.    NODE *tmp;
  1048.    long ltime, *time();
  1049.  
  1050.    if (tree == NULL)
  1051.       srand((unsigned) time(<ime));
  1052.    else
  1053.    {
  1054.       get_one(tree, &tmp);
  1055.       srand((unsigned) force_number(tmp));
  1056.    }
  1057.    return tmp_number(1.0);
  1058. }
  1059.  
  1060. NODE *do_sub(tree)
  1061. NODE *tree;
  1062. {
  1063.    NODE **tmp, *t1, *t2, *t3, *t4;
  1064.    char *temp;
  1065.    int redofields, new_len;
  1066.    char *regsub();
  1067.  
  1068.    switch (b_get_three(tree, &t1, &t2, &t3))
  1069.    {
  1070.    case 1:
  1071.       printf("Error: sub needs 2 or 3 parameters\n");
  1072.       abort();
  1073.       break;
  1074.    case 2:
  1075.       t3 = WHOLELINE;
  1076.       redofields = 1;
  1077.       break;
  1078.    default:
  1079.       redofields = 0;
  1080.       break;
  1081.    }
  1082.    t4 = tree_eval(t3);
  1083.    if (re_search(t1->rereg, t4->stptr, t4->stlen, 0, t4->stlen, &reregs) != -1)
  1084.    {
  1085.       if ((temp = malloc(64)) == NULL)
  1086.          panic("Memory exhausted");
  1087.       new_len = 64;
  1088.       temp = regsub(t4->stptr, temp, t2->stptr, &new_len);
  1089.       if ((t3->lnode->type == Node_field_spec) || redofields)
  1090.       {
  1091.          --FNR;
  1092.          --NR;
  1093.          parse_fields(temp, temp + strlen(temp), 0);
  1094.          free(temp);
  1095.          return (tmp_number(1.0));
  1096.       }
  1097.       tmp = get_lhs(t3);
  1098.       do_deref();
  1099.       *tmp = make_string(temp, strlen(temp));
  1100.       free(temp);
  1101.       return (tmp_number(1.0));
  1102.    }
  1103.    return (tmp_number(0.0));
  1104. }
  1105.  
  1106. NODE *do_substr(tree)
  1107. NODE *tree;
  1108. {
  1109.    NODE *t1, *t2, *t3;
  1110.    register int n1, n2;
  1111.  
  1112.    if (get_three(tree, &t1, &t2, &t3) < 3)
  1113.       n2 = 32000;
  1114.    else
  1115.       n2 = (int) force_number(t3);
  1116.    n1 = (int) force_number(t2) - 1;
  1117.    tree = force_string(t1);
  1118.    if (n1 < 0 || n1 >= tree->stlen || n2 <= 0)
  1119.       return Nnull_string;
  1120.    if (n1 + n2 > tree->stlen)
  1121.       n2 = tree->stlen - n1;
  1122.    return tmp_string(tree->stptr + n1, n2);
  1123. }
  1124.  
  1125. NODE *do_system(tree)
  1126. NODE *tree;
  1127. {
  1128.    NODE *tmp;
  1129.    int system();
  1130.  
  1131.    get_one(tree, &tmp);
  1132.    tmp = force_string(tmp);
  1133.    return (tmp_number(system(tmp->stptr)));
  1134. }
  1135.  
  1136. NODE *do_rand(tree)
  1137. NODE *tree;
  1138. {
  1139.    return (tmp_number((float) (rand() / 32767.0)));
  1140. }
  1141.  
  1142. /* The print command.  Its name is historical */
  1143. hack_print_node(tree)
  1144. NODE *tree;
  1145. {
  1146.    register FILE *fp;
  1147.  
  1148. #ifndef FAST
  1149.    if (!tree || tree->type != Node_K_print)
  1150.       abort();
  1151. #endif
  1152.    fp = deal_redirect(tree->rnode);
  1153.    tree = tree->lnode;
  1154.    if (!tree)
  1155.       tree = WHOLELINE;
  1156.    if (tree->type != Node_expression_list)
  1157.    {
  1158.       print_simple(tree, fp);
  1159.    }
  1160.    else
  1161.    {
  1162.       while (tree)
  1163.       {
  1164.          print_simple(tree_eval(tree->lnode), fp);
  1165.          tree = tree->rnode;
  1166.          if (tree)
  1167.             print_simple(OFS_node->var_value, fp);
  1168.       }
  1169.    }
  1170.    print_simple(ORS_node->var_value, fp);
  1171. }
  1172.  
  1173. /*
  1174.  * Get the arguments to functions.  No function cares if you give it too many
  1175.  * args (they're ignored).  Only a few fuctions complain about being given too
  1176.  * few args.  The rest have defaults 
  1177.  */
  1178. get_one(tree, res)
  1179. NODE *tree, **res;
  1180. {
  1181.    if (!tree)
  1182.    {
  1183.       *res = WHOLELINE;
  1184.       return;
  1185.    }
  1186. #ifndef FAST
  1187.    if (tree->type != Node_expression_list)
  1188.       abort();
  1189. #endif
  1190.    *res = tree_eval(tree->lnode);
  1191. }
  1192.  
  1193. get_two(tree, res1, res2)
  1194. NODE *tree, **res1, **res2;
  1195. {
  1196.    if (!tree)
  1197.    {
  1198.       *res1 = WHOLELINE;
  1199.       return;
  1200.    }
  1201. #ifndef FAST
  1202.    if (tree->type != Node_expression_list)
  1203.       abort();
  1204. #endif
  1205.    *res1 = tree_eval(tree->lnode);
  1206.    if (!tree->rnode)
  1207.       return;
  1208.    tree = tree->rnode;
  1209. #ifndef FAST
  1210.    if (tree->type != Node_expression_list)
  1211.       abort();
  1212. #endif
  1213.    *res2 = tree_eval(tree->lnode);
  1214. }
  1215.  
  1216. get_three(tree, res1, res2, res3)
  1217. NODE *tree, **res1, **res2, **res3;
  1218. {
  1219.    if (!tree)
  1220.    {
  1221.       *res1 = WHOLELINE;
  1222.       return 0;
  1223.    }
  1224. #ifndef FAST
  1225.    if (tree->type != Node_expression_list)
  1226.       abort();
  1227. #endif
  1228.    *res1 = tree_eval(tree->lnode);
  1229.    if (!tree->rnode)
  1230.       return 1;
  1231.    tree = tree->rnode;
  1232. #ifndef FAST
  1233.    if (tree->type != Node_expression_list)
  1234.       abort();
  1235. #endif
  1236.    *res2 = tree_eval(tree->lnode);
  1237.    if (!tree->rnode)
  1238.       return 2;
  1239.    tree = tree->rnode;
  1240. #ifndef FAST
  1241.    if (tree->type != Node_expression_list)
  1242.       abort();
  1243. #endif
  1244.    *res3 = tree_eval(tree->lnode);
  1245.    return 3;
  1246. }
  1247.  
  1248. a_get_three(tree, res1, res2, res3)
  1249. NODE *tree, **res1, **res2, **res3;
  1250. {
  1251.    if (!tree)
  1252.    {
  1253.       *res1 = WHOLELINE;
  1254.       return 0;
  1255.    }
  1256. #ifndef FAST
  1257.    if (tree->type != Node_expression_list)
  1258.       abort();
  1259. #endif
  1260.    *res1 = tree_eval(tree->lnode);
  1261.    if (!tree->rnode)
  1262.       return 1;
  1263.    tree = tree->rnode;
  1264. #ifndef FAST
  1265.    if (tree->type != Node_expression_list)
  1266.       abort();
  1267. #endif
  1268.    *res2 = tree->lnode;
  1269.    if (!tree->rnode)
  1270.       return 2;
  1271.    tree = tree->rnode;
  1272. #ifndef FAST
  1273.    if (tree->type != Node_expression_list)
  1274.       abort();
  1275. #endif
  1276.    *res3 = tree_eval(tree->lnode);
  1277.    return 3;
  1278. }
  1279.  
  1280. /* special get_three for do_sub and do_gsub. -ade- */
  1281.  
  1282. b_get_three(tree, res1, res2, res3)
  1283. NODE *tree, **res1, **res2, **res3;
  1284. {
  1285.    if (!tree)
  1286.    {
  1287.       *res1 = WHOLELINE;
  1288.       return 0;
  1289.    }
  1290. #ifndef FAST
  1291.    if (tree->type != Node_expression_list)
  1292.       abort();
  1293. #endif
  1294.    *res1 = tree_eval(tree->lnode);
  1295.    if (!tree->rnode)
  1296.       return 1;
  1297.    tree = tree->rnode;
  1298. #ifndef FAST
  1299.    if (tree->type != Node_expression_list)
  1300.       abort();
  1301. #endif
  1302.    *res2 = tree_eval(tree->lnode);
  1303.    if (!tree->rnode)
  1304.       return 2;
  1305.    tree = tree->rnode;
  1306. #ifndef FAST
  1307.    if (tree->type != Node_expression_list)
  1308.       abort();
  1309. #endif
  1310.    *res3 = tree->lnode;
  1311.    return 3;
  1312. }
  1313.  
  1314. /*
  1315.  * FOO this should re-allocate the buffer if it isn't big enough. Also, it should do RMS style only-parse-enough stuff. 
  1316.  */
  1317. /* This reads in a line from the input file */
  1318.  
  1319. /*
  1320.  * This used to do field parsing, that was broken off into its own * function for do_getline.  Note that inrec also takes two
  1321.  * parameters * now.  One is passed to parse_fields (type) and one specifies the * file to read from. -ADE- 
  1322.  */
  1323. inrec(type, in_file)
  1324. int type;
  1325. FILE *in_file;
  1326. {
  1327.    static char *buf, *buf_end;
  1328.    static bsz;
  1329.    register char *cur;
  1330.    register char *tmp;
  1331.    register char *ttmp;
  1332.    int cnt;
  1333.    int tcnt;
  1334.    register int c;
  1335.    int rs;
  1336.    int fs;
  1337.    NODE **get_lhs();
  1338.  
  1339.    rs = get_rs();
  1340.    if (!inrecbuf)
  1341.    {
  1342.       inrecbuf = malloc(128);
  1343.       bsz = 128;
  1344.       buf_end = buf + bsz;
  1345.    }
  1346.    buf = inrecbuf;
  1347.    cur = buf;
  1348.    cnt = 0;
  1349.    while ((c = getc(in_file)) != EOF)
  1350.    {
  1351.       if ((!rs && c == '\n' && cur[-1] == '\n' && cur != buf) || (c == rs))
  1352.          break;
  1353.       *cur++ = c;
  1354.       cnt++;
  1355.       if (cur == buf_end)
  1356.       {
  1357.          buf = realloc(buf, bsz * 2);
  1358.          cur = buf + bsz;
  1359.          bsz *= 2;
  1360.          buf_end = buf + bsz;
  1361.       }
  1362.    }
  1363.    *cur = '\0';
  1364.    parse_fields(buf, cur, type);
  1365.    if (c == EOF && cnt == 0)
  1366.       return 1;
  1367.    return 0;
  1368. }
  1369.  
  1370. /*
  1371.  * parse_fields does the field parsing. parse_type specifies the extent * of parsing and internal variable setting.  -ADE- 
  1372.  */
  1373. parse_fields(start, end, parse_type)
  1374. char *start, *end;
  1375. int parse_type;
  1376. {
  1377.    static char *buf, *buf_end;
  1378.    static bsz;
  1379.    register char *cur;
  1380.    register char *tmp;
  1381.    register char *ttmp;
  1382.    int cnt;
  1383.    int tcnt, ttmplen, re_val;
  1384.    register int c;
  1385.    int rs;
  1386.    struct re_pattern_buffer *re_fs, *make_regexp();
  1387.    char *fs;
  1388.    NODE **get_lhs();
  1389.  
  1390.    buf = start;
  1391.    cur = end;
  1392.    fs = get_fs();
  1393.    if (parse_type == 0 || parse_type == 2)
  1394.       blank_fields();
  1395.    if (strlen(fs) > 1)
  1396.       re_fs = make_regexp(fs);
  1397.    if (parse_type == 0 || parse_type == 2)
  1398.       NF = 0;
  1399.    cnt = cur - buf;
  1400.    if (parse_type == 0 || parse_type == 2)
  1401.    {
  1402.       set_field(0, buf, cnt);
  1403.       assign_number(&(NF_node->var_value), 0.0);
  1404.    }
  1405.    if (parse_type < 2)
  1406.    {
  1407.       NR++;
  1408.       assign_number(&(NR_node->var_value), 1.0 + force_number(NR_node->var_value));
  1409.       FNR++;
  1410.       assign_number(&(FNR_node->var_value), 1.0 + force_number(FNR_node->var_value));
  1411.    }
  1412.    if (parse_type == 1 || parse_type == 3)
  1413.       return;
  1414.    for (tmp = buf; tmp < cur; tmp++)
  1415.    {
  1416.       if (strlen(fs) > 1)              /* if fs is a string, make into a reg exp -ADE- */
  1417.       {
  1418.          tcnt = 0;
  1419.          ttmp = tmp;
  1420.          ttmplen = strlen(ttmp);
  1421.          re_val = re_search(re_fs, ttmp, ttmplen, 0, ttmplen, &reregs);
  1422.          if (re_val == -1)
  1423.          {
  1424.             tcnt == ttmplen;
  1425.             break;
  1426.          }
  1427.          if (re_val == 0)
  1428.          {
  1429.             tmp += reregs.end[0];
  1430.             continue;
  1431.          }
  1432.          tmp += reregs.end[0];
  1433.          tcnt = reregs.start[0];
  1434.       }
  1435.       else
  1436.       {
  1437.          if (*fs == ' ')
  1438.          {
  1439.             while ((*tmp == ' ' || *tmp == '\t') && tmp < cur)
  1440.                tmp++;
  1441.             if (tmp >= cur)
  1442.                break;
  1443.          }
  1444.          if (*fs == ' ')
  1445.          {
  1446.             tcnt = 0;
  1447.             ttmp = tmp;
  1448.             while (*tmp != ' ' && *tmp != '\t' && tmp < cur)
  1449.             {
  1450.                tmp++;
  1451.                tcnt++;
  1452.             }
  1453.          }
  1454.          else
  1455.          {
  1456.             tcnt = 0;
  1457.             ttmp = tmp;
  1458.             while (*tmp != *fs && tmp < cur)
  1459.             {
  1460.                tmp++;
  1461.                tcnt++;
  1462.             }
  1463.          }
  1464.       }
  1465.       set_field(++NF, ttmp, tcnt);
  1466.    }
  1467.    assign_number(&(NF_node->var_value), (AWKNUM) NF);
  1468. }
  1469.  
  1470. /* Redirection for printf and print commands */
  1471. FILE *deal_redirect(tree)
  1472. NODE *tree;
  1473. {
  1474.    register NODE *tmp;
  1475.    register struct redirect *rp;
  1476.    register char *str;
  1477.    register FILE *fp;
  1478. #ifdef UNIX
  1479.    /* %%% VANDYS: I guess you could run a prog to a file... */
  1480.    FILE *popen();
  1481. #endif
  1482.    int tflag;
  1483.  
  1484.    if (!tree)
  1485.       return stdout;
  1486.    tflag = (tree->type == Node_redirect_pipe) ? 1 : 2;
  1487.    tmp = tree_eval(tree->subnode);
  1488.    for (rp = reds; rp->flag != 0 && rp < &reds[20]; rp++)
  1489.    {                                   /* That limit again */
  1490.       if (rp->flag == tflag && cmp_nodes(rp->value, tmp) == 0)
  1491.          break;
  1492.    }
  1493.    if (rp == &reds[20])
  1494.    {
  1495.       panic("too many redirections", 0);
  1496.       return 0;
  1497.    }
  1498.    if (rp->flag != 0)
  1499.       return rp->fp;
  1500.    rp->flag = tflag;
  1501.    rp->value = dupnode(tmp);
  1502.    str = force_string(tmp)->stptr;
  1503.    switch (tree->type)
  1504.    {
  1505.    case Node_redirect_output:
  1506.       fp = rp->fp = fopen(str, "w");
  1507.       break;
  1508.    case Node_redirect_append:
  1509.       fp = rp->fp = fopen(str, "a");
  1510.       break;
  1511.    case Node_redirect_pipe:
  1512. #ifdef UNIX
  1513.       fp = rp->fp = popen(str, "w");
  1514. #else
  1515.       fp = 0;
  1516. #endif
  1517.       break;
  1518.    }
  1519.    if (fp == 0)
  1520.       panic("can't redirect to '%s'\n", str);
  1521.    rp++;
  1522.    rp->flag = 0;
  1523.    return fp;
  1524. }
  1525.  
  1526. /* Redirection for getline command      -ADE- */
  1527. FILE *deal_redirect_in(tree)
  1528. NODE *tree;
  1529. {
  1530.    register NODE *tmp;
  1531.    register struct redirect *rp;
  1532.    register char *str;
  1533.    extern FILE *input_file;
  1534.    register FILE *fp;
  1535. #ifdef UNIX
  1536.    /* %%% VANDYS: I guess you could run a prog to a file... */
  1537.    FILE *popen();
  1538. #endif
  1539.    int tflag;
  1540.  
  1541.    if (!tree)
  1542.       return input_file;
  1543.    tflag = (tree->type == Node_redirect_pipe) ? 1 : 2;
  1544.    tmp = tree_eval(tree->subnode);
  1545.    for (rp = reds; rp->flag != 0 && rp < &reds[20]; rp++)
  1546.    {                                   /* That limit again */
  1547.       if (rp->flag == tflag && cmp_nodes(rp->value, tmp) == 0)
  1548.          break;
  1549.    }
  1550.    if (rp == &reds[20])
  1551.    {
  1552.       panic("too many redirections", 0);
  1553.       return 0;
  1554.    }
  1555.    if (rp->flag != 0)
  1556.       return rp->fp;
  1557.    rp->flag = tflag;
  1558.    rp->value = dupnode(tmp);
  1559.    str = force_string(tmp)->stptr;
  1560.    switch (tree->type)
  1561.    {
  1562.    case Node_redirect_input:
  1563.       fp = rp->fp = fopen(str, "r");
  1564.       break;
  1565.    case Node_redirect_pipe:
  1566. #ifdef UNIX
  1567.       fp = rp->fp = popen(str, "r");
  1568. #else
  1569.       fp = 0;
  1570. #endif
  1571.       break;
  1572.    }
  1573.    if (fp == 0)
  1574.       panic("can't redirect from '%s'\n", str);
  1575.    rp++;
  1576.    rp->flag = 0;
  1577.    return fp;
  1578. }
  1579.  
  1580. print_simple(tree, fp)
  1581. NODE *tree;
  1582. FILE *fp;
  1583. {
  1584. #ifndef FAST
  1585.    /* Deal with some obscure bugs */
  1586.    if (tree == (NODE *) 0x55000000)
  1587.    {
  1588.       fprintf(fp, "***HUH***");
  1589.       return;
  1590.    }
  1591.    if ((int) tree & 01)
  1592.    {
  1593.       fprintf(fp, "$that's odd$");
  1594.       return;
  1595.    }
  1596. #endif
  1597.    tree = force_string(tree);
  1598.    fwrite(tree->stptr, sizeof(char), tree->stlen, fp);
  1599. }
  1600.  
  1601. #define EXPAND_DEST \
  1602.         {\
  1603.         if ((dst=realloc(dst,dlen*2))==NULL) panic("Memory exhausted");\
  1604.         dlen *= 2;\
  1605.         }
  1606.  
  1607. /*
  1608.  * substitute for a regular expression.  This should allow tagged regular * expressions, but I haven't tested it yet.  -ADE- 
  1609.  */
  1610.  
  1611. char *regsub(source, dest, pattern, dlength)
  1612. char *source;
  1613. char *dest;
  1614. char *pattern;
  1615. int *dlength;
  1616. {
  1617.    register char *src;
  1618.    register char *dst;
  1619.    char c;
  1620.    char *substart, *subend;
  1621.    char *pat;
  1622.    int no, len, dnext, dlen;
  1623.    extern char *strncpy();
  1624.  
  1625.    src = source;
  1626.    dst = dest;
  1627.    pat = pattern;
  1628.    substart = src + reregs.start[0];
  1629.    subend = src + reregs.end[0];
  1630.    dnext = 0;
  1631.    dlen = *dlength;
  1632.    while ((c = *src) != '\0')
  1633.    {
  1634.       if (src++ == substart)
  1635.       {
  1636.          while ((c = *pat++) != '\0')
  1637.          {
  1638.             if (c == '&')
  1639.                no = 0;
  1640.             else if (c == '\\' && '0' <= *pat && *pat <= '9')
  1641.                no = *src++ - '0';
  1642.             else
  1643.                no = -1;
  1644.             if (no < 0)
  1645.             {
  1646.                if (dlen <= dnext)
  1647.                   EXPAND_DEST;
  1648.                dst[dnext++] = c;
  1649.             }
  1650.             else if (reregs.start[no] != -1 && reregs.end[no] != -1)
  1651.             {
  1652.                len = reregs.end[no] - reregs.start[no];
  1653.                if (dlen <= (dnext + len))
  1654.                   EXPAND_DEST;
  1655.                (void) strncpy(dst, source + reregs.start[no], len);
  1656.                dst += len;
  1657.                dnext += len;
  1658.             }
  1659.          }
  1660.          src = subend;
  1661.       }
  1662.       else
  1663.       {
  1664.          if (dlen <= dnext)
  1665.             EXPAND_DEST;
  1666.          dst[dnext++] = c;
  1667.       }
  1668.    }
  1669.    if (dlen <= dnext)
  1670.       EXPAND_DEST;
  1671.    dst[dnext] = '\0';
  1672.    *dlength = dnext;
  1673.    return (dst);
  1674. }
  1675.