/* label.c */ #include #include #include "project.h" static label_t* labels = NULL; /* List of all known labels */ static unsigned capacity = 0; /* Amount of memory allocated */ static unsigned count = 0; /* Number of known labels */ static unsigned max_addr = 0; /* Highest labeled address */ static int virgin = 1; /* Installed atexit yet? */ /* Cleanup function. */ static void cleanup(void) { free(labels); } /* Adds a new label to the database. */ char* label_add(char* name, unsigned addr) { int i; /* Bail on duplicates */ for (i = 0; i < count; i++) if (strcmp(labels[i].name, name) == 0) return "duplicate label"; /* Grow label list if required */ if (capacity == count) { capacity = capacity == 0 ? 64 : capacity * 2; labels = realloc(labels, sizeof(label_t) * capacity); if (labels == NULL) die("Out of memory\n"); if (virgin) { virgin = 0; if (atexit(cleanup) != 0) { perror("atexit"); exit(EXIT_FAILURE); } } } /* Add a new entry to the label list */ labels[count].name = strdup(name); labels[count].addr = addr & 0xffff; count++; if (max_addr < addr) max_addr = addr; return NULL; } /* Returns a label's label_t* given its name. Returns NULL on failure. */ label_t* label_by_name(char* name) { int i; /* Scan the list */ for (i = 0; i < count; i++) if (strcmp(labels[i].name, name) == 0) return &labels[i]; return NULL; } /* Returns a label's label_t* given its address. */ label_t* label_by_addr(unsigned addr) { int i; /* Scan the list */ for (i = 0; i < count; i++) if (labels[i].addr == addr) return &labels[i]; return NULL; } /* Returns the label_t* for the first label _before_or_at_ the given address. */ label_t* label_before_addr(unsigned addr) { label_t* candidate = NULL; int i; /* Scan the list */ for (i = 0; i < count; i++) if (labels[i].addr <= addr && (candidate == NULL || candidate->addr < labels[i].addr)) candidate = &labels[i]; return candidate; } /* Returns the label_t* for the first label _after_ the given address. */ label_t* label_after_addr(unsigned addr) { label_t* candidate = NULL; int i; if (addr >= max_addr) return NULL; /* Scan the list */ for (i = 0; i < count; i++) if (labels[i].addr > addr && (candidate == NULL || candidate->addr > labels[i].addr)) candidate = &labels[i]; return candidate; } /* Empties the label table. */ void label_reset(void) { count = 0; } /* Loads a label map from a file. */ void label_load_map(char* filename) { char* buf = NULL; int buf_capacity = 0; FILE* handle; char delims[] = " :\t\n"; char* name, *addr, *dummy; /* First lose any previous label list */ label_reset(); /* Open the file */ handle = fopen(filename, "r"); if (handle == NULL) { perror("fopen"); exit(EXIT_FAILURE); } /* Read the file line-by-line */ while (1) { char* ret; if (getline(&buf, &buf_capacity, handle) == -1) { if (ferror(handle)) { perror("getline"); exit(EXIT_FAILURE); } else if (feof(handle)) break; } name = strtok(buf, delims); if (name == NULL) continue; /* Blank line */ addr = strtok(NULL, delims); if (addr == NULL) die("Invalid map file\n"); dummy = strtok(NULL, delims); if (dummy != NULL) die("Invalid map file\n"); ret = label_add(name, strtoul(addr, NULL, 16)); if (ret != NULL) die("%s\n", ret); } /* Done */ free(buf); if (fclose(handle) == EOF) { perror("fclose"); exit(EXIT_FAILURE); } } /* EOF */