- Update build system to support IOKit and CoreFoundation frameworks
[wine] / tools / winedump / symbol.c
1 /*
2  *  Symbol functions
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include "winedump.h"
25
26
27 /* Items that are swapped in arguments after the symbol structure
28  * has been populated
29  */
30 static const char *swap_after[] =
31 {
32   "\r", " ", /* Remove whitespace, normalise pointers and brackets */
33   "\t", " ",
34   "  ", " ",
35   " * ", " *",
36   "* *", "**",
37   "* ", "*",
38   " ,", ",",
39   "( ", "(",
40   " )", ")",
41   "wchar_t", "WCHAR", /* Help with Unicode compliles */
42   "wctype_t", "WCHAR",
43   "wint_t", "WCHAR",
44   NULL, NULL
45 };
46
47
48 /* Items containing these substrings are assumed to be wide character
49  * strings, unless they contain more that one '*'. A preceeding 'LP'
50  * counts as a '*', so 'LPWCSTR *' is a pointer, not a string
51  */
52 static const char *wide_strings[] =
53 {
54   "WSTR", "WCSTR", NULL
55 };
56
57 /* Items containing these substrings are assumed to be wide characters,
58  * unless they contain one '*'. A preceeding 'LP' counts as a '*',
59  * so 'WCHAR *' is string, while 'LPWCHAR *' is a pointer
60  */
61 static const char *wide_chars[] =
62 {
63   "WCHAR", NULL
64 };
65
66 /* Items containing these substrings are assumed to be ASCII character
67  * strings, as above
68  */
69 static const char *ascii_strings[] =
70 {
71   "STR", "CSTR", NULL
72 };
73
74
75 /* Items containing these substrings are assumed to be ASCII characters,
76  * as above
77  */
78 static const char *ascii_chars[] =
79 {
80   "CHAR", "char", NULL
81 };
82
83 /* Any type other than the following will produce a FIXME warning with -v
84  * when mapped to a long, to allow fixups
85  */
86 static const char *known_longs[] =
87 {
88   "char", "CHAR", "float", "int", "INT", "short", "SHORT", "long", "LONG",
89   "WCHAR", "BOOL", "bool", "INT16", "WORD", "DWORD", NULL
90 };
91
92 int symbol_init(parsed_symbol* sym, const char* name)
93 {
94     memset(sym, 0, sizeof(parsed_symbol));
95     sym->symbol = strdup(name);
96     return 0;
97 }
98
99 /*******************************************************************
100  *         symbol_clear
101  *
102  * Free the memory used by a symbol and initialise it
103  */
104 void symbol_clear(parsed_symbol *sym)
105 {
106  int i;
107
108  assert (sym);
109  assert (sym->symbol);
110
111  free (sym->symbol);
112
113  if (sym->return_text)
114    free (sym->return_text);
115
116  if (sym->function_name)
117    free (sym->function_name);
118
119  for (i = sym->argc - 1; i >= 0; i--)
120  {
121    if (sym->arg_text [i])
122      free (sym->arg_text [i]);
123    if (sym->arg_name [i])
124      free (sym->arg_name [i]);
125  }
126  memset (sym, 0, sizeof (parsed_symbol));
127 }
128
129
130 /*******************************************************************
131  *         symbol_is_valid_c
132  *
133  * Check if a symbol is a valid C identifier
134  */
135 int symbol_is_valid_c(const parsed_symbol *sym)
136 {
137   char *name;
138
139   assert (sym);
140   assert (sym->symbol);
141
142   name = sym->symbol;
143
144   while (*name)
145   {
146     if (!isalnum (*name) && *name != '_')
147       return 0;
148     name++;
149   }
150   return 1;
151 }
152
153
154 /*******************************************************************
155  *         symbol_get_call_convention
156  *
157  * Return the calling convention of a symbol
158  */
159 const char *symbol_get_call_convention(const parsed_symbol *sym)
160 {
161   int call = sym->flags ? sym->flags : CALLING_CONVENTION;
162
163   assert (sym);
164   assert (sym->symbol);
165
166   if (call & SYM_CDECL)
167     return "cdecl";
168   return "stdcall";
169 }
170
171
172 /*******************************************************************
173  *         symbol_get_spec_type
174  *
175  * Get the .spec file text for a symbols argument
176  */
177 const char *symbol_get_spec_type (const parsed_symbol *sym, size_t arg)
178 {
179   assert (arg < sym->argc);
180   switch (sym->arg_type [arg])
181   {
182   case ARG_STRING:      return "str";
183   case ARG_WIDE_STRING: return "wstr";
184   case ARG_POINTER:     return "ptr";
185   case ARG_DOUBLE:      return "double";
186   case ARG_STRUCT:
187   case ARG_FLOAT:
188   case ARG_LONG:        return "long";
189   }
190   assert (0);
191   return NULL;
192 }
193
194
195 /*******************************************************************
196  *         symbol_get_type
197  *
198  * Get the ARG_ constant for a type string
199  */
200 int   symbol_get_type (const char *string)
201 {
202   const char *iter = string;
203   const char **tab;
204   int ptrs = 0;
205
206   while (*iter && isspace(*iter))
207     iter++;
208   if (*iter == 'P' || *iter == 'H')
209     ptrs++; /* Win32 type pointer */
210
211   iter = string;
212   while (*iter)
213   {
214     if (*iter == '*' || (*iter == 'L' && iter[1] == 'P')
215         || (*iter == '[' && iter[1] == ']'))
216       ptrs++;
217     if (ptrs > 1)
218       return ARG_POINTER;
219     iter++;
220   }
221
222   /* 0 or 1 pointer */
223   tab = wide_strings;
224   while (*tab++)
225     if (strstr (string, tab[-1]))
226     {
227       if (ptrs < 2) return ARG_WIDE_STRING;
228       else          return ARG_POINTER;
229     }
230   tab = wide_chars;
231   while (*tab++)
232     if (strstr (string, tab[-1]))
233     {
234       if (!ptrs) return ARG_LONG;
235       else       return ARG_WIDE_STRING;
236     }
237   tab = ascii_strings;
238   while (*tab++)
239     if (strstr (string, tab[-1]))
240     {
241       if (ptrs < 2) return ARG_STRING;
242       else          return ARG_POINTER;
243     }
244   tab = ascii_chars;
245   while (*tab++)
246     if (strstr (string, tab[-1]))
247     {
248       if (!ptrs) return ARG_LONG;
249       else {
250         if (!strstr (string, "unsigned")) /* unsigned char * => ptr */
251           return ARG_STRING;
252       }
253     }
254
255   if (ptrs)
256     return ARG_POINTER; /* Pointer to some other type */
257
258   /* No pointers */
259   if (strstr (string, "double"))
260     return ARG_DOUBLE;
261
262   if (strstr (string, "float"))
263     return ARG_FLOAT;
264
265   if (strstr (string, "void") || strstr (string, "VOID"))
266     return ARG_VOID;
267
268   if (strstr (string, "struct") || strstr (string, "union"))
269     return ARG_STRUCT; /* Struct by value, ugh */
270
271   if (VERBOSE)
272   {
273     int known = 0;
274
275     tab = known_longs;
276     while (*tab++)
277     if (strstr (string, tab[-1]))
278     {
279       known = 1;
280       break;
281     }
282     /* Unknown types passed by value can be 'grep'ed out for fixup later */
283     if (!known)
284       printf ("/* FIXME: By value type: Assumed 'int' */ typedef int %s;\n",
285               string);
286   }
287   return ARG_LONG;
288 }
289
290
291 /*******************************************************************
292  *         symbol_clean_string
293  *
294  * Make a type string more Wine-friendly. Logically const :-)
295  */
296 void  symbol_clean_string (const char *string)
297 {
298   const char **tab = swap_after;
299   char *str = (char *)string;
300
301 #define SWAP(i, p, x, y) do { i = p; while ((i = str_replace (i, x, y))); } while(0)
302
303   while (tab [0])
304   {
305     char *p;
306     SWAP (p, str, tab [0], tab [1]);
307     tab += 2;
308   }
309   if (str [strlen (str) - 1] == ' ')
310     str [strlen (str) - 1] = '\0'; /* no trailing space */
311
312   if (*str == ' ')
313     memmove (str, str + 1, strlen (str)); /* No leading spaces */
314 }