/* * b u i l d 5 . c * * Subroutines * * Symbol table management * * sylookup finds a symbol, may create new one * syvalue finds a symbol, returns value (maybe returns NULL) * syset sets a value in a symbol * sysave saves a value in free storage and syset's it. * syperm makes values permanent (after reading model files) * syclean removes non-permanent symbols * sydump dump symbol table -- debug * sydodump dump one symbol -- debug * */ #include #include "build.h" static SYMBOL *sy_first = NULL; /* Symbol table chain */ SYMBOL * sylookup(name, create) char *name; /* Symbol name string */ int create; /* True if creation ok */ /* * Find (or create) a symbol, returning a pointer to it. If create * is FALSE and the symbol is not present, NULL is returned and * an error message written. */ { register SYMBOL *sy; for (sy = sy_first; sy != NULL; sy = sy->sy_next) { if (streq(name, sy->sy_name)) return (sy); } if (!create) { fprintf(stderr, "?No definition for symbol \"%s\"\n", name); } else { /* * Allocate a new symbol */ sy = myalloc(sizeof (SYMBOL)); sy->sy_next = sy_first; sy_first = sy; sy->sy_name = savest(name); /* * Note -- other fields were null'ed by myalloc. */ } return (sy); } char * syvalue(name) char *name; /* * Return value associated with name */ { register SYMBOL *sy; sy = sylookup(name, FALSE); return ((sy == NULL) ? NULL : sy->sy_value); } SYMBOL * sysave(name, value, flag) char *name; char *value; int flag; /* * after saving the value string in free storage, call syset to * put it in the symbol table. */ { return(syset(name, savest(value), flag)); } SYMBOL * syset(name, value, flag) char *name; char *value; int flag; /* * Give symbol this value -- the value is not savest'd. * flag has the bits to set in sy_flag. * If the value is to be savest'd, proceed as follows: * syset(name, savest(value), flag); * In general, flag should equal 0 or MODEL. The FREE bit * is set by syset(). It must be cleared (by calling syperm() or * explicitly if the value must not be free'd. */ { register SYMBOL *sy; sy = sylookup(name, TRUE); if (sy->sy_value != NULL && (sy->sy_flag & FREE)) myfree(sy->sy_value); if ((sy->sy_flag & USED) && !streq(name, "*") && !streq(name, "?")) { fprintf(stderr, "warning, %s changed from to \"%s\" after use\n", name, sy->sy_value, value); } sy->sy_value = value; sy->sy_flag |= (flag | FREE); /* Set flag bits */ sy->sy_flag &= ~DEFAULT; /* Not default value now */ return (sy); } syperm() /* * Make current symbol table permanent. This is called * after reading all model files. */ { register SYMBOL *sy; for (sy = sy_first; sy != NULL; sy = sy->sy_next) { sy->sy_perm = sy->sy_value; sy->sy_flag &= ~FREE; } } syclean() /* * Recover storage by deleting all non-permanent symbol values * Values are then reset to their defaults. */ { register SYMBOL *sy; for (sy = sy_first; sy != NULL; sy = sy->sy_next) { if (sy->sy_value != NULL && (sy->sy_flag & FREE)) myfree(sy->sy_value); sy->sy_value = sy->sy_perm; sy->sy_flag &= ~(FREE | USED); sy->sy_flag |= DEFAULT; } } sydump() /* * Dump symbol table */ { register SYMBOL *sy; printf("\n** ** symbol table dump"); #ifdef decus calltr(stdout); #endif for (sy = sy_first; sy != NULL; sy = sy->sy_next) { sydodump(sy->sy_name); } } sydodump(name) char *name; /* * Dump one symbol, given its name */ { register SYMBOL *sy; register char *value; register int flag; char *perm; if ((sy = sylookup(name, FALSE)) == NULL) printf("no definition of \"%s\"\n"); else { value = sy->sy_value; perm = sy->sy_perm; flag = sy->sy_flag; printf("$(%s %s%s%s%s%s) = {%s}", sy->sy_name, (value == perm) ? "P" : "", (flag & MODEL) ? "M" : "", (flag & FREE) ? "F" : "", (flag & USED) ? "U" : "", (flag & DEFAULT) ? "D" : "", (value != NULL) ? value : perm); if (value != perm) printf(", {%s}", perm); printf("\n"); } } int isdefault(name) char *name; /* * True if name has not been changed by a model or file string. */ { register SYMBOL *sy; sy = sylookup(name, FALSE); if (sy == NULL) return (TRUE); if ((sy->sy_flag & DEFAULT) != 0) return (TRUE); return (FALSE); } /* * File name management */ setfile(name, filetype, trash_directory) char *name; /* File name */ char *filetype; /* If none specified */ int trash_directory; /* TRUE to eliminate node::dev: */ /* * Save a file name string: * $? = filename.ext * $* = filename (no .ext) * * To save the currently open file, do * * setfile(fgetname(fd, work), NULL); */ { register char *np; register int c; if (trash_directory) { /* * Skip over node::dev:[account] */ for (np = &name[strlen(name)]; np > name && np[-1] != ':'; np--) ; /* * Skip over [account] */ if (*np == '[' || *np == '(') { while ((c = *np++) != EOS && c != ']' && c != ')') ; if (c == EOS) { fprintf(stderr, "bug, bad file name: \"%s\"\n", name); np--; } } } else np = name; setstrip(np, ';', "?", filetype); setstrip(np, '.', "*", NULL); } setstrip(np, strip, key, filetype) register char *np; /* Text */ char strip; /* Byte to strip */ char *key; /* Where to store it */ char *filetype; /* NULL if none, else ".foo" */ /* * Remove what's after strip and store under key. */ { register int c; register char *newp; int dotseen; newp = savest(np); dotseen = (filetype == NULL); for (np = newp; (c = *np) != EOS && c != strip;) { if (opsys == UNIX) np++; else *np++ = toupper(c); if (c == '.') dotseen = TRUE; } *np = EOS; np = myrealloc(newp, np-newp+1); /* Shorten it */ if (!dotseen) { np = csavest(np, filetype); /* maybe lengthen it */ } syset(key, np, 0); } /* * Storage allocation functions */ #ifndef vms char *my_free = NULL; /* Needed by myrealloc(), this */ /* must be set to malloc(1) on */ /* system startup. */ #endif #ifdef CHECKALLOC unsigned int curallo = 0; /* Bytes allocated */ unsigned int hwmallo = 0; /* Allocatin high water mark */ #endif char * myalloc(size) int size; /* Number of bytes to get */ /* * Allocate an area size bytes long. Return with the area set to 0. * If no memory, the program aborts. */ { register char *result; if ((result = calloc(size, sizeof (char))) == NULL) fatal("No memory", NULL); #ifdef CHECKALLOC curallo += (((unsigned int *) result)[-1]) - ((unsigned int)result); if (curallo > hwmallo) hwmallo = curallo; #endif return (result); } #ifdef CHECKALLOC myfree(old) char *old; /* * Free a buffer, update curallo */ { curallo -= (((unsigned int *) old)[-1]) - ((unsigned int)old); free(old); } #endif char * myrealloc(old, size) char *old; /* Old area */ int size; /* Number of bytes to get */ /* * Make the old allocated area size bytes long. * If no memory, the program aborts. */ { register char *result; myfree(old); /* Crashes if old == NULL */ #ifndef vms free(my_free); /* Crashes if my_free == NULL */ my_free = malloc(1); /* Reset the free pointer */ #endif if ((result = realloc(old, size)) == NULL) fatal("No memory", NULL); #ifdef CHECKALLOC curallo += (((unsigned int *) result)[-1]) - ((unsigned int)result); if (curallo > hwmallo) hwmallo = curallo; #endif return (result); } /* * Store strings in free memory */ char * savest(string) char *string; /* What to store */ /* * Save this string */ { register char *result; result = myalloc(strlen(string) + 1); strcpy(result, string); return(result); } char * csavest(old, new) char *old; /* Append new string onto old */ char *new; /* New stuff */ /* * Concatenate new onto old. Old was allocated using savest(). */ { register char *result; result = myrealloc(old, strlen(old) + strlen(new) + 1); strcat(result, new); return(result); } char * skipwhite(string) register char *string; /* String pointer */ /* * Skip over whitespace (space, tab, or newline). * Return pointer to first non-whitespace char or pointer to EOS. */ { while (*string != EOS && iswhite(*string)) string++; return (string); } int iswhite(byte) int byte; /* * TRUE if byte is whitespace (FALSE if byte is EOS). */ { return (byte == ' ' || byte == '\t' || byte == '\n'); } int mmatch(string, pattern, minimum) register char *string; /* What to look for */ char *pattern; /* Must be in lower case */ int minimum; /* Must match this many bytes */ /* * Match string against pattern. * mmatch() returns TRUE if string == pattern or at least minimum bytes * match. */ { register char *patt; register char *c; patt = pattern; while ((c = *string) != EOS && c == *patt) { patt++; string++; } return (*patt == EOS || (patt - pattern) >= minimum); } /* * File open and error message functions */ FILE * myfopen(name, mode) char *name; char *mode; /* * Fopen with error message */ { register FILE *fd; if (name == NULL) return (NULL); if ((fd = fopen(name, mode)) == NULL) { perror(name); } return (fd); } char * getline(fd) FILE *fd; /* * Read a line to inline. */ { return (fgets(inline, sizeof inline, fd)); } FILE * out(byte, fd) char byte; FILE *fd; { if (byte != EOS) putc(byte, fd); return (fd); } fatal(message, arg) char *message; char *arg; /* * Abort */ { if (arg != NULL) perror(arg); error(message); }