root/trunk/AISC_MKPTPS/mkptypes.cxx

Revision 8607, 52.4 KB (checked in by westram, 5 weeks ago)

merge from e4fix [8135] [8136] [8137] [8138] [8139] [8140] [8141] [8142] [8143] [8144] [8222]
this revives the reverted patches [8129] [8130] [8131] [8132]

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