user32/tests: Improve timer measurement method.
[wine.git] / tools / winedump / msmangle.c
blob4408e4181910da307c95ba57aa5bc3ec71fa21d0
1 /*
2 * Demangle VC++ symbols into C function prototypes
4 * Copyright 2000 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include "winedump.h"
25 /* Type for parsing mangled types */
26 typedef struct _compound_type
28 char dest_type;
29 int flags;
30 BOOL have_qualifiers;
31 char *expression;
32 } compound_type;
35 /* Initialise a compound type structure */
36 #define INIT_CT(ct) do { memset (&ct, 0, sizeof (ct)); } while (0)
38 /* free the memory used by a compound structure */
39 #define FREE_CT(ct) free (ct.expression)
41 /* Flags for data types */
42 #define DATA_VTABLE 0x1
44 /* Internal functions */
45 static char *demangle_datatype (char **str, compound_type *ct,
46 parsed_symbol* sym);
48 static char *get_constraints_convention_1 (char **str, compound_type *ct);
50 static char *get_constraints_convention_2 (char **str, compound_type *ct);
52 static char *get_type_string (const char c, const int constraints);
54 static int get_type_constant (const char c, const int constraints);
56 static char *get_pointer_type_string (compound_type *ct,
57 const char *expression);
60 /*******************************************************************
61 * demangle_symbol
63 * Demangle a C++ linker symbol into a C prototype
65 BOOL symbol_demangle (parsed_symbol *sym)
67 compound_type ct;
68 BOOL is_static = FALSE;
69 int is_const = 0;
70 char *function_name = NULL;
71 char *class_name = NULL;
72 char *name;
73 const char *const_status;
74 static unsigned int hash = 0; /* In case of overloaded functions */
75 unsigned int data_flags = 0;
77 assert (globals.do_code);
78 assert (sym && sym->symbol);
80 hash++;
82 /* MS mangled names always begin with '?' */
83 name = sym->symbol;
84 if (*name++ != '?')
85 return FALSE;
87 if (VERBOSE)
88 puts ("Attempting to demangle symbol");
90 /* Then function name or operator code */
91 if (*name == '?')
93 /* C++ operator code (one character, or two if the first is '_') */
94 switch (*++name)
96 case '0': function_name = xstrdup ("ctor"); break;
97 case '1': function_name = xstrdup ("dtor"); break;
98 case '2': function_name = xstrdup ("operator_new"); break;
99 case '3': function_name = xstrdup ("operator_delete"); break;
100 case '4': function_name = xstrdup ("operator_equals"); break;
101 case '5': function_name = xstrdup ("operator_shiftright"); break;
102 case '6': function_name = xstrdup ("operator_shiftleft"); break;
103 case '7': function_name = xstrdup ("operator_not"); break;
104 case '8': function_name = xstrdup ("operator_equalsequals"); break;
105 case '9': function_name = xstrdup ("operator_notequals"); break;
106 case 'A': function_name = xstrdup ("operator_array"); break;
107 case 'C': function_name = xstrdup ("operator_dereference"); break;
108 case 'D': function_name = xstrdup ("operator_multiply"); break;
109 case 'E': function_name = xstrdup ("operator_plusplus"); break;
110 case 'F': function_name = xstrdup ("operator_minusminus"); break;
111 case 'G': function_name = xstrdup ("operator_minus"); break;
112 case 'H': function_name = xstrdup ("operator_plus"); break;
113 case 'I': function_name = xstrdup ("operator_address"); break;
114 case 'J': function_name = xstrdup ("operator_dereferencememberptr"); break;
115 case 'K': function_name = xstrdup ("operator_divide"); break;
116 case 'L': function_name = xstrdup ("operator_modulo"); break;
117 case 'M': function_name = xstrdup ("operator_lessthan"); break;
118 case 'N': function_name = xstrdup ("operator_lessthanequal"); break;
119 case 'O': function_name = xstrdup ("operator_greaterthan"); break;
120 case 'P': function_name = xstrdup ("operator_greaterthanequal"); break;
121 case 'Q': function_name = xstrdup ("operator_comma"); break;
122 case 'R': function_name = xstrdup ("operator_functioncall"); break;
123 case 'S': function_name = xstrdup ("operator_complement"); break;
124 case 'T': function_name = xstrdup ("operator_xor"); break;
125 case 'U': function_name = xstrdup ("operator_logicalor"); break;
126 case 'V': function_name = xstrdup ("operator_logicaland"); break;
127 case 'W': function_name = xstrdup ("operator_or"); break;
128 case 'X': function_name = xstrdup ("operator_multiplyequals"); break;
129 case 'Y': function_name = xstrdup ("operator_plusequals"); break;
130 case 'Z': function_name = xstrdup ("operator_minusequals"); break;
131 case '_':
132 switch (*++name)
134 case '0': function_name = xstrdup ("operator_divideequals"); break;
135 case '1': function_name = xstrdup ("operator_moduloequals"); break;
136 case '2': function_name = xstrdup ("operator_shiftrightequals"); break;
137 case '3': function_name = xstrdup ("operator_shiftleftequals"); break;
138 case '4': function_name = xstrdup ("operator_andequals"); break;
139 case '5': function_name = xstrdup ("operator_orequals"); break;
140 case '6': function_name = xstrdup ("operator_xorequals"); break;
141 case '7': function_name = xstrdup ("vftable"); data_flags = DATA_VTABLE; break;
142 case '8': function_name = xstrdup ("vbtable"); data_flags = DATA_VTABLE; break;
143 case '9': function_name = xstrdup ("vcall"); data_flags = DATA_VTABLE; break;
144 case 'A': function_name = xstrdup ("typeof"); data_flags = DATA_VTABLE; break;
145 case 'B': function_name = xstrdup ("local_static_guard"); data_flags = DATA_VTABLE; break;
146 case 'C': function_name = xstrdup ("string"); data_flags = DATA_VTABLE; break;
147 case 'D': function_name = xstrdup ("vbase_dtor"); data_flags = DATA_VTABLE; break;
148 case 'E': function_name = xstrdup ("vector_dtor"); break;
149 case 'G': function_name = xstrdup ("scalar_dtor"); break;
150 case 'H': function_name = xstrdup ("vector_ctor_iter"); break;
151 case 'I': function_name = xstrdup ("vector_dtor_iter"); break;
152 case 'J': function_name = xstrdup ("vector_vbase_ctor_iter"); break;
153 case 'L': function_name = xstrdup ("eh_vector_ctor_iter"); break;
154 case 'M': function_name = xstrdup ("eh_vector_dtor_iter"); break;
155 case 'N': function_name = xstrdup ("eh_vector_vbase_ctor_iter"); break;
156 case 'O': function_name = xstrdup ("copy_ctor_closure"); break;
157 case 'S': function_name = xstrdup ("local_vftable"); data_flags = DATA_VTABLE; break;
158 case 'T': function_name = xstrdup ("local_vftable_ctor_closure"); break;
159 case 'U': function_name = xstrdup ("operator_new_vector"); break;
160 case 'V': function_name = xstrdup ("operator_delete_vector"); break;
161 case 'X': function_name = xstrdup ("placement_new_closure"); break;
162 case 'Y': function_name = xstrdup ("placement_delete_closure"); break;
163 default:
164 return FALSE;
166 break;
167 default:
168 /* FIXME: Other operators */
169 return FALSE;
171 name++;
173 else
175 /* Type or function name terminated by '@' */
176 function_name = name;
177 while (*name && *name++ != '@') ;
178 if (!*name)
179 return FALSE;
180 function_name = str_substring (function_name, name - 1);
183 /* Either a class name, or '@' if the symbol is not a class member */
184 if (*name == '@')
186 class_name = xstrdup ("global"); /* Non member function (or a datatype) */
187 name++;
189 else
191 /* Class the function is associated with, terminated by '@@' */
192 class_name = name;
193 while (*name && *name++ != '@') ;
194 if (*name++ != '@') {
195 free (function_name);
196 return FALSE;
198 class_name = str_substring (class_name, name - 2); /* Allocates a new string */
201 /* Function/Data type and access level */
202 /* FIXME: why 2 possible letters for each option? */
203 switch(*name++)
205 /* Data */
207 case '0' : /* private static */
208 case '1' : /* protected static */
209 case '2' : /* public static */
210 is_static = TRUE;
211 /* Fall through */
212 case '3' : /* non static */
213 case '4' : /* non static */
214 /* Data members need to be implemented: report */
215 INIT_CT (ct);
216 if (!demangle_datatype (&name, &ct, sym))
218 if (VERBOSE)
219 printf ("/*FIXME: %s: unknown data*/\n", sym->symbol);
220 free (function_name);
221 free (class_name);
222 return FALSE;
224 sym->flags |= SYM_DATA;
225 sym->argc = 1;
226 sym->arg_name[0] = strmake( "%s_%s%s_%s", OUTPUT_UC_DLL_NAME, class_name,
227 is_static ? "static" : "", function_name );
228 sym->arg_text[0] = strmake( "%s %s", ct.expression, sym->arg_name[0] );
229 FREE_CT (ct);
230 free (function_name);
231 free (class_name);
232 return TRUE;
234 case '6' : /* compiler generated static */
235 case '7' : /* compiler generated static */
236 if (data_flags & DATA_VTABLE)
238 sym->flags |= SYM_DATA;
239 sym->argc = 1;
240 sym->arg_name[0] = strmake( "%s_%s_%s", OUTPUT_UC_DLL_NAME, class_name, function_name );
241 sym->arg_text[0] = strmake( "void *%s", sym->arg_name[0] );
243 if (VERBOSE)
244 puts ("Demangled symbol OK [vtable]");
245 free (function_name);
246 free (class_name);
247 return TRUE;
249 free (function_name);
250 free (class_name);
251 return FALSE;
253 /* Functions */
255 case 'E' : /* private virtual */
256 case 'F' : /* private virtual */
257 case 'M' : /* protected virtual */
258 case 'N' : /* protected virtual */
259 case 'U' : /* public virtual */
260 case 'V' : /* public virtual */
261 /* Virtual functions need to be added to the exported vtable: report */
262 if (VERBOSE)
263 printf ("/*FIXME %s: %s::%s is virtual-add to vftable*/\n", sym->symbol,
264 class_name, function_name);
265 /* Fall through */
266 case 'A' : /* private */
267 case 'B' : /* private */
268 case 'I' : /* protected */
269 case 'J' : /* protected */
270 case 'Q' : /* public */
271 case 'R' : /* public */
272 /* Implicit 'this' pointer */
273 sym->arg_text [sym->argc] = strmake( "struct %s *", class_name );
274 sym->arg_type [sym->argc] = ARG_POINTER;
275 sym->arg_flag [sym->argc] = 0;
276 sym->arg_name [sym->argc++] = xstrdup ("_this");
277 /* New struct definitions can be 'grep'ed out for making a fixup header */
278 if (VERBOSE)
279 printf ("struct %s { void **vtable; /*FIXME: class definition */ };\n", class_name);
280 break;
281 case 'C' : /* private: static */
282 case 'D' : /* private: static */
283 case 'K' : /* protected: static */
284 case 'L' : /* protected: static */
285 case 'S' : /* public: static */
286 case 'T' : /* public: static */
287 is_static = TRUE; /* No implicit this pointer */
288 break;
289 case 'Y' :
290 case 'Z' :
291 break;
292 /* FIXME: G,H / O,P / W,X are private / protected / public thunks */
293 default:
294 free (function_name);
295 free (class_name);
296 return FALSE;
299 /* If there is an implicit this pointer, const status follows */
300 if (sym->argc)
302 switch (*name++)
304 case 'A': break; /* non-const */
305 case 'B': is_const = CT_CONST; break;
306 case 'C': is_const = CT_VOLATILE; break;
307 case 'D': is_const = (CT_CONST | CT_VOLATILE); break;
308 default:
309 free (function_name);
310 free (class_name);
311 return FALSE;
315 /* Next is the calling convention */
316 switch (*name++)
318 case 'A': /* __cdecl */
319 case 'B': /* __cdecl __declspec(dllexport) */
320 if (!sym->argc)
322 sym->flags |= SYM_CDECL;
323 break;
325 /* Else fall through */
326 case 'C': /* __pascal */
327 case 'D': /* __pascal __declspec(dllexport) */
328 case 'E': /* __thiscall */
329 case 'F': /* __thiscall __declspec(dllexport) */
330 case 'G': /* __stdcall */
331 case 'H': /* __stdcall __declspec(dllexport) */
332 case 'I': /* __fastcall */
333 case 'J': /* __fastcall __declspec(dllexport)*/
334 case 'K': /* default (none given) */
335 if (sym->argc)
336 sym->flags |= SYM_THISCALL;
337 else
338 sym->flags |= SYM_STDCALL;
339 break;
340 default:
341 free (function_name);
342 free (class_name);
343 return FALSE;
346 /* Return type, or @ if 'void' */
347 if (*name == '@')
349 sym->return_text = xstrdup ("void");
350 sym->return_type = ARG_VOID;
351 name++;
353 else
355 INIT_CT (ct);
356 if (!demangle_datatype (&name, &ct, sym)) {
357 free (function_name);
358 free (class_name);
359 return FALSE;
361 sym->return_text = ct.expression;
362 sym->return_type = get_type_constant(ct.dest_type, ct.flags);
363 ct.expression = NULL;
364 FREE_CT (ct);
367 /* Now come the function arguments */
368 while (*name && *name != 'Z')
370 /* Decode each data type and append it to the argument list */
371 if (*name != '@')
373 INIT_CT (ct);
374 if (!demangle_datatype(&name, &ct, sym)) {
375 free (function_name);
376 free (class_name);
377 return FALSE;
380 if (strcmp (ct.expression, "void"))
382 sym->arg_text [sym->argc] = ct.expression;
383 ct.expression = NULL;
384 sym->arg_type [sym->argc] = get_type_constant (ct.dest_type, ct.flags);
385 sym->arg_flag [sym->argc] = ct.flags;
386 sym->arg_name[sym->argc] = strmake( "arg%u", sym->argc );
387 sym->argc++;
389 else
390 break; /* 'void' terminates an argument list */
391 FREE_CT (ct);
393 else
394 name++;
397 while (*name == '@')
398 name++;
400 /* Functions are always terminated by 'Z'. If we made it this far and
401 * Don't find it, we have incorrectly identified a data type.
403 if (*name != 'Z') {
404 free (function_name);
405 free (class_name);
406 return FALSE;
409 /* Note: '()' after 'Z' means 'throws', but we don't care here */
411 /* Create the function name. Include a unique number because otherwise
412 * overloaded functions could have the same c signature.
414 switch (is_const)
416 case (CT_CONST | CT_VOLATILE): const_status = "_const_volatile"; break;
417 case CT_CONST: const_status = "_const"; break;
418 case CT_VOLATILE: const_status = "_volatile"; break;
419 default: const_status = "_"; break;
421 sym->function_name = strmake( "%s_%s%s%u", class_name, function_name,
422 is_static ? "_static" : const_status, hash );
424 assert (sym->return_text);
425 assert (sym->flags);
426 assert (sym->function_name);
428 free (class_name);
429 free (function_name);
431 if (VERBOSE)
432 puts ("Demangled symbol OK");
434 return TRUE;
438 /*******************************************************************
439 * demangle_datatype
441 * Attempt to demangle a C++ data type, which may be compound.
442 * a compound type is made up of a number of simple types. e.g:
443 * char** = (pointer to (pointer to (char)))
445 * Uses a simple recursive descent algorithm that is broken
446 * and/or incomplete, without a doubt ;-)
448 static char *demangle_datatype (char **str, compound_type *ct,
449 parsed_symbol* sym)
451 char *iter;
453 assert (str && *str);
454 assert (ct);
456 iter = *str;
458 if (!get_constraints_convention_1 (&iter, ct))
459 return NULL;
461 if (*iter == '_')
463 /* MS type: __int8,__int16 etc */
464 ct->flags |= CT_EXTENDED;
465 iter++;
468 switch (*iter)
470 case 'C': case 'D': case 'E': case 'F': case 'G':
471 case 'H': case 'I': case 'J': case 'K': case 'M':
472 case 'N': case 'O': case 'X': case 'Z':
473 /* Simple data types */
474 ct->dest_type = *iter++;
475 if (!get_constraints_convention_2 (&iter, ct))
476 return NULL;
477 ct->expression = get_type_string (ct->dest_type, ct->flags);
478 break;
479 case 'U':
480 case 'V':
481 /* Class/struct/union */
482 ct->dest_type = *iter++;
483 if (*iter == '0' || *iter == '1')
485 /* Referring to class type (implicit 'this') */
486 char *stripped;
487 if (!sym->argc)
488 return NULL;
490 iter++;
491 /* Apply our constraints to the base type (struct xxx *) */
492 stripped = xstrdup (sym->arg_text [0]);
494 /* If we're a reference, re-use the pointer already in the type */
495 if (!(ct->flags & CT_BY_REFERENCE))
496 stripped[ strlen (stripped) - 2] = '\0'; /* otherwise, strip it */
498 ct->expression = strmake( "%s%s", ct->flags & CT_CONST ? "const " :
499 ct->flags & CT_VOLATILE ? "volatile " : "", stripped);
500 free (stripped);
502 else if (*iter != '@')
504 /* The name of the class/struct, followed by '@@' */
505 char *struct_name = iter;
506 while (*iter && *iter++ != '@') ;
507 if (*iter++ != '@')
508 return NULL;
509 struct_name = str_substring (struct_name, iter - 2);
510 ct->expression = strmake( "%sstruct %s%s", ct->flags & CT_CONST ? "const " :
511 ct->flags & CT_VOLATILE ? "volatile " : "",
512 struct_name, ct->flags & CT_BY_REFERENCE ? " *" : "");
513 free (struct_name);
515 break;
516 case 'Q': /* FIXME: Array Just treated as pointer currently */
517 case 'P': /* Pointer */
519 compound_type sub_ct;
520 INIT_CT (sub_ct);
522 ct->dest_type = *iter++;
523 if (!get_constraints_convention_2 (&iter, ct))
524 return NULL;
526 /* FIXME: P6 = Function pointer, others who knows.. */
527 if (isdigit (*iter))
529 if (*iter == '6')
531 int sub_expressions = 0;
532 /* FIXME: this is still broken in some cases and it has to be
533 * merged with the function prototype parsing above...
535 iter += iter[1] == 'A' ? 2 : 3; /* FIXME */
536 if (!demangle_datatype (&iter, &sub_ct, sym))
537 return NULL;
538 ct->expression = strmake( "%s (*)(", sub_ct.expression );
539 if (*iter != '@')
541 while (*iter != 'Z')
543 FREE_CT (sub_ct);
544 INIT_CT (sub_ct);
545 if (!demangle_datatype (&iter, &sub_ct, sym))
546 return NULL;
547 if (sub_expressions)
548 ct->expression = strmake( "%s, %s", ct->expression, sub_ct.expression );
549 else
550 ct->expression = strmake( "%s%s", ct->expression, sub_ct.expression );
551 while (*iter == '@') iter++;
552 sub_expressions++;
554 } else while (*iter == '@') iter++;
555 iter++;
556 ct->expression = strmake( "%s)", ct->expression );
558 else
559 return NULL;
561 else
563 /* Recurse to get the pointed-to type */
564 if (!demangle_datatype (&iter, &sub_ct, sym))
565 return NULL;
567 ct->expression = get_pointer_type_string (ct, sub_ct.expression);
570 FREE_CT (sub_ct);
572 break;
573 case '0': case '1': case '2': case '3': case '4':
574 case '5': case '6': case '7': case '8': case '9':
575 /* Referring back to previously parsed type */
576 if (sym->argc >= (size_t)(*iter - '0'))
577 return NULL;
578 ct->dest_type = sym->arg_type [*iter - '0'];
579 ct->expression = xstrdup (sym->arg_text [*iter - '0']);
580 iter++;
581 break;
582 default :
583 return NULL;
585 if (!ct->expression)
586 return NULL;
588 return *str = iter;
592 /* Constraints:
593 * There are two conventions for specifying data type constants. I
594 * don't know how the compiler chooses between them, but I suspect it
595 * is based on ensuring that linker names are unique.
596 * Convention 1. The data type modifier is given first, followed
597 * by the data type it operates on. '?' means passed by value,
598 * 'A' means passed by reference. Note neither of these characters
599 * is a valid base data type. This is then followed by a character
600 * specifying constness or volatility.
601 * Convention 2. The base data type (which is never '?' or 'A') is
602 * given first. The character modifier is optionally given after
603 * the base type character. If a valid character modifier is present,
604 * then it only applies to the current data type if the character
605 * after that is not 'A' 'B' or 'C' (Because this makes a convention 1
606 * constraint for the next data type).
608 * The conventions are usually mixed within the same symbol.
609 * Since 'C' is both a qualifier and a data type, I suspect that
610 * convention 1 allows specifying e.g. 'volatile signed char*'. In
611 * convention 2 this would be 'CC' which is ambiguous (i.e. Is it two
612 * pointers, or a single pointer + modifier?). In convention 1 it
613 * is encoded as '?CC' which is not ambiguous. This probably
614 * holds true for some other types as well.
617 /*******************************************************************
618 * get_constraints_convention_1
620 * Get type constraint information for a data type
622 static char *get_constraints_convention_1 (char **str, compound_type *ct)
624 char *iter = *str, **retval = str;
626 if (ct->have_qualifiers)
627 return *str; /* Previously got constraints for this type */
629 if (*iter == '?' || *iter == 'A')
631 ct->have_qualifiers = TRUE;
632 ct->flags |= (*iter++ == '?' ? 0 : CT_BY_REFERENCE);
634 switch (*iter++)
636 case 'A' :
637 break; /* non-const, non-volatile */
638 case 'B' :
639 ct->flags |= CT_CONST;
640 break;
641 case 'C' :
642 ct->flags |= CT_VOLATILE;
643 break;
644 default :
645 return NULL;
649 return *retval = iter;
653 /*******************************************************************
654 * get_constraints_convention_2
656 * Get type constraint information for a data type
658 static char *get_constraints_convention_2 (char **str, compound_type *ct)
660 char *iter = *str, **retval = str;
662 /* FIXME: Why do arrays have both convention 1 & 2 constraints? */
663 if (ct->have_qualifiers && ct->dest_type != 'Q')
664 return *str; /* Previously got constraints for this type */
666 ct->have_qualifiers = TRUE; /* Even if none, we've got all we're getting */
668 switch (*iter)
670 case 'A' :
671 if (iter[1] != 'A' && iter[1] != 'B' && iter[1] != 'C')
672 iter++;
673 break;
674 case 'B' :
675 ct->flags |= CT_CONST;
676 iter++;
677 break;
678 case 'C' :
679 /* See note above, if we find 'C' it is _not_ a signed char */
680 ct->flags |= CT_VOLATILE;
681 iter++;
682 break;
685 return *retval = iter;
689 /*******************************************************************
690 * get_type_string
692 * Return a string containing the name of a data type
694 static char *get_type_string (const char c, const int constraints)
696 const char *type_string;
698 if (constraints & CT_EXTENDED)
700 switch (c)
702 case 'D': type_string = "__int8"; break;
703 case 'E': type_string = "unsigned __int8"; break;
704 case 'F': type_string = "__int16"; break;
705 case 'G': type_string = "unsigned __int16"; break;
706 case 'H': type_string = "__int32"; break;
707 case 'I': type_string = "unsigned __int32"; break;
708 case 'J': type_string = "__int64"; break;
709 case 'K': type_string = "unsigned __int64"; break;
710 case 'L': type_string = "__int128"; break;
711 case 'M': type_string = "unsigned __int128"; break;
712 case 'N': type_string = "int"; break; /* bool */
713 case 'W': type_string = "WCHAR"; break; /* wchar_t */
714 default:
715 return NULL;
718 else
720 switch (c)
722 case 'C': /* Signed char, fall through */
723 case 'D': type_string = "char"; break;
724 case 'E': type_string = "unsigned char"; break;
725 case 'F': type_string = "short int"; break;
726 case 'G': type_string = "unsigned short int"; break;
727 case 'H': type_string = "int"; break;
728 case 'I': type_string = "unsigned int"; break;
729 case 'J': type_string = "long"; break;
730 case 'K': type_string = "unsigned long"; break;
731 case 'M': type_string = "float"; break;
732 case 'N': type_string = "double"; break;
733 case 'O': type_string = "long double"; break;
734 /* FIXME: T = union */
735 case 'U':
736 case 'V': type_string = "struct"; break;
737 case 'X': return xstrdup ("void");
738 case 'Z': return xstrdup ("...");
739 default:
740 return NULL;
744 return strmake( "%s%s%s", constraints & CT_CONST ? "const " :
745 constraints & CT_VOLATILE ? "volatile " : "", type_string,
746 constraints & CT_BY_REFERENCE ? " *" : "" );
750 /*******************************************************************
751 * get_type_constant
753 * Get the ARG_* constant for this data type
755 static int get_type_constant (const char c, const int constraints)
757 /* Any reference type is really a pointer */
758 if (constraints & CT_BY_REFERENCE)
759 return ARG_POINTER;
761 switch (c)
763 case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I':
764 case 'J': case 'K':
765 return ARG_LONG;
766 case 'M':
767 return ARG_FLOAT;
768 case 'N': case 'O':
769 return ARG_DOUBLE;
770 case 'P': case 'Q':
771 return ARG_POINTER;
772 case 'U': case 'V':
773 return ARG_STRUCT;
774 case 'X':
775 return ARG_VOID;
776 case 'Z':
777 default:
778 return -1;
783 /*******************************************************************
784 * get_pointer_type_string
786 * Return a string containing 'pointer to expression'
788 static char *get_pointer_type_string (compound_type *ct,
789 const char *expression)
791 /* FIXME: set a compound flag for bracketing expression if needed */
792 return strmake( "%s%s%s", ct->flags & CT_CONST ? "const " :
793 ct->flags & CT_VOLATILE ? "volatile " : "", expression,
794 ct->flags & CT_BY_REFERENCE ? " **" : " *" );