1 | /* Program to extract function declarations from C source code |
---|
2 | * Written by Eric R. Smith and placed in the public domain |
---|
3 | * Thanks to: |
---|
4 | * Jwahar R. Bammi, for catching several bugs and providing the Unix makefiles |
---|
5 | * Byron T. Jenings Jr. for cleaning up the space code, providing a Unix |
---|
6 | * manual page, and some ANSI and C++ improvements. |
---|
7 | * Skip Gilbrech for code to skip parameter names in prototypes. |
---|
8 | * ... and many others for helpful comments and suggestions. |
---|
9 | */ |
---|
10 | |
---|
11 | /* if your compiler claims to be ANSI but doesn't have stddef.h or stdlib.h, |
---|
12 | * change the next line. |
---|
13 | * (and then complain to the supplier of the defective compiler) |
---|
14 | */ |
---|
15 | |
---|
16 | /* |
---|
17 | * many extension were made for use in ARB build process |
---|
18 | * by Ralf Westram <ralf@arb-home.de> |
---|
19 | */ |
---|
20 | |
---|
21 | #include <stddef.h> |
---|
22 | #include <stdlib.h> |
---|
23 | #include <assert.h> |
---|
24 | #include <unistd.h> |
---|
25 | #include <stdio.h> |
---|
26 | #include <ctype.h> |
---|
27 | #include <string.h> |
---|
28 | |
---|
29 | #ifndef EXIT_SUCCESS |
---|
30 | #define EXIT_SUCCESS 0 |
---|
31 | #define EXIT_FAILURE 1 |
---|
32 | #endif |
---|
33 | |
---|
34 | static void Version(void); |
---|
35 | |
---|
36 | |
---|
37 | #define check_heap_sanity() do{ char *x = malloc(10); free(x); }while(0) |
---|
38 | |
---|
39 | #if defined(DEBUG) |
---|
40 | /* #define DEBUG_PRINTS */ |
---|
41 | #endif /* DEBUG */ |
---|
42 | |
---|
43 | #ifdef DEBUG_PRINTS |
---|
44 | /* #define DEBUG_PRINT(s) do{ fputs((s), stderr); check_heap_sanity(); }while(0) */ |
---|
45 | #define DEBUG_PRINT(s) fputs((s), stderr) |
---|
46 | #else |
---|
47 | #define DEBUG_PRINT(s) |
---|
48 | #endif |
---|
49 | |
---|
50 | #define PRINT(s) fputs((s), stdout) |
---|
51 | |
---|
52 | #define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_')) |
---|
53 | #define ABORTED ( (Word *) -1 ) |
---|
54 | #define MAXPARAM 20 /* max. number of parameters to a function */ |
---|
55 | #define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */ |
---|
56 | |
---|
57 | |
---|
58 | static int dostatic = 0; /* include static functions? */ |
---|
59 | static int doinline = 0; /* include inline functions? */ |
---|
60 | static int donum = 0; /* print line numbers? */ |
---|
61 | static int define_macro = 1; /* define macro for prototypes? */ |
---|
62 | static int use_macro = 1; /* use a macro for prototypes? */ |
---|
63 | static int use_main = 0; /* add prototype for main? */ |
---|
64 | static int no_parm_names = 0; /* no parm names - only types */ |
---|
65 | static int print_extern = 0; /* use "extern" before function declarations */ |
---|
66 | static int dont_promote = 0; /* don't promote prototypes */ |
---|
67 | static int promote_lines = 0; /* promote 'AISC_MKPT_PROMOTE'-lines */ |
---|
68 | static int aisc = 0; /* aisc compatible output */ |
---|
69 | static int cansibycplus = 0; /* produce extern "C" */ |
---|
70 | static int promote_extern_c = 0; /* produce extern "C" into prototype */ |
---|
71 | static int extern_c_seen = 0; /* true if extern "C" was parsed */ |
---|
72 | static int search__attribute__ = 0; /* search for gnu-extension __attribute__(()) ? */ |
---|
73 | static int search__ATTR__ = 0; /* search for ARB-__attribute__-macros (__ATTR__) ? */ |
---|
74 | |
---|
75 | static const char *include_wrapper = NULL; /* add include wrapper (contains name of header or NULL) */ |
---|
76 | |
---|
77 | static int inquote = 0; /* in a quote?? */ |
---|
78 | static int newline_seen = 1; /* are we at the start of a line */ |
---|
79 | static int glastc = ' '; /* last char. seen by getsym() */ |
---|
80 | |
---|
81 | static char *current_file = 0; /* name of current file */ |
---|
82 | static char *current_dir = 0; /* name of current directory */ |
---|
83 | static char *header_comment = 0; /* comment written into header */ |
---|
84 | static long linenum = 1L; /* line number in current file */ |
---|
85 | |
---|
86 | static char const *macro_name = "P_"; /* macro to use for prototypes */ |
---|
87 | static char const *ourname; /* our name, from argv[] array */ |
---|
88 | |
---|
89 | /* ------------------------------------------------------------ */ |
---|
90 | |
---|
91 | static void errorAt(long line, const char *msg) { |
---|
92 | printf("\n" |
---|
93 | "#line %li \"%s/%s\"\n" |
---|
94 | "#error in aisc_mkpt: %s\n", |
---|
95 | line, |
---|
96 | current_dir, |
---|
97 | current_file, |
---|
98 | msg); |
---|
99 | } |
---|
100 | |
---|
101 | static void error(const char *msg) { |
---|
102 | errorAt(linenum, msg); |
---|
103 | } |
---|
104 | |
---|
105 | /* char *sym_part = 0;*/ /* create only prototypes starting with 'sym_start' */ |
---|
106 | /* int sym_part_len = 0; */ |
---|
107 | |
---|
108 | typedef struct sym_part { |
---|
109 | char *part; |
---|
110 | int len; /* strlen(part) */ |
---|
111 | struct sym_part *next; |
---|
112 | } SymPart; |
---|
113 | |
---|
114 | static SymPart *symParts = 0; /* create only prototypes for parts in this list */ |
---|
115 | |
---|
116 | static void addSymParts(const char *parts) { |
---|
117 | char *p = strdup(parts); |
---|
118 | const char *sep = ","; |
---|
119 | char *s = strtok(p, sep); |
---|
120 | |
---|
121 | while (s) { |
---|
122 | SymPart *sp = malloc(sizeof(*sp)); |
---|
123 | |
---|
124 | sp->part = strdup(s); |
---|
125 | sp->len = strlen(s); |
---|
126 | sp->next = symParts; |
---|
127 | |
---|
128 | symParts = sp; |
---|
129 | |
---|
130 | s = strtok(0, sep); |
---|
131 | } |
---|
132 | |
---|
133 | free(p); |
---|
134 | } |
---|
135 | |
---|
136 | static int containsSymPart(const char *name) { |
---|
137 | SymPart *sp = symParts; |
---|
138 | int contains = 0; |
---|
139 | |
---|
140 | while (sp && !contains) { |
---|
141 | contains = strstr(name, sp->part)!=0; |
---|
142 | sp = sp->next; |
---|
143 | } |
---|
144 | |
---|
145 | return contains; |
---|
146 | } |
---|
147 | |
---|
148 | static void freeSymParts() { |
---|
149 | SymPart *next = symParts; |
---|
150 | |
---|
151 | while (next) { |
---|
152 | SymPart *del = next; |
---|
153 | next = del->next; |
---|
154 | |
---|
155 | free(del->part); |
---|
156 | free(del); |
---|
157 | } |
---|
158 | } |
---|
159 | |
---|
160 | typedef struct word { |
---|
161 | struct word *next; |
---|
162 | char string[1]; |
---|
163 | } Word; |
---|
164 | |
---|
165 | /* #include "mkptypes.h" */ |
---|
166 | |
---|
167 | /* |
---|
168 | * Routines for manipulating lists of words. |
---|
169 | */ |
---|
170 | |
---|
171 | static Word *word_alloc(const char *s) |
---|
172 | { |
---|
173 | Word *w; |
---|
174 | |
---|
175 | /* note that sizeof(Word) already contains space for a terminating null |
---|
176 | * however, we add 1 so that typefixhack can promote "float" to "double" |
---|
177 | * by just doing a strcpy. |
---|
178 | */ |
---|
179 | w = (Word *) malloc(sizeof(Word) + strlen(s) + 1); |
---|
180 | strcpy(w->string, s); |
---|
181 | w->next = NULL; |
---|
182 | return w; |
---|
183 | } |
---|
184 | |
---|
185 | static void word_free(Word *w) |
---|
186 | { |
---|
187 | Word *oldw; |
---|
188 | while (w) { |
---|
189 | oldw = w; |
---|
190 | w = w->next; |
---|
191 | free((char *)oldw); |
---|
192 | } |
---|
193 | } |
---|
194 | |
---|
195 | /* return the length of a list; empty words are not counted */ |
---|
196 | static int List_len(Word *w) |
---|
197 | { |
---|
198 | int count = 0; |
---|
199 | |
---|
200 | while (w) { |
---|
201 | if (*w->string) count++; |
---|
202 | w = w->next; |
---|
203 | } |
---|
204 | return count; |
---|
205 | } |
---|
206 | |
---|
207 | /* Append two lists, and return the result */ |
---|
208 | |
---|
209 | static Word *word_append(Word *w1, Word *w2){ |
---|
210 | Word *r, *w; |
---|
211 | |
---|
212 | r = w = word_alloc(""); |
---|
213 | |
---|
214 | while (w1) { |
---|
215 | w->next = word_alloc(w1->string); |
---|
216 | w = w->next; |
---|
217 | w1 = w1->next; |
---|
218 | } |
---|
219 | while (w2) { |
---|
220 | w->next = word_alloc(w2->string); |
---|
221 | w = w->next; |
---|
222 | w2 = w2->next; |
---|
223 | } |
---|
224 | |
---|
225 | return r; |
---|
226 | } |
---|
227 | |
---|
228 | /* see if the last entry in w2 is in w1 */ |
---|
229 | |
---|
230 | static int foundin(Word *w1, Word *w2){ |
---|
231 | while (w2->next) |
---|
232 | w2 = w2->next; |
---|
233 | |
---|
234 | while (w1) { |
---|
235 | if (strcmp(w1->string, w2->string)==0) |
---|
236 | return 1; |
---|
237 | w1 = w1->next; |
---|
238 | } |
---|
239 | return 0; |
---|
240 | } |
---|
241 | |
---|
242 | /* add the string s to the given list of words */ |
---|
243 | |
---|
244 | static void addword(Word *w, const char *s){ |
---|
245 | while (w->next) w = w->next; |
---|
246 | w->next = word_alloc(s); |
---|
247 | |
---|
248 | DEBUG_PRINT("addword: '"); |
---|
249 | DEBUG_PRINT(s); |
---|
250 | DEBUG_PRINT("'\n"); |
---|
251 | } |
---|
252 | |
---|
253 | /* typefixhack: promote formal parameters of type "char", "unsigned char", |
---|
254 | "short", or "unsigned short" to "int". |
---|
255 | */ |
---|
256 | |
---|
257 | static void typefixhack(Word *w){ |
---|
258 | Word *oldw = 0; |
---|
259 | |
---|
260 | if (dont_promote) |
---|
261 | return; |
---|
262 | |
---|
263 | while (w) { |
---|
264 | if (*w->string) { |
---|
265 | if ((strcmp(w->string, "char")==0 || strcmp(w->string, "short")==0) && (List_len(w->next) < 2) ) { |
---|
266 | /* delete any "unsigned" specifier present -- yes, it's supposed to do this */ |
---|
267 | if (oldw && strcmp(oldw->string, "unsigned")==0) { |
---|
268 | oldw->next = w->next; |
---|
269 | free((char *)w); |
---|
270 | w = oldw; |
---|
271 | } |
---|
272 | strcpy(w->string, "int"); |
---|
273 | } |
---|
274 | else if (strcmp(w->string, "float")==0 && List_len(w->next) < 2 ) { |
---|
275 | strcpy(w->string, "double"); |
---|
276 | } |
---|
277 | } |
---|
278 | w = w->next; |
---|
279 | } |
---|
280 | } |
---|
281 | |
---|
282 | /* read a character: if it's a newline, increment the line count */ |
---|
283 | |
---|
284 | static int ngetc(FILE *f){ |
---|
285 | int c; |
---|
286 | |
---|
287 | c = getc(f); |
---|
288 | if (c == '\n') linenum++; |
---|
289 | |
---|
290 | return c; |
---|
291 | } |
---|
292 | |
---|
293 | #define MAX_COMMENT_SIZE 10000 |
---|
294 | |
---|
295 | static char last_comment[MAX_COMMENT_SIZE]; |
---|
296 | static int lc_size = 0; |
---|
297 | static char *found__attribute__ = 0; |
---|
298 | static char *found__ATTR__ = 0; |
---|
299 | |
---|
300 | static void clear_found_attribute() { |
---|
301 | free(found__attribute__); found__attribute__ = 0; |
---|
302 | free(found__ATTR__ ); found__ATTR__ = 0; |
---|
303 | } |
---|
304 | |
---|
305 | static void search_comment_for_attribute() { |
---|
306 | char *att; |
---|
307 | |
---|
308 | if (found__attribute__ || found__ATTR__) return; // only take first __attribute__ |
---|
309 | |
---|
310 | last_comment[lc_size] = 0; // close string |
---|
311 | |
---|
312 | att = strstr(last_comment, "__attribute__"); |
---|
313 | if (att != 0) { |
---|
314 | char *a = att+13; |
---|
315 | int parens = 1; |
---|
316 | |
---|
317 | while (*a && *a != '(') ++a; // search '(' |
---|
318 | if (*a++ == '(') { // if '(' found |
---|
319 | while (parens && *a) { |
---|
320 | switch (*a++) { |
---|
321 | case '(': parens++; break; |
---|
322 | case ')': parens--; break; |
---|
323 | } |
---|
324 | } |
---|
325 | *a = 0; |
---|
326 | DEBUG_PRINT("__attribute__ found!\n"); |
---|
327 | found__attribute__ = strdup(att); |
---|
328 | if (search__ATTR__) { error("found '__attribute__' but expected '__ATTR__..'"); } |
---|
329 | } |
---|
330 | } |
---|
331 | |
---|
332 | att = strstr(last_comment, "__ATTR__"); |
---|
333 | if (att != 0) { |
---|
334 | char *a = att+8; |
---|
335 | |
---|
336 | while (*a && (isalnum(*a) || *a == '_')) ++a; // goto end of name |
---|
337 | |
---|
338 | if (*a == '(') { |
---|
339 | int parens = 1; |
---|
340 | a++; |
---|
341 | |
---|
342 | while (parens && *a) { |
---|
343 | switch (*a++) { |
---|
344 | case '(': parens++; break; |
---|
345 | case ')': parens--; break; |
---|
346 | } |
---|
347 | } |
---|
348 | *a = 0; |
---|
349 | DEBUG_PRINT("__ATTR__ with parameters found!\n"); |
---|
350 | found__ATTR__ = strdup(att); |
---|
351 | } |
---|
352 | else { |
---|
353 | *a = 0; |
---|
354 | DEBUG_PRINT("__ATTR__ w/o parameters found!\n"); |
---|
355 | found__ATTR__ = strdup(att); |
---|
356 | } |
---|
357 | if (search__attribute__) { error("found '__ATTR__..' but expected '__attribute__'"); } |
---|
358 | } |
---|
359 | |
---|
360 | if (found__attribute__ && found__ATTR__) { |
---|
361 | error("Either specify __attribute__ or __ATTR__... - not both\n"); |
---|
362 | } |
---|
363 | } |
---|
364 | |
---|
365 | struct promotion; |
---|
366 | struct promotion { |
---|
367 | char *to_promote; // text to promote to header |
---|
368 | struct promotion *next; |
---|
369 | }; |
---|
370 | |
---|
371 | static struct promotion *promotions = 0; |
---|
372 | |
---|
373 | static void add_promotion(char *to_promote) { |
---|
374 | struct promotion *new_promotion = malloc(sizeof(struct promotion)); |
---|
375 | new_promotion->to_promote = to_promote; |
---|
376 | new_promotion->next = 0; |
---|
377 | |
---|
378 | if (!promotions) { |
---|
379 | promotions = new_promotion; |
---|
380 | } |
---|
381 | else { // append |
---|
382 | struct promotion *last = promotions; |
---|
383 | while (last->next) last = last->next; |
---|
384 | |
---|
385 | last->next = new_promotion; |
---|
386 | } |
---|
387 | } |
---|
388 | |
---|
389 | static void print_promotions() { |
---|
390 | struct promotion *p = promotions; |
---|
391 | |
---|
392 | if (promotions) fputc('\n', stdout); |
---|
393 | |
---|
394 | while (p) { |
---|
395 | struct promotion *next = p->next; |
---|
396 | |
---|
397 | printf("%s\n", p->to_promote); |
---|
398 | free(p->to_promote); |
---|
399 | free(p); |
---|
400 | |
---|
401 | p = next; |
---|
402 | } |
---|
403 | |
---|
404 | if (promotions) fputc('\n', stdout); |
---|
405 | promotions = 0; |
---|
406 | } |
---|
407 | |
---|
408 | static const char *promotion_tag = "AISC_MKPT_PROMOTE:"; |
---|
409 | static int promotion_tag_len = 18; |
---|
410 | |
---|
411 | static void search_comment_for_promotion() { |
---|
412 | char *promotion_found; |
---|
413 | last_comment[lc_size] = 0; // close string |
---|
414 | |
---|
415 | promotion_found = strstr(last_comment, promotion_tag); |
---|
416 | while (promotion_found) { |
---|
417 | char *behind_promo = promotion_found+promotion_tag_len; |
---|
418 | char *eol, *eoc; |
---|
419 | assert(behind_promo[-1] == ':'); // wrong promotion_tag_len |
---|
420 | |
---|
421 | eol = strchr(behind_promo, '\n'); |
---|
422 | eoc = strstr(behind_promo, "*/"); |
---|
423 | |
---|
424 | if (eoc && eol) { |
---|
425 | if (eoc<eol) eol = eoc; |
---|
426 | } |
---|
427 | else if (!eol) { |
---|
428 | eol = eoc; |
---|
429 | } |
---|
430 | |
---|
431 | if (!eol) eol = strchr(behind_promo, 0); |
---|
432 | |
---|
433 | assert(eol); |
---|
434 | if (!eol) { |
---|
435 | promotion_found = 0; |
---|
436 | } |
---|
437 | else { |
---|
438 | int promo_length = eol-behind_promo; |
---|
439 | char *to_promote = malloc(promo_length+1); |
---|
440 | |
---|
441 | memcpy(to_promote, behind_promo, promo_length); |
---|
442 | to_promote[promo_length] = 0; |
---|
443 | |
---|
444 | DEBUG_PRINT("promotion found!\n"); |
---|
445 | |
---|
446 | add_promotion(to_promote); |
---|
447 | promotion_found = strstr(eol, promotion_tag); |
---|
448 | } |
---|
449 | } |
---|
450 | } |
---|
451 | |
---|
452 | /* read the next character from the file. If the character is '\' then |
---|
453 | * read and skip the next character. Any comment sequence is converted |
---|
454 | * to a blank. |
---|
455 | * |
---|
456 | * if a comment contains __attribute__ and search__attribute__ != 0 |
---|
457 | * the attribute string is stored in found__attribute__ |
---|
458 | * |
---|
459 | * if a comment contains __ATTR__ and search__ATTR__ != 0 |
---|
460 | * the attribute string is stored in found__ATTR__ |
---|
461 | */ |
---|
462 | |
---|
463 | |
---|
464 | static int fnextch(FILE *f){ |
---|
465 | int c, lastc, incomment; |
---|
466 | |
---|
467 | c = ngetc(f); |
---|
468 | while (c == '\\') { |
---|
469 | DEBUG_PRINT("fnextch: in backslash loop\n"); |
---|
470 | c = ngetc(f); /* skip a character */ |
---|
471 | c = ngetc(f); |
---|
472 | } |
---|
473 | if (c == '/' && !inquote) { |
---|
474 | c = ngetc(f); |
---|
475 | if (c == '*') { |
---|
476 | long commentStartLine = linenum; |
---|
477 | |
---|
478 | incomment = 1; |
---|
479 | c = ' '; |
---|
480 | DEBUG_PRINT("fnextch: comment seen\n"); |
---|
481 | lc_size = 0; |
---|
482 | |
---|
483 | while (incomment) { |
---|
484 | lastc = c; |
---|
485 | c = ngetc(f); |
---|
486 | last_comment[lc_size++] = c; |
---|
487 | assert(lc_size<MAX_COMMENT_SIZE); |
---|
488 | |
---|
489 | if (lastc == '*' && c == '/') incomment = 0; |
---|
490 | else if (c < 0) { |
---|
491 | error("EOF reached in comment"); |
---|
492 | errorAt(commentStartLine, "comment started here"); |
---|
493 | return c; |
---|
494 | } |
---|
495 | } |
---|
496 | if (search__attribute__ || search__ATTR__) search_comment_for_attribute(); |
---|
497 | if (promote_lines) search_comment_for_promotion(); |
---|
498 | return fnextch(f); |
---|
499 | } |
---|
500 | else if (c == '/') { /* C++ style comment */ |
---|
501 | incomment = 1; |
---|
502 | c = ' '; |
---|
503 | DEBUG_PRINT("fnextch: C++ comment seen\n"); |
---|
504 | lc_size = 0; |
---|
505 | |
---|
506 | while (incomment) { |
---|
507 | lastc = c; |
---|
508 | c = ngetc(f); |
---|
509 | last_comment[lc_size++] = c; |
---|
510 | assert(lc_size<MAX_COMMENT_SIZE); |
---|
511 | |
---|
512 | if (lastc != '\\' && c == '\n') incomment = 0; |
---|
513 | else if (c < 0) break; |
---|
514 | } |
---|
515 | if (search__attribute__ || search__ATTR__) search_comment_for_attribute(); |
---|
516 | if (promote_lines) search_comment_for_promotion(); |
---|
517 | |
---|
518 | if (c == '\n') return c; |
---|
519 | return fnextch(f); |
---|
520 | } |
---|
521 | else { |
---|
522 | /* if we pre-fetched a linefeed, remember to adjust the line number */ |
---|
523 | if (c == '\n') linenum--; |
---|
524 | ungetc(c, f); |
---|
525 | return '/'; |
---|
526 | } |
---|
527 | } |
---|
528 | return c; |
---|
529 | } |
---|
530 | |
---|
531 | |
---|
532 | /* Get the next "interesting" character. Comments are skipped, and strings |
---|
533 | * are converted to "0". Also, if a line starts with "#" it is skipped. |
---|
534 | */ |
---|
535 | |
---|
536 | static int nextch(FILE *f){ |
---|
537 | int c, n; |
---|
538 | char *p, numbuf[10]; |
---|
539 | |
---|
540 | c = fnextch(f); |
---|
541 | |
---|
542 | /* skip preprocessor directives */ |
---|
543 | /* EXCEPTION: #line nnn or #nnn lines are interpreted */ |
---|
544 | |
---|
545 | if (newline_seen && c == '#') { |
---|
546 | /* skip blanks */ |
---|
547 | do { |
---|
548 | c = fnextch(f); |
---|
549 | } while ( c >= 0 && (c == '\t' || c == ' ') ); |
---|
550 | /* check for #line */ |
---|
551 | if (c == 'l') { |
---|
552 | c = fnextch(f); |
---|
553 | if (c != 'i') /* not a #line directive */ |
---|
554 | goto skip_rest_of_line; |
---|
555 | do { |
---|
556 | c = fnextch(f); |
---|
557 | } while (c >= 0 && c != '\n' && !isdigit(c)); |
---|
558 | } |
---|
559 | |
---|
560 | /* if we have a digit it's a line number, from the preprocessor */ |
---|
561 | if (c >= 0 && isdigit(c)) { |
---|
562 | p = numbuf; |
---|
563 | for (n = 8; n >= 0; --n) { |
---|
564 | *p++ = c; |
---|
565 | c = fnextch(f); |
---|
566 | if (c <= 0 || !isdigit(c)) |
---|
567 | break; |
---|
568 | } |
---|
569 | *p = 0; |
---|
570 | linenum = atol(numbuf) - 1; |
---|
571 | } |
---|
572 | |
---|
573 | /* skip the rest of the line */ |
---|
574 | skip_rest_of_line: |
---|
575 | while (c >= 0 && c != '\n') |
---|
576 | c = fnextch(f); |
---|
577 | if (c < 0) |
---|
578 | return c; |
---|
579 | } |
---|
580 | newline_seen = (c == '\n'); |
---|
581 | |
---|
582 | if (c == '\'' || c == '\"') { |
---|
583 | char buffer[11]; |
---|
584 | int index = 0; |
---|
585 | long quoteStartLine = linenum; |
---|
586 | |
---|
587 | DEBUG_PRINT("nextch: in a quote\n"); |
---|
588 | inquote = c; |
---|
589 | while ( (c = fnextch(f)) >= 0 ) { |
---|
590 | if (c == inquote) { |
---|
591 | buffer[index] = 0; |
---|
592 | DEBUG_PRINT("quoted content='"); |
---|
593 | DEBUG_PRINT(buffer); |
---|
594 | DEBUG_PRINT("'\n"); |
---|
595 | |
---|
596 | DEBUG_PRINT("nextch: out of quote\n"); |
---|
597 | |
---|
598 | if (linenum != quoteStartLine) { |
---|
599 | error("multiline quotes"); |
---|
600 | errorAt(quoteStartLine, "quotes opened here"); |
---|
601 | } |
---|
602 | |
---|
603 | if (inquote=='\"' && strcmp(buffer, "C")==0) { |
---|
604 | inquote = 0; |
---|
605 | return '$'; /* found "C" (needed for 'extern "C"')*/ |
---|
606 | } |
---|
607 | inquote = 0; |
---|
608 | return '0'; |
---|
609 | } |
---|
610 | else { |
---|
611 | if (index<10) buffer[index++] = c; |
---|
612 | } |
---|
613 | } |
---|
614 | error("EOF in a quote"); |
---|
615 | errorAt(quoteStartLine, "quote started here"); |
---|
616 | DEBUG_PRINT("nextch: EOF in a quote\n"); |
---|
617 | } |
---|
618 | return c; |
---|
619 | } |
---|
620 | |
---|
621 | /* |
---|
622 | * Get the next symbol from the file, skipping blanks. |
---|
623 | * Return 0 if OK, -1 for EOF. |
---|
624 | * Also collapses everything between { and } |
---|
625 | */ |
---|
626 | |
---|
627 | static int getsym(char *buf, FILE *f){ |
---|
628 | int c; |
---|
629 | int inbrack = 0; |
---|
630 | |
---|
631 | #if defined(DEBUG_PRINTS) |
---|
632 | char *bufStart = buf; |
---|
633 | #endif /* DEBUG_PRINTS */ |
---|
634 | |
---|
635 | c = glastc; |
---|
636 | while ((c > 0) && isspace(c)) { |
---|
637 | c = nextch(f); |
---|
638 | } |
---|
639 | |
---|
640 | if (c < 0) { |
---|
641 | DEBUG_PRINT("EOF read in getsym\n"); |
---|
642 | return -1; |
---|
643 | } |
---|
644 | |
---|
645 | if (c == '{') { |
---|
646 | long bracketStartLine = linenum; |
---|
647 | |
---|
648 | inbrack = 1; |
---|
649 | DEBUG_PRINT("getsym: in '{'\n"); |
---|
650 | while (inbrack) { |
---|
651 | c = nextch(f); |
---|
652 | if (c < 0) { |
---|
653 | error("EOF seen in bracket loop (unbalanced brackets?)"); |
---|
654 | errorAt(bracketStartLine, "bracket opened here"); |
---|
655 | DEBUG_PRINT("getsym: EOF seen in bracket loop\n"); |
---|
656 | glastc = c; |
---|
657 | return c; |
---|
658 | } |
---|
659 | if (c == '{') { |
---|
660 | inbrack++; |
---|
661 | #if defined(DEBUG_PRINTS) |
---|
662 | fprintf(stderr, "inbrack=%i (line=%li)\n", inbrack, linenum); |
---|
663 | #endif /* DEBUG_PRINTS */ |
---|
664 | } |
---|
665 | else if (c == '}') { |
---|
666 | inbrack--; |
---|
667 | #if defined(DEBUG_PRINTS) |
---|
668 | fprintf(stderr, "inbrack=%i (line=%li)\n", inbrack, linenum); |
---|
669 | #endif /* DEBUG_PRINTS */ |
---|
670 | } |
---|
671 | } |
---|
672 | strcpy(buf, "{}"); |
---|
673 | glastc = nextch(f); |
---|
674 | DEBUG_PRINT("getsym: returning brackets '"); |
---|
675 | } |
---|
676 | else if (!ISCSYM(c)) { |
---|
677 | *buf++ = c; |
---|
678 | *buf = 0; |
---|
679 | glastc = nextch(f); |
---|
680 | |
---|
681 | DEBUG_PRINT("getsym: returning special symbol '"); |
---|
682 | } |
---|
683 | else { |
---|
684 | while (ISCSYM(c)) { |
---|
685 | *buf++ = c; |
---|
686 | c = nextch(f); |
---|
687 | } |
---|
688 | *buf = 0; |
---|
689 | glastc = c; |
---|
690 | DEBUG_PRINT("getsym: returning word '"); |
---|
691 | } |
---|
692 | |
---|
693 | DEBUG_PRINT(bufStart); |
---|
694 | DEBUG_PRINT("'\n"); |
---|
695 | |
---|
696 | return 0; |
---|
697 | } |
---|
698 | |
---|
699 | /* |
---|
700 | * skipit: skip until a ";" or the end of a function declaration is seen |
---|
701 | */ |
---|
702 | static int skipit(char *buf, FILE *f){ |
---|
703 | int i; |
---|
704 | |
---|
705 | do { |
---|
706 | DEBUG_PRINT("in skipit loop\n"); |
---|
707 | |
---|
708 | i = getsym(buf, f); |
---|
709 | if (i < 0) return i; |
---|
710 | |
---|
711 | DEBUG_PRINT("skipit: '"); |
---|
712 | DEBUG_PRINT(buf); |
---|
713 | DEBUG_PRINT("'\n"); |
---|
714 | |
---|
715 | } while (*buf != ';' && *buf != '{'); |
---|
716 | |
---|
717 | return 0; |
---|
718 | } |
---|
719 | |
---|
720 | /* |
---|
721 | * find most common type specifiers for purpose of ruling them out as |
---|
722 | * parm names |
---|
723 | */ |
---|
724 | |
---|
725 | static int is_type_word(char *s){ |
---|
726 | static const char *typewords[] = { |
---|
727 | "char", "const", "double", "enum", |
---|
728 | "float", "int", "long", "short", |
---|
729 | "signed", "struct", "union", "unsigned", |
---|
730 | "void", "volatile", (char *)0 |
---|
731 | }; |
---|
732 | |
---|
733 | const char **ss; |
---|
734 | |
---|
735 | for (ss = typewords; *ss; ++ss) |
---|
736 | if (strcmp(s, *ss) == 0) |
---|
737 | return 1; |
---|
738 | |
---|
739 | return 0; |
---|
740 | } |
---|
741 | |
---|
742 | |
---|
743 | /* Ad-hoc macro to recognize parameter name for purposes of removal. |
---|
744 | * Idea is to remove the bulk of easily recognized parm names without |
---|
745 | * losing too many type specifiers. (sg) |
---|
746 | */ |
---|
747 | #define IS_PARM_NAME(w) \ |
---|
748 | (ISCSYM(*(w)->string) && !is_type_word((w)->string) && \ |
---|
749 | (!(w)->next || *(w)->next->string == ',' || \ |
---|
750 | *(w)->next->string == '[')) |
---|
751 | |
---|
752 | |
---|
753 | /* |
---|
754 | * given a list representing a type and a variable name, extract just |
---|
755 | * the base type, e.g. "struct word *x" would yield "struct word" |
---|
756 | */ |
---|
757 | |
---|
758 | static Word *typelist(Word *p){ |
---|
759 | Word *w, *r; |
---|
760 | |
---|
761 | r = w = word_alloc(""); |
---|
762 | while (p && p->next) { |
---|
763 | /* handle int *x --> int */ |
---|
764 | if (p->string[0] && !ISCSYM(p->string[0])) |
---|
765 | break; |
---|
766 | /* handle int x[] --> int */ |
---|
767 | if (p->next->string[0] == '[') |
---|
768 | break; |
---|
769 | w->next = word_alloc(p->string); |
---|
770 | w = w->next; |
---|
771 | p = p->next; |
---|
772 | } |
---|
773 | return r; |
---|
774 | } |
---|
775 | |
---|
776 | /* |
---|
777 | * Get a parameter list; when this is called the next symbol in line |
---|
778 | * should be the first thing in the list. |
---|
779 | */ |
---|
780 | |
---|
781 | static Word *getparamlist(FILE *f){ |
---|
782 | static Word *pname[MAXPARAM]; /* parameter names */ |
---|
783 | Word *tlist, /* type name */ |
---|
784 | *plist; /* temporary */ |
---|
785 | int np = 0; /* number of parameters */ |
---|
786 | int typed[MAXPARAM]; /* parameter has been given a type */ |
---|
787 | int tlistdone; /* finished finding the type name */ |
---|
788 | int sawsomething; |
---|
789 | int i; |
---|
790 | int inparen = 0; |
---|
791 | char buf[80]; |
---|
792 | |
---|
793 | DEBUG_PRINT("in getparamlist\n"); |
---|
794 | for (i = 0; i < MAXPARAM; i++) |
---|
795 | typed[i] = 0; |
---|
796 | |
---|
797 | plist = word_alloc(""); |
---|
798 | |
---|
799 | /* first, get the stuff inside brackets (if anything) */ |
---|
800 | |
---|
801 | sawsomething = 0; /* gets set nonzero when we see an arg */ |
---|
802 | for (;;) { |
---|
803 | if (getsym(buf, f) < 0) return NULL; |
---|
804 | if (*buf == ')' && (--inparen < 0)) { |
---|
805 | if (sawsomething) { /* if we've seen an arg */ |
---|
806 | pname[np] = plist; |
---|
807 | plist = word_alloc(""); |
---|
808 | np++; |
---|
809 | } |
---|
810 | break; |
---|
811 | } |
---|
812 | if (*buf == ';') { /* something weird */ |
---|
813 | return ABORTED; |
---|
814 | } |
---|
815 | sawsomething = 1; /* there's something in the arg. list */ |
---|
816 | if (*buf == ',' && inparen == 0) { |
---|
817 | pname[np] = plist; |
---|
818 | plist = word_alloc(""); |
---|
819 | np++; |
---|
820 | } |
---|
821 | else { |
---|
822 | addword(plist, buf); |
---|
823 | if (*buf == '(') inparen++; |
---|
824 | } |
---|
825 | } |
---|
826 | |
---|
827 | /* next, get the declarations after the function header */ |
---|
828 | |
---|
829 | inparen = 0; |
---|
830 | |
---|
831 | tlist = word_alloc(""); |
---|
832 | plist = word_alloc(""); |
---|
833 | tlistdone = 0; |
---|
834 | sawsomething = 0; |
---|
835 | for(;;) { |
---|
836 | if (getsym(buf, f) < 0) return NULL; |
---|
837 | |
---|
838 | /* handle a list like "int x,y,z" */ |
---|
839 | if (*buf == ',' && !inparen) { |
---|
840 | if (!sawsomething) |
---|
841 | return NULL; |
---|
842 | for (i = 0; i < np; i++) { |
---|
843 | if (!typed[i] && foundin(plist, pname[i])) { |
---|
844 | typed[i] = 1; |
---|
845 | word_free(pname[i]); |
---|
846 | pname[i] = word_append(tlist, plist); |
---|
847 | /* promote types */ |
---|
848 | typefixhack(pname[i]); |
---|
849 | break; |
---|
850 | } |
---|
851 | } |
---|
852 | if (!tlistdone) { |
---|
853 | tlist = typelist(plist); |
---|
854 | tlistdone = 1; |
---|
855 | } |
---|
856 | word_free(plist); |
---|
857 | plist = word_alloc(""); |
---|
858 | } |
---|
859 | /* handle the end of a list */ |
---|
860 | else if (*buf == ';') { |
---|
861 | if (!sawsomething) |
---|
862 | return ABORTED; |
---|
863 | for (i = 0; i < np; i++) { |
---|
864 | if (!typed[i] && foundin(plist, pname[i])) { |
---|
865 | typed[i] = 1; |
---|
866 | word_free(pname[i]); |
---|
867 | pname[i] = word_append(tlist, plist); |
---|
868 | typefixhack(pname[i]); |
---|
869 | break; |
---|
870 | } |
---|
871 | } |
---|
872 | tlistdone = 0; |
---|
873 | word_free(tlist); word_free(plist); |
---|
874 | tlist = word_alloc(""); |
---|
875 | plist = word_alloc(""); |
---|
876 | } |
---|
877 | /* handle the beginning of the function */ |
---|
878 | else if (strcmp(buf, "{}")==0) break; |
---|
879 | /* otherwise, throw the word into the list (except for "register") */ |
---|
880 | else if (strcmp(buf, "register")) { |
---|
881 | addword(plist, buf); |
---|
882 | if (*buf == '(') inparen++; |
---|
883 | else if (*buf == ')') inparen--; |
---|
884 | else sawsomething = 1; |
---|
885 | } |
---|
886 | } |
---|
887 | |
---|
888 | /* Now take the info we have and build a prototype list */ |
---|
889 | |
---|
890 | /* empty parameter list means "void" */ |
---|
891 | if (np == 0) return word_alloc("void"); |
---|
892 | |
---|
893 | plist = tlist = word_alloc(""); |
---|
894 | |
---|
895 | /* how to handle parameters which contain only one word ? |
---|
896 | * |
---|
897 | * void -> void |
---|
898 | * xxx -> int xxx (if AUTO_INT is defined) |
---|
899 | * int -> int dummyXX (otherwise) |
---|
900 | */ |
---|
901 | |
---|
902 | /* #define AUTO_INT */ |
---|
903 | |
---|
904 | { |
---|
905 | #if !defined(AUTO_INT) |
---|
906 | int dummy_counter = 1; |
---|
907 | char dummy_name[] = "dummy_xx"; |
---|
908 | #define DUMMY_COUNTER_POS 6 |
---|
909 | #endif |
---|
910 | |
---|
911 | for (i = 0; i < np; i++) { |
---|
912 | #if !defined(AUTO_INT) |
---|
913 | int add_dummy_name = 0; |
---|
914 | #endif |
---|
915 | { |
---|
916 | Word *pn_list = pname[i]; |
---|
917 | int cnt = 0; |
---|
918 | int is_void = 0; |
---|
919 | |
---|
920 | while (pn_list) { /* count words */ |
---|
921 | if (pn_list->string[0]) { |
---|
922 | ++cnt; |
---|
923 | if (strcmp(pn_list->string, "void")==0) is_void = 1; |
---|
924 | } |
---|
925 | pn_list = pn_list->next; |
---|
926 | } |
---|
927 | if (cnt==1 && !is_void) { /* only name, but not void */ |
---|
928 | /* no type or no parameter name */ |
---|
929 | #ifdef AUTO_INT |
---|
930 | /* If no type provided, make it an "int" */ |
---|
931 | addword(tlist, "int"); /* add int to tlist before adding pname[i] */ |
---|
932 | #else |
---|
933 | add_dummy_name = 1; /* add a dummy name after adding pname[i] */ |
---|
934 | #endif |
---|
935 | } |
---|
936 | } |
---|
937 | |
---|
938 | while (tlist->next) tlist = tlist->next; |
---|
939 | tlist->next = pname[i]; |
---|
940 | |
---|
941 | #if !defined(AUTO_INT) |
---|
942 | if (add_dummy_name) { |
---|
943 | assert(dummy_counter<100); |
---|
944 | dummy_name[DUMMY_COUNTER_POS] = (dummy_counter/10)+'0'; |
---|
945 | dummy_name[DUMMY_COUNTER_POS] = (dummy_counter%10)+'0'; |
---|
946 | addword(tlist, dummy_name); |
---|
947 | dummy_counter++; |
---|
948 | } |
---|
949 | #endif |
---|
950 | |
---|
951 | if (i < np - 1) addword(tlist, ","); |
---|
952 | } |
---|
953 | } |
---|
954 | |
---|
955 | /* debugging output */ |
---|
956 | #if 0 |
---|
957 | printf("/* "); |
---|
958 | tlist = plist; |
---|
959 | while (tlist) { |
---|
960 | printf("'%s', ", tlist->string); |
---|
961 | tlist = tlist->next; |
---|
962 | } |
---|
963 | printf(" */\n"); |
---|
964 | #endif |
---|
965 | |
---|
966 | return plist; |
---|
967 | } |
---|
968 | |
---|
969 | /* |
---|
970 | * emit a function declaration. The attributes and name of the function |
---|
971 | * are in wlist; the parameters are in plist. |
---|
972 | */ |
---|
973 | |
---|
974 | static void emit(Word *wlist, Word *plist, long startline) { |
---|
975 | Word *w; |
---|
976 | int count = 0; |
---|
977 | int needspace = 0; |
---|
978 | int isstatic = 0; |
---|
979 | int ismain = 0; |
---|
980 | int refs = 0 ; |
---|
981 | |
---|
982 | if (promote_lines) print_promotions(); |
---|
983 | |
---|
984 | for (w = wlist; w; w = w->next) { |
---|
985 | if (w->string[0]) { |
---|
986 | count ++; |
---|
987 | if (strcmp(w->string, "static") == 0) isstatic = 1; |
---|
988 | else if (strcmp(w->string, "main" ) == 0) ismain = 1; |
---|
989 | } |
---|
990 | } |
---|
991 | |
---|
992 | if (ismain && !use_main) return; |
---|
993 | |
---|
994 | if (aisc) { |
---|
995 | if (count < 2) { |
---|
996 | printf("int\t"); |
---|
997 | w = wlist; |
---|
998 | } else { |
---|
999 | refs = 0; |
---|
1000 | for (w = wlist; w; w = w->next) { |
---|
1001 | if (w->string[0]) { |
---|
1002 | printf("%s,\t", w->string); |
---|
1003 | w = w->next; |
---|
1004 | break; |
---|
1005 | } |
---|
1006 | } |
---|
1007 | } |
---|
1008 | for (;w; w = w->next) { |
---|
1009 | if (w->string[0] == '*') { |
---|
1010 | refs++; |
---|
1011 | continue; |
---|
1012 | } |
---|
1013 | if (w->string[0]) { |
---|
1014 | printf("%s,", w->string); |
---|
1015 | break; |
---|
1016 | } |
---|
1017 | } |
---|
1018 | if (refs) { |
---|
1019 | printf("\tlink%i,\t{\n", refs); |
---|
1020 | refs = 0; |
---|
1021 | }else{ |
---|
1022 | printf("\tterm,\t{\n"); |
---|
1023 | } |
---|
1024 | refs = 0; |
---|
1025 | printf("\t@TYPE,\t@IDENT,\t@REF;\n"); |
---|
1026 | if (strcmp(plist->string, "void")) { /* if parameter is not 'void' */ |
---|
1027 | int name_seen = 0; |
---|
1028 | int unnamed_counter = 1; |
---|
1029 | for (w = plist; w; w = w->next) { |
---|
1030 | if (w->string[0] == '*') { |
---|
1031 | refs++; |
---|
1032 | name_seen = 0; |
---|
1033 | continue; |
---|
1034 | } |
---|
1035 | if (w->string[0] == ',') { |
---|
1036 | if (refs) { |
---|
1037 | printf("\tlink%i;\n", refs); |
---|
1038 | refs = 0; |
---|
1039 | continue; |
---|
1040 | } else { |
---|
1041 | printf("\tterm;\n"); |
---|
1042 | continue; |
---|
1043 | } |
---|
1044 | } |
---|
1045 | if (w->string[0]) { |
---|
1046 | printf("\t%s,", w->string); |
---|
1047 | name_seen = 1; |
---|
1048 | } |
---|
1049 | } |
---|
1050 | if (refs) { |
---|
1051 | if (!name_seen) { |
---|
1052 | /* automatically insert missing parameter names */ |
---|
1053 | printf("\tunnamed%i,", unnamed_counter++); |
---|
1054 | } |
---|
1055 | printf("\tlink%i;\n", refs); |
---|
1056 | refs = 0; |
---|
1057 | } else { |
---|
1058 | printf("\tterm;\n"); |
---|
1059 | } |
---|
1060 | } |
---|
1061 | printf("};\n\n"); |
---|
1062 | return; |
---|
1063 | } |
---|
1064 | DEBUG_PRINT("emit called\n"); |
---|
1065 | if (donum) |
---|
1066 | printf("/*%8ld */ ", startline); |
---|
1067 | |
---|
1068 | |
---|
1069 | /* if the -e flag was given, and it's not a static function, print "extern" */ |
---|
1070 | |
---|
1071 | if (print_extern && !isstatic) { |
---|
1072 | printf("extern "); |
---|
1073 | } |
---|
1074 | |
---|
1075 | if (count < 2) { |
---|
1076 | printf("int"); |
---|
1077 | needspace = 1; |
---|
1078 | } |
---|
1079 | |
---|
1080 | for (w = wlist; w; w = w->next) { |
---|
1081 | if (needspace) |
---|
1082 | putchar(' '); |
---|
1083 | printf("%s", w->string); |
---|
1084 | needspace = ISCSYM(w->string[0]); |
---|
1085 | } |
---|
1086 | |
---|
1087 | if (use_macro) printf(" %s((", macro_name); |
---|
1088 | else putchar('('); |
---|
1089 | |
---|
1090 | needspace = 0; |
---|
1091 | for (w = plist; w; w = w->next) { |
---|
1092 | if (no_parm_names && IS_PARM_NAME(w)) |
---|
1093 | continue; |
---|
1094 | if (w->string[0] == ',') |
---|
1095 | needspace = 1; |
---|
1096 | else if (w->string[0] == '[') |
---|
1097 | needspace = 0; |
---|
1098 | else |
---|
1099 | { |
---|
1100 | if (needspace) |
---|
1101 | putchar(' '); |
---|
1102 | needspace = ISCSYM(w->string[0]); |
---|
1103 | } |
---|
1104 | printf("%s", w->string); |
---|
1105 | } |
---|
1106 | |
---|
1107 | if (use_macro) PRINT("))"); |
---|
1108 | else PRINT(")"); |
---|
1109 | |
---|
1110 | if (found__attribute__) { PRINT(" "); PRINT(found__attribute__); } |
---|
1111 | if (found__ATTR__ ) { PRINT(" "); PRINT(found__ATTR__ ); } |
---|
1112 | |
---|
1113 | PRINT(";\n"); |
---|
1114 | } |
---|
1115 | |
---|
1116 | /* |
---|
1117 | * parse all function declarations and print to STDOUT |
---|
1118 | */ |
---|
1119 | |
---|
1120 | static void getdecl(FILE *f, const char *header) { |
---|
1121 | Word *plist, *wlist = NULL; |
---|
1122 | char buf[80]; |
---|
1123 | int sawsomething; |
---|
1124 | long startline; /* line where declaration started */ |
---|
1125 | int oktoprint; |
---|
1126 | int header_printed = 0; |
---|
1127 | |
---|
1128 | current_file = strdup(header); |
---|
1129 | |
---|
1130 | again: |
---|
1131 | DEBUG_PRINT("again\n"); |
---|
1132 | word_free(wlist); |
---|
1133 | wlist = word_alloc(""); |
---|
1134 | sawsomething = 0; |
---|
1135 | oktoprint = 1; |
---|
1136 | extern_c_seen = 0; |
---|
1137 | |
---|
1138 | for(;;) { |
---|
1139 | DEBUG_PRINT("main getdecl loop\n"); |
---|
1140 | if (getsym(buf,f) < 0) { |
---|
1141 | DEBUG_PRINT("EOF in getdecl loop\n"); |
---|
1142 | return; |
---|
1143 | } |
---|
1144 | |
---|
1145 | DEBUG_PRINT("getdecl: '"); |
---|
1146 | DEBUG_PRINT(buf); |
---|
1147 | DEBUG_PRINT("'\n"); |
---|
1148 | |
---|
1149 | /* try to guess when a declaration is not an external function definition */ |
---|
1150 | if (strcmp(buf, ",")==0 || |
---|
1151 | strcmp(buf, "=")==0 || |
---|
1152 | strcmp(buf, "typedef")==0 || |
---|
1153 | strcmp(buf, "[")==0) |
---|
1154 | { |
---|
1155 | skipit(buf, f); |
---|
1156 | goto again; |
---|
1157 | } |
---|
1158 | |
---|
1159 | if (strcmp(buf, "{}")==0) { |
---|
1160 | if (!extern_c_seen) skipit(buf, f); |
---|
1161 | goto again; |
---|
1162 | } |
---|
1163 | |
---|
1164 | if (strcmp(buf, "extern")==0) { |
---|
1165 | if (getsym(buf, f)<0) { |
---|
1166 | DEBUG_PRINT("EOF in getdecl loop\n"); |
---|
1167 | return; |
---|
1168 | } |
---|
1169 | |
---|
1170 | DEBUG_PRINT("test auf extern \"C\": '"); |
---|
1171 | DEBUG_PRINT(buf); |
---|
1172 | DEBUG_PRINT("'\n"); |
---|
1173 | |
---|
1174 | if (strcmp(buf, "$")==0) { /* symbol used if "C" was found */ |
---|
1175 | extern_c_seen = 1; |
---|
1176 | if (promote_extern_c) { |
---|
1177 | addword(wlist, "extern"); |
---|
1178 | addword(wlist, "\"C\" "); |
---|
1179 | sawsomething = 1; |
---|
1180 | } |
---|
1181 | continue; |
---|
1182 | } |
---|
1183 | |
---|
1184 | skipit(buf, f); |
---|
1185 | goto again; |
---|
1186 | } |
---|
1187 | |
---|
1188 | if (oktoprint && !dostatic && strcmp(buf, "static")==0) { |
---|
1189 | oktoprint = 0; |
---|
1190 | } |
---|
1191 | if (oktoprint && !doinline && strcmp(buf, "inline")==0) { |
---|
1192 | oktoprint = 0; |
---|
1193 | } |
---|
1194 | |
---|
1195 | /* for the benefit of compilers that allow "inline" declarations */ |
---|
1196 | /* if (strcmp(buf, "inline") == 0 && !sawsomething) continue; */ |
---|
1197 | if (strcmp(buf, ";") == 0) goto again; |
---|
1198 | |
---|
1199 | /* A left parenthesis *might* indicate a function definition */ |
---|
1200 | if (strcmp(buf, "(")==0) { |
---|
1201 | startline = linenum; |
---|
1202 | if (!sawsomething || !(plist = getparamlist(f))) { |
---|
1203 | skipit(buf, f); |
---|
1204 | goto again; |
---|
1205 | } |
---|
1206 | if (plist == ABORTED) |
---|
1207 | goto again; |
---|
1208 | |
---|
1209 | /* It seems to have been what we wanted */ |
---|
1210 | |
---|
1211 | if (oktoprint) { /* check function-name */ |
---|
1212 | Word *w; |
---|
1213 | |
---|
1214 | for (w=wlist; w->next && oktoprint; w=w->next) { |
---|
1215 | if (w->string[0]==':' && w->string[1]==0) oktoprint = 0; /* do not emit prototypes for member functions */ |
---|
1216 | } |
---|
1217 | |
---|
1218 | if (oktoprint && symParts && !containsSymPart(w->string)) { /* name does not contain sym_part */ |
---|
1219 | oktoprint = 0; /* => do not emit prototype */ |
---|
1220 | } |
---|
1221 | } |
---|
1222 | |
---|
1223 | if (oktoprint) { |
---|
1224 | if (!header_printed) { |
---|
1225 | if (aisc) printf("\n# %s\n", header); |
---|
1226 | else printf("\n/* %s */\n", header); |
---|
1227 | header_printed = 1; |
---|
1228 | } |
---|
1229 | emit(wlist, plist, startline); |
---|
1230 | } |
---|
1231 | clear_found_attribute(); |
---|
1232 | |
---|
1233 | word_free(plist); |
---|
1234 | goto again; |
---|
1235 | } |
---|
1236 | |
---|
1237 | addword(wlist, buf); |
---|
1238 | sawsomething = 1; |
---|
1239 | } |
---|
1240 | } |
---|
1241 | |
---|
1242 | static void Usage(void){ |
---|
1243 | fprintf(stderr, "Usage: %s [flags] [files ...]", ourname); |
---|
1244 | fputs("\nSupported flags:" |
---|
1245 | "\n -a make a funcion list for aisc_includes (default: generate C prototypes)" |
---|
1246 | "\n" |
---|
1247 | "\n -e put an explicit \"extern\" keyword in declarations" |
---|
1248 | "\n" |
---|
1249 | "\n -n put line numbers of declarations as comments" |
---|
1250 | "\n" |
---|
1251 | "\n -s promote declarations for static functions" |
---|
1252 | "\n -i promote declarations for inline functions" |
---|
1253 | "\n -m promote declaration of 'main()' (default is to skip it)" |
---|
1254 | "\n -F part[,part]* only promote declarations for functionnames containing one of the parts" |
---|
1255 | "\n" |
---|
1256 | "\n -W don't promote types in old style declarations" |
---|
1257 | "\n -x omit parameter names in prototypes" |
---|
1258 | "\n" |
---|
1259 | "\n -p sym use \"sym\" as the prototype macro (default \"P_\")" |
---|
1260 | "\n -z omit prototype macro definition" |
---|
1261 | "\n -A omit prototype macro; header files are strict ANSI" |
---|
1262 | "\n" |
---|
1263 | "\n -C insert 'extern \"C\"'" |
---|
1264 | "\n -E prefix 'extern \"C\"' at prototype" |
---|
1265 | "\n" |
---|
1266 | "\n -g search for GNU extension __attribute__ in comment behind function header" |
---|
1267 | "\n -G search for ARB macro __ATTR__ in comment behind function header" |
---|
1268 | "\n" |
---|
1269 | "\n -P promote /*AISC_MKPT_PROMOTE:forHeader*/ to header" |
---|
1270 | "\n" |
---|
1271 | "\n -w add standard include wrapper" |
---|
1272 | "\n" |
---|
1273 | "\n -c \"text\" add text as comment into header" |
---|
1274 | "\n" |
---|
1275 | "\n -V print version number" |
---|
1276 | "\n" |
---|
1277 | , stderr); |
---|
1278 | exit(EXIT_FAILURE); |
---|
1279 | } |
---|
1280 | |
---|
1281 | int main(int argc, char **argv){ |
---|
1282 | FILE *f; |
---|
1283 | char *t, *iobuf; |
---|
1284 | int exit_if_noargs = 0; |
---|
1285 | |
---|
1286 | if (argv[0] && argv[0][0]) { |
---|
1287 | |
---|
1288 | ourname = strrchr(argv[0], '/'); |
---|
1289 | if (!ourname) |
---|
1290 | ourname = argv[0]; |
---|
1291 | } |
---|
1292 | else { |
---|
1293 | ourname = "mkptypes"; |
---|
1294 | } |
---|
1295 | |
---|
1296 | argv++; argc--; |
---|
1297 | |
---|
1298 | iobuf = (char *)malloc(NEWBUFSIZ); |
---|
1299 | while (*argv && **argv == '-') { |
---|
1300 | t = *argv++; --argc; t++; |
---|
1301 | while (*t) { |
---|
1302 | if (*t == 'e') print_extern = 1; |
---|
1303 | else if (*t == 'A') use_macro = 0; |
---|
1304 | else if (*t == 'C') cansibycplus = 1; |
---|
1305 | else if (*t == 'E') promote_extern_c = 1; |
---|
1306 | else if (*t == 'W') dont_promote = 1; |
---|
1307 | else if (*t == 'a') aisc = 1; |
---|
1308 | else if (*t == 'g') search__attribute__ = 1; |
---|
1309 | else if (*t == 'G') search__ATTR__ = 1; |
---|
1310 | else if (*t == 'n') donum = 1; |
---|
1311 | else if (*t == 's') dostatic = 1; |
---|
1312 | else if (*t == 'i') doinline = 1; |
---|
1313 | else if (*t == 'x') no_parm_names = 1; /* no parm names, only types (sg) */ |
---|
1314 | else if (*t == 'z') define_macro = 0; |
---|
1315 | else if (*t == 'P') promote_lines = 1; |
---|
1316 | else if (*t == 'm') use_main = 1; |
---|
1317 | else if (*t == 'p') { |
---|
1318 | t = *argv++; --argc; |
---|
1319 | if (!t) Usage(); |
---|
1320 | use_macro = 1; |
---|
1321 | macro_name = t; |
---|
1322 | break; |
---|
1323 | } |
---|
1324 | else if (*t == 'c') { |
---|
1325 | t = *argv++; --argc; |
---|
1326 | if (!t) Usage(); |
---|
1327 | header_comment = t; |
---|
1328 | break; |
---|
1329 | } |
---|
1330 | else if (*t == 'w') { |
---|
1331 | t = *argv++; --argc; |
---|
1332 | if (!t) Usage(); |
---|
1333 | include_wrapper = t; |
---|
1334 | break; |
---|
1335 | } |
---|
1336 | else if (*t == 'F') { |
---|
1337 | t = *argv++; --argc; |
---|
1338 | if (!t) Usage(); |
---|
1339 | addSymParts(t); |
---|
1340 | break; |
---|
1341 | } |
---|
1342 | else if (*t == 'V') { |
---|
1343 | exit_if_noargs = 1; |
---|
1344 | Version(); |
---|
1345 | } |
---|
1346 | else Usage(); |
---|
1347 | t++; |
---|
1348 | } |
---|
1349 | } |
---|
1350 | |
---|
1351 | if (search__ATTR__ && search__attribute__) { |
---|
1352 | fputs("Either use option -g or -G (not both)", stderr); |
---|
1353 | exit(EXIT_FAILURE); |
---|
1354 | } |
---|
1355 | |
---|
1356 | if (argc == 0 && exit_if_noargs) { |
---|
1357 | exit(EXIT_FAILURE); |
---|
1358 | } |
---|
1359 | |
---|
1360 | char *include_macro = 0; |
---|
1361 | if (aisc) { |
---|
1362 | if (header_comment) { |
---|
1363 | fputs("# *********************************************************\n", stdout); |
---|
1364 | printf("# %s\n", header_comment); |
---|
1365 | } |
---|
1366 | fputs("# *********************************************************\n" |
---|
1367 | "# This file is generated by aisc_mkpt.\n" |
---|
1368 | "# Any changes you make here will be overwritten later!\n" |
---|
1369 | "# *********************************************************\n" |
---|
1370 | "\n" |
---|
1371 | "@FUNCTION_TYPE, @FUNCTION, @FUNCTION_REF;", stdout); |
---|
1372 | } |
---|
1373 | else { |
---|
1374 | fputs("/*\n", stdout); |
---|
1375 | if (header_comment) printf(" * %s.\n *\n", header_comment); |
---|
1376 | fputs(" * This file is generated by aisc_mkpt.\n" |
---|
1377 | " * Any changes you make here will be overwritten later!\n" |
---|
1378 | " *\n" |
---|
1379 | " */\n\n", stdout); |
---|
1380 | |
---|
1381 | if (include_wrapper) { |
---|
1382 | int p; |
---|
1383 | include_macro = strdup(include_wrapper); |
---|
1384 | for (p = 0; include_macro[p]; p++) { |
---|
1385 | char c = include_macro[p]; |
---|
1386 | c = strchr(".-", c) ? '_' : toupper(c); |
---|
1387 | include_macro[p] = c; |
---|
1388 | } |
---|
1389 | |
---|
1390 | printf("#ifndef %s\n" |
---|
1391 | "#define %s\n" |
---|
1392 | "\n", |
---|
1393 | include_macro, |
---|
1394 | include_macro); |
---|
1395 | } |
---|
1396 | |
---|
1397 | if (use_macro) { |
---|
1398 | if (define_macro) { |
---|
1399 | fprintf(stdout, |
---|
1400 | "#ifndef %s\n" |
---|
1401 | "# if defined(__STDC__) || defined(__cplusplus)\n" |
---|
1402 | "# define %s(s) s\n" |
---|
1403 | "# else\n" |
---|
1404 | "# define %s(s) ()\n" |
---|
1405 | "# endif\n" |
---|
1406 | "#else\n" |
---|
1407 | "# error %s already defined elsewhere\n" |
---|
1408 | "#endif\n\n", |
---|
1409 | macro_name, macro_name, macro_name, macro_name); |
---|
1410 | } |
---|
1411 | else { |
---|
1412 | fprintf(stdout, |
---|
1413 | "#ifndef %s\n" |
---|
1414 | "# error %s is not defined\n" |
---|
1415 | "#endif\n\n", |
---|
1416 | macro_name, macro_name); |
---|
1417 | } |
---|
1418 | } |
---|
1419 | if (search__attribute__) { |
---|
1420 | fputs("/* hide __attribute__'s for non-gcc compilers: */\n" |
---|
1421 | "#ifndef __GNUC__\n" |
---|
1422 | "# ifndef __attribute__\n" |
---|
1423 | "# define __attribute__(x)\n" |
---|
1424 | "# endif\n" |
---|
1425 | "#endif\n\n", stdout); |
---|
1426 | } |
---|
1427 | if (search__ATTR__) { |
---|
1428 | fputs("/* define ARB attributes: */\n" |
---|
1429 | "#ifndef ATTRIBUTES_H\n" |
---|
1430 | "# include <attributes.h>\n" |
---|
1431 | "#endif\n\n", stdout); |
---|
1432 | } |
---|
1433 | if (cansibycplus) { |
---|
1434 | fputs("#ifdef __cplusplus\n" |
---|
1435 | "extern \"C\" {\n" |
---|
1436 | "#endif\n\n", stdout); |
---|
1437 | } |
---|
1438 | } |
---|
1439 | |
---|
1440 | current_dir = strdup(getcwd(0,255)); |
---|
1441 | if (argc == 0) { |
---|
1442 | getdecl(stdin, "<from stdin>"); |
---|
1443 | } |
---|
1444 | else { |
---|
1445 | |
---|
1446 | while (argc > 0 && *argv) { |
---|
1447 | DEBUG_PRINT("trying new file '"); |
---|
1448 | DEBUG_PRINT(*argv); |
---|
1449 | DEBUG_PRINT("'\n"); |
---|
1450 | |
---|
1451 | if (!(f = fopen(*argv, "r"))) { |
---|
1452 | perror(*argv); |
---|
1453 | exit(EXIT_FAILURE); |
---|
1454 | } |
---|
1455 | if (iobuf) setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ); |
---|
1456 | |
---|
1457 | linenum = 1; |
---|
1458 | newline_seen = 1; |
---|
1459 | glastc = ' '; |
---|
1460 | getdecl(f, *argv); |
---|
1461 | argc--; argv++; |
---|
1462 | fclose(f); |
---|
1463 | |
---|
1464 | free(current_file); |
---|
1465 | current_file = 0; |
---|
1466 | } |
---|
1467 | } |
---|
1468 | if (aisc) { |
---|
1469 | } |
---|
1470 | else { |
---|
1471 | if (cansibycplus) { |
---|
1472 | fputs("\n#ifdef __cplusplus\n" |
---|
1473 | "}\n" |
---|
1474 | "#endif\n", stdout); |
---|
1475 | } |
---|
1476 | if (use_macro && define_macro) { |
---|
1477 | printf("\n#undef %s\n", macro_name); /* clean up namespace */ |
---|
1478 | } |
---|
1479 | |
---|
1480 | if (include_wrapper) { |
---|
1481 | printf("\n" |
---|
1482 | "#else\n" |
---|
1483 | "#error %s included twice\n" |
---|
1484 | "#endif /* %s */\n", |
---|
1485 | include_wrapper, |
---|
1486 | include_macro); |
---|
1487 | } |
---|
1488 | } |
---|
1489 | |
---|
1490 | free(include_macro); |
---|
1491 | freeSymParts(); |
---|
1492 | free(current_file); |
---|
1493 | free(current_dir); |
---|
1494 | |
---|
1495 | return EXIT_SUCCESS; |
---|
1496 | } |
---|
1497 | |
---|
1498 | static void Version(void) { |
---|
1499 | fprintf(stderr, "%s 1.1 ARB\n", ourname); |
---|
1500 | } |
---|