1 /*
2 * Prototype search and parsing 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include "winedump.h"
25
26 static char *grep_buff = NULL;
27 static char *fgrep_buff = NULL;
28
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);
31
32
33 /*******************************************************************
34 * symbol_search
35 *
36 * Call Patrik Stridvall's 'function_grep.pl' script to retrieve a
37 * function prototype from include file(s)
38 */
39 int symbol_search (parsed_symbol *sym)
40 {
41 static const size_t MAX_RESULT_LEN = 1024;
42 FILE *grep;
43 int attempt = 0;
44
45 assert (globals.do_code);
46 assert (globals.directory);
47 assert (sym && sym->symbol);
48
49 if (!symbol_is_valid_c (sym))
50 return - 1;
51
52 if (!grep_buff)
53 grep_buff = (char *) malloc (MAX_RESULT_LEN);
54
55 if (!fgrep_buff)
56 fgrep_buff = (char *) malloc (MAX_RESULT_LEN);
57
58 if (!grep_buff || !fgrep_buff)
59 fatal ("Out of Memory");
60
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).
65 */
66 while (attempt < 2)
67 {
68 FILE *f_grep;
69 char *cmd = str_create (4, "grep -d recurse -l \"", sym->symbol,
70 !attempt ? "[:blank:]*(\" " : "\" ", globals.directory);
71
72 if (VERBOSE)
73 puts (cmd);
74
75 fflush (NULL); /* See 'man popen' */
76
77 if (!(grep = popen (cmd, "r")))
78 fatal ("Cannot execute grep -l");
79 free (cmd);
80
81 while (fgets (grep_buff, MAX_RESULT_LEN, grep))
82 {
83 int i;
84 const char *extension = grep_buff;
85 for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++) {
86 if (grep_buff[i] == '.')
87 extension = &grep_buff[i];
88 }
89 grep_buff[i] = '\0';
90
91 /* Definitely not in these: */
92 if (strcmp(extension,".dll") == 0 ||
93 strcmp(extension,".lib") == 0 ||
94 strcmp(extension,".so") == 0 ||
95 strcmp(extension,".o") == 0)
96 continue;
97
98 if (VERBOSE)
99 puts (grep_buff);
100
101 cmd = str_create (5, "function_grep.pl ", sym->symbol,
102 " \"", grep_buff, "\"");
103
104 if (VERBOSE)
105 puts (cmd);
106
107 fflush (NULL); /* See 'man popen' */
108
109 if (!(f_grep = popen (cmd, "r")))
110 fatal ("Cannot execute function_grep.pl");
111 free (cmd);
112
113 while (fgets (grep_buff, MAX_RESULT_LEN, f_grep))
114 {
115 char *iter = grep_buff;
116
117 /* Keep only the first line */
118 symbol_clean_string(grep_buff);
119
120 for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++)
121 ;
122 grep_buff[i] = '\0';
123
124 if (VERBOSE)
125 puts (grep_buff);
126
127 while ((iter = strstr (iter, sym->symbol)))
128 {
129 if (iter > grep_buff && (iter[-1] == ' ' || iter[-1] == '*') &&
130 (iter[strlen (sym->symbol)] == ' ' ||
131 iter[strlen (sym->symbol)] == '('))
132 {
133 if (VERBOSE)
134 printf ("Prototype '%s' looks OK, processing\n", grep_buff);
135
136 if (!symbol_from_prototype (sym, grep_buff))
137 {
138 pclose (f_grep);
139 pclose (grep);
140 return 0; /* OK */
141 }
142 if (VERBOSE)
143 puts ("Failed, trying next");
144 }
145 else
146 iter += strlen (sym->symbol);
147 }
148 }
149 pclose (f_grep);
150 }
151 pclose (grep);
152 attempt++;
153 }
154
155 return -1; /* Not found */
156 }
157
158
159 /*******************************************************************
160 * symbol_from_prototype
161 *
162 * Convert a C prototype into a symbol
163 */
164 static int symbol_from_prototype (parsed_symbol *sym, const char *proto)
165 {
166 const char *iter;
167 int found;
168
169 proto = get_type (sym, proto, -1); /* Get return type */
170 if (!proto)
171 return -1;
172
173 iter = str_match (proto, sym->symbol, &found);
174
175 if (!found)
176 {
177 char *call;
178 /* Calling Convention */
179 iter = strchr (iter, ' ');
180 if (!iter)
181 return -1;
182
183 call = str_substring (proto, iter);
184
185 if (!strcasecmp (call, "cdecl") || !strcasecmp (call, "__cdecl"))
186 sym->flags |= SYM_CDECL;
187 else
188 sym->flags |= SYM_STDCALL;
189 free (call);
190 iter = str_match (iter, sym->symbol, &found);
191
192 if (!found)
193 return -1;
194
195 if (VERBOSE)
196 printf ("Using %s calling convention\n",
197 sym->flags & SYM_CDECL ? "cdecl" : "stdcall");
198 }
199 else
200 sym->flags = CALLING_CONVENTION;
201
202 sym->function_name = strdup (sym->symbol);
203 proto = iter;
204
205 /* Now should be the arguments */
206 if (*proto++ != '(')
207 return -1;
208
209 for (; *proto == ' '; proto++);
210
211 if (!strncmp (proto, "void", 4))
212 return 0;
213
214 do
215 {
216 /* Process next argument */
217 str_match (proto, "...", &sym->varargs);
218 if (sym->varargs)
219 return 0;
220
221 if (!(proto = get_type (sym, proto, sym->argc)))
222 return -1;
223
224 sym->argc++;
225
226 if (*proto == ',')
227 proto++;
228 else if (*proto != ')')
229 return -1;
230
231 } while (*proto != ')');
232
233 return 0;
234 }
235
236
237 /*******************************************************************
238 * get_type
239 *
240 * Read a type from a prototype
241 */
242 static const char *get_type (parsed_symbol *sym, const char *proto, int arg)
243 {
244 int is_const, is_volatile, is_struct, is_signed, is_unsigned, ptrs = 0;
245 const char *iter, *type_str, *base_type, *catch_unsigned;
246 char dest_type, *type_str_tmp;
247
248 assert (sym && sym->symbol);
249 assert (proto && *proto);
250 assert (arg < 0 || (unsigned)arg == sym->argc);
251
252 type_str = proto;
253
254 proto = str_match (proto, "const", &is_const);
255 proto = str_match (proto, "volatile", &is_volatile);
256 proto = str_match (proto, "struct", &is_struct);
257 if (!is_struct)
258 proto = str_match (proto, "union", &is_struct);
259
260 catch_unsigned = proto;
261
262 proto = str_match (proto, "unsigned", &is_unsigned);
263 proto = str_match (proto, "signed", &is_signed);
264
265 /* Can have 'unsigned const' or 'const unsigned' etc */
266 if (!is_const)
267 proto = str_match (proto, "const", &is_const);
268 if (!is_volatile)
269 proto = str_match (proto, "volatile", &is_volatile);
270
271 base_type = proto;
272 iter = str_find_set (proto, " ,*)");
273 if (!iter)
274 return NULL;
275
276 if (arg < 0 && (is_signed || is_unsigned))
277 {
278 /* Prevent calling convention from being swallowed by 'un/signed' alone */
279 if (strncmp (base_type, "int", 3) && strncmp (base_type, "long", 4) &&
280 strncmp (base_type, "short", 5) && strncmp (base_type, "char", 4))
281 {
282 iter = proto;
283 base_type = catch_unsigned;
284 } else
285 catch_unsigned = NULL;
286 }
287 else
288 catch_unsigned = NULL;
289
290 /* FIXME: skip const/volatile here too */
291 for (proto = iter; *proto; proto++)
292 if (*proto == '*')
293 ptrs++;
294 else if (*proto != ' ')
295 break;
296
297 if (!*proto)
298 return NULL;
299
300 type_str = type_str_tmp = str_substring (type_str, proto);
301 if (iter == base_type || catch_unsigned)
302 {
303 /* 'unsigned' with no type */
304 char *tmp = str_create (2, type_str, " int");
305 free (type_str_tmp);
306 type_str = type_str_tmp = tmp;
307 }
308 symbol_clean_string (type_str);
309
310 dest_type = symbol_get_type (type_str);
311
312 if (arg < 0)
313 {
314 sym->return_text = (char*)type_str;
315 sym->return_type = dest_type;
316 }
317 else
318 {
319 sym->arg_type [arg] = dest_type;
320 sym->arg_flag [arg] = is_const ? CT_CONST : is_volatile ? CT_VOLATILE : 0;
321
322 if (*proto == ',' || *proto == ')')
323 sym->arg_name [arg] = str_create_num (1, arg, "arg");
324 else
325 {
326 iter = str_find_set (proto, " ,)");
327 if (!iter)
328 {
329 free (type_str_tmp);
330 return NULL;
331 }
332 sym->arg_name [arg] = str_substring (proto, iter);
333 proto = iter;
334 }
335 sym->arg_text [arg] = (char*)type_str;
336
337 }
338 return proto;
339 }
340
341
342 #ifdef __GNUC__
343 /*******************************************************************
344 * search_cleanup
345 *
346 * Free memory used while searching (a niceity)
347 */
348 void search_cleanup (void) __attribute__ ((destructor));
349 void search_cleanup (void)
350 {
351 free (grep_buff);
352 free (fgrep_buff);
353 }
354 #endif
355
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.