Make the testing framework thread safe.
[wine/gsoc_dplay.git] / tools / winedump / search.c
blobc817e7db3f6e5f35a85a168e1b2577f282ae59c2
1 /*
2 * Prototype search and parsing functions
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "winedump.h"
22 static char *grep_buff = NULL;
23 static char *fgrep_buff = NULL;
25 static int symbol_from_prototype (parsed_symbol *sym, const char *prototype);
26 static const char *get_type (parsed_symbol *sym, const char *proto, int arg);
29 /*******************************************************************
30 * symbol_search
32 * Call Patrik Stridvall's 'function_grep.pl' script to retrieve a
33 * function prototype from include file(s)
35 int symbol_search (parsed_symbol *sym)
37 static const size_t MAX_RESULT_LEN = 1024;
38 FILE *grep;
39 int attempt = 0;
41 assert (globals.do_code);
42 assert (globals.directory);
43 assert (sym && sym->symbol);
45 if (!symbol_is_valid_c (sym))
46 return - 1;
48 if (!grep_buff)
49 grep_buff = (char *) malloc (MAX_RESULT_LEN);
51 if (!fgrep_buff)
52 fgrep_buff = (char *) malloc (MAX_RESULT_LEN);
54 if (!grep_buff || !fgrep_buff)
55 fatal ("Out of Memory");
57 /* Use 'grep' to tell us which possible files the function is in,
58 * then use 'function_grep.pl' to get the prototype. If this fails the
59 * first time then give grep a more general query (that doesn't
60 * require an opening argument brace on the line with the function name).
62 while (attempt < 2)
64 FILE *f_grep;
65 char *cmd = str_create (4, "grep -d recurse -l \"", sym->symbol,
66 !attempt ? "[:blank:]*(\" " : "\" ", globals.directory);
68 if (VERBOSE)
69 puts (cmd);
71 fflush (NULL); /* See 'man popen' */
73 if (!(grep = popen (cmd, "r")))
74 fatal ("Cannot execute grep -l");
75 free (cmd);
77 while (fgets (grep_buff, MAX_RESULT_LEN, grep))
79 int i;
80 for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++)
82 grep_buff[i] = '\0';
84 if (VERBOSE)
85 puts (grep_buff);
87 cmd = str_create (5, "function_grep.pl ", sym->symbol,
88 " \"", grep_buff, "\"");
90 if (VERBOSE)
91 puts (cmd);
93 fflush (NULL); /* See 'man popen' */
95 if (!(f_grep = popen (cmd, "r")))
96 fatal ("Cannot execute function_grep.pl");
97 free (cmd);
99 while (fgets (grep_buff, MAX_RESULT_LEN, f_grep))
101 char *iter = grep_buff;
103 /* Keep only the first line */
104 symbol_clean_string(grep_buff);
106 for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++)
108 grep_buff[i] = '\0';
110 if (VERBOSE)
111 puts (grep_buff);
113 while ((iter = strstr (iter, sym->symbol)))
115 if (iter > grep_buff && iter[-1] == ' ' &&
116 (iter[strlen (sym->symbol)] == ' ' ||
117 iter[strlen (sym->symbol)] == '('))
119 if (VERBOSE)
120 printf ("Prototype '%s' looks OK, processing\n", grep_buff);
122 if (!symbol_from_prototype (sym, grep_buff))
124 pclose (f_grep);
125 pclose (grep);
126 return 0; /* OK */
128 if (VERBOSE)
129 puts ("Failed, trying next");
131 else
132 iter += strlen (sym->symbol);
135 pclose (f_grep);
137 pclose (grep);
138 attempt++;
141 return -1; /* Not found */
145 /*******************************************************************
146 * symbol_from_prototype
148 * Convert a C prototype into a symbol
150 static int symbol_from_prototype (parsed_symbol *sym, const char *proto)
152 char *iter;
153 int found;
155 proto = get_type (sym, proto, -1); /* Get return type */
156 if (!proto)
157 return -1;
159 iter = (char *)str_match (proto, sym->symbol, &found);
161 if (!found)
163 char *call;
164 /* Calling Convention */
165 iter = strchr (iter, ' ');
166 if (!iter)
167 return -1;
169 call = str_substring (proto, iter);
171 if (!strcasecmp (call, "cdecl") || !strcasecmp (call, "__cdecl"))
172 sym->flags |= SYM_CDECL;
173 else
174 sym->flags |= SYM_STDCALL;
175 free (call);
176 iter = (char *)str_match (iter, sym->symbol, &found);
178 if (!found)
179 return -1;
181 if (VERBOSE)
182 printf ("Using %s calling convention\n",
183 sym->flags & SYM_CDECL ? "cdecl" : "stdcall");
185 else
186 sym->flags = CALLING_CONVENTION;
188 sym->function_name = strdup (sym->symbol);
189 proto = iter;
191 /* Now should be the arguments */
192 if (*proto++ != '(')
193 return -1;
195 for (; *proto == ' '; proto++);
197 if (!strncmp (proto, "void", 4))
198 return 0;
202 /* Process next argument */
203 str_match (proto, "...", &sym->varargs);
204 if (sym->varargs)
205 return 0;
207 if (!(proto = get_type (sym, proto, sym->argc)))
208 return -1;
210 sym->argc++;
212 if (*proto == ',')
213 proto++;
214 else if (*proto != ')')
215 return -1;
217 } while (*proto != ')');
219 return 0;
223 /*******************************************************************
224 * get_type
226 * Read a type from a prototype
228 static const char *get_type (parsed_symbol *sym, const char *proto, int arg)
230 int is_const, is_volatile, is_struct, is_signed, is_unsigned, ptrs = 0;
231 char *iter, *type_str, *base_type, *catch_unsigned, dest_type;
233 assert (sym && sym->symbol);
234 assert (proto && *proto);
235 assert (arg < 0 || (unsigned)arg == sym->argc);
237 type_str = (char *)proto;
239 proto = str_match (proto, "const", &is_const);
240 proto = str_match (proto, "volatile", &is_volatile);
241 proto = str_match (proto, "struct", &is_struct);
242 if (!is_struct)
243 proto = str_match (proto, "union", &is_struct);
245 catch_unsigned = (char *)proto;
247 proto = str_match (proto, "unsigned", &is_unsigned);
248 proto = str_match (proto, "signed", &is_signed);
250 /* Can have 'unsigned const' or 'const unsigned' etc */
251 if (!is_const)
252 proto = str_match (proto, "const", &is_const);
253 if (!is_volatile)
254 proto = str_match (proto, "volatile", &is_volatile);
256 base_type = (char *)proto;
257 iter = (char *)str_find_set (proto, " ,*)");
258 if (!iter)
259 return NULL;
261 if (arg < 0 && (is_signed || is_unsigned))
263 /* Prevent calling convention from being swallowed by 'un/signed' alone */
264 if (strncmp (base_type, "int", 3) && strncmp (base_type, "long", 4) &&
265 strncmp (base_type, "short", 5) && strncmp (base_type, "char", 4))
267 iter = (char *)proto;
268 base_type = catch_unsigned;
271 else
272 catch_unsigned = NULL;
274 /* FIXME: skip const/volatile here too */
275 for (proto = iter; *proto; proto++)
276 if (*proto == '*')
277 ptrs++;
278 else if (*proto != ' ')
279 break;
281 if (!*proto)
282 return NULL;
284 type_str = str_substring (type_str, proto);
285 if (iter == base_type || catch_unsigned)
287 /* 'unsigned' with no type */
288 char *tmp = str_create (2, type_str, " int");
289 free (type_str);
290 type_str = tmp;
292 symbol_clean_string (type_str);
294 dest_type = symbol_get_type (type_str);
296 if (arg < 0)
298 sym->return_text = type_str;
299 sym->return_type = dest_type;
301 else
303 sym->arg_type [arg] = dest_type;
304 sym->arg_flag [arg] = is_const ? CT_CONST : is_volatile ? CT_VOLATILE : 0;
306 if (*proto == ',' || *proto == ')')
307 sym->arg_name [arg] = str_create_num (1, arg, "arg");
308 else
310 iter = (char *)str_find_set (proto, " ,)");
311 if (!iter)
313 free (type_str);
314 return NULL;
316 sym->arg_name [arg] = str_substring (proto, iter);
317 proto = iter;
319 sym->arg_text [arg] = type_str;
322 return proto;
326 #ifdef __GNUC__
327 /*******************************************************************
328 * search_cleanup
330 * Free memory used while searching (a niceity)
332 void search_cleanup (void) __attribute__ ((destructor));
333 void search_cleanup (void)
335 if (grep_buff)
336 free (grep_buff);
338 if (fgrep_buff)
339 free (fgrep_buff);
341 #endif