home *** CD-ROM | disk | FTP | other *** search
- /*
-
-
- Copyright (C) 1990 Texas Instruments Incorporated.
-
- Permission is granted to any individual or institution to use, copy, modify,
- and distribute this software, provided that this complete copyright and
- permission notice is maintained, intact, in all copies and supporting
- documentation.
-
- Texas Instruments Incorporated provides this software "as is" without
- express or implied warranty.
-
-
- *
- * Edit history
- * Created: LGO 30-Mar-89 -- Initial design and implementation.
- *
- * The DEFPACKAGE macro for Symbolic C++.
- *
- * Syntax:
- * DEFPACKAGE NAME <PATH> [OPTIONS]
- *
- * Where NAME is a symbol prefix, PATH is the name of an include file where
- * definitions are kept, and OPTIONS are optional, seprated by comma's and
- * one of the following:
- *
- * count=identifier
- * This says that the include file should include a #define identifier
- * whose expansion is the number of symbols defined.
- *
- * use_first=int
- * When non-zero, the symbol value used is the first definition.
- * Redefinition attempts are ignored. (this is used by the ONCE-ONLY
- * macro)
- *
- * noblank=int
- * When non-zero, remove all whitespace from symbol names
- *
- * case=upper
- * This says to upcase all symbol names.
- * case=lower
- * This says to downcase all symbol names.
- * case=cap
- * This says to capitalize the first letter of each symbol name, and
- * downcase the rest.
- * case=sensitive
- * This says to leave the case alone. This is the default.
- *
- * start=int
- * This says to start counting from int (default is zero).
- * increment=int
- * This says to increment counting by int (default is one).
- * template=int
- * This value is inclusive-or'ed with every symbol value.
- * max=int
- * This says to generate an error when the number of symbol exceeds int.
- *
- * Symbols are inserted in a package with the following macro:
- *
- * DEFPACKAGE_SYMBOL(package, symbol, type, value, property, expander)
- *
- * where:
- * package is the name of a package (the DEFPACKAGE must preceed)
- * symbol is the name of the symbol
- * type [optional] is the type of the value
- * value [optional] is the value of the symbol or property
- * property [optional] is the name of the property (empty means use the
- * value slot)
- * expander=identifier
- * This says to replace the DEFPACKAGE_SYMBOL invocation
- * with the result of calling the "identifier" macro.
- *
- * The expander macro is called with the following arguments:
- *
- * expander(index, symbol, type, value)
- *
- * where:
- * expander is the expander macro specified in the DEFPACKAGE_SYMBOL
- * index is the symbol's index number
- * symbol is the name of the symbol
- * type is the type of the value [may be empty]
- * value is the value of the symbol or property [may be empty]
- *
- * DEFPACKAGE_SYMBOL causes three macro definitions to be written to the
- * package's definition file:
- *
- * pkgname_DEFINITIONS - expands into macro calls to define the symbols
- * pkgname_VALUES - expands into macro calls to set symbol values
- * pkgname_PROPERTIES - expands into macro calls to set symbol properties
- *
- * where pkgname is the name of the package. Each of these macros takes a
- * single parameter which is the name of the function or macro to call for each
- * symbol.
- *
- * Examples:
- * #define package##_DEFINITIONS(define_macro) \
- * define_macro(index, name)
- *
- * #define package##_VALUES(value_macro) \
- * value_macro(index, name, type, value)
- *
- * #define package##_PROPERTIES(property_macro) \
- * property_macro(index, name, property, type, value)
- *
- * where:
- * index is the symbol index.
- * name is the symbol name.
- * type is the type of the value
- * value is the value of the symbol
- * property is a pointer to the properties symbol
- *
- * See package.h for examples.
- *
- * In order to define sym_names, the sym_db file must be included in a single
- * .C file. If the makefile has a dependency between the .C file and the
- * sym_db file, then the .C file will be re-compiled whenever someone adds a
- * new symbol. The .C file which includes the sym_db file can add other
- * support for symbols, such as allocating static vectors indexed by symbols,
- * defining hash tables, variable-length vectors and intern functions.
- */
-
- /*
- * This file exports the following functions:
- * PACKAGE*
- * package_define(char* name, char* filename, char* count,
- * char* scase,
- * long start, long incr, long template,
- * long max, long use_first);
- *
- * int
- * define_symbol(argc, argv);
- *
- * void
- * symbol_define(PACKAGE* pkg, char* name, char* type,
- * char* value, char* property);
- *
- * void
- * finish_symbols();
- */
- #include "defmacio.h"
-
- typedef enum {c_sensitive, c_upper, c_lower, c_cap} CASE;
-
- typedef struct package {
- struct package* next; /* Next package in package_list */
- char* name; /* Package name */
- char* filename; /* Package definition file name */
- FILE* file; /* Package definition file */
- struct Hash_Table* symbols; /* Symbol table */
- Boolean is_changed; /* TRUE when file must be written */
- long index; /* Largest index in package */
- long count; /* Number of symbols in the package */
- char* count_name; /* Name of #define to hold symbol count */
- CASE scase; /* one of upper, lower, cap, sensitive */
- char* case_name; /* string version of scase */
- long start; /* Starting symbol index */
- long incr; /* symbol index increment */
- long template; /* symbol index template */
- long max; /* symbol index maximum */
- Boolean use_first; /* TRUE to ignore symbol value redefinitions */
- Boolean nospace; /* TRUE to remove whitespace from symbol names */
- char* header; /* Header at start of definition file */
- } PACKAGE;
-
- static PACKAGE* package_list = NULL;
-
- typedef struct property {
- struct property* next; /* Pointer to next value, or NULL */
- char* property; /* Property name string */
- char* value; /* Value string */
- char* type; /* Type of value */
- } PROPERTY;
-
- typedef struct symbol {
- char* name; /* Symbol name */
- long index; /* Symbol index */
- char* type; /* Symbol type */
- char* value; /* Symbol value */
- PROPERTY* props; /* pointer to properties or NULL */
- } SYMBOL;
-
- static SYMBOL*
- add_symbol(pkg, name, index)
- PACKAGE* pkg;
- char* name;
- long index;
- {
- SYMBOL* symbol = (SYMBOL*) getmem(sizeof(SYMBOL));
- symbol->name = name;
- symbol->index = index;
- symbol->type = "";
- symbol->value = "";
- symbol->props = NULL;
- put_hash(pkg->symbols, name, symbol);
- if(index > pkg->index) pkg->index = index;
- pkg->count++;
- return symbol;
- }
-
- static long next_index(pkg)
- PACKAGE* pkg;
- {
- long template = pkg->template;
- long result = ((pkg->index & ~template) + pkg->incr);
- if (pkg->max > 0 && result > pkg->max)
- cerror ("DEFPACKAGE-SYMBOL: too many symbols in the %s package", pkg->name);
- return result | template;
- }
-
- /*
- * Given a package object and the symbol name,
- * intern the symbol in the package, and insert the
- * symbol replacement into the input stream.
- */
- SYMBOL*
- symbol_define(pkg, name, type, value, property)
- PACKAGE* pkg;
- char* name;
- char* type;
- char* value;
- char* property;
- {
- SYMBOL* symbol;
- if (pkg->nospace) /* Trim whitespace */
- name = c_trim_all(name, " \t\n");
- /* Set symbol name case */
- switch (pkg->scase) {
- case c_upper: c_upcase(name);
- case c_lower: c_downcase(name);
- case c_cap: c_capitalize(name);
- } /* Lookup symbol */
- symbol = (SYMBOL*) get_hash(pkg->symbols, name);
- if (symbol == NULL) { /* Create new symbols */
- symbol = add_symbol(pkg, name, pkg->index);
- pkg->index = next_index(pkg);
- pkg->is_changed = TRUE;
- }
- if (*value != EOS) {
- if (*property == EOS) { /* Set value */
- if (!pkg->use_first || *symbol->value == EOS) {
- if (!pkg->is_changed &&
- (strcmp(symbol->type, type) != 0 ||
- strcmp(symbol->value, value) != 0))
- pkg->is_changed = TRUE;
- symbol->type = type;
- symbol->value = value;
- }
- } else { /* Set property */
- PROPERTY* prop = symbol->props;
- for (; prop != NULL; prop = prop->next)
- if (!strcmp(prop->property, property)) break;
- if(prop == NULL) {
- prop = (PROPERTY*) getmem(sizeof(PROPERTY));
- prop->property = property;
- prop->next = symbol->props;
- symbol->props = prop;
- pkg->is_changed = TRUE;
- }
- if (!pkg->is_changed &&
- (strcmp(prop->type, type) != 0 ||
- strcmp(prop->value, value) != 0))
- pkg->is_changed = TRUE;
- prop->type = type;
- prop->value = value;
- }
- }
- return symbol;
- }
-
- /* Read in the file which describes the symbols in package */
- /* The package file starts with the following: */
-
- static char* header =
- "/*\n\
- * DEFPACKAGE %-20s definitions file.\n\
- *\n\
- * This file is automatically generated by the cpp DEFPACKAGE facility\n\
- * DO NOT EDIT THIS FILE, because it may be re-writen the next time CPP\n\
- * is run.\n\
- *\n\
- * This file is for:\n\
- * DEFPACKAGE %s";
-
- static char* header_warning = "\n/* WARNING: Do not remove this line */\n";
-
- static Boolean
- token_scan(pkg, search, end)
- PACKAGE* pkg;
- char* search;
- char end;
- {
- FILE* stream = pkg->file;
- int len = strlen(search);
- int i;
- for(i=0; i<len;) {
- char c = fgetc(stream);
- append_char(work_string, c);
- if(c == search[i]) { i++; continue;}
- if(c == EOF) return FALSE;
- if(c == end) return FALSE;
- if (i>0) {
- i=0;
- if(c == search[i]) { i++; continue;}
- }
- }
- *(work_string->buffp) = EOS;
- return TRUE;
- }
-
- /*
- * HACK ALERT
- * Read a line from stream, and put it in the input buffer used by getchar
- * This lets read_package use the scan_next utility in defmacio.c
- */
- static void
- read_inline(stream)
- FILE* stream;
- {
- #define INBUFLEN 200
- static char instring[INBUFLEN];
- fgets(instring, INBUFLEN, stream);
- set_inbuffer(instring);
- }
-
- static Boolean
- read_package (pkg)
- PACKAGE* pkg;
- {
- FILE* stream = pkg->file;
- char token[400];
- char error[100];
- char* symname;
- long symindex=-1;
- /* Check for empty file */
- char c = fgetc(stream);
- if (c == EOF) pkg->is_changed = TRUE;
- else {
- /* Scan the header */
- scan_start();
- append_char(work_string, c);
- if(!token_scan(pkg, header_warning, EOF)) {
- cerror ("defpackage: Can't find \"Do not remove\" comment in the %s file",
- pkg->filename);
- return FALSE;
- } /* Everything up to header_warning is header*/
- pkg->header = savestring(work_string->buff);
- /*
- * MACRO package##_DEFINITIONS(define_macro, value_macro, property_macro) {
- * define_macro (index, name)
- * value_macro (index, type, value)
- * property_macro(index, property, type, value)
- * }
- */
- if(!token_scan(pkg, "_DEFINITIONS", EOF)) {
- cerror ("defpackage: Can't find pkg_DEFINITIONS in the %s file",
- pkg->filename);
- return FALSE;
- }
- token_scan(pkg, "\n", EOF);
- for(;;) {
- enum {Tdefine, Tvalue, Tproperty} type;
- char* type_name;
- char* value_name;
- char* property_name;
- long index;
-
- read_inline(stream);
- c = skip_blanks(); /* Quit on close brace '}' */
- if (c == '}') break;
- unget();
- copytoken(token);
- if (strcmp(token, "define_macro") == 0) type = Tdefine;
- else if (strcmp(token, "value_macro") == 0) type = Tvalue;
- else if (strcmp(token, "property_macro") == 0) type = Tproperty;
- else {
- sprintf (error, "defpackage: unknown macro %s while reading %s",
- token, pkg->filename);
- cerror(error, "");
- return FALSE;
- }
- if((c = skip_blanks()) != '(') {
- sprintf(error, "defpackage: Found '%c' instead of '(' after %s in %s",
- c, token, pkg->filename);
- cerror(error, "");
- return FALSE;
- }
- copytoken(error);
- index = strtol(error, &value_name, 10);
- if (*value_name != '\0') {
- sprintf (error, "defpackage: bad symbol number in %s while reading %s",
- token, pkg->filename);
- cerror(error, "");
- return FALSE;
- }
- skip_blanks(); /* Skip comma */
- property_name = "";
- switch (type) {
- case Tdefine:
- symname = scan_token(",)");
- symindex = index;
- add_symbol(pkg, symname, index);
- break;
- case Tproperty:
- property_name = scan_token(",)"); /* Get property */
- /* fall through */
- case Tvalue:
- getchar(); /* Skip comma */
- type_name = scan_token(",)"); /* Get type */
- getchar(); /* Skip comma */
- value_name = scan_token(",)"); /* Get value */
- if (index != symindex) {
- sprintf(error, "defpackage: macros out of order reading %s(%d...) in %s",
- token, index, pkg->filename);
- cerror(error, "");
- return FALSE;
- }
- symbol_define(pkg, symname, type_name, value_name, property_name);
- break;
- }
- if((c = skip_blanks()) != ')') {
- sprintf(error, "defpackage: '%c' instead of ')' while reading %s(%d...) in %s",
- c, token, index, pkg->filename);
- cwarn(error, "");
- }
- }
- }
- return TRUE;
- }
-
- static void write_package (pkg)
- PACKAGE* pkg;
- {
- SYMBOL* symbol;
- char* name = pkg->name;
- FILE* stream = pkg->file; /* Header */
- SYMBOL** symtab = (SYMBOL**) getmem(sizeof(SYMBOL*)*pkg->count);
- int i;
- if (pkg->header != NULL) /* If a header read in */
- fprintf(stream, pkg->header); /* use it */
- else { /* else use the default header */
- fprintf (stream, header, name, name);
- /* defpackage options */
- fprintf (stream, " <%s> name=%s,\n",
- pkg->name, pkg->filename, pkg->count_name);
- fprintf (stream, " *\t count=%s, case=%s,\n",
- pkg->count_name, pkg->case_name);
- fprintf (stream, " *\t start=%d, increment=%d, template=%d, max=%d\n",
- pkg->start, pkg->incr, pkg->template, pkg->max);
- fprintf (stream, " */\n\n");
- fprintf (stream, "%s", header_warning);
- }
- /* COUNT #define */
- if(*pkg->count_name)
- fprintf (stream, "#define %s %d\n\n", pkg->count_name, pkg->count);
- /*
- * MACRO package##_DEFINITIONS(define_macro, value_macro, property_macro) {
- * define_macro (index, name)
- * value_macro (index, type, value)
- * property_macro(index, property, type, value)
- * }
- */
- fprintf (stream, "MACRO %s_DEFINITIONS", name);
- fprintf (stream, "(define_macro, value_macro, property_macro) {");
- for(i=0; i < pkg->count; i++) symtab[i] = NULL;
- symbol = (SYMBOL*) next_hash(pkg->symbols, TRUE);
- for(i=0; symbol != NULL; i++) { /* Sort symbols by index */
- if(symbol->index >= pkg->count) {
- char error[100];
- sprintf(error, "Symbol %s has a bad index %ld, ignored",
- symbol->name, symbol->index);
- cerror(error, "");
- }
- else
- symtab[symbol->index] = symbol;
- symbol = (SYMBOL*) next_hash(pkg->symbols, FALSE);
- }
- for(i=0; i < pkg->count; i++) {
- symbol = symtab[i];
- if (symbol != NULL) {
- PROPERTY* prop = symbol->props;
- fprintf (stream, "\n define_macro (%ld, %s)",
- symbol->index, symbol->name);
- if(*symbol->value)
- fprintf (stream, "\n value_macro (%ld, %s, %s)",
- symbol->index,
- (*symbol->type) ? symbol->type : "void*",
- (*symbol->value) ? symbol->value : "0");
- while(prop) {
- fprintf (stream, "\n property_macro(%ld, %s, %s, %s)",
- symbol->index, prop->property,
- (*prop->type) ? prop->type : "void*",
- (*prop->value) ? prop->value : "0");
- prop = prop->next;
- }
- }
- #ifdef paranioa
- else
- fprintf (stderr, "Warning: Missing symbol %d from package %s\n",
- i, name);
- #endif
- }
- fprintf (stream, "\n}\n");
- }
-
- void
- package_define(name, filename, count_name, case_name,
- start, incr, template, max, use_first, nospace)
- char* name;
- char* filename;
- char* count_name;
- char* case_name;
- long start;
- long incr;
- long template;
- long max;
- long use_first;
- long nospace;
- {
- PACKAGE* pkg; /* check for package already defined */
- for(pkg = package_list; pkg != NULL; pkg=pkg->next)
- if (strcmp(pkg->name, name) == 0) {
- cerror("DEFPACKAGE: redefining the %s package", name);
- return;
- }
- pkg = (PACKAGE*) getmem(sizeof (PACKAGE));
- if ((pkg->file = fopen (filename, "r+")) == NULL) {/* If we can't open the file */
- cerror ("defpackage: cannot open %s for update", filename);
- return;
- }
- pkg->next = package_list; /* Link new package on package list */
- package_list = pkg;
- pkg->is_changed = FALSE;
- pkg->symbols = init_Hash_Table();
- pkg->name = name;
- pkg->filename = filename;
- pkg->count = 0;
- pkg->count_name = count_name;
- pkg->start = start;
- pkg->index = start;
- pkg->incr = (incr>0) ? incr : 1;
- pkg->template = template;
- pkg->max = max;
- pkg->use_first = (use_first != 0);
- pkg->nospace = (nospace != 0);
- pkg->scase = c_sensitive;
- pkg->case_name = "sensitive";
- if (*case_name != EOS) {
- pkg->case_name = case_name;
- c_downcase(case_name);
- if (strcmp(case_name, "sensitive") == 0)
- pkg->scase = c_sensitive;
- else if (strcmp(case_name, "upper") == 0)
- pkg->scase = c_upper;
- else if (strcmp(case_name, "lower") == 0)
- pkg->scase = c_lower;
- else if (strcmp(case_name, "cap") == 0)
- pkg->scase = c_cap;
- else
- cerror ("defpackage: Illegal case: %s", case_name);
- }
- pkg->header = NULL;
- read_package(pkg); /* Read package from file */
- if (pkg->count > 0) {
- pkg->is_changed = FALSE;
- pkg->index = next_index(pkg); /* setup the next index */
- }
- }
-
- /*
- * Given a symbol name in a package, return its value string
- */
- char* lookup_symbol(pkgname, symname)
- char* pkgname;
- char* symname;
- {
- char* value = NULL;
- static char* pkgname_cache = NULL;
- static PACKAGE* package = NULL;
-
- if (pkgname != pkgname_cache) {
- pkgname_cache = pkgname;
- /* Lookup package */
- for(package=package_list; package!=NULL; package=package->next)
- if(!strcmp(package->name, pkgname)) break;
- }
- if (package != NULL) {
- SYMBOL* symbol = (SYMBOL*) get_hash(package->symbols, symname);
- if (symbol != NULL)
- value = symbol->value;
- }
- return value;
- }
-
- /*
- * DEFPACKAGE_SYMBOL(package, symbol, type, value, property, expander)
- */
- int
- define_symbol(argc, argv)
- int argc;
- char* argv[];
- {
- char* parms[6];
- int i;
- PACKAGE* pkg;
- while(getchar() != '(') ; /* Skip over macro name */
- for(i=0; i<6; i++) parms[i] = ""; /* Initialize parms */
- for(i=0; i<6; i++) {
- parms[i] = scan_token(",)");
- if (getchar() == ')') break; /* Quit on ) */
- }
- /* Lookup package */
- for(pkg=package_list; pkg!=NULL; pkg=pkg->next)
- if(!strcmp(pkg->name, parms[0])) break;
- if(pkg == NULL) {
- cerror("DEFPACKAGE_SYMBOL: undefined package name: %s", parms[0]);
- return 1;
- } else {
- char result[100];
- SYMBOL* symbol =
- symbol_define(pkg, parms[1], parms[2], parms[3], parms[4]);
- /*
- * insert replacement string
- * expander(index, symbol, type, value)
- */
- char* expander = parms[5];
- if (*expander != EOS) {
- sprintf(result, "%s(%d, ", expander, symbol->index);
- puts(result);
- put_string(symbol->name);
- sprintf(result, ", %s, %s)",
- (*symbol->type) ? symbol->type : "void*",
- (*symbol->value) ? symbol->value : "0");
- puts(result);
- }
- }
- return 0;
- }
-
- /*
- * Called just before cpp terminates
- * We write out the new header file here (when necessary)
- */
- static void
- finalize_package(pkg)
- struct package* pkg;
- {
- if(pkg->is_changed) { /* If package was updated/changed */
- /* fprintf(stderr, "Writing %s\n", pkg->filename); *********** DEBUG ********* */
- rewind(pkg->file);
- write_package(pkg); /* Write new header file */
- }
- close(pkg->file);
- }
-
- /*
- * This is called at the end of CPP to close and/or re-write package header files
- */
- finish_symbols() {
- PACKAGE* pkg = package_list;
- for (; pkg != NULL; pkg = pkg->next)
- finalize_package(pkg);
- }
-