diff options
Diffstat (limited to 'srcpos.c')
-rw-r--r-- | srcpos.c | 151 |
1 files changed, 68 insertions, 83 deletions
@@ -25,117 +25,102 @@ #include "srcpos.h" -/* - * Like yylineno, this is the current open file pos. - */ -struct dtc_file *srcpos_file; +static char *dirname(const char *path) +{ + const char *slash = strrchr(path, '/'); -/* - * The empty source position. - */ + if (slash) { + int len = slash - path; + char *dir = xmalloc(len + 1); -struct dtc_file dtc_empty_file = { - .dir = NULL, - .name = "<no file>", - .file = NULL -}; + memcpy(dir, path, len); + dir[len] = '\0'; + return dir; + } + return NULL; +} -srcpos srcpos_empty = { - .first_line = 0, - .first_column = 0, - .last_line = 0, - .last_column = 0, - .file = &dtc_empty_file -}; +struct srcfile_state *current_srcfile; /* = NULL */ +/* Detect infinite include recursion. */ +#define MAX_SRCFILE_DEPTH (100) +static int srcfile_depth; /* = 0 */ -static int -dtc_open_one(struct dtc_file *file, const char *search, const char *fname) +FILE *srcfile_relative_open(const char *fname, char **fullnamep) { + FILE *f; char *fullname; - if (search) { - fullname = xmalloc(strlen(search) + strlen(fname) + 2); - - strcpy(fullname, search); - strcat(fullname, "/"); - strcat(fullname, fname); + if (streq(fname, "-")) { + f = stdin; + fullname = xstrdup("<stdin>"); } else { - fullname = xstrdup(fname); + if (!current_srcfile || !current_srcfile->dir + || (fname[0] == '/')) + fullname = xstrdup(fname); + else + fullname = join_path(current_srcfile->dir, fname); + + f = fopen(fullname, "r"); + if (!f) + die("Couldn't open \"%s\": %s\n", fname, + strerror(errno)); } - file->file = fopen(fullname, "r"); - if (!file->file) { + if (fullnamep) + *fullnamep = fullname; + else free(fullname); - return 0; - } - file->name = fullname; - return 1; + return f; } - -struct dtc_file * -dtc_open_file(const char *fname, const struct search_path *search) +void srcfile_push(const char *fname) { - static const struct search_path default_search = { NULL, NULL, NULL }; + struct srcfile_state *srcfile; - struct dtc_file *file; - const char *slash; + if (srcfile_depth++ >= MAX_SRCFILE_DEPTH) + die("Includes nested too deeply"); - file = xmalloc(sizeof(struct dtc_file)); + srcfile = xmalloc(sizeof(*srcfile)); - slash = strrchr(fname, '/'); - if (slash) { - char *dir = xmalloc(slash - fname + 1); - - memcpy(dir, fname, slash - fname); - dir[slash - fname] = 0; - file->dir = dir; - } else { - file->dir = NULL; - } - - if (streq(fname, "-")) { - file->name = "stdin"; - file->file = stdin; - return file; - } - - if (fname[0] == '/') { - file->file = fopen(fname, "r"); - if (!file->file) - goto fail; + srcfile->f = srcfile_relative_open(fname, &srcfile->name); + srcfile->dir = dirname(srcfile->name); + srcfile->prev = current_srcfile; + current_srcfile = srcfile; +} - file->name = xstrdup(fname); - return file; - } +int srcfile_pop(void) +{ + struct srcfile_state *srcfile = current_srcfile; - if (!search) - search = &default_search; + assert(srcfile); - while (search) { - if (dtc_open_one(file, search->dir, fname)) - return file; + current_srcfile = srcfile->prev; - if (errno != ENOENT) - goto fail; + if (fclose(srcfile->f)) + die("Error closing \"%s\": %s\n", srcfile->name, strerror(errno)); - search = search->next; - } + /* FIXME: We allow the srcfile_state structure to leak, + * because it could still be referenced from a location + * variable being carried through the parser somewhere. To + * fix this we could either allocate all the files from a + * table, or use a pool allocator. */ -fail: - die("Couldn't open \"%s\": %s\n", fname, strerror(errno)); + return current_srcfile ? 1 : 0; } +/* + * The empty source position. + */ -void -dtc_close_file(struct dtc_file *file) -{ - if (fclose(file->file)) - die("Error closing \"%s\": %s\n", file->name, strerror(errno)); -} - +srcpos srcpos_empty = { + .first_line = 0, + .first_column = 0, + .last_line = 0, + .last_column = 0, + .file = NULL, +}; srcpos * srcpos_copy(srcpos *pos) |