sane: Fix memory leak in create_item (Coverity).
[wine.git] / tools / winedump / search.c
blob21f9986d0a6d43b997d8ae584b1ba3ca1a6372ea
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include "winedump.h"
25 static char *grep_buff = NULL;
26 static char *fgrep_buff = NULL;
28 static BOOL symbol_from_prototype (parsed_symbol *sym, const char *prototype);
29 static const char *get_type (parsed_symbol *sym, const char *proto, int arg);
32 /*******************************************************************
33 * symbol_search
35 * Call Patrik Stridvall's 'function_grep.pl' script to retrieve a
36 * function prototype from include file(s)
38 BOOL symbol_search (parsed_symbol *sym)
40 static const size_t MAX_RESULT_LEN = 1024;
41 FILE *grep;
42 int attempt = 0;
44 assert (globals.do_code);
45 assert (globals.directory);
46 assert (sym && sym->symbol);
48 if (!symbol_is_valid_c (sym))
49 return FALSE;
51 if (!grep_buff)
52 grep_buff = xmalloc (MAX_RESULT_LEN);
54 if (!fgrep_buff)
55 fgrep_buff = xmalloc (MAX_RESULT_LEN);
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 = strmake( "grep -d recurse -l \"%s%s\" %s", 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 const char *extension = grep_buff;
81 for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++) {
82 if (grep_buff[i] == '.')
83 extension = &grep_buff[i];
85 grep_buff[i] = '\0';
87 /* Definitely not in these: */
88 if (strcmp(extension,".dll") == 0 ||
89 strcmp(extension,".lib") == 0 ||
90 strcmp(extension,".so") == 0 ||
91 strcmp(extension,".o") == 0)
92 continue;
94 if (VERBOSE)
95 puts (grep_buff);
97 cmd = strmake( "function_grep.pl %s \"%s\"", sym->symbol, grep_buff );
99 if (VERBOSE)
100 puts (cmd);
102 fflush (NULL); /* See 'man popen' */
104 if (!(f_grep = popen (cmd, "r")))
105 fatal ("Cannot execute function_grep.pl");
106 free (cmd);
108 while (fgets (grep_buff, MAX_RESULT_LEN, f_grep))
110 char *iter = grep_buff;
112 /* Keep only the first line */
113 symbol_clean_string(grep_buff);
115 for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++)
117 grep_buff[i] = '\0';
119 if (VERBOSE)
120 puts (grep_buff);
122 while ((iter = strstr (iter, sym->symbol)))
124 if (iter > grep_buff && (iter[-1] == ' ' || iter[-1] == '*') &&
125 (iter[strlen (sym->symbol)] == ' ' ||
126 iter[strlen (sym->symbol)] == '('))
128 if (VERBOSE)
129 printf ("Prototype '%s' looks OK, processing\n", grep_buff);
131 if (symbol_from_prototype (sym, grep_buff))
133 pclose (f_grep);
134 pclose (grep);
135 return TRUE; /* OK */
137 if (VERBOSE)
138 puts ("Failed, trying next");
140 else
141 iter += strlen (sym->symbol);
144 pclose (f_grep);
146 pclose (grep);
147 attempt++;
150 return FALSE; /* Not found */
154 /*******************************************************************
155 * symbol_from_prototype
157 * Convert a C prototype into a symbol
159 static BOOL symbol_from_prototype (parsed_symbol *sym, const char *proto)
161 const char *iter;
162 BOOL found;
164 proto = get_type (sym, proto, -1); /* Get return type */
165 if (!proto)
166 return FALSE;
168 iter = str_match (proto, sym->symbol, &found);
170 if (!found)
172 char *call;
173 /* Calling Convention */
174 iter = strchr (iter, ' ');
175 if (!iter)
176 return FALSE;
178 call = str_substring (proto, iter);
180 if (!strcasecmp (call, "cdecl") || !strcasecmp (call, "__cdecl"))
181 sym->flags |= SYM_CDECL;
182 else
183 sym->flags |= SYM_STDCALL;
184 free (call);
185 iter = str_match (iter, sym->symbol, &found);
187 if (!found)
188 return FALSE;
190 if (VERBOSE)
191 printf ("Using %s calling convention\n",
192 sym->flags & SYM_CDECL ? "cdecl" : "stdcall");
194 else
195 sym->flags = CALLING_CONVENTION;
197 sym->function_name = xstrdup (sym->symbol);
198 proto = iter;
200 /* Now should be the arguments */
201 if (*proto++ != '(')
202 return FALSE;
204 for (; *proto == ' '; proto++);
206 if (!strncmp (proto, "void", 4))
207 return TRUE;
211 /* Process next argument */
212 str_match (proto, "...", &sym->varargs);
213 if (sym->varargs)
214 return TRUE;
216 if (!(proto = get_type (sym, proto, sym->argc)))
217 return FALSE;
219 sym->argc++;
221 if (*proto == ',')
222 proto++;
223 else if (*proto != ')')
224 return FALSE;
226 } while (*proto != ')');
228 return TRUE;
232 /*******************************************************************
233 * get_type
235 * Read a type from a prototype
237 static const char *get_type (parsed_symbol *sym, const char *proto, int arg)
239 BOOL is_const, is_volatile, is_struct, is_signed, is_unsigned;
240 int ptrs = 0;
241 const char *iter, *base_type, *catch_unsigned, *proto_str;
242 char dest_type, *type_str;
244 assert (sym && sym->symbol);
245 assert (proto && *proto);
246 assert (arg < 0 || (unsigned)arg == sym->argc);
249 proto_str = str_match (proto, "const", &is_const);
250 proto_str = str_match (proto_str, "volatile", &is_volatile);
251 proto_str = str_match (proto_str, "struct", &is_struct);
252 if (!is_struct)
253 proto_str = str_match (proto_str, "union", &is_struct);
255 catch_unsigned = proto_str;
257 proto_str = str_match (proto_str, "unsigned", &is_unsigned);
258 proto_str = str_match (proto_str, "signed", &is_signed);
260 /* Can have 'unsigned const' or 'const unsigned' etc */
261 if (!is_const)
262 proto_str = str_match (proto_str, "const", &is_const);
263 if (!is_volatile)
264 proto_str = str_match (proto_str, "volatile", &is_volatile);
266 base_type = proto_str;
267 iter = str_find_set (proto_str, " ,*)");
268 if (!iter)
269 return NULL;
271 if (arg < 0 && (is_signed || is_unsigned))
273 /* Prevent calling convention from being swallowed by 'un/signed' alone */
274 if (strncmp (base_type, "int", 3) && strncmp (base_type, "long", 4) &&
275 strncmp (base_type, "short", 5) && strncmp (base_type, "char", 4))
277 iter = proto_str;
278 base_type = catch_unsigned;
279 } else
280 catch_unsigned = NULL;
282 else
283 catch_unsigned = NULL;
285 /* FIXME: skip const/volatile here too */
286 for (proto_str = iter; *proto_str; proto_str++)
287 if (*proto_str == '*')
288 ptrs++;
289 else if (*proto_str != ' ')
290 break;
292 if (!*proto_str)
293 return NULL;
295 type_str = str_substring (proto, proto_str);
296 if (iter == base_type || catch_unsigned)
298 /* 'unsigned' with no type */
299 type_str = strmake( "%s int", type_str );
301 symbol_clean_string (type_str);
303 dest_type = symbol_get_type (type_str);
305 if (arg < 0)
307 sym->return_text = type_str;
308 sym->return_type = dest_type;
310 else
312 sym->arg_type [arg] = dest_type;
313 sym->arg_flag [arg] = is_const ? CT_CONST : is_volatile ? CT_VOLATILE : 0;
315 if (*proto_str == ',' || *proto_str == ')')
316 sym->arg_name [arg] = strmake( "arg%u", arg );
317 else
319 iter = str_find_set (proto_str, " ,)");
320 if (!iter)
322 free (type_str);
323 return NULL;
325 sym->arg_name [arg] = str_substring (proto_str, iter);
326 proto_str = iter;
328 sym->arg_text [arg] = type_str;
331 return proto_str;