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