Added ability to turn on/off debug channels.
[wine.git] / tools / winedump / search.c
blob437f210a32c4746970692f9689dab787e201ada2
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include "winedump.h"
26 static char *grep_buff = NULL;
27 static char *fgrep_buff = NULL;
29 static int symbol_from_prototype (parsed_symbol *sym, const char *prototype);
30 static const char *get_type (parsed_symbol *sym, const char *proto, int arg);
33 /*******************************************************************
34 * symbol_search
36 * Call Patrik Stridvall's 'function_grep.pl' script to retrieve a
37 * function prototype from include file(s)
39 int symbol_search (parsed_symbol *sym)
41 static const size_t MAX_RESULT_LEN = 1024;
42 FILE *grep;
43 int attempt = 0;
45 assert (globals.do_code);
46 assert (globals.directory);
47 assert (sym && sym->symbol);
49 if (!symbol_is_valid_c (sym))
50 return - 1;
52 if (!grep_buff)
53 grep_buff = (char *) malloc (MAX_RESULT_LEN);
55 if (!fgrep_buff)
56 fgrep_buff = (char *) malloc (MAX_RESULT_LEN);
58 if (!grep_buff || !fgrep_buff)
59 fatal ("Out of Memory");
61 /* Use 'grep' to tell us which possible files the function is in,
62 * then use 'function_grep.pl' to get the prototype. If this fails the
63 * first time then give grep a more general query (that doesn't
64 * require an opening argument brace on the line with the function name).
66 while (attempt < 2)
68 FILE *f_grep;
69 char *cmd = str_create (4, "grep -d recurse -l \"", sym->symbol,
70 !attempt ? "[:blank:]*(\" " : "\" ", globals.directory);
72 if (VERBOSE)
73 puts (cmd);
75 fflush (NULL); /* See 'man popen' */
77 if (!(grep = popen (cmd, "r")))
78 fatal ("Cannot execute grep -l");
79 free (cmd);
81 while (fgets (grep_buff, MAX_RESULT_LEN, grep))
83 int i;
84 for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++)
86 grep_buff[i] = '\0';
88 if (VERBOSE)
89 puts (grep_buff);
91 cmd = str_create (5, "function_grep.pl ", sym->symbol,
92 " \"", grep_buff, "\"");
94 if (VERBOSE)
95 puts (cmd);
97 fflush (NULL); /* See 'man popen' */
99 if (!(f_grep = popen (cmd, "r")))
100 fatal ("Cannot execute function_grep.pl");
101 free (cmd);
103 while (fgets (grep_buff, MAX_RESULT_LEN, f_grep))
105 char *iter = grep_buff;
107 /* Keep only the first line */
108 symbol_clean_string(grep_buff);
110 for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++)
112 grep_buff[i] = '\0';
114 if (VERBOSE)
115 puts (grep_buff);
117 while ((iter = strstr (iter, sym->symbol)))
119 if (iter > grep_buff && iter[-1] == ' ' &&
120 (iter[strlen (sym->symbol)] == ' ' ||
121 iter[strlen (sym->symbol)] == '('))
123 if (VERBOSE)
124 printf ("Prototype '%s' looks OK, processing\n", grep_buff);
126 if (!symbol_from_prototype (sym, grep_buff))
128 pclose (f_grep);
129 pclose (grep);
130 return 0; /* OK */
132 if (VERBOSE)
133 puts ("Failed, trying next");
135 else
136 iter += strlen (sym->symbol);
139 pclose (f_grep);
141 pclose (grep);
142 attempt++;
145 return -1; /* Not found */
149 /*******************************************************************
150 * symbol_from_prototype
152 * Convert a C prototype into a symbol
154 static int symbol_from_prototype (parsed_symbol *sym, const char *proto)
156 char *iter;
157 int found;
159 proto = get_type (sym, proto, -1); /* Get return type */
160 if (!proto)
161 return -1;
163 iter = (char *)str_match (proto, sym->symbol, &found);
165 if (!found)
167 char *call;
168 /* Calling Convention */
169 iter = strchr (iter, ' ');
170 if (!iter)
171 return -1;
173 call = str_substring (proto, iter);
175 if (!strcasecmp (call, "cdecl") || !strcasecmp (call, "__cdecl"))
176 sym->flags |= SYM_CDECL;
177 else
178 sym->flags |= SYM_STDCALL;
179 free (call);
180 iter = (char *)str_match (iter, sym->symbol, &found);
182 if (!found)
183 return -1;
185 if (VERBOSE)
186 printf ("Using %s calling convention\n",
187 sym->flags & SYM_CDECL ? "cdecl" : "stdcall");
189 else
190 sym->flags = CALLING_CONVENTION;
192 sym->function_name = strdup (sym->symbol);
193 proto = iter;
195 /* Now should be the arguments */
196 if (*proto++ != '(')
197 return -1;
199 for (; *proto == ' '; proto++);
201 if (!strncmp (proto, "void", 4))
202 return 0;
206 /* Process next argument */
207 str_match (proto, "...", &sym->varargs);
208 if (sym->varargs)
209 return 0;
211 if (!(proto = get_type (sym, proto, sym->argc)))
212 return -1;
214 sym->argc++;
216 if (*proto == ',')
217 proto++;
218 else if (*proto != ')')
219 return -1;
221 } while (*proto != ')');
223 return 0;
227 /*******************************************************************
228 * get_type
230 * Read a type from a prototype
232 static const char *get_type (parsed_symbol *sym, const char *proto, int arg)
234 int is_const, is_volatile, is_struct, is_signed, is_unsigned, ptrs = 0;
235 char *iter, *type_str, *base_type, *catch_unsigned, dest_type;
237 assert (sym && sym->symbol);
238 assert (proto && *proto);
239 assert (arg < 0 || (unsigned)arg == sym->argc);
241 type_str = (char *)proto;
243 proto = str_match (proto, "const", &is_const);
244 proto = str_match (proto, "volatile", &is_volatile);
245 proto = str_match (proto, "struct", &is_struct);
246 if (!is_struct)
247 proto = str_match (proto, "union", &is_struct);
249 catch_unsigned = (char *)proto;
251 proto = str_match (proto, "unsigned", &is_unsigned);
252 proto = str_match (proto, "signed", &is_signed);
254 /* Can have 'unsigned const' or 'const unsigned' etc */
255 if (!is_const)
256 proto = str_match (proto, "const", &is_const);
257 if (!is_volatile)
258 proto = str_match (proto, "volatile", &is_volatile);
260 base_type = (char *)proto;
261 iter = (char *)str_find_set (proto, " ,*)");
262 if (!iter)
263 return NULL;
265 if (arg < 0 && (is_signed || is_unsigned))
267 /* Prevent calling convention from being swallowed by 'un/signed' alone */
268 if (strncmp (base_type, "int", 3) && strncmp (base_type, "long", 4) &&
269 strncmp (base_type, "short", 5) && strncmp (base_type, "char", 4))
271 iter = (char *)proto;
272 base_type = catch_unsigned;
275 else
276 catch_unsigned = NULL;
278 /* FIXME: skip const/volatile here too */
279 for (proto = iter; *proto; proto++)
280 if (*proto == '*')
281 ptrs++;
282 else if (*proto != ' ')
283 break;
285 if (!*proto)
286 return NULL;
288 type_str = str_substring (type_str, proto);
289 if (iter == base_type || catch_unsigned)
291 /* 'unsigned' with no type */
292 char *tmp = str_create (2, type_str, " int");
293 free (type_str);
294 type_str = tmp;
296 symbol_clean_string (type_str);
298 dest_type = symbol_get_type (type_str);
300 if (arg < 0)
302 sym->return_text = type_str;
303 sym->return_type = dest_type;
305 else
307 sym->arg_type [arg] = dest_type;
308 sym->arg_flag [arg] = is_const ? CT_CONST : is_volatile ? CT_VOLATILE : 0;
310 if (*proto == ',' || *proto == ')')
311 sym->arg_name [arg] = str_create_num (1, arg, "arg");
312 else
314 iter = (char *)str_find_set (proto, " ,)");
315 if (!iter)
317 free (type_str);
318 return NULL;
320 sym->arg_name [arg] = str_substring (proto, iter);
321 proto = iter;
323 sym->arg_text [arg] = type_str;
326 return proto;
330 #ifdef __GNUC__
331 /*******************************************************************
332 * search_cleanup
334 * Free memory used while searching (a niceity)
336 void search_cleanup (void) __attribute__ ((destructor));
337 void search_cleanup (void)
339 if (grep_buff)
340 free (grep_buff);
342 if (fgrep_buff)
343 free (fgrep_buff);
345 #endif