2 * Prototype search and parsing functions
4 * Copyright 2000 Jon Griffiths
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 /*******************************************************************
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;
27 assert (globals
.do_code
);
28 assert (globals
.directory
);
29 assert (sym
&& sym
->symbol
);
31 if (!symbol_is_valid_c (sym
))
35 grep_buff
= (char *) malloc (MAX_RESULT_LEN
);
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).
51 char *cmd
= str_create (4, "grep -d recurse -l \"", sym
->symbol
,
52 !attempt
? "[:blank:]*(\" " : "\" ", globals
.directory
);
57 fflush (NULL
); /* See 'man popen' */
59 if (!(grep
= popen (cmd
, "r")))
60 fatal ("Cannot execute grep -l");
63 while (fgets (grep_buff
, MAX_RESULT_LEN
, grep
))
66 for (i
= 0; grep_buff
[i
] && grep_buff
[i
] != '\n' ; i
++)
73 cmd
= str_create (5, "function_grep.pl ", sym
->symbol
,
74 " \"", grep_buff
, "\"");
79 fflush (NULL
); /* See 'man popen' */
81 if (!(f_grep
= popen (cmd
, "r")))
82 fatal ("Cannot execute function_grep.pl");
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
++)
99 while ((iter
= strstr (iter
, sym
->symbol
)))
101 if (iter
> grep_buff
&& iter
[-1] == ' ' &&
102 (iter
[strlen (sym
->symbol
)] == ' ' ||
103 iter
[strlen (sym
->symbol
)] == '('))
106 puts ("Prototype looks OK, processing");
108 if (!symbol_from_prototype (sym
, grep_buff
))
115 puts ("Failed, trying next");
118 iter
+= strlen (sym
->symbol
);
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
)
141 proto
= get_type (sym
, proto
, -1); /* Get return type */
145 iter
= (char *)str_match (proto
, sym
->symbol
, &found
);
149 /* Calling Convention */
150 iter
= strchr (iter
, ' ');
154 sym
->calling_convention
= str_substring (proto
, iter
);
156 iter
= (char *)str_match (iter
, sym
->symbol
, &found
);
162 sym
->calling_convention
= strdup (CALLING_CONVENTION
);
164 sym
->function_name
= strdup (sym
->symbol
);
167 /* Now should be the arguments */
171 for (; *proto
== ' '; proto
++);
173 if (!strncmp (proto
, "void", 4))
178 /* Process next argument */
179 str_match (proto
, "...", &sym
->varargs
);
183 if (!(proto
= get_type (sym
, proto
, sym
->argc
)))
190 else if (*proto
!= ')')
193 } while (*proto
!= ')');
199 /*******************************************************************
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
);
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 */
228 proto
= str_match (proto
, "const", &is_const
);
230 proto
= str_match (proto
, "volatile", &is_volatile
);
232 base_type
= (char *)proto
;
233 iter
= (char *)str_find_set (proto
, " ,*)");
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
;
248 catch_unsigned
= NULL
;
250 /* FIXME: skip const/volatile here too */
251 for (proto
= iter
; *proto
; proto
++)
254 else if (*proto
!= ' ')
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");
268 symbol_clean_string (type_str
);
270 dest_type
= symbol_get_type (type_str
);
274 sym
->return_text
= type_str
;
275 sym
->return_type
= dest_type
;
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");
286 iter
= (char *)str_find_set (proto
, " ,)");
292 sym
->arg_name
[arg
] = str_substring (proto
, iter
);
295 sym
->arg_text
[arg
] = type_str
;
303 /*******************************************************************
306 * Free memory used while searching (a niceity)
308 void search_cleanup (void) __attribute__ ((destructor
));
309 void search_cleanup (void)