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