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