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
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 /*******************************************************************
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;
44 assert (globals
.do_code
);
45 assert (globals
.directory
);
46 assert (sym
&& sym
->symbol
);
48 if (!symbol_is_valid_c (sym
))
52 grep_buff
= xmalloc (MAX_RESULT_LEN
);
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).
65 char *cmd
= strmake( "grep -d recurse -l \"%s%s\" %s", sym
->symbol
,
66 !attempt
? "[:blank:]*(" : "", globals
.directory
);
71 fflush (NULL
); /* See 'man popen' */
73 if (!(grep
= popen (cmd
, "r")))
74 fatal ("Cannot execute grep -l");
77 while (fgets (grep_buff
, MAX_RESULT_LEN
, grep
))
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
];
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)
97 cmd
= strmake( "function_grep.pl %s \"%s\"", sym
->symbol
, grep_buff
);
102 fflush (NULL
); /* See 'man popen' */
104 if (!(f_grep
= popen (cmd
, "r")))
105 fatal ("Cannot execute function_grep.pl");
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
++)
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
)] == '('))
129 printf ("Prototype '%s' looks OK, processing\n", grep_buff
);
131 if (symbol_from_prototype (sym
, grep_buff
))
135 return TRUE
; /* OK */
138 puts ("Failed, trying next");
141 iter
+= strlen (sym
->symbol
);
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
)
164 proto
= get_type (sym
, proto
, -1); /* Get return type */
168 iter
= str_match (proto
, sym
->symbol
, &found
);
173 /* Calling Convention */
174 iter
= strchr (iter
, ' ');
178 call
= str_substring (proto
, iter
);
180 if (!strcasecmp (call
, "cdecl") || !strcasecmp (call
, "__cdecl"))
181 sym
->flags
|= SYM_CDECL
;
183 sym
->flags
|= SYM_STDCALL
;
185 iter
= str_match (iter
, sym
->symbol
, &found
);
191 printf ("Using %s calling convention\n",
192 sym
->flags
& SYM_CDECL
? "cdecl" : "stdcall");
195 sym
->flags
= CALLING_CONVENTION
;
197 sym
->function_name
= xstrdup (sym
->symbol
);
200 /* Now should be the arguments */
204 for (; *proto
== ' '; proto
++);
206 if (!strncmp (proto
, "void", 4))
211 /* Process next argument */
212 str_match (proto
, "...", &sym
->varargs
);
216 if (!(proto
= get_type (sym
, proto
, sym
->argc
)))
223 else if (*proto
!= ')')
226 } while (*proto
!= ')');
232 /*******************************************************************
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
;
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
);
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 */
262 proto_str
= str_match (proto_str
, "const", &is_const
);
264 proto_str
= str_match (proto_str
, "volatile", &is_volatile
);
266 base_type
= proto_str
;
267 iter
= str_find_set (proto_str
, " ,*)");
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))
278 base_type
= catch_unsigned
;
280 catch_unsigned
= NULL
;
283 catch_unsigned
= NULL
;
285 /* FIXME: skip const/volatile here too */
286 for (proto_str
= iter
; *proto_str
; proto_str
++)
287 if (*proto_str
== '*')
289 else if (*proto_str
!= ' ')
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
);
307 sym
->return_text
= type_str
;
308 sym
->return_type
= dest_type
;
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
);
319 iter
= str_find_set (proto_str
, " ,)");
325 sym
->arg_name
[arg
] = str_substring (proto_str
, iter
);
328 sym
->arg_text
[arg
] = type_str
;