source: tags/arb_5.5/AISC_MKPTPS/mkptypes.c

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