#undef SPEC_DEBUG
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <strings.h>
#include <libc.h>
#include <mach/mach.h>
#include <mach-o/loader.h>
#include <mach-o/reloc.h>
#include "stuff/errors.h"
#include "stuff/allocate.h"
#include "stuff/hash_string.h"
#include "stuff/bool.h"
#include "stuff/bytesex.h"
#include "libgcc.h"
#include "mkshlib.h"
#define BRANCH_LIST_SIZE 1301
#define OBJECT_HASH_SIZE 251
#define OBJECT_LIST_SIZE 256
#define ODDBALL_LIST_SIZE 256
char *target_name = (char *)0;
long minor_version = 0;
long image_version = 0;
long text_addr = BAD_ADDRESS;
long data_addr = BAD_ADDRESS;
struct branch *branch_hash[BRANCH_HASH_SIZE];
struct branch **branch_list;
static long branch_list_size;
long nbranch_list;
struct oddball *oddball_hash[ODDBALL_HASH_SIZE];
static struct oddball **oddball_list;
static long oddball_list_size;
static long noddball_list;
static struct object **object_hash;
struct object **object_list;
static long object_list_size;
long nobject_list;
struct alias *aliases;
static long line_num;
static long spec_error;
static struct object *init_object;
static int max_slotnum_seen = 0;
static long newstate(char *p, long oldstate);
static void branch(char *p);
static void object(char *p);
static void filelist(
char *file_name,
char *directory_name,
enum libgcc libgcc_state);
static char *new_object(
char *object_name,
enum bool filelist,
enum libgcc libgcc_state);
static void init(char *p);
static void alias(char *p);
static void oddball(char *p, long state);
static char *next(char *p);
#define STATE_NONE 0
#define STATE_BRANCH 1
#define STATE_OBJECT 2
#define STATE_INIT 3
#define STATE_ALIAS 4
#define STATE_PRIVATE 5
#define STATE_NOBRANCH 6
#define STATE_UNDEFINED 7
void
parse_spec(void)
{
FILE *spec_stream;
long state, i, hash_key;
char line[BUFSIZ], *p;
struct object *op;
struct oddball *obp;
struct branch *bp;
if((spec_stream = fopen(spec_filename, "r")) == NULL)
system_fatal("can't open: %s", spec_filename);
line_num = 0;
state = STATE_NONE;
while(fgets(line, BUFSIZ, spec_stream) != NULL){
line_num++;
if(strlen(line) == BUFSIZ - 1 && line[BUFSIZ - 1] != '\n')
fatal("line %ld in: %s too long (maximum %d)", line_num,
spec_filename, BUFSIZ);
p = line;
while(isspace(*p))
p++;
if(*p == '\0')
continue;
if(*p == '#'){
state = newstate(p, state);
}
else{
switch(state){
case STATE_BRANCH:
branch(p);
break;
case STATE_OBJECT:
object(p);
break;
case STATE_INIT:
init(p);
break;
case STATE_ALIAS:
alias(p);
break;
case STATE_PRIVATE:
case STATE_NOBRANCH:
case STATE_UNDEFINED:
oddball(p, state);
break;
default:
fatal("unrecognized specification in: %s on line %ld",
spec_filename, line_num);
}
}
}
if(ferror(spec_stream))
system_fatal("read error on: %s", spec_filename);
fclose(spec_stream);
if(target_name == (char *)0){
error("shared library target name not specified in: %s (use "
"#target <name>)", spec_filename);
spec_error++;
}
if(minor_version == 0){
error("shared library minor version not specified in: %s (use "
"#minor_version <decimal number>)", spec_filename);
spec_error++;
}
if(text_addr == BAD_ADDRESS){
error("shared library %s segment address not specified in: %s "
"(use #address %s <hex address>)", SEG_TEXT, spec_filename,
SEG_TEXT);
spec_error++;
}
if(data_addr == BAD_ADDRESS){
error("shared library %s segment address not specified in: %s "
"(use #address %s <hex address>)", SEG_DATA, spec_filename,
SEG_DATA);
spec_error++;
}
if(nbranch_list == 0){
error("no #branch table entries specified in: %s ", spec_filename);
spec_error++;
}
for(i = 0; i <= max_slotnum_seen; i++){
if(branch_list[i] == (struct branch *)0){
error("branch table entry %ld not specified in: %s ",
i, spec_filename);
spec_error++;
}
}
if(nobject_list == 0){
error("no #objects entries specified in: %s ", spec_filename);
spec_error++;
}
for(i = 0; i < OBJECT_HASH_SIZE; i++){
op = object_hash[i];
while(op != (struct object *)0){
if(op->init_only){
error("object: %s has #init specfication in: %s but not "
"listed in #objects specification section", op->name,
spec_filename);
spec_error++;
}
op = op->next;
}
}
free(object_hash);
for(i = 0; i < ODDBALL_HASH_SIZE; i++){
obp = oddball_hash[i];
while(obp != (struct oddball *)0){
hash_key = hash_string(obp->name) % BRANCH_HASH_SIZE;
bp = branch_hash[hash_key];
while(bp != (struct branch *)0){
if(strcmp(bp->name, obp->name) == 0){
if(obp->nobranch){
error("nobranch_text symbol: %s has a branch slot "
"(%ld) in: %s", bp->name, bp->max_slotnum,
spec_filename);
spec_error++;
}
else if(obp->private){
error("private_extern symbol: %s has a branch slot "
"(%ld) in: %s", bp->name, bp->max_slotnum,
spec_filename);
spec_error++;
}
else if(obp->undefined){
error("undefined symbol: %s has a branch slot "
"(%ld) in: %s", bp->name, bp->max_slotnum,
spec_filename);
spec_error++;
}
}
bp = bp->next;
}
obp = obp->next;
}
}
#ifdef SPEC_DEBUG
printf("Data structures built from the specification file: %s\n",
spec_filename);
printf("\ttarget_name = %s\n", target_name);
printf("\tminor_version = %d\n", minor_version);
printf("\ttext_addr = 0x%x\n", text_addr);
printf("\tdata_addr = 0x%x\n", data_addr);
for(i = 0; i < nobject_list; i++){
printf("\tobject_list[%d] = 0x%x { %s, %s, 0x%x, %d, 0x%x }\n", i,
object_list[i],
object_list[i]->name,
object_list[i]->base_name,
object_list[i]->inits,
object_list[i]->init_only,
object_list[i]->next);
ip = object_list[i]->inits;
while(ip){
printf("\t\tpinit = %s sinit = %s\n", ip->pinit, ip->sinit);
ip = ip->next;
}
}
for(i = 0; i < branch_list_size; i++){
if(branch_list[i] != (struct branch *)0)
printf("\tbranch_list[%d] = 0x%x { %s, %s, %d, 0x%x }\n", i,
branch_list[i],
branch_list[i]->name,
branch_list[i]->old_name,
branch_list[i]->max_slotnum,
branch_list[i]->next);
}
ap = aliases;
while(ap != (struct alias *)0){
printf("\talias list: %s %s\n", ap->alias_name, ap->real_name);
ap = ap->next;
}
for(i = 0; i < noddball_list; i++){
printf("\toddball_list[%d] = 0x%x { %s, private = %d nobranch = %d "
"undefined = %d }\n", i, oddball_list[i],
oddball_list[i]->name, oddball_list[i]->private,
oddball_list[i]->nobranch, oddball_list[i]->undefined);
}
#endif SPEC_DEBUG
free(oddball_list);
if(spec_error)
exit(1);
}
static
long
newstate(
char *p,
long oldstate)
{
char *directive, *minor_version_string, *segment_name, *address_string, *q,
*object_name, *base_name, *file_name, *directory_name;
long hash_key;
unsigned long address;
enum libgcc libgcc_state;
p++;
if(*p == '\0')
return(oldstate);
while(isspace(*p))
p++;
if(*p == '\0' || *p == '#')
return(oldstate);
directive = p;
p = next(p);
if(strcmp(directive, "branch") == 0){
if(*p != '\0')
fatal("junk after #branch directive in: %s on line %ld",
spec_filename, line_num);
if(branch_list != (struct branch **)0)
fatal("#branch directive appears more that once in: %s on "
"line %ld", spec_filename, line_num);
branch_list = allocate(BRANCH_LIST_SIZE *
sizeof(struct branch *));
bzero(branch_list, BRANCH_LIST_SIZE * sizeof(struct branch *));
branch_list_size = BRANCH_LIST_SIZE;
return(STATE_BRANCH);
} else if(strcmp(directive, "objects") == 0){
if(*p != '\0')
fatal("junk after #objects directive in: %s on line %ld",
spec_filename, line_num);
if(object_list != (struct object **)0)
fatal("#objects directive appears more that once in: %s on "
"line %ld", spec_filename, line_num);
object_list = allocate(OBJECT_LIST_SIZE *
sizeof(struct object *));
object_list_size = OBJECT_LIST_SIZE;
nobject_list = 0;
if(object_hash == (struct object **)0){
object_hash = allocate(OBJECT_HASH_SIZE *
sizeof(struct object *));
bzero(object_hash,
OBJECT_HASH_SIZE * sizeof(struct object *));
}
return(STATE_OBJECT);
} else if(strcmp(directive, "filelist") == 0){
if(oldstate != STATE_OBJECT)
fatal("#filelist directive in: %s on line %ld seen when a "
"#object directive is not in effect", spec_filename,
line_num);
if(*p == '\0')
fatal("no file name specified for #filelist directive in: "
"%s on line %ld", spec_filename, line_num);
file_name = p;
p = next(p);
libgcc_state = NOT_LIBGCC;
if(*p != '\0'){
directory_name = p;
p = next(p);
if(*p == 'n'){
if(strncmp(p, "new_libgcc", sizeof("new_libgcc")-1) != 0)
fatal("junk after #filelist directive in: %s on line "
"%ld", spec_filename, line_num);
p += sizeof("new_libgcc") - 1;
p = next(p);
libgcc_state = NEW_LIBGCC;
}
else if(*p == 'o'){
if(strncmp(p, "old_libgcc", sizeof("old_libgcc")-1) != 0)
fatal("junk after #filelist directive in: %s on line "
"%ld", spec_filename, line_num);
p += sizeof("old_libgcc") - 1;
p = next(p);
libgcc_state = OLD_LIBGCC;
}
if(*p != '\0')
fatal("junk after #filelist directive in: %s on line %ld",
spec_filename, line_num);
}
else{
directory_name = NULL;
}
filelist(file_name, directory_name, libgcc_state);
return(STATE_OBJECT);
} else if(strcmp(directive, "init") == 0){
if(*p == '\0')
fatal("no object file name specified for #init directive in: "
"%s on line %ld", spec_filename, line_num);
object_name = p;
p = next(p);
if(*p != '\0')
fatal("junk after #init directive in: %s on line %ld",
spec_filename, line_num);
if(object_hash == (struct object **)0){
object_hash = allocate(OBJECT_HASH_SIZE *
sizeof(struct object *));
bzero(object_hash,
OBJECT_HASH_SIZE * sizeof(struct object *));
}
base_name = rindex(object_name, '/');
if(base_name == (char *)0)
base_name = object_name;
else
base_name++;
hash_key = hash_string(base_name) % OBJECT_HASH_SIZE;
init_object = object_hash[hash_key];
while(init_object != (struct object *)0){
if(strcmp(init_object->base_name, base_name) == 0){
if(strcmp(init_object->name, object_name) != 0){
fatal("object files: %s and %s in: %s must have unique "
"base file names (%s)", init_object->name,
object_name, spec_filename, base_name);
}
break;
}
init_object = init_object->next;
}
if(init_object == (struct object *)0){
init_object = allocate(sizeof(struct object));
init_object->name = savestr(object_name);
init_object->base_name = rindex(init_object->name, '/');
if(init_object->base_name == (char *)0)
init_object->base_name = init_object->name;
else
init_object->base_name++;
init_object->inits = (struct init *)0;
init_object->init_only = 1;
init_object->next = object_hash[hash_key];
object_hash[hash_key] = init_object;
}
return(STATE_INIT);
} else if(strcmp(directive, "target") == 0){
if(target_name != (char *)0)
fatal("#target directive appears more that once in: %s on "
"line %ld", spec_filename, line_num);
if(*p == '\0')
fatal("no file name specified for #target directive in: %s on "
"line %ld", spec_filename, line_num);
target_name = p;
p = next(p);
if(*p != '\0')
fatal("junk after #target directive in: %s on line %ld",
spec_filename, line_num);
p = rindex(target_name, '/');
if(p != (char *)0)
p++;
else
p = target_name;
while(*p != '\0'){
if(!isalnum(*p) && *p != '_' && *p != '.' && *p != '-')
fatal("base name of target: %s in: %s on line %ld must have"
" only alphanumeric, '_', '-', or '.' characters in "
"it", target_name, spec_filename, line_num);
p++;
}
target_name = savestr(target_name);
return(STATE_NONE);
} else if(strcmp(directive, "address") == 0){
if(*p == '\0')
fatal("no segment name and address specified for #address "
"directive in: %s on line %ld", spec_filename, line_num);
segment_name = p;
p = next(p);
if(*p == '\0')
fatal("missing address for #address directive in: %s on line "
"%ld", spec_filename, line_num);
address_string = p;
p = next(p);
if(*p != '\0')
fatal("junk after #address directive in: %s on line %ld",
spec_filename, line_num);
address = strtoul(address_string, &q, 16);
if(*q != '\0')
fatal("bad #address value: %s in: %s on line %ld",
address_string, spec_filename, line_num);
if(address % getpagesize() != 0)
fatal("#address value: 0x%x in: %s on line %ld must be a "
"multiple of the system pagesize (0x%x)",
(unsigned int)address, spec_filename, line_num,
(unsigned int)getpagesize());
if(strcmp(segment_name, SEG_TEXT) == 0){
if(text_addr != BAD_ADDRESS && text_addr != address)
fatal("#address directive for: %s segment appears more "
"that once in: %s on line %ld", SEG_TEXT,
spec_filename, line_num);
text_addr = address;
} else if(strcmp(segment_name, SEG_DATA) == 0){
if(data_addr != BAD_ADDRESS && data_addr != address)
fatal("#address directive for: %s segment appears more "
"that once in: %s on line %ld", SEG_DATA,
spec_filename, line_num);
data_addr = address;
} else {
fatal("segment name: %s for #address directive in: %s on "
"line %ld must be either %s or %s", segment_name,
spec_filename, line_num, SEG_TEXT, SEG_DATA);
}
return(STATE_NONE);
} else if(strcmp(directive, "minor_version") == 0){
if(minor_version != 0)
fatal("minor_version specified more than once (in the file: %s "
"on the line %ld and on the command line or previouly in "
"the specification file)", spec_filename, line_num);
if(*p == '\0')
fatal("missing value for #minor_version directive in: %s on "
"line %ld", spec_filename, line_num);
minor_version_string = p;
p = next(p);
if(*p != '\0')
fatal("junk after #minor_version directive in: %s on line %ld",
spec_filename, line_num);
minor_version = atol(minor_version_string);
if(minor_version <= 0)
fatal("#minor_version value: %ld in: %s on line %ld must be "
"greater than 0", minor_version, spec_filename, line_num);
return(STATE_NONE);
} else if(strcmp(directive, "alias") == 0){
if(*p != '\0')
fatal("junk after #alias directive in: %s on line %ld",
spec_filename, line_num);
if(oddball_list == (struct oddball **)0){
oddball_list = allocate(ODDBALL_LIST_SIZE *
sizeof(struct oddball *));
oddball_list_size = OBJECT_LIST_SIZE;
noddball_list = 0;
}
return(STATE_ALIAS);
} else if(strcmp(directive, "private_externs") == 0){
if(*p != '\0')
fatal("junk after #private_externs directive in: %s on line "
"%ld", spec_filename, line_num);
if(oddball_list == (struct oddball **)0){
oddball_list = allocate(ODDBALL_LIST_SIZE *
sizeof(struct oddball *));
oddball_list_size = OBJECT_LIST_SIZE;
noddball_list = 0;
}
return(STATE_PRIVATE);
} else if(strcmp(directive, "nobranch_text") == 0){
if(*p != '\0')
fatal("junk after #nobranch_text directive in: %s on line "
"%ld", spec_filename, line_num);
if(oddball_list == (struct oddball **)0){
oddball_list = allocate(ODDBALL_LIST_SIZE *
sizeof(struct oddball *));
oddball_list_size = OBJECT_LIST_SIZE;
noddball_list = 0;
}
return(STATE_NOBRANCH);
} else if(strcmp(directive, "undefined") == 0){
if(*p != '\0')
fatal("junk after #undefined directive in: %s on line "
"%ld", spec_filename, line_num);
if(oddball_list == (struct oddball **)0){
oddball_list = allocate(ODDBALL_LIST_SIZE *
sizeof(struct oddball *));
oddball_list_size = OBJECT_LIST_SIZE;
noddball_list = 0;
}
return(STATE_UNDEFINED);
}
fatal("unknown directive: #%s in: %s on line: %ld", directive,
spec_filename, line_num);
return(STATE_NONE);
}
static
void
branch(
char *p)
{
char *branch_name, *old_name, *q;
long min_slotnum, max_slotnum, hash_key, i;
struct branch *bp;
old_name = NULL;
if(*p == '\0')
return;
while(isspace(*p))
p++;
if(*p == '\0' || *p == '#')
return;
branch_name = p;
p = next(p);
if(*p == '\0')
fatal("missing branch table possition number in: %s on line %ld",
spec_filename, line_num);
min_slotnum = strtol(p, &q, 10);
if(q == p)
fatal("bad branch table possition number in: %s on line %ld",
spec_filename, line_num);
if(min_slotnum < 0)
fatal("branch table possition number in: %s on line %ld must be "
"greater than zero", spec_filename, line_num);
p = q;
while(isspace(*p))
p++;
if(*p != '\0' && *p != '#' && *p != '-' && *p != 'o')
fatal("bad branch table specification in: %s on line %ld",
spec_filename, line_num);
if(*p == '-'){
p++;
while(isspace(*p))
p++;
if(*p == '\0')
fatal("missing upper branch table possition range in: %s on "
"line %ld", spec_filename, line_num);
max_slotnum = strtol(p, &q, 10);
if(q == p)
fatal("bad upper branch table possition range in: %s on line "
"%ld", spec_filename, line_num);
if(max_slotnum < min_slotnum)
fatal("bad upper branch table possition range (%ld) in: %s on "
"line %ld must be greater than lower (%ld)", max_slotnum,
spec_filename, line_num, min_slotnum);
while(isspace(*q))
q++;
if(*q != '\0' && *q != '#')
fatal("junk after #branch specification in: %s on line %ld",
spec_filename, line_num);
}
else if(*p == 'o'){
if(strncmp(p, "old_name", sizeof("old_name")-1) != 0)
fatal("junk after #branch specification in: %s on line %ld",
spec_filename, line_num);
p += sizeof("old_name") - 1;
while(isspace(*p))
p++;
if(*p == '\0' || *p == '#')
fatal("missing symbol name after \"old_name\" for #branch "
"specification in: %s on line %ld", spec_filename,
line_num);
old_name = p;
p = next(p);
if(*p != '\0' && *p != '#')
fatal("junk after #branch specification in: %s on line %ld",
spec_filename, line_num);
max_slotnum = min_slotnum;
}
else{
max_slotnum = min_slotnum;
}
hash_key = hash_string(branch_name) % BRANCH_HASH_SIZE;
bp = branch_hash[hash_key];
while(bp != (struct branch *)0){
if(strcmp(bp->name, branch_name) == 0){
if(bp->max_slotnum < max_slotnum)
bp->max_slotnum = max_slotnum;
break;
}
bp = bp->next;
}
if(bp == (struct branch *)0){
bp = allocate(sizeof(struct branch));
bp->name = savestr(branch_name);
if(old_name != NULL)
bp->old_name = savestr(old_name);
if(strcmp(bp->name, EMPTY_SLOT_NAME) == 0)
bp->empty_slot = 1;
else
bp->empty_slot = 0;
bp->max_slotnum = max_slotnum;
bp->next = branch_hash[hash_key];
branch_hash[hash_key] = bp;
}
if(max_slotnum >= branch_list_size){
branch_list = reallocate(branch_list, max_slotnum * 2 *
sizeof(struct branch *));
bzero(branch_list + branch_list_size,
branch_list_size * sizeof(struct branch *));
branch_list_size = max_slotnum * 2;
}
for(i = min_slotnum; i <= max_slotnum; i++){
if(branch_list[i] != (struct branch *)0 &&
branch_list[i] != bp){
error("#branch position %ld multiply specified in: %s on line "
"%ld", i, spec_filename, line_num);
spec_error++;
}
else{
if(branch_list[i] != bp)
nbranch_list++;
branch_list[i] = bp;
}
}
if(max_slotnum > max_slotnum_seen)
max_slotnum_seen = max_slotnum;
}
static
void
object(
char *p)
{
char *object_name;
if(*p == '\0')
return;
while(isspace(*p))
p++;
if(*p == '\0' || *p == '#')
return;
object_name = p;
p = next(p);
while(*object_name != '\0'){
p = new_object(object_name, FALSE, NOT_LIBGCC);
object_name = p;
p = next(p);
}
}
static
void
filelist(
char *file_name,
char *directory_name,
enum libgcc libgcc_state)
{
FILE *filelist_stream;
long n;
char line[BUFSIZ], *p, *object_name;
if(directory_name != NULL){
if(directory_name[strlen(directory_name) - 1] != '/')
directory_name = makestr(directory_name, "/", NULL);
}
if((filelist_stream = fopen(file_name, "r")) == NULL)
system_fatal("can't open: %s from #filelist directive in: %s on "
"line %ld", file_name, spec_filename, line_num);
n = 0;
while(fgets(line, BUFSIZ, filelist_stream) != NULL){
n++;
if(strlen(line) == BUFSIZ - 1 && line[BUFSIZ - 1] != '\n')
fatal("line %ld in: %s too long (maximum %d)", n, file_name,
BUFSIZ);
p = strchr(line, '\n');
*p = '\0';
if(directory_name != NULL)
object_name = makestr(directory_name, line, NULL);
else
object_name = line;
new_object(object_name, TRUE, libgcc_state);
}
fclose(filelist_stream);
}
static
char *
new_object(
char *object_name,
enum bool filelist,
enum libgcc libgcc_state)
{
char *p, *base_name;
long hash_key;
struct object *op;
if(nobject_list + 1 > object_list_size){
object_list = reallocate(object_list, object_list_size * 2 *
sizeof(struct object *));
object_list_size *= 2;
}
base_name = rindex(object_name, '/');
if(base_name == (char *)0)
base_name = object_name;
else
base_name++;
hash_key = hash_string(base_name) % OBJECT_HASH_SIZE;
op = object_hash[hash_key];
while(op != (struct object *)0){
if(strcmp(op->base_name, base_name) == 0){
if(strcmp(op->name, object_name) != 0){
fatal("object files: %s and %s must have unique base "
"file names (%s)", op->name, object_name, base_name);
}
if(filelist == TRUE)
return(NULL);
if(op->init_only)
break;
fatal("object file name: %s appears more than once in: %s "
"on line %ld", object_name, spec_filename, line_num);
}
op = op->next;
}
p = base_name;
while(*p != '\0'){
if(!isalnum(*p) && *p != '_' && *p != '.' && *p != '-')
fatal("base name of object: %s in: %s on line %ld must have"
" only alphanumeric, '_', '-', or '.' characters in "
"it", object_name, spec_filename, line_num);
p++;
}
if(op == (struct object *)0){
op = allocate(sizeof(struct object));
bzero(op, sizeof(struct object));
op->name = savestr(object_name);
op->base_name = rindex(op->name, '/');
if(op->base_name == (char *)0)
op->base_name = op->name;
else
op->base_name++;
op->libgcc_state = libgcc_state;
op->next = object_hash[hash_key];
object_hash[hash_key] = op;
}
else{
op->init_only = 0;
}
object_list[nobject_list++] = op;
return(p);
}
static
void
init(
char *p)
{
char *pinit, *sinit;
struct init *ip;
if(*p == '\0')
return;
while(isspace(*p))
p++;
if(*p == '\0' || *p == '#')
return;
pinit = p;
p = next(p);
if(*p == '\0')
fatal("missing symbol name for #init specification in: %s on line "
"%ld", spec_filename, line_num);
sinit = p;
p = next(p);
if(*p != '\0')
fatal("junk after #init specification in: %s on line %ld",
spec_filename, line_num);
ip = allocate(sizeof(struct init));
ip->pinit = savestr(pinit);
ip->sinit = savestr(sinit);
ip->next = init_object->inits;
init_object->inits = ip;
}
static
void
alias(
char *p)
{
char *alias_name, *real_name;
struct alias *ap;
if(*p == '\0')
return;
while(isspace(*p))
p++;
if(*p == '\0' || *p == '#')
return;
alias_name = p;
p = next(p);
if(*p == '\0')
fatal("missing symbol name for #alias specification in: %s on line "
"%ld", spec_filename, line_num);
real_name = p;
p = next(p);
if(*p != '\0')
fatal("junk after #alias specification in: %s on line %ld",
spec_filename, line_num);
ap = allocate(sizeof(struct alias));
ap->alias_name = savestr(alias_name);
ap->real_name = savestr(real_name);
ap->next = aliases;
aliases = ap;
oddball(alias_name, STATE_PRIVATE);
}
static
void
oddball(
char *p,
long state)
{
char *name;
long hash_key;
struct oddball *obp;
if(*p == '\0')
return;
while(isspace(*p))
p++;
if(*p == '\0' || *p == '#')
return;
name = p;
p = next(p);
while(*name != '\0'){
if(noddball_list + 1 > oddball_list_size){
oddball_list = reallocate(oddball_list, oddball_list_size * 2 *
sizeof(struct oddball *));
oddball_list_size *= 2;
}
hash_key = hash_string(name) % ODDBALL_HASH_SIZE;
obp = oddball_hash[hash_key];
while(obp != (struct oddball *)0){
if(strcmp(obp->name, name) == 0)
break;
obp = obp->next;
}
if(obp == (struct oddball *)0){
obp = allocate(sizeof(struct oddball));
bzero(obp, sizeof(struct oddball));
obp->name = savestr(name);
obp->next = oddball_hash[hash_key];
oddball_hash[hash_key] = obp;
oddball_list[noddball_list++] = obp;
}
switch(state){
case STATE_PRIVATE:
obp->private = 1;
break;
case STATE_NOBRANCH:
obp->nobranch = 1;
break;
case STATE_UNDEFINED:
obp->undefined = 1;
break;
}
name = p;
p = next(p);
}
}
static
char *
next(
char *p)
{
while(!isspace(*p) && *p != '\0')
p++;
if(*p != '\0'){
*p = '\0';
p++;
while(isspace(*p))
p++;
if(*p == '#')
*p = '\0';
}
return(p);
}