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