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