#include #include #include #include #include #include #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 * * 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 , version 0.43(BETA)"; /* * If your flex generates a scanner where yytext is * "char *yytext" * instead of * "char yytext[YYLMAX]" * then add "-DYYTEXT_PTR" to CFLAGS in the Makefile */ #ifdef YYTEXT_PTR 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(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. */ 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; }