home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / ld / cplus-dem.c next >
Encoding:
C/C++ Source or Header  |  1991-04-30  |  18.3 KB  |  975 lines

  1. /*-
  2.  * This code is derived from software copyrighted by the Free Software
  3.  * Foundation.
  4.  */
  5.  
  6. #ifndef lint
  7. static char sccsid[] = "@(#)cplus-dem.c    5.4 (Berkeley) 4/30/91";
  8. #endif /* not lint */
  9.  
  10. /* Demangler for GNU C++ 
  11.    Copyright (C) 1989 Free Software Foundation, Inc.
  12.    written by James Clark (jjc@jclark.uucp)
  13.    
  14.    This program is free software; you can redistribute it and/or modify
  15.    it under the terms of the GNU General Public License as published by
  16.    the Free Software Foundation; either version 1, or (at your option)
  17.    any later version.
  18.  
  19.    This program is distributed in the hope that it will be useful,
  20.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.    GNU General Public License for more details.
  23.  
  24.    You should have received a copy of the GNU General Public License
  25.    along with this program; if not, write to the Free Software
  26.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  27.  
  28. /* This is for g++ 1.36.1 (November 6 version). It will probably
  29.    require changes for any other version.
  30.  
  31.    Modified for g++ 1.36.2 (November 18 version).  */
  32.  
  33. /* This file exports one function
  34.  
  35.    char *cplus_demangle (const char *name)
  36.    
  37.    If `name' is a mangled function name produced by g++, then
  38.    a pointer to a malloced string giving a C++ representation
  39.    of the name will be returned; otherwise NULL will be returned.
  40.    It is the caller's responsibility to free the string which
  41.    is returned.
  42.  
  43.    For example,
  44.    
  45.    cplus_demangle ("_foo__1Ai")
  46.    
  47.    returns
  48.  
  49.    "A::foo(int)"
  50.  
  51.    This file imports xmalloc and xrealloc, which are like malloc and
  52.    realloc except that they generate a fatal error if there is no
  53.    available memory. */
  54.  
  55. /* #define nounderscore 1 /* define this is names don't start with _ */
  56.  
  57. #include <stdio.h>
  58. #include <ctype.h>
  59.  
  60. #ifdef USG
  61. #include <memory.h>
  62. #include <string.h>
  63. #else
  64. #include <strings.h>
  65. #define memcpy(s1, s2, n) bcopy ((s2), (s1), (n))
  66. #define memcmp(s1, s2, n) bcmp ((s2), (s1), (n))
  67. #define strchr index 
  68. #define strrchr rindex
  69. #endif
  70.  
  71. #ifndef __STDC__
  72. #define const
  73. #endif
  74.  
  75. #ifdef __STDC__
  76. extern char *cplus_demangle (const char *type);
  77. #else
  78. extern char *cplus_demangle ();
  79. #endif
  80.  
  81. #ifdef __STDC__
  82. extern char *xmalloc (int);
  83. extern char *xrealloc (char *, int);
  84. #else
  85. extern char *xmalloc ();
  86. extern char *xrealloc ();
  87. #endif
  88.  
  89. static char **typevec = 0;
  90. static int ntypes = 0;
  91. static int typevec_size = 0;
  92.  
  93. static struct {
  94.   const char *in;
  95.   const char *out;
  96. } optable[] = {
  97.   "new", " new",
  98.   "delete", " delete",
  99.   "ne", "!=",
  100.   "eq", "==",
  101.   "ge", ">=",
  102.   "gt", ">",
  103.   "le", "<=",
  104.   "lt", "<",
  105.   "plus", "+",
  106.   "minus", "-",
  107.   "mult", "*",
  108.   "convert", "+",    /* unary + */
  109.   "negate", "-",    /* unary - */
  110.   "trunc_mod", "%",
  111.   "trunc_div", "/",
  112.   "truth_andif", "&&",
  113.   "truth_orif", "||",
  114.   "truth_not", "!",
  115.   "postincrement", "++",
  116.   "postdecrement", "--",
  117.   "bit_ior", "|",
  118.   "bit_xor", "^",
  119.   "bit_and", "&",
  120.   "bit_not", "~",
  121.   "call", "()",
  122.   "cond", "?:",
  123.   "alshift", "<<",
  124.   "arshift", ">>",
  125.   "component", "->",
  126.   "indirect", "*",
  127.   "method_call", "->()",
  128.   "addr", "&",        /* unary & */
  129.   "array", "[]",
  130.   "nop", "",            /* for operator= */
  131. };
  132.  
  133. /* Beware: these aren't '\0' terminated. */
  134.  
  135. typedef struct {
  136.   char *b;            /* pointer to start of string */
  137.   char *p;            /* pointer after last character */
  138.   char *e;            /* pointer after end of allocated space */
  139. } string;
  140.  
  141. #ifdef __STDC__
  142. static void string_need (string *s, int n);
  143. static void string_delete (string *s);
  144. static void string_init (string *s);
  145. static void string_clear (string *s);
  146. static int string_empty (string *s);
  147. static void string_append (string *p, const char *s);
  148. static void string_appends (string *p, string *s);
  149. static void string_appendn (string *p, const char *s, int n);
  150. static void string_prepend (string *p, const char *s);
  151. #if 0
  152. static void string_prepends (string *p, string *s);
  153. #endif
  154. static void string_prependn (string *p, const char *s, int n);
  155. static int get_count (const char **type, int *count);
  156. static int do_args (const char **type, string *decl);
  157. static int do_type (const char **type, string *result);
  158. static int do_arg (const char **type, string *result);
  159. static int do_args (const char **type, string *decl);
  160. static void munge_function_name (string *name);
  161. static void remember_type (const char *type, int len);
  162. #else
  163. static void string_need ();
  164. static void string_delete ();
  165. static void string_init ();
  166. static void string_clear ();
  167. static int string_empty ();
  168. static void string_append ();
  169. static void string_appends ();
  170. static void string_appendn ();
  171. static void string_prepend ();
  172. static void string_prepends ();
  173. static void string_prependn ();
  174. static int get_count ();
  175. static int do_args ();
  176. static int do_type ();
  177. static int do_arg ();
  178. static int do_args ();
  179. static void munge_function_name ();
  180. static void remember_type ();
  181. #endif
  182.  
  183. char *
  184. cplus_demangle (type)
  185.      const char *type;
  186. {
  187.   string decl;
  188.   int n;
  189.   int success = 0;
  190.   int constructor = 0;
  191.   int const_flag = 0;
  192.   int i;
  193.   const char *p;
  194. #ifndef LONGERNAMES
  195.   const char *premangle;
  196. #endif
  197.  
  198.   if (type == NULL || *type == '\0')
  199.     return NULL;
  200. #ifndef nounderscore
  201.   if (*type++ != '_')
  202.     return NULL;
  203. #endif
  204.   p = type;
  205.   while (*p != '\0' && !(*p == '_' && p[1] == '_'))
  206.     p++;
  207.   if (*p == '\0')
  208.     {
  209.       /* destructor */
  210.       if (type[0] == '_' && type[1] == '$' && type[2] == '_')
  211.     {
  212.       int n = (strlen (type) - 3)*2 + 3 + 2 + 1;
  213.       char *tem = (char *) xmalloc (n);
  214.       strcpy (tem, type + 3);
  215.       strcat (tem, "::~");
  216.       strcat (tem, type + 3);
  217.       strcat (tem, "()");
  218.       return tem;
  219.     }
  220.       /* static data member */
  221.       if (*type != '_' && (p = strchr (type, '$')) != NULL)
  222.     {
  223.       int n = strlen (type) + 2;
  224.       char *tem = (char *) xmalloc (n);
  225.       memcpy (tem, type, p - type);
  226.       strcpy (tem + (p - type), "::");
  227.       strcpy (tem + (p - type) + 2, p + 1);
  228.       return tem;
  229.     }
  230.       /* virtual table */
  231.       if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$')
  232.     {
  233.       int n = strlen (type + 4) + 14 + 1;
  234.       char *tem = (char *) xmalloc (n);
  235.       strcpy (tem, type + 4);
  236.       strcat (tem, " virtual table");
  237.       return tem;
  238.     }
  239.       return NULL;
  240.     }
  241.  
  242.   string_init (&decl);
  243.  
  244.   if (p == type)
  245.     {
  246.       if (!isdigit (p[2]))
  247.     {
  248.       string_delete (&decl);
  249.       return NULL;
  250.     }
  251.       constructor = 1;
  252.     }
  253.   else
  254.     {
  255.       string_appendn (&decl, type, p - type);
  256.       munge_function_name (&decl);
  257.     }
  258.   p += 2;
  259.  
  260. #ifndef LONGERNAMES
  261.   premangle = p;
  262. #endif
  263.   switch (*p)
  264.     {
  265.     case 'C':
  266.       /* a const member function */
  267.       if (!isdigit (p[1]))
  268.     {
  269.       string_delete (&decl);
  270.       return NULL;
  271.     }
  272.       p += 1;
  273.       const_flag = 1;
  274.       /* fall through */
  275.     case '0':
  276.     case '1':
  277.     case '2':
  278.     case '3':
  279.     case '4':
  280.     case '5':
  281.     case '6':
  282.     case '7':
  283.     case '8':
  284.     case '9':
  285.       n = 0;
  286.       do
  287.     {
  288.       n *= 10;
  289.       n += *p - '0';
  290.       p += 1;
  291.     }
  292.       while (isdigit (*p));
  293.       if (strlen (p) < n)
  294.     {
  295.       string_delete (&decl);
  296.       return NULL;
  297.     }
  298.       if (constructor)
  299.     {
  300.       string_appendn (&decl, p, n);
  301.       string_append (&decl, "::");
  302.       string_appendn (&decl, p, n);
  303.     }
  304.       else
  305.     {
  306.       string_prepend (&decl, "::");
  307.       string_prependn (&decl, p, n);
  308.     }
  309.       p += n;
  310. #ifndef LONGERNAMES
  311.       remember_type (premangle, p - premangle);
  312. #endif
  313.       success = do_args (&p, &decl);
  314.       if (const_flag)
  315.     string_append (&decl, " const");
  316.       break;
  317.     case 'F':
  318.       p += 1;
  319.       success = do_args (&p, &decl);
  320.       break;
  321.     }
  322.  
  323.   for (i = 0; i < ntypes; i++)
  324.     if (typevec[i] != NULL)
  325.       free (typevec[i]);
  326.   ntypes = 0;
  327.   if (typevec != NULL)
  328.     {
  329.       free ((char *)typevec);
  330.       typevec = NULL;
  331.       typevec_size = 0;
  332.     }
  333.  
  334.   if (success)
  335.     {
  336.       string_appendn (&decl, "", 1);
  337.       return decl.b;
  338.     }
  339.   else
  340.     {
  341.       string_delete (&decl);
  342.       return NULL;
  343.     }
  344. }
  345.  
  346. static int
  347. get_count (type, count)
  348.      const char **type;
  349.      int *count;
  350. {
  351.   if (!isdigit (**type))
  352.     return 0;
  353.   *count = **type - '0';
  354.   *type += 1;
  355.   /* see flush_repeats in cplus-method.c */
  356.   if (isdigit (**type))
  357.     {
  358.       const char *p = *type;
  359.       int n = *count;
  360.       do 
  361.     {
  362.       n *= 10;
  363.       n += *p - '0';
  364.       p += 1;
  365.     } 
  366.       while (isdigit (*p));
  367.       if (*p == '_')
  368.     {
  369.       *type = p + 1;
  370.       *count = n;
  371.     }
  372.     }
  373.   return 1;
  374. }
  375.  
  376. /* result will be initialised here; it will be freed on failure */
  377.  
  378. static int
  379. do_type (type, result)
  380.      const char **type;
  381.      string *result;
  382. {
  383.   int n;
  384.   int done;
  385.   int non_empty = 0;
  386.   int success;
  387.   string decl;
  388.   const char *remembered_type;
  389.  
  390.   string_init (&decl);
  391.   string_init (result);
  392.  
  393.   done = 0;
  394.   success = 1;
  395.   while (success && !done)
  396.     {
  397.       int member;
  398.       switch (**type)
  399.     {
  400.     case 'P':
  401.       *type += 1;
  402.       string_prepend (&decl, "*");
  403.       break;
  404.  
  405.     case 'R':
  406.       *type += 1;
  407.       string_prepend (&decl, "&");
  408.       break;
  409.  
  410.     case 'T':
  411.       *type += 1;
  412.       if (!get_count (type, &n) || n >= ntypes)
  413.         success = 0;
  414.       else
  415.         {
  416.           remembered_type = typevec[n];
  417.           type = &remembered_type;
  418.         }
  419.       break;
  420.  
  421.     case 'F':
  422.       *type += 1;
  423.       if (!string_empty (&decl) && decl.b[0] == '*')
  424.         {
  425.           string_prepend (&decl, "(");
  426.           string_append (&decl, ")");
  427.         }
  428.       if (!do_args (type, &decl) || **type != '_')
  429.         success = 0;
  430.       else
  431.         *type += 1;
  432.       break;
  433.  
  434.     case 'M':
  435.     case 'O':
  436.       {
  437.         int constp = 0;
  438.         int volatilep = 0;
  439.  
  440.         member = **type == 'M';
  441.         *type += 1;
  442.         if (!isdigit (**type))
  443.           {
  444.         success = 0;
  445.         break;
  446.           }
  447.         n = 0;
  448.         do
  449.           {
  450.         n *= 10;
  451.         n += **type - '0';
  452.         *type += 1;
  453.           } 
  454.         while (isdigit (**type));
  455.         if (strlen (*type) < n)
  456.           {
  457.         success = 0;
  458.         break;
  459.           }
  460.         string_append (&decl, ")");
  461.         string_prepend (&decl, "::");
  462.         string_prependn (&decl, *type, n);
  463.         string_prepend (&decl, "(");
  464.         *type += n;
  465.         if (member)
  466.           {
  467.         if (**type == 'C')
  468.           {
  469.             *type += 1;
  470.             constp = 1;
  471.           }
  472.         if (**type == 'V')
  473.           {
  474.             *type += 1;
  475.             volatilep = 1;
  476.           }
  477.         if (*(*type)++ != 'F')
  478.           {
  479.             success = 0;
  480.             break;
  481.           }
  482.           }
  483.         if ((member && !do_args (type, &decl)) || **type != '_')
  484.           {
  485.         success = 0;
  486.         break;
  487.           }
  488.         *type += 1;
  489.         if (constp)
  490.           {
  491.         if (non_empty)
  492.           string_append (&decl, " ");
  493.         else
  494.           non_empty = 1;
  495.         string_append (&decl, "const");
  496.           }
  497.         if (volatilep)
  498.           {
  499.         if (non_empty)
  500.           string_append (&decl, " ");
  501.         else
  502.           non_empty = 1;
  503.         string_append (&decl, "volatilep");
  504.           }
  505.         break;
  506.       }
  507.  
  508.     case 'C':
  509.       if ((*type)[1] == 'P')
  510.         {
  511.           *type += 1;
  512.           if (!string_empty (&decl))
  513.         string_prepend (&decl, " ");
  514.           string_prepend (&decl, "const");
  515.           break;
  516.         }
  517.  
  518.       /* fall through */
  519.     default:
  520.       done = 1;
  521.       break;
  522.     }
  523.     }
  524.  
  525.   done = 0;
  526.   non_empty = 0;
  527.   while (success && !done)
  528.     {
  529.       switch (**type)
  530.     {
  531.     case 'C':
  532.       *type += 1;
  533.       if (non_empty)
  534.         string_append (result, " ");
  535.       else
  536.         non_empty = 1;
  537.       string_append (result, "const");
  538.       break;
  539.     case 'U':
  540.       *type += 1;
  541.       if (non_empty)
  542.         string_append (result, " ");
  543.       else
  544.         non_empty = 1;
  545.       string_append (result, "unsigned");
  546.       break;
  547.     case 'V':
  548.       *type += 1;
  549.       if (non_empty)
  550.         string_append (result, " ");
  551.       else
  552.         non_empty = 1;
  553.       string_append (result, "volatile");
  554.       break;
  555.     default:
  556.       done = 1;
  557.       break;
  558.     }
  559.     }
  560.  
  561.   if (success)
  562.     switch (**type)
  563.       {
  564.       case '\0':
  565.       case '_':
  566.     break;
  567.       case 'v':
  568.     *type += 1;
  569.     if (non_empty)
  570.       string_append (result, " ");
  571.     string_append (result, "void");
  572.     break;
  573.       case 'x':
  574.     *type += 1;
  575.     if (non_empty)
  576.       string_append (result, " ");
  577.     string_append (result, "long long");
  578.     break;
  579.       case 'l':
  580.     *type += 1;
  581.     if (non_empty)
  582.       string_append (result, " ");
  583.     string_append (result, "long");
  584.     break;
  585.       case 'i':
  586.     *type += 1;
  587.     if (non_empty)
  588.       string_append (result, " ");
  589.     string_append (result, "int");
  590.     break;
  591.       case 's':
  592.     *type += 1;
  593.     if (non_empty)
  594.       string_append (result, " ");
  595.     string_append (result, "short");
  596.     break;
  597.       case 'c':
  598.     *type += 1;
  599.     if (non_empty)
  600.       string_append (result, " ");
  601.     string_append (result, "char");
  602.     break;
  603.       case 'r':
  604.     *type += 1;
  605.     if (non_empty)
  606.       string_append (result, " ");
  607.     string_append (result, "long double");
  608.     break;
  609.       case 'd':
  610.     *type += 1;
  611.     if (non_empty)
  612.       string_append (result, " ");
  613.     string_append (result, "double");
  614.     break;
  615.       case 'f':
  616.     *type += 1;
  617.     if (non_empty)
  618.       string_append (result, " ");
  619.     string_append (result, "float");
  620.     break;
  621.       case 'G':
  622.     *type += 1;
  623.     if (!isdigit (**type))
  624.       {
  625.         success = 0;
  626.         break;
  627.       }
  628.     /* fall through */
  629.       case '0':
  630.       case '1':
  631.       case '2':
  632.       case '3':
  633.       case '4':
  634.       case '5':
  635.       case '6':
  636.       case '7':
  637.       case '8':
  638.       case '9':
  639.     n = 0;
  640.     do
  641.       {
  642.         n *= 10;
  643.         n += **type - '0';
  644.         *type += 1;
  645.       }
  646.     while (isdigit (**type));
  647.     if (strlen (*type) < n)
  648.       {
  649.         success = 0;
  650.         break;
  651.       }
  652.     if (non_empty)
  653.       string_append (result, " ");
  654.     string_appendn (result, *type, n);
  655.     *type += n;
  656.     break;
  657.       default:
  658.     success = 0;
  659.     break;
  660.       }
  661.  
  662.   if (success)
  663.     {
  664.       if (!string_empty (&decl))
  665.     {
  666.       string_append (result, " ");
  667.       string_appends (result, &decl);
  668.     }
  669.       string_delete (&decl);
  670.       return 1;
  671.     }
  672.   else
  673.     {
  674.       string_delete (&decl);
  675.       string_delete (result);
  676.       return 0;
  677.     }
  678. }
  679.  
  680. /* `result' will be initialised in do_type; it will be freed on failure */
  681.  
  682. static int
  683. do_arg (type, result)
  684.      const char **type;
  685.      string *result;
  686. {
  687.   const char *start = *type;
  688.  
  689.   if (!do_type (type, result))
  690.     return 0;
  691.   remember_type (start, *type - start);
  692.   return 1;
  693. }
  694.  
  695. static void
  696. remember_type (start, len)
  697.      const char *start;
  698.      int len;
  699. {
  700.   char *tem;
  701.  
  702.   if (ntypes >= typevec_size)
  703.     {
  704.       if (typevec_size == 0)
  705.     {
  706.       typevec_size = 3;
  707.       typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
  708.     }
  709.       else
  710.     {
  711.       typevec_size *= 2;
  712.       typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
  713.     }
  714.     }
  715.   tem = (char *) xmalloc (len + 1);
  716.   memcpy (tem, start, len);
  717.   tem[len] = '\0';
  718.   typevec[ntypes++] = tem;
  719. }
  720.  
  721. /* `decl' must be already initialised, usually non-empty;
  722.    it won't be freed on failure */
  723.  
  724. static int
  725. do_args (type, decl)
  726.      const char **type;
  727.      string *decl;
  728. {
  729.   string arg;
  730.   int need_comma = 0;
  731.  
  732.   string_append (decl, "(");
  733.  
  734.   while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
  735.     {
  736.       if (**type == 'N')
  737.     {
  738.       int r;
  739.       int t;
  740.       *type += 1;
  741.       if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
  742.         return 0;
  743.       while (--r >= 0)
  744.         {
  745.           const char *tem = typevec[t];
  746.           if (need_comma)
  747.         string_append (decl, ", ");
  748.           if (!do_arg (&tem, &arg))
  749.         return 0;
  750.           string_appends (decl, &arg);
  751.           string_delete (&arg);
  752.           need_comma = 1;
  753.         }
  754.     }
  755.       else
  756.     {
  757.       if (need_comma)
  758.         string_append (decl, ", ");
  759.       if (!do_arg (type, &arg))
  760.         return 0;
  761.       string_appends (decl, &arg);
  762.       string_delete (&arg);
  763.       need_comma = 1;
  764.     }
  765.     }
  766.  
  767.   if (**type == 'v')
  768.     *type += 1;
  769.   else if (**type == 'e')
  770.     {
  771.       *type += 1;
  772.       if (need_comma)
  773.     string_append (decl, ",");
  774.       string_append (decl, "...");
  775.     }
  776.  
  777.   string_append (decl, ")");
  778.   return 1;
  779. }
  780.  
  781. static void
  782. munge_function_name (name)
  783.      string *name;
  784. {
  785.   if (!string_empty (name) && name->p - name->b >= 3 
  786.       && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
  787.     {
  788.       int i;
  789.       /* see if it's an assignment expression */
  790.       if (name->p - name->b >= 10 /* op$assign_ */
  791.       && memcmp (name->b + 3, "assign_", 7) == 0)
  792.     {
  793.       for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
  794.         {
  795.           int len = name->p - name->b - 10;
  796.           if (strlen (optable[i].in) == len
  797.           && memcmp (optable[i].in, name->b + 10, len) == 0)
  798.         {
  799.           string_clear (name);
  800.           string_append (name, "operator");
  801.           string_append (name, optable[i].out);
  802.           string_append (name, "=");
  803.           return;
  804.         }
  805.         }
  806.     }
  807.       else
  808.     {
  809.       for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
  810.         {
  811.           int len = name->p - name->b - 3;
  812.           if (strlen (optable[i].in) == len 
  813.           && memcmp (optable[i].in, name->b + 3, len) == 0)
  814.         {
  815.           string_clear (name);
  816.           string_append (name, "operator");
  817.           string_append (name, optable[i].out);
  818.           return;
  819.         }
  820.         }
  821.     }
  822.       return;
  823.     }
  824.   else if (!string_empty (name) && name->p - name->b >= 5
  825.        && memcmp (name->b, "type$", 5) == 0)
  826.     {
  827.       /* type conversion operator */
  828.       string type;
  829.       const char *tem = name->b + 5;
  830.       if (do_type (&tem, &type))
  831.     {
  832.       string_clear (name);
  833.       string_append (name, "operator ");
  834.       string_appends (name, &type);
  835.       string_delete (&type);
  836.       return;
  837.     }
  838.     }
  839. }
  840.  
  841. /* a mini string-handling package */
  842.  
  843. static void
  844. string_need (s, n)
  845.      string *s;
  846.      int n;
  847. {
  848.   if (s->b == NULL)
  849.     {
  850.       if (n < 32)
  851.     n = 32;
  852.       s->p = s->b = (char *) xmalloc (n);
  853.       s->e = s->b + n;
  854.     }
  855.   else if (s->e - s->p < n)
  856.     {
  857.       int tem = s->p - s->b;
  858.       n += tem;
  859.       n *= 2;
  860.       s->b = (char *) xrealloc (s->b, n);
  861.       s->p = s->b + tem;
  862.       s->e = s->b + n;
  863.     }
  864. }
  865.  
  866. static void
  867. string_delete (s)
  868.      string *s;
  869. {
  870.   if (s->b != NULL)
  871.     {
  872.       free (s->b);
  873.       s->b = s->e = s->p = NULL;
  874.     }
  875. }
  876.  
  877. static void
  878. string_init (s)
  879.      string *s;
  880. {
  881.   s->b = s->p = s->e = NULL;
  882. }
  883.  
  884. static void 
  885. string_clear (s)
  886.      string *s;
  887. {
  888.   s->p = s->b;
  889. }
  890.  
  891. static int
  892. string_empty (s)
  893.      string *s;
  894. {
  895.   return s->b == s->p;
  896. }
  897.  
  898. static void
  899. string_append (p, s)
  900.      string *p;
  901.      const char *s;
  902. {
  903.   int n;
  904.   if (s == NULL || *s == '\0')
  905.     return;
  906.   n = strlen (s);
  907.   string_need (p, n);
  908.   memcpy (p->p, s, n);
  909.   p->p += n;
  910. }
  911.  
  912. static void
  913. string_appends (p, s)
  914.      string *p, *s;
  915. {
  916.   int n;
  917.   if (s->b == s->p)
  918.     return;
  919.   n = s->p - s->b;
  920.   string_need (p, n);
  921.   memcpy (p->p, s->b, n);
  922.   p->p += n;
  923. }
  924.  
  925. static void
  926. string_appendn (p, s, n)
  927.      string *p;
  928.      const char *s;
  929.      int n;
  930. {
  931.   if (n == 0)
  932.     return;
  933.   string_need (p, n);
  934.   memcpy (p->p, s, n);
  935.   p->p += n;
  936. }
  937.  
  938. static void
  939. string_prepend (p, s)
  940.      string *p;
  941.      const char *s;
  942. {
  943.   if (s == NULL || *s == '\0')
  944.     return;
  945.   string_prependn (p, s, strlen (s));
  946. }
  947.  
  948. #if 0
  949. static void
  950. string_prepends (p, s)
  951.      string *p, *s;
  952. {
  953.   if (s->b == s->p)
  954.     return;
  955.   string_prependn (p, s->b, s->p - s->b);
  956. }
  957. #endif
  958.  
  959. static void
  960. string_prependn (p, s, n)
  961.      string *p;
  962.      const char *s;
  963.      int n;
  964. {
  965.   char *q;
  966.  
  967.   if (n == 0)
  968.     return;
  969.   string_need (p, n);
  970.   for (q = p->p - 1; q >= p->b; q--)
  971.     q[n] = q[0];
  972.   memcpy (p->b, s, n);
  973.   p->p += n;
  974. }
  975.