home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / NGAWK1.ZIP / AWK3.C < prev    next >
C/C++ Source or Header  |  1988-07-17  |  33KB  |  1,573 lines

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