wined3d: Don't change the draw buffer in IWineD3DDeviceImpl_SetFrontBackBuffers().
[wine] / tools / winedump / msmangle.c
1 /*
2  *  Demangle VC++ symbols into C function prototypes
3  *
4  *  Copyright 2000 Jon Griffiths
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include "winedump.h"
25
26 /* Type for parsing mangled types */
27 typedef struct _compound_type
28 {
29   char  dest_type;
30   int   flags;
31   int   have_qualifiers;
32   char *expression;
33 } compound_type;
34
35
36 /* Initialise a compound type structure */
37 #define INIT_CT(ct) do { memset (&ct, 0, sizeof (ct)); } while (0)
38
39 /* free the memory used by a compound structure */
40 #define FREE_CT(ct) free (ct.expression)
41
42 /* Flags for data types */
43 #define DATA_VTABLE   0x1
44
45 /* Internal functions */
46 static char *demangle_datatype (char **str, compound_type *ct,
47                                 parsed_symbol* sym);
48
49 static char *get_constraints_convention_1 (char **str, compound_type *ct);
50
51 static char *get_constraints_convention_2 (char **str, compound_type *ct);
52
53 static char *get_type_string (const char c, const int constraints);
54
55 static int   get_type_constant (const char c, const int constraints);
56
57 static char *get_pointer_type_string (compound_type *ct,
58                                       const char *expression);
59
60
61 /*******************************************************************
62  *         demangle_symbol
63  *
64  * Demangle a C++ linker symbol into a C prototype
65  */
66 int symbol_demangle (parsed_symbol *sym)
67 {
68   compound_type ct;
69   int is_static = 0, 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;
76
77   assert (globals.do_code);
78   assert (sym && sym->symbol);
79
80   hash++;
81
82   /* MS mangled names always begin with '?' */
83   name = sym->symbol;
84   if (*name++ != '?')
85     return -1;
86
87   if (VERBOSE)
88     puts ("Attempting to demangle symbol");
89
90   /* Then function name or operator code */
91   if (*name == '?')
92   {
93     /* C++ operator code (one character, or two if the first is '_') */
94     switch (*++name)
95     {
96     case '0': function_name = strdup ("ctor"); break;
97     case '1': function_name = strdup ("dtor"); break;
98     case '2': function_name = strdup ("operator_new"); break;
99     case '3': function_name = strdup ("operator_delete"); break;
100     case '4': function_name = strdup ("operator_equals"); break;
101     case '5': function_name = strdup ("operator_shiftright"); break;
102     case '6': function_name = strdup ("operator_shiftleft"); break;
103     case '7': function_name = strdup ("operator_not"); break;
104     case '8': function_name = strdup ("operator_equalsequals"); break;
105     case '9': function_name = strdup ("operator_notequals"); break;
106     case 'A': function_name = strdup ("operator_array"); break;
107     case 'C': function_name = strdup ("operator_dereference"); break;
108     case 'D': function_name = strdup ("operator_multiply"); break;
109     case 'E': function_name = strdup ("operator_plusplus"); break;
110     case 'F': function_name = strdup ("operator_minusminus"); break;
111     case 'G': function_name = strdup ("operator_minus"); break;
112     case 'H': function_name = strdup ("operator_plus"); break;
113     case 'I': function_name = strdup ("operator_address"); break;
114     case 'J': function_name = strdup ("operator_dereferencememberptr"); break;
115     case 'K': function_name = strdup ("operator_divide"); break;
116     case 'L': function_name = strdup ("operator_modulo"); break;
117     case 'M': function_name = strdup ("operator_lessthan"); break;
118     case 'N': function_name = strdup ("operator_lessthanequal"); break;
119     case 'O': function_name = strdup ("operator_greaterthan"); break;
120     case 'P': function_name = strdup ("operator_greaterthanequal"); break;
121     case 'Q': function_name = strdup ("operator_comma"); break;
122     case 'R': function_name = strdup ("operator_functioncall"); break;
123     case 'S': function_name = strdup ("operator_complement"); break;
124     case 'T': function_name = strdup ("operator_xor"); break;
125     case 'U': function_name = strdup ("operator_logicalor"); break;
126     case 'V': function_name = strdup ("operator_logicaland"); break;
127     case 'W': function_name = strdup ("operator_or"); break;
128     case 'X': function_name = strdup ("operator_multiplyequals"); break;
129     case 'Y': function_name = strdup ("operator_plusequals"); break;
130     case 'Z': function_name = strdup ("operator_minusequals"); break;
131     case '_':
132       switch (*++name)
133       {
134       case '0': function_name = strdup ("operator_divideequals"); break;
135       case '1': function_name = strdup ("operator_moduloequals"); break;
136       case '2': function_name = strdup ("operator_shiftrightequals"); break;
137       case '3': function_name = strdup ("operator_shiftleftequals"); break;
138       case '4': function_name = strdup ("operator_andequals"); break;
139       case '5': function_name = strdup ("operator_orequals"); break;
140       case '6': function_name = strdup ("operator_xorequals"); break;
141       case '7': function_name = strdup ("vftable"); data_flags = DATA_VTABLE; break;
142       case '8': function_name = strdup ("vbtable"); data_flags = DATA_VTABLE; break;
143       case '9': function_name = strdup ("vcall"); data_flags = DATA_VTABLE; break;
144       case 'A': function_name = strdup ("typeof"); data_flags = DATA_VTABLE; break;
145       case 'B': function_name = strdup ("local_static_guard"); data_flags = DATA_VTABLE; break;
146       case 'C': function_name = strdup ("string"); data_flags = DATA_VTABLE; break;
147       case 'D': function_name = strdup ("vbase_dtor"); data_flags = DATA_VTABLE; break;
148       case 'E': function_name = strdup ("vector_dtor"); break;
149       case 'G': function_name = strdup ("scalar_dtor"); break;
150       case 'H': function_name = strdup ("vector_ctor_iter"); break;
151       case 'I': function_name = strdup ("vector_dtor_iter"); break;
152       case 'J': function_name = strdup ("vector_vbase_ctor_iter"); break;
153       case 'L': function_name = strdup ("eh_vector_ctor_iter"); break;
154       case 'M': function_name = strdup ("eh_vector_dtor_iter"); break;
155       case 'N': function_name = strdup ("eh_vector_vbase_ctor_iter"); break;
156       case 'O': function_name = strdup ("copy_ctor_closure"); break;
157       case 'S': function_name = strdup ("local_vftable"); data_flags = DATA_VTABLE; break;
158       case 'T': function_name = strdup ("local_vftable_ctor_closure"); break;
159       case 'U': function_name = strdup ("operator_new_vector"); break;
160       case 'V': function_name = strdup ("operator_delete_vector"); break;
161       case 'X': function_name = strdup ("placement_new_closure"); break;
162       case 'Y': function_name = strdup ("placement_delete_closure"); break;
163       default:
164         return -1;
165       }
166       break;
167     default:
168       /* FIXME: Other operators */
169       return -1;
170     }
171     name++;
172   }
173   else
174   {
175     /* Type or function name terminated by '@' */
176     function_name = name;
177     while (*name && *name++ != '@') ;
178     if (!*name)
179       return -1;
180     function_name = str_substring (function_name, name - 1);
181   }
182
183   /* Either a class name, or '@' if the symbol is not a class member */
184   if (*name == '@')
185   {
186     class_name = strdup ("global"); /* Non member function (or a datatype) */
187     name++;
188   }
189   else
190   {
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 -1;
197     }
198     class_name = str_substring (class_name, name - 2); /* Allocates a new string */
199   }
200
201   /* Function/Data type and access level */
202   /* FIXME: why 2 possible letters for each option? */
203   switch(*name++)
204   {
205   /* Data */
206
207   case '0' : /* private static */
208   case '1' : /* protected static */
209   case '2' : /* public static */
210     is_static = 1;
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))
217     {
218       if (VERBOSE)
219         printf ("/*FIXME: %s: unknown data*/\n", sym->symbol);
220       free (function_name);
221       free (class_name);
222       return -1;
223     }
224     sym->flags |= SYM_DATA;
225     sym->argc = 1;
226     sym->arg_name[0] = str_create (5, OUTPUT_UC_DLL_NAME, "_", class_name,
227                                   is_static ? "static_" : "_", function_name);
228     sym->arg_text[0] = str_create (3, ct.expression, " ", sym->arg_name[0]);
229     FREE_CT (ct);
230     free (function_name);
231     free (class_name);
232     return 0;
233
234   case '6' : /* compiler generated static */
235   case '7' : /* compiler generated static */
236     if (data_flags & DATA_VTABLE)
237     {
238       sym->flags |= SYM_DATA;
239       sym->argc = 1;
240       sym->arg_name[0] = str_create (5, OUTPUT_UC_DLL_NAME, "_", class_name,
241                                      "_", function_name);
242       sym->arg_text[0] = str_create (2, "void *", sym->arg_name[0]);
243
244       if (VERBOSE)
245         puts ("Demangled symbol OK [vtable]");
246       free (function_name);
247       free (class_name);
248       return 0;
249     }
250     free (function_name);
251     free (class_name);
252     return -1;
253
254   /* Functions */
255
256   case 'E' : /* private virtual */
257   case 'F' : /* private virtual */
258   case 'M' : /* protected virtual */
259   case 'N' : /* protected virtual */
260   case 'U' : /* public virtual */
261   case 'V' : /* public virtual */
262     /* Virtual functions need to be added to the exported vtable: report */
263     if (VERBOSE)
264       printf ("/*FIXME %s: %s::%s is virtual-add to vftable*/\n", sym->symbol,
265               class_name, function_name);
266     /* Fall through */
267   case 'A' : /* private */
268   case 'B' : /* private */
269   case 'I' : /* protected */
270   case 'J' : /* protected */
271   case 'Q' : /* public */
272   case 'R' : /* public */
273     /* Implicit 'this' pointer */
274     sym->arg_text [sym->argc] = str_create (3, "struct ", class_name, " *");
275     sym->arg_type [sym->argc] = ARG_POINTER;
276     sym->arg_flag [sym->argc] = 0;
277     sym->arg_name [sym->argc++] = strdup ("_this");
278     /* New struct definitions can be 'grep'ed out for making a fixup header */
279     if (VERBOSE)
280       printf ("struct %s { void **vtable; /*FIXME: class definition */ };\n", class_name);
281     break;
282   case 'C' : /* private: static */
283   case 'D' : /* private: static */
284   case 'K' : /* protected: static */
285   case 'L' : /* protected: static */
286   case 'S' : /* public: static */
287   case 'T' : /* public: static */
288     is_static = 1; /* No implicit this pointer */
289     break;
290   case 'Y' :
291   case 'Z' :
292     break;
293   /* FIXME: G,H / O,P / W,X are private / protected / public thunks */
294   default:
295     free (function_name);
296     free (class_name);
297     return -1;
298   }
299
300   /* If there is an implicit this pointer, const status follows */
301   if (sym->argc)
302   {
303    switch (*name++)
304    {
305    case 'A': break; /* non-const */
306    case 'B': is_const = CT_CONST; break;
307    case 'C': is_const = CT_VOLATILE; break;
308    case 'D': is_const = (CT_CONST | CT_VOLATILE); break;
309    default:
310     free (function_name);
311     free (class_name);
312      return -1;
313    }
314   }
315
316   /* Next is the calling convention */
317   switch (*name++)
318   {
319   case 'A': /* __cdecl */
320   case 'B': /* __cdecl __declspec(dllexport) */
321     if (!sym->argc)
322     {
323       sym->flags |= SYM_CDECL;
324       break;
325     }
326     /* Else fall through */
327   case 'C': /* __pascal */
328   case 'D': /* __pascal __declspec(dllexport) */
329   case 'E': /* __thiscall */
330   case 'F': /* __thiscall __declspec(dllexport) */
331   case 'G': /* __stdcall */
332   case 'H': /* __stdcall __declspec(dllexport) */
333   case 'I': /* __fastcall */
334   case 'J': /* __fastcall __declspec(dllexport)*/
335   case 'K': /* default (none given) */
336     if (sym->argc)
337       sym->flags |= SYM_THISCALL;
338     else
339       sym->flags |= SYM_STDCALL;
340     break;
341   default:
342     free (function_name);
343     free (class_name);
344     return -1;
345   }
346
347   /* Return type, or @ if 'void' */
348   if (*name == '@')
349   {
350     sym->return_text = strdup ("void");
351     sym->return_type = ARG_VOID;
352     name++;
353   }
354   else
355   {
356     INIT_CT (ct);
357     if (!demangle_datatype (&name, &ct, sym)) {
358       free (function_name);
359       free (class_name);
360       return -1;
361     }
362     sym->return_text = ct.expression;
363     sym->return_type = get_type_constant(ct.dest_type, ct.flags);
364     ct.expression = NULL;
365     FREE_CT (ct);
366   }
367
368   /* Now come the function arguments */
369   while (*name && *name != 'Z')
370   {
371     /* Decode each data type and append it to the argument list */
372     if (*name != '@')
373     {
374       INIT_CT (ct);
375       if (!demangle_datatype(&name, &ct, sym)) {
376         free (function_name);
377         free (class_name);
378         return -1;
379       }
380
381       if (strcmp (ct.expression, "void"))
382       {
383         sym->arg_text [sym->argc] = ct.expression;
384         ct.expression = NULL;
385         sym->arg_type [sym->argc] = get_type_constant (ct.dest_type, ct.flags);
386         sym->arg_flag [sym->argc] = ct.flags;
387         sym->arg_name[sym->argc] = str_create_num (1, sym->argc, "arg");
388         sym->argc++;
389       }
390       else
391         break; /* 'void' terminates an argument list */
392       FREE_CT (ct);
393     }
394     else
395       name++;
396   }
397
398   while (*name == '@')
399     name++;
400
401   /* Functions are always terminated by 'Z'. If we made it this far and
402    * Don't find it, we have incorrectly identified a data type.
403    */
404   if (*name != 'Z') {
405     free (function_name);
406     free (class_name);
407     return -1;
408   }
409
410   /* Note: '()' after 'Z' means 'throws', but we don't care here */
411
412   /* Create the function name. Include a unique number because otherwise
413    * overloaded functions could have the same c signature.
414    */
415   switch (is_const)
416   {
417   case (CT_CONST | CT_VOLATILE): const_status = "_const_volatile"; break;
418   case CT_CONST: const_status = "_const"; break;
419   case CT_VOLATILE: const_status = "_volatile"; break;
420   default: const_status = "_"; break;
421   }
422   sym->function_name = str_create_num (4, hash, class_name, "_",
423        function_name, is_static ? "_static" : const_status);
424
425   assert (sym->return_text);
426   assert (sym->flags);
427   assert (sym->function_name);
428
429   free (class_name);
430   free (function_name);
431
432   if (VERBOSE)
433     puts ("Demangled symbol OK");
434
435   return 0;
436 }
437
438
439 /*******************************************************************
440  *         demangle_datatype
441  *
442  * Attempt to demangle a C++ data type, which may be compound.
443  * a compound type is made up of a number of simple types. e.g:
444  * char** = (pointer to (pointer to (char)))
445  *
446  * Uses a simple recursive descent algorithm that is broken
447  * and/or incomplete, without a doubt ;-)
448  */
449 static char *demangle_datatype (char **str, compound_type *ct,
450                                 parsed_symbol* sym)
451 {
452   char *iter;
453
454   assert (str && *str);
455   assert (ct);
456
457   iter = *str;
458
459   if (!get_constraints_convention_1 (&iter, ct))
460     return NULL;
461
462   if (*iter == '_')
463   {
464     /* MS type: __int8,__int16 etc */
465     ct->flags |= CT_EXTENDED;
466     iter++;
467   }
468
469   switch (*iter)
470   {
471     case 'C': case 'D': case 'E': case 'F': case 'G':
472     case 'H': case 'I': case 'J': case 'K': case 'M':
473     case 'N': case 'O': case 'X': case 'Z':
474       /* Simple data types */
475       ct->dest_type = *iter++;
476       if (!get_constraints_convention_2 (&iter, ct))
477         return NULL;
478       ct->expression = get_type_string (ct->dest_type, ct->flags);
479       break;
480     case 'U':
481     case 'V':
482       /* Class/struct/union */
483       ct->dest_type = *iter++;
484       if (*iter == '0' || *iter == '1')
485       {
486         /* Referring to class type (implicit 'this') */
487         char *stripped;
488         if (!sym->argc)
489           return NULL;
490
491         iter++;
492         /* Apply our constraints to the base type (struct xxx *) */
493         stripped = strdup (sym->arg_text [0]);
494         if (!stripped)
495           fatal ("Out of Memory");
496
497         /* If we're a reference, re-use the pointer already in the type */
498         if (!(ct->flags & CT_BY_REFERENCE))
499           stripped[ strlen (stripped) - 2] = '\0'; /* otherwise, strip it */
500
501         ct->expression = str_create (2, ct->flags & CT_CONST ? "const " :
502                          ct->flags & CT_VOLATILE ? "volatile " : "", stripped);
503         free (stripped);
504       }
505       else if (*iter != '@')
506       {
507         /* The name of the class/struct, followed by '@@' */
508         char *struct_name = iter;
509         while (*iter && *iter++ != '@') ;
510         if (*iter++ != '@')
511           return NULL;
512         struct_name = str_substring (struct_name, iter - 2);
513         ct->expression = str_create (4, ct->flags & CT_CONST ? "const " :
514                          ct->flags & CT_VOLATILE ? "volatile " : "", "struct ",
515                          struct_name, ct->flags & CT_BY_REFERENCE ? " *" : "");
516         free (struct_name);
517       }
518       break;
519     case 'Q': /* FIXME: Array Just treated as pointer currently  */
520     case 'P': /* Pointer */
521       {
522         compound_type sub_ct;
523         INIT_CT (sub_ct);
524
525         ct->dest_type = *iter++;
526         if (!get_constraints_convention_2 (&iter, ct))
527           return NULL;
528
529         /* FIXME: P6 = Function pointer, others who knows.. */
530         if (isdigit (*iter))
531         {
532           if (*iter == '6')
533           {
534               int sub_expressions = 0;
535               /* FIXME: there are a tons of memory leaks here */
536               /* FIXME: this is still broken in some cases and it has to be
537                * merged with the function prototype parsing above...
538                */
539               iter += iter[1] == 'A' ? 2 : 3; /* FIXME */
540               if (!demangle_datatype (&iter, &sub_ct, sym))
541                   return NULL;
542               ct->expression = str_create(2, sub_ct.expression, " (*)(");
543               if (*iter != '@')
544               {
545                   while (*iter != 'Z')
546                   {
547                       FREE_CT (sub_ct);
548                       INIT_CT (sub_ct);
549                       if (!demangle_datatype (&iter, &sub_ct, sym))
550                           return NULL;
551                       if (sub_expressions)
552                               ct->expression = str_create(3, ct->expression, ", ", sub_ct.expression);
553                       else
554                               ct->expression = str_create(2, ct->expression, sub_ct.expression);
555                       while (*iter == '@') iter++;
556                       sub_expressions++;
557                   }
558               } else while (*iter == '@') iter++;
559               iter++;
560               ct->expression = str_create(2, ct->expression, ")");
561           }
562           else
563               return NULL;
564         }
565         else
566         {
567             /* Recurse to get the pointed-to type */
568             if (!demangle_datatype (&iter, &sub_ct, sym))
569                 return NULL;
570
571             ct->expression = get_pointer_type_string (ct, sub_ct.expression);
572         }
573
574         FREE_CT (sub_ct);
575       }
576       break;
577     case '0': case '1': case '2': case '3': case '4':
578     case '5': case '6': case '7': case '8': case '9':
579       /* Referring back to previously parsed type */
580       if (sym->argc >= (size_t)('0' - *iter))
581         return NULL;
582       ct->dest_type = sym->arg_type ['0' - *iter];
583       ct->expression = strdup (sym->arg_text ['0' - *iter]);
584       iter++;
585       break;
586     default :
587       return NULL;
588   }
589   if (!ct->expression)
590     return NULL;
591
592   return (char *)(*str = iter);
593 }
594
595
596 /* Constraints:
597  * There are two conventions for specifying data type constants. I
598  * don't know how the compiler chooses between them, but I suspect it
599  * is based on ensuring that linker names are unique.
600  * Convention 1. The data type modifier is given first, followed
601  *   by the data type it operates on. '?' means passed by value,
602  *   'A' means passed by reference. Note neither of these characters
603  *   is a valid base data type. This is then followed by a character
604  *   specifying constness or volatility.
605  * Convention 2. The base data type (which is never '?' or 'A') is
606  *   given first. The character modifier is optionally given after
607  *   the base type character. If a valid character modifier is present,
608  *   then it only applies to the current data type if the character
609  *   after that is not 'A' 'B' or 'C' (Because this makes a convention 1
610  *   constraint for the next data type).
611  *
612  * The conventions are usually mixed within the same symbol.
613  * Since 'C' is both a qualifier and a data type, I suspect that
614  * convention 1 allows specifying e.g. 'volatile signed char*'. In
615  * convention 2 this would be 'CC' which is ambiguous (i.e. Is it two
616  * pointers, or a single pointer + modifier?). In convention 1 it
617  * is encoded as '?CC' which is not ambiguous. This probably
618  * holds true for some other types as well.
619  */
620
621 /*******************************************************************
622  *         get_constraints_convention_1
623  *
624  * Get type constraint information for a data type
625  */
626 static char *get_constraints_convention_1 (char **str, compound_type *ct)
627 {
628   char *iter = *str, **retval = str;
629
630   if (ct->have_qualifiers)
631     return (char *)*str; /* Previously got constraints for this type */
632
633   if (*iter == '?' || *iter == 'A')
634   {
635     ct->have_qualifiers = 1;
636     ct->flags |= (*iter++ == '?' ? 0 : CT_BY_REFERENCE);
637
638     switch (*iter++)
639     {
640     case 'A' :
641       break; /* non-const, non-volatile */
642     case 'B' :
643       ct->flags |= CT_CONST;
644       break;
645     case 'C' :
646       ct->flags |= CT_VOLATILE;
647       break;
648     default  :
649       return NULL;
650     }
651   }
652
653   return (char *)(*retval = iter);
654 }
655
656
657 /*******************************************************************
658  *         get_constraints_convention_2
659  *
660  * Get type constraint information for a data type
661  */
662 static char *get_constraints_convention_2 (char **str, compound_type *ct)
663 {
664   char *iter = *str, **retval = str;
665
666   /* FIXME: Why do arrays have both convention 1 & 2 constraints? */
667   if (ct->have_qualifiers && ct->dest_type != 'Q')
668     return (char *)*str; /* Previously got constraints for this type */
669
670   ct->have_qualifiers = 1; /* Even if none, we've got all we're getting */
671
672   switch (*iter)
673   {
674   case 'A' :
675     if (iter[1] != 'A' && iter[1] != 'B' && iter[1] != 'C')
676       iter++;
677     break;
678   case 'B' :
679     ct->flags |= CT_CONST;
680     iter++;
681     break;
682   case 'C' :
683     /* See note above, if we find 'C' it is _not_ a signed char */
684     ct->flags |= CT_VOLATILE;
685     iter++;
686     break;
687   }
688
689   return (char *)(*retval = iter);
690 }
691
692
693 /*******************************************************************
694  *         get_type_string
695  *
696  * Return a string containing the name of a data type
697  */
698 static char *get_type_string (const char c, const int constraints)
699 {
700   const char *type_string;
701
702   if (constraints & CT_EXTENDED)
703   {
704     switch (c)
705     {
706     case 'D': type_string = "__int8"; break;
707     case 'E': type_string = "unsigned __int8"; break;
708     case 'F': type_string = "__int16"; break;
709     case 'G': type_string = "unsigned __int16"; break;
710     case 'H': type_string = "__int32"; break;
711     case 'I': type_string = "unsigned __int32"; break;
712     case 'J': type_string = "__int64"; break;
713     case 'K': type_string = "unsigned __int64"; break;
714     case 'L': type_string = "__int128"; break;
715     case 'M': type_string = "unsigned __int128"; break;
716     case 'N': type_string = "int"; break; /* bool */
717     case 'W': type_string = "WCHAR"; break; /* wchar_t */
718     default:
719       return NULL;
720    }
721   }
722   else
723   {
724     switch (c)
725     {
726     case 'C': /* Signed char, fall through */
727     case 'D': type_string = "char"; break;
728     case 'E': type_string = "unsigned char"; break;
729     case 'F': type_string = "short int"; break;
730     case 'G': type_string = "unsigned short int"; break;
731     case 'H': type_string = "int"; break;
732     case 'I': type_string = "unsigned int"; break;
733     case 'J': type_string = "long"; break;
734     case 'K': type_string = "unsigned long"; break;
735     case 'M': type_string = "float"; break;
736     case 'N': type_string = "double"; break;
737     case 'O': type_string = "long double"; break;
738     /* FIXME: T = union */
739     case 'U':
740     case 'V': type_string = "struct"; break;
741     case 'X': return strdup ("void");
742     case 'Z': return strdup ("...");
743     default:
744       return NULL;
745    }
746   }
747
748   return str_create (3, constraints & CT_CONST ? "const " :
749                      constraints & CT_VOLATILE ? "volatile " : "", type_string,
750                      constraints & CT_BY_REFERENCE ? " *" : "");
751 }
752
753
754 /*******************************************************************
755  *         get_type_constant
756  *
757  * Get the ARG_* constant for this data type
758  */
759 static int get_type_constant (const char c, const int constraints)
760 {
761   /* Any reference type is really a pointer */
762   if (constraints & CT_BY_REFERENCE)
763      return ARG_POINTER;
764
765   switch (c)
766   {
767   case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I':
768   case 'J': case 'K':
769     return ARG_LONG;
770   case 'M':
771     return ARG_FLOAT;
772   case 'N': case 'O':
773     return ARG_DOUBLE;
774   case 'P': case 'Q':
775     return ARG_POINTER;
776   case 'U': case 'V':
777     return ARG_STRUCT;
778   case 'X':
779     return ARG_VOID;
780   case 'Z':
781   default:
782     return -1;
783   }
784 }
785
786
787 /*******************************************************************
788  *         get_pointer_type_string
789  *
790  * Return a string containing 'pointer to expression'
791  */
792 static char *get_pointer_type_string (compound_type *ct,
793                                       const char *expression)
794 {
795   /* FIXME: set a compound flag for bracketing expression if needed */
796   return str_create (3, ct->flags & CT_CONST ? "const " :
797                      ct->flags & CT_VOLATILE ? "volatile " : "", expression,
798                      ct->flags & CT_BY_REFERENCE ? " **" : " *");
799
800 }