Added spec generation tool specmaker.
[wine/hacks.git] / tools / specmaker / search.c
blob289b8721230c7c9711a31519dfc619201bf3d155
1 /*
2 * Prototype search and parsing functions
4 * Copyright 2000 Jon Griffiths
5 */
6 #include "specmaker.h"
8 static char *grep_buff = NULL;
9 static char *fgrep_buff = NULL;
11 static int symbol_from_prototype (parsed_symbol *sym, const char *prototype);
12 static const char *get_type (parsed_symbol *sym, const char *proto, int arg);
15 /*******************************************************************
16 * symbol_search
18 * Call Patrik Stridvall's 'function_grep.pl' script to retrieve a
19 * function prototype from include file(s)
21 int symbol_search (parsed_symbol *sym)
23 static const size_t MAX_RESULT_LEN = 1024;
24 FILE *grep;
25 int attempt = 0;
27 assert (globals.do_code);
28 assert (globals.directory);
29 assert (sym && sym->symbol);
31 if (!symbol_is_valid_c (sym))
32 return - 1;
34 if (!grep_buff)
35 grep_buff = (char *) malloc (MAX_RESULT_LEN);
37 if (!fgrep_buff)
38 fgrep_buff = (char *) malloc (MAX_RESULT_LEN);
40 if (!grep_buff || !fgrep_buff)
41 fatal ("Out of Memory");
43 /* Use 'grep' to tell us which possible files the function is in,
44 * then use 'function_grep.pl' to get the prototype. If this fails the
45 * first time then give grep a more general query (that doesn't
46 * require an opening argument brace on the line with the function name).
48 while (attempt < 2)
50 FILE *f_grep;
51 char *cmd = str_create (4, "grep -d recurse -l \"", sym->symbol,
52 !attempt ? "[:blank:]*(\" " : "\" ", globals.directory);
54 if (VERBOSE)
55 puts (cmd);
57 fflush (NULL); /* See 'man popen' */
59 if (!(grep = popen (cmd, "r")))
60 fatal ("Cannot execute grep -l");
61 free (cmd);
63 while (fgets (grep_buff, MAX_RESULT_LEN, grep))
65 int i;
66 for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++)
68 grep_buff[i] = '\0';
70 if (VERBOSE)
71 puts (grep_buff);
73 cmd = str_create (5, "function_grep.pl ", sym->symbol,
74 " \"", grep_buff, "\"");
76 if (VERBOSE)
77 puts (cmd);
79 fflush (NULL); /* See 'man popen' */
81 if (!(f_grep = popen (cmd, "r")))
82 fatal ("Cannot execute function_grep.pl");
83 free (cmd);
85 while (fgets (grep_buff, MAX_RESULT_LEN, f_grep))
87 char *iter = grep_buff;
89 /* Keep only the first line */
90 symbol_clean_string(grep_buff);
92 for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++)
94 grep_buff[i] = '\0';
96 if (VERBOSE)
97 puts (grep_buff);
99 while ((iter = strstr (iter, sym->symbol)))
101 if (iter > grep_buff && iter[-1] == ' ' &&
102 (iter[strlen (sym->symbol)] == ' ' ||
103 iter[strlen (sym->symbol)] == '('))
105 if (VERBOSE)
106 puts ("Prototype looks OK, processing");
108 if (!symbol_from_prototype (sym, grep_buff))
110 pclose (f_grep);
111 pclose (grep);
112 return 0; /* OK */
114 if (VERBOSE)
115 puts ("Failed, trying next");
117 else
118 iter += strlen (sym->symbol);
121 pclose (f_grep);
123 pclose (grep);
124 attempt++;
127 return -1; /* Not found */
131 /*******************************************************************
132 * symbol_from_prototype
134 * Convert a C prototype into a symbol
136 static int symbol_from_prototype (parsed_symbol *sym, const char *proto)
138 char *iter;
139 int found;
141 proto = get_type (sym, proto, -1); /* Get return type */
142 if (!proto)
143 return -1;
145 iter = (char *)str_match (proto, sym->symbol, &found);
147 if (!found)
149 /* Calling Convention */
150 iter = strchr (iter, ' ');
151 if (!iter)
152 return -1;
154 sym->calling_convention = str_substring (proto, iter);
156 iter = (char *)str_match (iter, sym->symbol, &found);
158 if (!found)
159 return -1;
161 else
162 sym->calling_convention = strdup (CALLING_CONVENTION);
164 sym->function_name = strdup (sym->symbol);
165 proto = iter;
167 /* Now should be the arguments */
168 if (*proto++ != '(')
169 return -1;
171 for (; *proto == ' '; proto++);
173 if (!strncmp (proto, "void", 4))
174 return 0;
178 /* Process next argument */
179 str_match (proto, "...", &sym->varargs);
180 if (sym->varargs)
181 return 0;
183 if (!(proto = get_type (sym, proto, sym->argc)))
184 return -1;
186 sym->argc++;
188 if (*proto == ',')
189 proto++;
190 else if (*proto != ')')
191 return -1;
193 } while (*proto != ')');
195 return 0;
199 /*******************************************************************
200 * get_type
202 * Read a type from a prototype
204 static const char *get_type (parsed_symbol *sym, const char *proto, int arg)
206 int is_const, is_volatile, is_struct, is_signed, is_unsigned, ptrs = 0;
207 char *iter, *type_str, *base_type, *catch_unsigned, dest_type;
209 assert (sym && sym->symbol);
210 assert (proto && *proto);
211 assert (arg < 0 || (unsigned)arg == sym->argc);
213 type_str = (char *)proto;
215 proto = str_match (proto, "const", &is_const);
216 proto = str_match (proto, "volatile", &is_volatile);
217 proto = str_match (proto, "struct", &is_struct);
218 if (!is_struct)
219 proto = str_match (proto, "union", &is_struct);
221 catch_unsigned = (char *)proto;
223 proto = str_match (proto, "unsigned", &is_unsigned);
224 proto = str_match (proto, "signed", &is_signed);
226 /* Can have 'unsigned const' or 'const unsigned' etc */
227 if (!is_const)
228 proto = str_match (proto, "const", &is_const);
229 if (!is_volatile)
230 proto = str_match (proto, "volatile", &is_volatile);
232 base_type = (char *)proto;
233 iter = (char *)str_find_set (proto, " ,*)");
234 if (!iter)
235 return NULL;
237 if (arg < 0 && (is_signed || is_unsigned))
239 /* Prevent calling convention from being swallowed by 'un/signed' alone */
240 if (strncmp (base_type, "int", 3) && strncmp (base_type, "long", 4) &&
241 strncmp (base_type, "short", 5) && strncmp (base_type, "char", 4))
243 iter = (char *)proto;
244 base_type = catch_unsigned;
247 else
248 catch_unsigned = NULL;
250 /* FIXME: skip const/volatile here too */
251 for (proto = iter; *proto; proto++)
252 if (*proto == '*')
253 ptrs++;
254 else if (*proto != ' ')
255 break;
257 if (!*proto)
258 return NULL;
260 type_str = str_substring (type_str, proto);
261 if (iter == base_type || catch_unsigned)
263 /* 'unsigned' with no type */
264 char *tmp = str_create (2, type_str, " int");
265 free (type_str);
266 type_str = tmp;
268 symbol_clean_string (type_str);
270 dest_type = symbol_get_type (type_str);
272 if (arg < 0)
274 sym->return_text = type_str;
275 sym->return_type = dest_type;
277 else
279 sym->arg_type [arg] = dest_type;
280 sym->arg_flag [arg] = is_const ? CT_CONST : is_volatile ? CT_VOLATILE : 0;
282 if (*proto == ',' || *proto == ')')
283 sym->arg_name [arg] = str_create_num (1, arg, "arg");
284 else
286 iter = (char *)str_find_set (proto, " ,)");
287 if (!iter)
289 free (type_str);
290 return NULL;
292 sym->arg_name [arg] = str_substring (proto, iter);
293 proto = iter;
295 sym->arg_text [arg] = type_str;
298 return proto;
302 #ifdef __GNUC__
303 /*******************************************************************
304 * search_cleanup
306 * Free memory used while searching (a niceity)
308 void search_cleanup (void) __attribute__ ((destructor));
309 void search_cleanup (void)
311 if (grep_buff)
312 free (grep_buff);
314 if (fgrep_buff)
315 free (fgrep_buff);
317 #endif