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