home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <limits.h>
- #include <ctype.h>
- #include "lexsyms.h"
-
- /*
- * This is version 0.43 of genksyms.c (BETA)
- *
- * In this source, the crc and findsym functions are:
- *
- * updcrc32 function from gzip (see also the source: makecrc32.c)
- * findsym function from insmod
- * (function written by Jon Tombs and/or Bas Laarhoven)
- *
- * The rest of this source is copyright (C) 1994, Bjorn Ekwall <bj0rn@blox.se>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- */
-
- char *copyright = "(C) 1994, 1995 Bjorn Ekwall <bj0rn@blox.se>, version 0.43(BETA)";
-
- /*
- * If your flex generates a scanner where yytext is
- * "char *yytext"
- * instead of
- * "char yytext[YYLMAX]"
- * then change the "#if 0" below to "#if 1"
- */
-
- #if 0
- extern char *yytext;
- #else
- extern char yytext[];
- #endif
- extern int yylex(void);
-
- FILE *logfile;
- int line_no;
- int debug;
- int dump_defs;
- int warnings = 0; /* at least for ALPHA versions, use '-q' at your own risk */
- char *progname;
- char *expand_key;
- char *outfile_dir = ".";
- int outfile_flag = 0;
- FILE *outfile = (FILE *)0;
- char outfilename[PATH_MAX];
- char infile[PATH_MAX];
- char macroname[PATH_MAX];
- int use_globals = 0;
-
- #define MAXTMP 10000
- static char tmpbuffer[MAXTMP];
- static char *pbuffer = tmpbuffer;
-
- char *header[] = {
- "/**** This file is generated by genksyms DO NOT EDIT! ****/",
- "#if defined(CONFIG_MODVERSIONS) && !defined(__GENKSYMS__)",
- 0
- };
-
- #define MARK '#' /* kludge to mark unresolved references while parsing */
-
- struct symbol {
- char *key;
- char *value;
- struct symbol *child[2];
- struct symbol *trail;
- };
-
- void show_globals(struct symbol *);
-
- struct symbol *trail;
- struct symbol *type_root; /* for typdef */
- struct symbol *enum_root; /* for enum */
- struct symbol *s_u_root; /* for for struct or union */
- struct symbol *symbol_root; /* for symbols */
-
- /*
- * Look up an name in the symbol table. If "add" is not null, add a
- * the entry to the table. The table is stored as a splay tree.
- * (Bjorn: This is one of my favourites!)
- */
- struct symbol *
- findsym(struct symbol **root, char *key, struct symbol *add)
- {
- struct symbol *left, *right;
- struct symbol **leftp, **rightp;
- struct symbol *sp1, *sp2, *sp3;
- int cmp;
- int path1, path2;
-
- if (add) {
- add->key = key;
- }
- sp1 = *root;
- if (sp1 == NULL)
- return add? *root = add : NULL;
- leftp = &left, rightp = &right;
- for (;;) {
- cmp = strcmp( sp1->key, key);
- if (cmp == 0)
- break;
- if (cmp > 0) {
- sp2 = sp1->child[0];
- path1 = 0;
- } else {
- sp2 = sp1->child[1];
- path1 = 1;
- }
- if (sp2 == NULL) {
- if (! add)
- break;
- sp2 = add;
- }
- cmp = strcmp(sp2->key, key);
- if (cmp == 0) {
- one_level_only:
- if (path1 == 0) { /* sp2 is left child of sp1 */
- *rightp = sp1;
- rightp = &sp1->child[0];
- } else {
- *leftp = sp1;
- leftp = &sp1->child[1];
- }
- sp1 = sp2;
- break;
- }
- if (cmp > 0) {
- sp3 = sp2->child[0];
- path2 = 0;
- } else {
- sp3 = sp2->child[1];
- path2 = 1;
- }
- if (sp3 == NULL) {
- if (! add)
- goto one_level_only;
- sp3 = add;
- }
- if (path1 == 0) {
- if (path2 == 0) {
- sp1->child[0] = sp2->child[1];
- sp2->child[1] = sp1;
- *rightp = sp2;
- rightp = &sp2->child[0];
- } else {
- *rightp = sp1;
- rightp = &sp1->child[0];
- *leftp = sp2;
- leftp = &sp2->child[1];
- }
- } else {
- if (path2 == 0) {
- *leftp = sp1;
- leftp = &sp1->child[1];
- *rightp = sp2;
- rightp = &sp2->child[0];
- } else {
- sp1->child[1] = sp2->child[0];
- sp2->child[0] = sp1;
- *leftp = sp2;
- leftp = &sp2->child[1];
- }
- }
- sp1 = sp3;
- }
- /*
- * Now sp1 points to the result of the search. If cmp is zero,
- * we had a match; otherwise not.
- */
- *leftp = sp1->child[0];
- *rightp = sp1->child[1];
- sp1->child[0] = left;
- sp1->child[1] = right;
- *root = sp1;
- return cmp == 0? sp1 : NULL;
- }
-
- /* crc function slightly modified from gzip */
- /*
- * Run a null-terminated string through the crc shift register.
- * If s is a NULL pointer, then initialize the crc shift register
- * contents instead.
- * Return the current crc in either case.
- */
-
- static unsigned long crctab32[] = {
- #include "crc32.tab"
- };
-
- unsigned long
- updcrc32(register unsigned char *s)
- {
- static unsigned long crcreg;
- register unsigned long c, *t;
-
- if (s == 0)
- c = 0xffffffffU;
- else {
- c = crcreg;
- t = crctab32;
- while (*s)
- c = t[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
- }
- crcreg = c;
- return c ^ 0xffffffffU;
- }
-
- void
- drop_table(struct symbol *symtab)
- {
- if (symtab) {
- if (symtab->child[0])
- drop_table(symtab->child[0]);
-
- if (symtab->child[1])
- drop_table(symtab->child[1]);
-
- if (symtab->key)
- free(symtab->key);
-
- if (symtab->value)
- free(symtab->value);
-
- free(symtab);
- }
- }
-
- void
- restart_file(char *id)
- {
- char *p;
- char *s;
-
- if (debug) fprintf(logfile, "RESTART %s\n", id);
-
- if ((use_globals > 0) && symbol_root)
- show_globals(symbol_root);
-
- if (use_globals < 0)
- use_globals = 1;
-
- line_no = 0;
-
- if (outfile && (outfile != stdout)) {
- if (!dump_defs) {
- fprintf(outfile, "#endif /* %s */\n", macroname);
- fprintf(outfile, "#endif /* CONFIG_MODVERSIONS !__GENKSYMS__ */\n");
- }
-
- fclose(outfile);
- outfile = (FILE *)0;
- }
-
- strcpy(infile, strchr(id, '\"'));
-
- if ((p = strrchr(id, '.')))
- *p = '\0';
- if ((p = strrchr(id, '/')))
- ++p;
- else if ((p = strchr(id, '\"')))
- ++p;
- else {
- fprintf(stderr, "Illegal filename: %s\n", id);
- p = "_unknown";
- }
-
- sprintf(outfilename, "%s/%s.ver", outfile_dir, p);
-
- s = macroname;
- *s++ = '_';
- while (*p) {
- if (*p == '.')
- *s = '_';
- else
- *s = toupper(*p);
- ++s; ++p;
- }
- strcpy(s, "_VER_");
-
- if (outfile == stdout) {
- char **txt = header;
-
- /* Print the header */
- while (!dump_defs && *txt)
- fprintf(outfile, "%s\n", *txt++);
- fprintf(outfile, "#ifndef %s\n", macroname);
- fprintf(outfile, "#define %s\n", macroname);
- }
-
- /* Clean the old tables */
-
- if (type_root) {
- drop_table(type_root);
- type_root = (struct symbol *)0;
- }
-
- if (enum_root) {
- drop_table(enum_root);
- enum_root = (struct symbol *)0;
- }
-
- if (s_u_root) {
- drop_table(s_u_root);
- s_u_root = (struct symbol *)0;
- }
-
- if (symbol_root) {
- drop_table(symbol_root);
- symbol_root = (struct symbol *)0;
- }
- }
-
- /*
- * Save string in a safe place for later reference
- */
- char *
- savestr(char *str, int len)
- {
- char *p;
-
- p = (char *)malloc(len + 1);
- strcpy(p, str);
-
- return p;
- }
-
- /*
- * Centralized error reporting
- */
- void
- put_err(char *s)
- {
- if (warnings)
- fprintf(logfile, "%s %s: input line %d: Note: %s\n",
- progname, infile, line_no, s);
- }
-
- /*
- * Centralized error reporting with an extra parameter
- */
- void
- put_err2(char *s1, char *s2)
- {
- if (warnings) {
- fprintf(logfile, "%s %s: input line %d: Note: ",
- progname, infile, line_no);
- fprintf(logfile, s1, s2);
- fprintf(logfile, "\n");
- }
- }
-
- /*
- * stuff a string to the end of the work buffer while parsing
- */
- void
- put(char *s)
- {
- strcat(pbuffer, s);
- pbuffer += strlen(s);
-
- strcat(pbuffer, " ");
- ++pbuffer;
- if ((pbuffer - tmpbuffer) >= MAXTMP) {
- fprintf(stderr, "PANIC: buffer overflow! Quitting!\n");
- exit(1);
- }
- }
-
- /*
- * Save all symbols (identifiers) found while parsing,
- * so that the symbol table later can be updated with the full definition.
- * We don't know the full definition when we find the symbol while scanning!
- */
- char **id_stack;
- int id_stack_size;
- int id_next;
-
- void
- push_id(char *s) /* yytext */
- {
- char *key;
-
- if (debug) fprintf(logfile, "found def <%s>\n", s);
- key = savestr(s, strlen(s));
-
- if (id_stack) {
- if (id_next >= id_stack_size) {
- id_stack = (char **)realloc(id_stack,
- (id_stack_size + 1) * sizeof(char *));
- id_stack_size += 1;
- }
- }
- else {
- id_stack = (char **)malloc(sizeof(char *));
- id_stack_size = 1;
- }
-
- id_stack[id_next++] = key;
- }
-
- /*
- * Flush the work buffer since we have completed the scan of this
- * definition/declaration.
- * If we have found any identifiers (i.e. this was not just a type declaration)
- * we create entries in the symbol table for these identifiers,
- * with references to this definition.
- */
- void
- reset_buf(int saveit)
- {
- struct symbol *p;
- int i;
- char *value;
-
- if (debug) fprintf(logfile, "BUFFER: <%s>\n", tmpbuffer);
-
- if (saveit && id_next) {
-
- for (i = 0; i < id_next; ++i) {
- if (debug) fprintf(logfile, "DEF <%s>\n", id_stack[i]);
- value = savestr(tmpbuffer, pbuffer - tmpbuffer);
- p = (struct symbol *)calloc(1, sizeof(struct symbol));
- p->value = value;
- findsym(&symbol_root, id_stack[i], p);
- }
- }
- else {
- while (id_next > 0)
- free(id_stack[--id_next]);
- }
-
- id_next = 0; /* empty stack */
- pbuffer = tmpbuffer;
- *pbuffer = '\0';
- }
-
- /*
- * Save a struct/union/enum declaration to its respective symbol table.
- * (Different namespaces for enum vs struct/union)
- * This entry will be used later when expanding a declaration/definition
- * for a "X(symbol)" in the input stream.
- */
- struct symbol *
- save_tag(int sym, char *tag, char *defstart)
- {
- struct symbol *p;
- struct symbol **root;
-
- if (sym == ENUM)
- root = &enum_root;
- else
- root = &s_u_root;
-
- p = (struct symbol *)calloc(1, sizeof(struct symbol));
- p->value = savestr(defstart, pbuffer - defstart);
- findsym(root, tag, p);
-
- if (debug) fprintf(logfile, "S/U/E def <%s> <%s>\n", tag, defstart);
-
- return p;
- }
-
- /*
- * Check the relevant symbol tables for any previous declaration of a
- * struct/union or enum.
- * If we find it, we return 1 else 0.
- * If found: add the definition to the current workbuffer,
- * so that the fully expanded definition of the current symbol will
- * be available when we finally are going looking for it (for the crc)
- *
- * (NOT USED. I left it here for debugging purposes...)
- */
- int
- expand_tag(int sym, char *tag)
- {
- struct symbol *p;
- struct symbol **root;
-
- if (sym == ENUM)
- root = &enum_root;
- else
- root = &s_u_root;
-
-
- if ((p = findsym(root, tag, 0))) {
- put(p->value);
- if (debug) fprintf(logfile, "S/U/E expand <%s>\n", tag);
- return 1;
- }
- else
- return 0;
- }
-
- /*
- * Save a typedef definition to its own symbol table.
- * (Different namespaces for typedefs vs enum or struct/union)
- * This entry will be used later when expanding a declaration/definition
- * during the parsing of the input stream.
- */
- void
- save_type(char *type_tag)
- {
- struct symbol *p;
- struct symbol **root = &type_root;
-
- p = (struct symbol *)calloc(1, sizeof(struct symbol));
- /* subtract 1 to remove trailing space */
- /* it will be added back when expanding */
- --pbuffer;
- *pbuffer = '\0';
- p->value = savestr(tmpbuffer, strlen(tmpbuffer));
- findsym(root, type_tag, p);
-
- if (debug) fprintf(logfile, "TYPEDEF def <%s> <%s>\n", type_tag, p->value);
- }
-
- /*
- * Check the relevant symbol tables for any previous declaration of a
- * typedef with this tag.
- * IF we find it, we immediately add the full definition ('typedef' and all)
- * to the current workbuffer, so that the fully expanded definition of the
- * current symbol will be easily available when we later are going looking
- * for it (for the crc).
- */
- int
- expand_type(char *type_tag)
- {
- struct symbol *p;
- struct symbol **root = &type_root;
-
- if ((p = findsym(root, type_tag, 0))) {
- put(p->value);
- if (debug) fprintf(logfile, "TYPEDEF expand <%s>\n", type_tag);
- return 1;
- }
- else
- return 0;
- }
-
- /*
- * Silly little wrapper for the crc computation.
- * This also prints the (partial) definition if the '-D' option was used
- */
- unsigned long
- dump_str(char *s)
- {
- if (dump_defs)
- printf("%s", s);
-
- return updcrc32((unsigned char *)s);
- }
-
- /*
- * Potentially recursive fucntion for expanding the text of a definition.
- * IF there is a MARK in the string, it signifies that a reference to
- * a struct/union/enum is going on.
- * The tag (and type) of the reference will be grep-ed for and looked
- * up in the relevant symbol table.
- *
- * This will find all the basic types for every declaration/definition
- * in the input stream (you can see the expansion with the '-D' option)...
- *
- * The fully expanded string is put through a 32bit crc computation,
- * so that any changes in any part of the kernel that might "interfere"
- * with the compatibility of the current symbol, will give a different crc!
- */
- unsigned long
- expand_def(char *value)
- {
- struct symbol **root;
- struct symbol *p;
- unsigned long crc = 0;
- char *start = value;
- char *stop;
- char *marked;
- char saved = '\0';
-
- while ((stop = strchr(start, MARK))) {
- *stop = '\0'; /* null-terminate the partial string */
- crc = dump_str(start); /* the string up to the mark */
- *stop = MARK; /* restore the string */
- start = ++stop;
- /* find type and tag, differ between struct/union vs enum */
- if (strncmp(start, "num", 3) == 0) { /* Yikes, an enum! */
- root = &enum_root;
- marked = "enum";
- }
- else {
- root = &s_u_root;
- if (*start == 't') /* struct */
- marked = "struct";
- else
- marked = "union";
- }
-
- /* skip over tag after we have gotten hold of it */
- /* skip #truct #nion #num */
- if ((start = strchr(start, ' ')) == (char *)0) {
- put_err("Ouch, lost sync in symbol expansion (1)");
- break;
- }
- /* find start of tag string */
- if (*++start <= ' ') { /* safe guy.. */
- put_err("Ouch, lost sync in symbol expansion (2)");
- break;
- }
- /* find end of tag string */
- if ((stop = strchr(start, ' ')) != (char *)0) {
- saved = *stop;
- *stop = '\0';
- }
-
- /* start _should_ point to the null-terminated tag */
- /* stop points to the end of the null-terminated tag */
- /* OR stop is NULL for "pre-nulled" string */
-
- if ((p = findsym(root, start, 0)) == (struct symbol *)0) {
- struct symbol *nodup;
- char *here = pbuffer;
- char *savstart = savestr(start, strlen(start));
-
- if (warnings)
- fprintf(logfile, "%s %s: warning: symbol [%s]: "
- "unknown '%s %s'\n",
- progname, infile, expand_key, marked, start);
- /* sound action: */
- /* save the offender: no duplicate warnings */
- put(marked);
- put(start);
- put("{ UNKNOWN }");
- if (strcmp(start, "enum") == 0)
- nodup = save_tag(ENUM, savstart, here);
- else
- nodup = save_tag(STRUCT, savstart, here);
- nodup->trail = trail; /* mark it, no loops! */
- trail = nodup;
- crc = dump_str(here); /* the new definition */
- pbuffer = here;
- *pbuffer = '\0';
- }
- else { /* found it */
- if (p->trail) { /* been here before in this expansion */
- dump_str(marked); /* the type */
- dump_str(" ");
- dump_str(start); /* the tag */
- crc = dump_str(" ");
- }
- else { /* Not here before, expand it */
- /* The value contains the type and tag */
- p->trail = trail; /* mark it, no loops! */
- trail = p;
- if (stop)
- *stop = saved; /* restore the string */
- crc = expand_def(p->value);
- }
- }
-
- /* let us continue with the rest of the string */
- if (stop) {
- *stop = saved; /* restore the string */
- start = ++stop;
- }
- else {
- start = (char *)0; /* flag end of input, for below */
- break;
- }
- }
- /* no more marks have been found (if any!) */
-
- /*
- * take care of the proper tail of the input string
- * (might be the whole string...)
- */
- if (start && *start)
- crc = dump_str(start);
-
- return crc;
- }
-
- /*
- * Basic main loop for expanding the name of a symbol to its FULL
- * declaration, down to the basic level (like char, int and stuff)...
- */
- void
- show_def(char *key, char *value)
- {
- unsigned long last_crc;
- struct symbol *p;
- struct symbol tail;
-
- if (debug) fprintf(logfile, "FOUND <%s> = ", key);
-
- /* reset CRC */
- updcrc32(0);
-
- if (dump_defs)
- printf("FOUND <%s> = <", key);
-
- expand_key = key;
- trail = &tail; /* just a marker */
- last_crc = expand_def(value);
- while (trail != &tail) { /* clean up */
- p = trail;
- trail = p->trail;
- p->trail = (struct symbol *)0;
- }
-
- if (outfile_flag && !outfile) {
- char **txt = header;
-
- if ((outfile = fopen(outfilename, "w")) == (FILE *)0) {
- perror(outfilename);
- exit(1);
- }
-
- while (!dump_defs && *txt)
- fprintf(outfile, "%s\n", *txt++);
- fprintf(outfile, "#ifndef %s\n", macroname);
- fprintf(outfile, "#define %s\n", macroname);
- }
-
- if (!dump_defs)
- fprintf(outfile, "#define %s\t_set_ver(%s, %08lx)\n",
- key, key, last_crc);
-
- if (dump_defs)
- printf(">\n");
- }
-
- /*
- * This function will create a version header based on globals
- * instead of symbols mentioned in an explicit symbol table: X(symbol)
- * It is called at end-of-file IF no symbol table has been found,
- * i.e. from restart_file() or from main() after a finished run.
- */
- void
- show_globals(struct symbol *symtab)
- {
- if (symtab) {
- if (symtab->child[0])
- show_globals(symtab->child[0]);
-
- if (symtab->child[1])
- show_globals(symtab->child[1]);
-
- if (symtab->value) {
- if (strncmp(symtab->value, "static ", 7) != 0)
- /* found one! */
- show_def(symtab->key, symtab->value);
- }
- }
- }
-
- /*
- * This is the "black hole" for strings and character constants
- */
- void
- skip_string()
- {
- int sym;
- char match;
-
- match = yytext[0];
-
- if (debug) fprintf(logfile, "skipping %c string at line %d\n", match, line_no);
-
- while ((sym = yylex())) {
- switch (sym) {
- case STRING:
- if (yytext[0] == match) {
- if (debug) fprintf(logfile, "done skipping string\n");
- return;
- }
-
- default:
- if (yytext[0] == '\\')
- yylex(); /* skip escaped */
- if (debug) fprintf(logfile, "line %d: skip sym %d = <%s>\n", line_no, sym, yytext);
- break;
- }
- }
-
- if (debug) fprintf(logfile, "done skipping string\n");
- return;
- }
-
- /*
- * This (recursive) loop will take care of all '{' '}' nested blocks
- * in the input stream that are _not_ enum/struct/union declarations.
- * So, initializers (e.g. for arrays and structs) and function bodies
- * will disappear down into this black hole...
- *
- * Only _special_ identifiers that conform to: "X(identifier)"
- * will result in any output.
- *
- * This type of strings should only found in sources using them to
- * denote the kernel symbols in a symbol table that is going to be exported.
- *
- * The action will be to generate the "magic" definitions in module
- * include files, e.g. <linux/module_version.h>
- */
- int
- skip_block()
- {
- struct symbol *p;
- int sym;
- int maybe = 0;
-
- if (debug) fprintf(logfile, "ENTER SKIP BLOCK\n");
-
- while ((sym = yylex())) {
- switch (sym) {
- case FILENAME: /* This is an error! */
- put_err("Illegal file start block");
- return 0;
-
- case RBRACE:
- if (debug) fprintf(logfile, "LEAVE SKIP BLOCK\n");
- return 1;
-
- case LBRACE:
- maybe = 0;
- if (skip_block() == 0) {
- if (debug) fprintf(logfile, "LEAVE SKIP BLOCK\n");
- return 0;
- }
- break;
-
- case STRING:
- skip_string();
- break;
-
- case IDENT:
- if (maybe == 2) {
- /* might be defined even... */
- if ((p = findsym(&symbol_root, yytext, 0))) {
- /* found one! */
- show_def(yytext, p->value);
- /*
- * If there is a symbol table, we
- * shouldn't create a header based
- * on any globals in the source...
- */
- if (use_globals > 0)
- use_globals = -1;
- }
- else {
- put_err2("Unkown symbol '%s'", yytext);
- }
- maybe = 0;
- }
- else if ((maybe == 0) && (strcmp(yytext, "X") == 0))
- maybe = 1; /* MAYBE an exported symbol... */
- else
- maybe = 0;
- break;
-
- case LPAREN:
- if (maybe == 1)
- maybe = 2;
- else
- maybe = 0;
- break;
-
- default:
- maybe = 0;
- break;
- }
- }
-
- if (debug) fprintf(logfile, "LEAVE SKIP BLOCK\n");
- return 0;
- }
-
- /*
- * Parse (maybe recursively) a struct/union/enum definition block.
- * Append it to the work buffer.
- *
- * This code is in many respects similar to the code in parse(),
- * but I felt it was easier to maintain one function for the top
- * level, where all the global definitions are, and another
- * function that just had to decode a struct/union/enum definition...
- */
- void
- build_block(void)
- {
- int sym;
- int sym1;
- char *tag = (char *)0;
- char *marker;
- char *here;
-
-
- while ((sym = yylex())) {
- again:
- switch (sym) {
- case FILENAME: /* This is an error! */
- put_err("Illegal file start build");
- return;
-
- case TYPEDEF:
- put_err("No typedef allowed here");
- break;
-
- case STRING:
- skip_string();
- break;
-
- case RBRACE:
- put("}");
- return;
-
- case LBRACE:
- put("{");
- build_block();
- break;
-
- case ENUM:
- case UNION:
- case STRUCT:
- marker = pbuffer; /* current "put" pointer */
- put(yytext);
-
- if ((sym1 = yylex()) == IDENT) { /* need a tag */
- tag = savestr(yytext, strlen(yytext));
- put(yytext);
- sym1 = yylex();
- }
- else
- tag = (char *)0;
-
- if (sym1 != LBRACE) { /* then it is a reference */
- if (tag) { /* refer */
- /*
- * mark for easy retrieval later
- *
- * struct -> #truct
- * union -> #nion
- * enum -> #num
- */
- *marker = MARK; /* kludge! */
- }
- else
- put_err("Not a legal definition");
- sym = sym1;
- goto again;
- }
- /* else sym == LBRACE i.e. a definition! */
-
- here = pbuffer;
-
- put("{");
- build_block();
- if (tag) { /* i.e. not anonymous */
- save_tag(sym, tag, marker);
-
- /* The definition is saved separately,
- * so the workbuffer will only have to
- * show an expandable definition
- */
- pbuffer = here;
- *pbuffer = '\0';
- *marker = MARK;
- }
-
- break;
-
- case IDENT:
- if (!expand_type(yytext))
- put(yytext); /* it was not a typedef */
- break;
-
- case OTHER:
- put(yytext);
- break;
-
- default:
- put(yytext);
- break;
- }
- }
-
- return;
- }
-
- /*
- * Main loop for parsing top level definitions/declarations in the
- * input stream. It has only a rudimentary knowledge of ANSI C,
- * but it _should_ do the right thing...
- *
- * The right thing is hereby defined to be:
- *
- * - Save all typedefs, and look for identifiers that are previously
- * defined as typedefs. Expand these by replacing the identifier
- * with the _full_ typedef definition, and append this to the work buffer.
- *
- * - Save all tagged definitions of struct/union/enum for use in possible
- * expansions at a later time (i.e. when we find the construct: 'X(symbol)'
- * in the input stream). This definition is saved as a separate entity,
- * but is also appended to the current work buffer.
- *
- * - Mark all references to tagged struct/union/enum so that they can
- * easily identified when we later (recursively) expand the definition
- * of a symbol in the input stream (i.e. the 'X(symbol)' as above).
- * The marked reference (marked by changing the first character of
- * the type into '#') is appended to the current work buffer.
- *
- * - Keep track of all global identifiers in the input stream.
- * When a complete definition is parsed, entries will be made in the
- * symbol table, with references to the parsed definition.
- * This definition is created in the work buffer at the time of parsing,
- * and is saved away (malloc) when the full definition has been parsed.
- *
- * - For all other tokens in the input stream: append to the work buffer.
- * Actually only a few tokens are recognized by the lexical analysis,
- * so the OTHER will be handled a charater at a time.
- *
- * NOTE: The work buffer (and thus the internal version of a definition)
- * consist of the tokens, each one followed by a SPACE.
- * The final semicolon in a struct/union/enum definition is not included.
- */
- void
- parse(void)
- {
- int sym;
- int sym1;
- int started = 0; /* have we started a definition/declaration? */
- int type_def = 0; /* is this part of a typedef? */
- int parlev = 0; /* number of unmatched LPARENs, see comment at IDENT! */
- char *marker;
- char *tag;
- char *type_tag = (char *)0;
- char *here;
-
- while ((sym = yylex())) {
- /* top level */
- top_level:
- switch (sym) {
- case FILENAME: /* This is the start of a new source! */
- restart_file(yytext);
- break;
-
- case 0:
- return;
-
- case STRING:
- skip_string();
- break;
-
- case TYPEDEF:
- if (started || type_def) {
- put_err("No typedef allowed here");
- }
- started = 1;
- type_def = 1;
- type_tag = (char *)0;
- put(yytext);
- break;
-
- case ENUM:
- case UNION:
- case STRUCT:
- if (started && !type_def && (parlev == 0)) {
- put_err2("'%s' is not allowed here", yytext);
- }
- started = 1;
-
- marker = pbuffer; /* current "put" pointer */
- put(yytext);
-
- if ((sym1 = yylex()) == IDENT) { /* tag */
- tag = savestr(yytext, strlen(yytext));
- put(yytext);
- sym1 = yylex();
- }
- else
- tag = (char *)0;
-
-
- if (sym1 == LBRACE) { /* define */
- here = pbuffer;
-
- put("{");
- build_block();
- if (tag) {
- save_tag(sym, tag, marker);
- pbuffer = here;
- *pbuffer = '\0';
- *marker = MARK;
- }
-
- if ((sym = yylex()) == SEMI) {
- parlev = 0;
- started = 0;
- if (type_def)
- put_err("Illegal typedef");
- type_def = 0;
- if (type_tag)
- free(type_tag);
- /* begin anew in buffer! */
- reset_buf(0);
- }
- else {
- goto top_level;
- }
- }
- else { /* refer */
- if (tag) {
- /*
- * make a mark for easy
- * retrieval later...
- *
- * struct -> #truct
- * union -> #nion
- * enum -> #num
- */
- *marker = MARK; /* kludge! */
- }
- else {
- put_err("Not a legal definition");
- }
- sym = sym1;
- goto top_level;
- }
- break;
-
- case IDENT: /* must be a TYPE or a typedef at start! */
- if (!expand_type(yytext)) {
- if (!started && !type_def) {
- /* OK, OK... it is an int in disguise */
- /*
- put_err2("type for identifier '%s' is missing", yytext);
- */
- }
- if (type_def && !type_tag) {
- type_tag = savestr(yytext, strlen(yytext));
- }
- else {
- /* The following, and only real, use
- * of parlev is here to stop IDENTs in
- * function parameters from
- * cluttering up the symbol table.
- * I take the risk that there aren't
- * that many "raw" globally defined
- * pointers to functions, but that
- * they instead are typedef'ed
- *
- * IF this will ever be a problem,
- * just change the "#if" 1 to "#if 0"...
- */
- #if 0
- if (parlev == 0)
- #endif
- push_id(yytext);
- }
- put(yytext);
- }
- started = 1;
- break;
-
- case LBRACE:
- if (!started) {
- put_err("No '{' allowed here");
- }
- if (skip_block() == 0)
- return;
- /* FALLTHRU */
- case SEMI:
- started = 0;
- if (type_def) {
- type_def = 0;
- if (type_tag)
- save_type(type_tag);
- type_tag = (char *)0;
- reset_buf(0);
- }
- else {
- reset_buf(1); /* save it if it is a def */
- }
- parlev = 0;
- break;
-
- case LPAREN:
- put("(");
- ++parlev;
- break;
-
- case RPAREN:
- put(")");
- --parlev;
- break;
-
- case TYPE: /* data types: int ... */
- started = 1;
- /* FALLTHRU */
- case S_TYPE: /* storage types: extern ... */
- put(yytext);
- break;
-
- default:
- case OTHER:
- if (!started) {
- put_err2("No '%s' allowed here", yytext);
- }
- put(yytext);
- break;
- }
- }
- }
-
- int
- yywrap()
- {
- return 1;
- }
-
- int
- main(int argc, char **argv)
- {
- extern int mkdir(char *, int); /* I'm lazy */
- char *p;
-
- logfile = stderr;
-
- if ((p = strrchr(argv[0], '/')))
- progname = p + 1;
- else
- progname = argv[0];
-
- while ((argc > 1) && (*(p = argv[1]) == '-')) {
- while (*++p) {
- switch (*p) {
- case 'd':
- debug += 1;
- if (debug > 1)
- logfile = stdout;
- break;
-
- case 'g':
- use_globals = 1;
- break;
-
- case 'w':
- warnings = 1;
- break;
-
- case 'q':
- warnings = 0;
- break;
-
- case 'V':
- printf("%s\n", copyright);
- break;
-
- case 'D':
- dump_defs = 1;
- break;
-
- default:
- fprintf(stderr, "usage: %s [-gwqdD] directory\n", progname);
- exit (1);
- break;
- }
- }
- ++argv;
- --argc;
-
- }
-
- if ((argc > 1) && (argv[1][0])) {
- outfile_dir = argv[1];
- outfile_flag = 1;
- outfile = (FILE *)0;
- ++argv;
- --argc;
-
- for (p = outfile_dir + 1; (p = strchr(p, '/')); p = p+1) {
- *p = '\0';
- if (access(outfile_dir, F_OK) < 0) {
- if (mkdir(outfile_dir, 0755) < 0) {
- perror(outfile_dir);
- exit(1);
- }
- }
- *p = '/';
- }
- if (access(outfile_dir, R_OK | W_OK | F_OK) < 0) {
- if (mkdir(outfile_dir, 0755) < 0) {
- perror(outfile_dir);
- exit(1);
- }
- }
- }
- else
- outfile = stdout;
-
- parse();
-
- if ((use_globals > 0) && symbol_root)
- show_globals(symbol_root);
-
- if (!dump_defs && outfile) {
- fprintf(outfile, "#endif /* %s */\n", macroname);
- fprintf(outfile, "#endif /* CONFIG_MODVERSIONS !__GENKSYMS__ */\n");
- }
- if (outfile != stdout)
- fclose(outfile);
-
- return 0;
- }
-