home *** CD-ROM | disk | FTP | other *** search
/ Shareware Supreme Volume 6 #1 / swsii.zip / swsii / 099 / SH164AS.ZIP / SHELL / SH10.C < prev    next >
C/C++ Source or Header  |  1992-02-28  |  16KB  |  848 lines

  1. /* MS-DOS SHELL - Function Processing
  2.  *
  3.  * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited
  4.  *
  5.  * This code is subject to the following copyright restrictions:
  6.  *
  7.  * 1.  Redistribution and use in source and binary forms are permitted
  8.  *     provided that the above copyright notice is duplicated in the
  9.  *     source form and the copyright notice in file sh6.c is displayed
  10.  *     on entry to the program.
  11.  *
  12.  * 2.  The sources (or parts thereof) or objects generated from the sources
  13.  *     (or parts of sources) cannot be sold under any circumstances.
  14.  *
  15.  *    $Header: C:/SRC/SHELL/RCS/sh10.c 1.5 90/09/11 19:40:46 Ian_Stewartson Exp $
  16.  *
  17.  *    $Log:    sh10.c $
  18.  * Revision 1.5  90/09/11  19:40:46  Ian_Stewartson
  19.  * Fix bug in case printing/deletion in functions
  20.  * 
  21.  * Revision 1.4  90/08/14  23:33:32  MS_user
  22.  * Fix memory bugs - Add Copy function code to code a function tree
  23.  * before it is executed.
  24.  * 
  25.  * Revision 1.3  90/05/31  09:51:06  MS_user
  26.  * Add some signal lockouts to prevent corruption
  27.  * 
  28.  * Revision 1.2  90/04/25  22:34:04  MS_user
  29.  * Fix case in TELIF where then and else parts are not defined
  30.  * 
  31.  * Revision 1.1  90/01/25  13:40:54  MS_user
  32.  * Initial revision
  33.  * 
  34.  */
  35.  
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #include <stdio.h>
  39. #include <process.h>
  40. #include <dos.h>
  41. #include <signal.h>
  42. #include <errno.h>
  43. #include <setjmp.h>
  44. #include <ctype.h>
  45. #include <string.h>
  46. #include <unistd.h>
  47. #include <stdlib.h>
  48. #include <fcntl.h>
  49. #include <limits.h>
  50. #include <dirent.h>
  51. #include "sh.h"
  52.  
  53.  
  54. /* Function declarations */
  55.  
  56. static void    Print_Command (C_Op *);
  57. static void    Print_IO (IO_Actions *);
  58. static void    Print_Case (C_Op *);
  59. static void    Print_IString (char *, int);
  60. static void    Set_Free_ExTree (C_Op *, void (*)(char *));
  61. static void    Set_Free_Command (C_Op *, void (*)(char *));
  62. static void    Set_Free_Case (C_Op *, void (*)(char *));
  63. static C_Op    *Copy_ExTree (C_Op *);
  64. static void    Copy_Command (C_Op *, C_Op *);
  65. static C_Op    *Copy_Case (C_Op *);
  66. static void    Set_ExTree (char *);
  67. static void    Free_ExTree (char *);
  68. static void    *field_dup (void *, size_t);
  69.  
  70. static int    Print_indent;            /* Current indent level    */
  71.  
  72. /*
  73.  * print the execute tree - used for displaying functions
  74.  */
  75.  
  76. void        Print_ExTree (t)
  77. register C_Op    *t;
  78. {
  79.     char        **wp;
  80.  
  81.     if (t == (C_Op *)NULL)
  82.     return;
  83.  
  84. /* Check for start of print */
  85.  
  86.     if (t->type == TFUNC)
  87.     {
  88.     Print_indent = 0;
  89.     v1_puts (*t->words);
  90.     v1a_puts (" ()");
  91.     Print_ExTree (t->left);
  92.     return;
  93.     }
  94.  
  95. /* Otherwise, process the tree and print it */
  96.  
  97.     switch (t->type) 
  98.     {
  99.     case TPAREN:            /* ()            */
  100.     case TCOM:            /* A command process    */
  101.         Print_Command (t);
  102.         return;
  103.  
  104.     case TPIPE:            /* Pipe processing        */
  105.         Print_ExTree (t->left);
  106.         Print_IString ("|\n", 0);
  107.         Print_ExTree (t->right);
  108.         return;
  109.  
  110.     case TLIST:            /* Entries in a for statement    */
  111.         Print_ExTree (t->left);
  112.         Print_ExTree (t->right);
  113.         return;
  114.  
  115.     case TOR:            /* || and &&            */
  116.     case TAND:
  117.         Print_ExTree (t->left);
  118.  
  119.         if (t->right != (C_Op *)NULL)
  120.         {
  121.         Print_IString ((t->type == TAND) ? "&&\n" : "||\n", 0);
  122.         Print_ExTree (t->right);
  123.         }
  124.  
  125.         return;
  126.  
  127.     case TFOR:            /* First part of a for statement*/
  128.         Print_IString ("for ", 0);
  129.         v1_puts (t->str);
  130.  
  131.         if ((wp = t->words) != (char **)NULL)
  132.         {
  133.         v1_puts (" in");
  134.  
  135.         while (*wp != (char *)NULL)
  136.         {
  137.             v1_putc (SP);
  138.             v1_puts (*wp++);
  139.         }
  140.         }
  141.  
  142.         v1_putc (NL);
  143.         Print_IString ("do\n", 1);
  144.         Print_ExTree (t->left);
  145.         Print_IString ("done\n", -1);
  146.         return;
  147.  
  148.     case TWHILE:            /* WHILE and UNTIL functions    */
  149.     case TUNTIL:
  150.         Print_IString ((t->type == TWHILE) ? "while " : "until ", 1);
  151.         Print_ExTree (t->left);
  152.         Print_IString ("do\n", 0);
  153.         Print_ExTree (t->right);
  154.         Print_IString ("done\n", -1);
  155.         return;
  156.  
  157.     case TIF:            /* IF and ELSE IF functions    */
  158.     case TELIF:
  159.         if (t->type == TIF)
  160.         Print_IString ("if\n", 1);
  161.         
  162.         else
  163.         Print_IString ("elif\n", 1);
  164.         
  165.         Print_ExTree (t->left);
  166.  
  167.         if (t->right != (C_Op *)NULL)
  168.         {
  169.         Print_indent -= 1;
  170.         Print_IString ("then\n", 1);
  171.         Print_ExTree (t->right->left);
  172.  
  173.         if (t->right->right != (C_Op *)NULL)
  174.         {
  175.             Print_indent -= 1;
  176.  
  177.             if (t->right->right->type != TELIF)
  178.             Print_IString ("else\n", 1);
  179.  
  180.             Print_ExTree (t->right->right);
  181.         }
  182.         }
  183.  
  184.         if (t->type == TIF)
  185.         Print_IString ("fi\n", -1);
  186.  
  187.         return;
  188.  
  189.     case TCASE:            /* CASE function        */
  190.         Print_IString ("case ", 1);
  191.         v1_puts (t->str);
  192.         v1a_puts (" in");
  193.         Print_Case (t->left);
  194.         Print_IString (" esac\n", -1);
  195.         return;
  196.  
  197.     case TBRACE:            /* {} statement            */
  198.         Print_IString ("{\n", 1);
  199.         if (t->left != (C_Op *)NULL)
  200.         Print_ExTree (t->left);
  201.  
  202.         Print_IString ("}\n", -1);
  203.         return;
  204.     }
  205. }
  206.  
  207. /*
  208.  * Print a command line
  209.  */
  210.  
  211. static void    Print_Command (t)
  212. register C_Op    *t;
  213. {
  214.     char    *cp;
  215.     IO_Actions    **iopp;
  216.     char    **wp = t->words;
  217.     char    **owp = wp;
  218.  
  219.     if (t->type == TCOM) 
  220.     {
  221.     while ((cp = *wp++) != (char *)NULL)
  222.         ;
  223.  
  224.     cp = *wp;
  225.  
  226. /* strip all initial assignments not correct wrt PATH=yyy command  etc */
  227.  
  228.     if ((cp == (char *)NULL) && (t->ioact == (IO_Actions **)NULL))
  229.     {
  230.         Print_IString (null, 0);
  231.  
  232.         while (*owp != (char *)NULL)
  233.         v1a_puts (*(owp++));
  234.  
  235.         return;
  236.     }
  237.     }
  238.  
  239. /* Parenthesis ? */
  240.  
  241.     if (t->type == TPAREN)
  242.     {
  243.     Print_IString ("(\n", 1);
  244.     Print_ExTree (t->left);
  245.     Print_IString (")", -1);
  246.     }
  247.  
  248.     else
  249.     {
  250.     Print_IString (null, 0);
  251.  
  252.     while (*owp != (char *)NULL)
  253.     {
  254.         v1_puts (*owp++);
  255.  
  256.         if (*owp != (char *)NULL)
  257.         v1_putc (SP);
  258.     }
  259.     }
  260.  
  261. /* Set up anyother IO required */
  262.  
  263.     if ((iopp = t->ioact) != (IO_Actions **)NULL) 
  264.     {
  265.     while (*iopp != (IO_Actions *)NULL)
  266.         Print_IO (*iopp++);
  267.     }
  268.  
  269.     v1_putc (NL);
  270. }
  271.  
  272. /*
  273.  * Print the IO re-direction
  274.  */
  275.  
  276. static void        Print_IO (iop)
  277. register IO_Actions    *iop;
  278. {
  279.     int        unit = iop->io_unit;
  280.     static char    *cunit = " x";
  281.  
  282.     if (unit == IODEFAULT)    /* take default */
  283.     unit = (iop->io_flag & (IOREAD | IOHERE)) ? STDIN_FILENO
  284.                           : STDOUT_FILENO;
  285.  
  286. /* Output unit number */
  287.  
  288.     cunit[1] = (char)(unit + '0');
  289.     v1_puts (cunit);
  290.  
  291.     switch (iop->io_flag) 
  292.     {
  293.     case IOHERE:
  294.     case IOHERE | IOXHERE:
  295.         v1_putc ('<');
  296.  
  297.     case IOREAD:
  298.         v1_putc ('<');
  299.         break;
  300.  
  301.     case IOWRITE | IOCAT:
  302.         v1_putc ('>');
  303.  
  304.     case IOWRITE:
  305.         v1_putc ('>');
  306.         break;
  307.  
  308.     case IODUP:
  309.         v1_puts (">&");
  310.         v1_putc (*iop->io_name);
  311.         return;
  312.     }
  313.  
  314.     v1_puts (iop->io_name);
  315. }
  316.  
  317. /*
  318.  * Print out the contents of a case statement
  319.  */
  320.  
  321. static void    Print_Case (t)
  322. C_Op        *t;
  323. {
  324.     register C_Op    *t1;
  325.     register char    **wp;
  326.  
  327.     if (t == (C_Op *)NULL)
  328.     return;
  329.  
  330. /* type - TLIST - go down the left tree first and then processes this level */
  331.  
  332.     if (t->type == TLIST) 
  333.     {
  334.     Print_Case (t->left);
  335.     t1 = t->right;
  336.     }
  337.     
  338.     else
  339.     t1 = t;
  340.  
  341. /* Output the conditions */
  342.  
  343.     Print_IString (null, 0);
  344.  
  345.     for (wp = t1->words; *wp != (char *)NULL;)
  346.     {
  347.     v1_puts (*(wp++));
  348.  
  349.     if (*wp != (char *)NULL)
  350.         v1_puts (" | ");
  351.     }
  352.  
  353.     v1a_puts (" )");
  354.     Print_indent += 1;
  355.  
  356. /* Output the commands */
  357.  
  358.     Print_ExTree (t1->left);
  359.     Print_IString (";;\n", -1);
  360. }
  361.  
  362. /*
  363.  * Print an indented string
  364.  */
  365.  
  366. static void    Print_IString (cp, indent)
  367. char        *cp;
  368. int        indent;
  369. {
  370.     int        i;
  371.  
  372.     if (indent < 0)
  373.     Print_indent += indent;
  374.  
  375.     for (i = 0; i < (Print_indent / 2); i++)
  376.     v1_putc ('\t');
  377.  
  378.     if (Print_indent % 2)
  379.     v1_puts ("    ");
  380.     
  381.     v1_puts (cp);
  382.  
  383.     if (indent > 0)
  384.     Print_indent += indent;
  385. }
  386.  
  387. /*
  388.  * Look up a function in the save tree
  389.  */
  390.  
  391. Fun_Ops        *Fun_Search (name)
  392. char        *name;
  393. {
  394.     Fun_Ops    *fp;
  395.  
  396.     for (fp = fun_list; fp != (Fun_Ops *)NULL; fp = fp->next)
  397.     {
  398.     if (strcmp (*(fp->tree->words), name) == 0)
  399.         return fp;
  400.     }
  401.  
  402.     return (Fun_Ops *)NULL;
  403. }
  404.  
  405. /*
  406.  * Save or delete a function tree
  407.  */
  408.  
  409. void    Save_Function (t, delete_only)
  410. C_Op    *t;
  411. bool    delete_only;            /* True - delete        */
  412. {
  413.     char        *name = *t->words;
  414.     register Fun_Ops    *fp = Fun_Search (name);
  415.     Fun_Ops        *p_fp = (Fun_Ops *)NULL;
  416.     void        (*save_signal)(int);
  417.  
  418. /* Find the entry */
  419.  
  420.     for (fp = fun_list; (fp != (Fun_Ops *)NULL) &&
  421.             (strcmp (*(fp->tree->words), name) != 0);
  422.             p_fp = fp, fp = fp->next);
  423.  
  424. /* Disable signals */
  425.  
  426.     save_signal = signal (SIGINT, SIG_IGN);
  427.  
  428. /* If it already exists, free the tree and delete the entry */
  429.  
  430.     if (fp != (Fun_Ops *)NULL)
  431.     {
  432.     Set_Free_ExTree (fp->tree, Free_ExTree);
  433.  
  434.     if (p_fp == (Fun_Ops *)NULL)
  435.         fun_list = fp->next;
  436.  
  437.     else
  438.         p_fp->next = fp->next;
  439.  
  440.     DELETE (fp);
  441.     }
  442.  
  443. /* Restore signals */
  444.  
  445.     signal (SIGINT, save_signal);
  446.  
  447. /* If delete only - exit */
  448.  
  449.     if (delete_only)
  450.     return;
  451.  
  452. /* Create new entry */
  453.  
  454.     if ((fp = (Fun_Ops *)space (sizeof (Fun_Ops))) == (Fun_Ops *)NULL)
  455.     return;
  456.  
  457. /* Disable signals */
  458.  
  459.     save_signal = signal (SIGINT, SIG_IGN);
  460.  
  461. /* Set up the tree */
  462.  
  463.     setarea ((char *)fp, 0);
  464.     Set_Free_ExTree (t, Set_ExTree);
  465.  
  466.     fp->tree = t;
  467.     fp->next = fun_list;
  468.     fun_list = fp;
  469.  
  470. /* Restore signals */
  471.  
  472.     signal (SIGINT, save_signal);
  473. }
  474.  
  475. /*
  476.  * Set ExTree areas to zero function
  477.  */
  478.  
  479. static void    Set_ExTree (s)
  480. char        *s;
  481. {
  482.     setarea (s, 0);
  483. }
  484.  
  485. /*
  486.  * Free the ExTree function
  487.  */
  488.  
  489. static void    Free_ExTree (s)
  490. char        *s;
  491. {
  492.     DELETE (s);
  493. }
  494.  
  495. /*
  496.  * Set/Free function tree area by recursively processing of tree
  497.  */
  498.  
  499. static void    Set_Free_ExTree (t, func)
  500. C_Op        *t;
  501. void        (*func)(char *);
  502. {
  503.     char        **wp;
  504.  
  505.     if (t == (C_Op *)NULL)
  506.     return;
  507.  
  508. /* Check for start of print */
  509.  
  510.     if (t->type == TFUNC)
  511.     {
  512.     (*func)(*t->words);
  513.     (*func)((char *)t->words);
  514.     Set_Free_ExTree (t->left, func);
  515.     }
  516.  
  517. /* Otherwise, process the tree and print it */
  518.  
  519.     switch (t->type) 
  520.     {
  521.     case TPAREN:            /* ()            */
  522.     case TCOM:            /* A command process    */
  523.         Set_Free_Command (t, func);
  524.         break;
  525.  
  526.     case TPIPE:            /* Pipe processing        */
  527.     case TLIST:            /* Entries in a for statement    */
  528.     case TOR:            /* || and &&            */
  529.     case TAND:
  530.     case TWHILE:            /* WHILE and UNTIL functions    */
  531.     case TUNTIL:
  532.         Set_Free_ExTree (t->left, func);
  533.         Set_Free_ExTree (t->right, func);
  534.         break;
  535.  
  536.     case TFOR:            /* First part of a for statement*/
  537.         (*func)(t->str);
  538.  
  539.         if ((wp = t->words) != (char **)NULL)
  540.         {
  541.         while (*wp != (char *)NULL)
  542.             (*func) (*wp++);
  543.  
  544.         (*func)((char *)t->words);
  545.         }
  546.  
  547.         Set_Free_ExTree (t->left, func);
  548.         break;
  549.  
  550.     case TIF:            /* IF and ELSE IF functions    */
  551.     case TELIF:
  552.         if (t->right != (C_Op *)NULL)
  553.         {
  554.         Set_Free_ExTree (t->right->left, func);
  555.         Set_Free_ExTree (t->right->right, func);
  556.         (*func)((char *)t->right);
  557.         }
  558.  
  559.     case TBRACE:            /* {} statement            */
  560.         Set_Free_ExTree (t->left, func);
  561.         break;
  562.  
  563.     case TCASE:            /* CASE function        */
  564.         (*func)(t->str);
  565.         Set_Free_Case (t->left, func);
  566.         break;
  567.     }
  568.  
  569.     (*func)((char *)t);
  570. }
  571.  
  572. /*
  573.  * Set/Free a command line
  574.  */
  575.  
  576. static void    Set_Free_Command (t, func)
  577. C_Op        *t;
  578. void        (*func)(char *);
  579. {
  580.     IO_Actions    **iopp;
  581.     char    **wp = t->words;
  582.  
  583. /* Parenthesis ? */
  584.  
  585.     if (t->type == TPAREN)
  586.     Set_Free_ExTree (t->left, func);
  587.  
  588.     else
  589.     {
  590.     while (*wp != (char *)NULL)
  591.         (*func)(*wp++);
  592.  
  593.     (*func) ((char *)t->words);
  594.     }
  595.  
  596. /* Process up any IO required */
  597.  
  598.     if ((iopp = t->ioact) != (IO_Actions **)NULL) 
  599.     {
  600.     while (*iopp != (IO_Actions *)NULL)
  601.     {
  602.         (*func)((char *)(*iopp)->io_name);
  603.         (*func)((char *)*iopp);
  604.         iopp++;
  605.     }
  606.  
  607.     (*func)((char *)t->ioact);
  608.     }
  609. }
  610.  
  611. /*
  612.  * Set/Free the contents of a case statement
  613.  */
  614.  
  615. static void    Set_Free_Case (t, func)
  616. C_Op        *t;
  617. void        (*func)(char *);
  618. {
  619.     register C_Op    *t1;
  620.     register char    **wp;
  621.  
  622.     if (t == (C_Op *)NULL)
  623.     return;
  624.  
  625. /* type - TLIST - go down the left tree first and then processes this level */
  626.  
  627.     if (t->type == TLIST) 
  628.     {
  629.     Set_Free_Case (t->left, func);
  630.     (*func)((char *)t->left);
  631.     t1 = t->right;
  632.     }
  633.     
  634.     else
  635.     t1 = t;
  636.  
  637. /* Set/Free the conditions */
  638.  
  639.     for (wp = t1->words; *wp != (char *)NULL;)
  640.     (*func)(*(wp++));
  641.  
  642.     (*func)((char *)t1->words);
  643.  
  644.     Set_Free_ExTree (t1->left, func);
  645.     
  646.     if (t1 == t->right)
  647.     (*func)((char *)t->right);
  648. }
  649.  
  650. /*
  651.  * Copy function tree area by recursively processing of tree
  652.  */
  653.  
  654. static C_Op    *Copy_ExTree (Old_t)
  655. C_Op        *Old_t;
  656. {
  657.     char    **wp;
  658.     C_Op    *New_t;
  659.     Word_B    *wb = (Word_B *)NULL;
  660.  
  661.     if (Old_t == (C_Op *)NULL)
  662.     return (C_Op *)NULL;
  663.  
  664.     New_t = (C_Op *) field_dup (Old_t, sizeof (C_Op));
  665.  
  666. /* Check for start of print */
  667.  
  668.     if (Old_t->type == TFUNC)
  669.     {
  670.     New_t->words = (char **)getcell (sizeof (char *) * 2);
  671.     *New_t->words = strsave (*Old_t->words, areanum);
  672.     New_t->left = Copy_ExTree (Old_t->left);
  673.     }
  674.  
  675. /* Otherwise, process the tree and print it */
  676.  
  677.     switch (Old_t->type) 
  678.     {
  679.     case TPAREN:            /* ()            */
  680.     case TCOM:            /* A command process    */
  681.         Copy_Command (Old_t, New_t);
  682.         break;
  683.  
  684.     case TPIPE:            /* Pipe processing        */
  685.     case TLIST:            /* Entries in a for statement    */
  686.     case TOR:            /* || and &&            */
  687.     case TAND:
  688.     case TWHILE:            /* WHILE and UNTIL functions    */
  689.     case TUNTIL:
  690.         New_t->left  = Copy_ExTree (Old_t->left);
  691.         New_t->right = Copy_ExTree (Old_t->right);
  692.         break;
  693.  
  694.     case TFOR:            /* First part of a for statement*/
  695.         New_t->str = strsave (Old_t->str, areanum);
  696.  
  697.         if ((wp = Old_t->words) != (char **)NULL)
  698.         {
  699.         while (*wp != (char *)NULL)
  700.             wb = addword (strsave (*(wp++), areanum), wb);
  701.  
  702.         New_t->words = getwords (addword ((char *)NULL, wb));
  703.         }
  704.  
  705.         New_t->left = Copy_ExTree (Old_t->left);
  706.         break;
  707.  
  708.     case TIF:            /* IF and ELSE IF functions    */
  709.     case TELIF:
  710.         if (Old_t->right != (C_Op *)NULL)
  711.         {
  712.         New_t->right = (C_Op *)field_dup (Old_t->right, sizeof (C_Op));
  713.         New_t->right->left  = Copy_ExTree (Old_t->right->left);
  714.         New_t->right->right = Copy_ExTree (Old_t->right->right);
  715.         }
  716.  
  717.     case TBRACE:            /* {} statement            */
  718.         New_t->left = Copy_ExTree (Old_t->left);
  719.         break;
  720.  
  721.     case TCASE:            /* CASE function        */
  722.         New_t->str = strsave (Old_t->str, areanum);
  723.         New_t->left = Copy_Case (Old_t->left);
  724.         break;
  725.     }
  726.  
  727.     return New_t;
  728. }
  729.  
  730. /*
  731.  * Copy a command line
  732.  */
  733.  
  734. static void    Copy_Command (Old_t, New_t)
  735. C_Op        *Old_t, *New_t;
  736. {
  737.     IO_Actions    **iopp;
  738.     char    **wp = Old_t->words;
  739.     Word_B    *wb = (Word_B *)NULL;
  740.     IO_Actions    *iop;
  741.  
  742. /* Parenthesis ? */
  743.  
  744.     if (Old_t->type == TPAREN)
  745.     New_t->left = Copy_ExTree (Old_t->left);
  746.  
  747.     else
  748.     {
  749.     while (*wp != (char *)NULL)
  750.         wb = addword (strsave (*(wp++), areanum), wb);
  751.  
  752.     New_t->words = getwords (addword ((char *)NULL, wb));
  753.     }
  754.  
  755. /* Process up any IO required */
  756.  
  757.     if ((iopp = Old_t->ioact) != (IO_Actions **)NULL) 
  758.     {
  759.     wb = (Word_B *)NULL;
  760.  
  761.     while (*iopp != (IO_Actions *)NULL)
  762.     {
  763.         iop = (IO_Actions *)field_dup (*iopp, sizeof (IO_Actions));
  764.         iop->io_name = strsave ((*iopp)->io_name, areanum);
  765.         wb = addword ((char *)iop, wb);
  766.         ++iopp;
  767.     }
  768.  
  769.      New_t->ioact = (IO_Actions **)getwords (addword ((char *)NULL, wb));
  770.     }
  771. }
  772.  
  773. /*
  774.  * Copy the contents of a case statement
  775.  */
  776.  
  777. static C_Op    *Copy_Case (Old_t)
  778. C_Op        *Old_t;
  779. {
  780.     register C_Op    *Old_t1, *New_t, *New_t1;
  781.     register char    **wp;
  782.     Word_B        *wb = (Word_B *)NULL;
  783.  
  784.     if (Old_t == (C_Op *)NULL)
  785.     return (C_Op *)NULL;
  786.  
  787. /* type - TLIST - go down the left tree first and then processes this level */
  788.  
  789.     New_t = (C_Op *)field_dup (Old_t, sizeof (C_Op));
  790.  
  791.     if (Old_t->type == TLIST) 
  792.     {
  793.     New_t->left  = Copy_Case (Old_t->left);
  794.     New_t->right = (C_Op *)field_dup (Old_t->right, sizeof (C_Op));
  795.     Old_t1         = Old_t->right;
  796.     New_t1         = New_t->right;
  797.     }
  798.     
  799.     else
  800.     {
  801.     New_t1 = New_t;
  802.     Old_t1 = Old_t;
  803.     }
  804.  
  805. /* Duplicate the word block */
  806.  
  807.     wp = Old_t1->words;
  808.  
  809.     while (*wp != (char *)NULL)
  810.     wb = addword (strsave (*(wp++), areanum), wb);
  811.  
  812.     New_t1->words = getwords (addword ((char *)NULL, wb));
  813.     New_t1->left  = Copy_ExTree (Old_t1->left);
  814.     return New_t;
  815. }
  816.  
  817.  
  818. /*
  819.  * Duplicate a field 
  820.  */
  821.  
  822. static void    *field_dup (source, size)
  823. void        *source;
  824. size_t        size;
  825. {
  826.     return memcpy (space (size), source, size);
  827. }
  828.  
  829. /* Duplicate the tree */
  830.  
  831. C_Op        *Copy_Function (Old_t)
  832. C_Op        *Old_t;
  833. {
  834.     int        *save_errpt;
  835.     jmp_buf    new_errpt;
  836.     C_Op    *New_t = (C_Op *)NULL;
  837.  
  838. /* Set up for error handling - like out of space */
  839.  
  840.     save_errpt = e.errpt;
  841.  
  842.     if (setjmp (new_errpt) == 0)
  843.     New_t = Copy_ExTree (Old_t);
  844.  
  845.     e.errpt = save_errpt;
  846.     return New_t; 
  847. }
  848.