diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/preproc.c | 63 |
1 files changed, 56 insertions, 7 deletions
diff --git a/src/preproc.c b/src/preproc.c index ce32a29..56dcc22 100644 --- a/src/preproc.c +++ b/src/preproc.c @@ -1,8 +1,8 @@ /* grecs - Gray's Extensible Configuration System - Copyright (C) 2007-2012 Sergey Poznyakoff + Copyright (C) 2007-2014 Sergey Poznyakoff Grecs is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @@ -25,12 +25,13 @@ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <errno.h> #include <signal.h> +#include <glob.h> #include <wordsplit.h> int grecs_log_to_stderr = 1; void (*grecs_log_setup_hook) () = NULL; @@ -59,12 +60,15 @@ static size_t linebufsize = 0; static char *linebuf; static size_t bufsize; static char *putback_buffer; static size_t putback_size; static size_t putback_max; +static glob_t include_glob; +static size_t include_pos; +static int include_once; static int push_source (const char *name, int once); static int pop_source (void); static int parse_include (const char *text, int once); ssize_t @@ -284,13 +288,15 @@ struct file_data { }; static int pp_list_find(struct grecs_list *list, struct file_data *dptr) { struct grecs_list_entry *ep; - + + if (!list) + return 0; for (ep = list->head; !dptr->found && ep; ep = ep->next) { const char *dir = ep->data; size_t size = strlen (dir) + 1 + dptr->namelen + 1; if (size > dptr->buflen) { dptr->buflen = size; dptr->buf = grecs_realloc(dptr->buf, dptr->buflen); @@ -392,23 +398,30 @@ incl_compare(void const *data1, void const *data2) const struct input_file_ident *id1 = data1; const struct input_file_ident *id2 = data2; return !(id1->device == id2->device && id1->i_node == id2->i_node); } static int +incl_copy(void *dst, void *src) +{ + memcpy(dst, src, sizeof(struct input_file_ident)); + return 0; +} + +static int source_lookup(struct stat *st) { struct input_file_ident key; int install = 1; if (!incl_sources) { incl_sources = grecs_symtab_create( sizeof(struct input_file_ident), incl_hasher, incl_compare, - NULL, + incl_copy, NULL,/*FIXME: alloc*/ NULL); if (!incl_sources) grecs_alloc_die(); } @@ -502,12 +515,20 @@ pop_source() /* Restore previous context */ ctx = context_stack->prev; grecs_free(context_stack); context_stack = ctx; + if (include_pos < include_glob.gl_pathc) { + push_source(include_glob.gl_pathv[include_pos++], include_once); + return 0; + } else if (include_glob.gl_pathc) { + globfree(&include_glob); + include_pos = include_glob.gl_pathc = 0; + } + if (!context_stack) { if (grecs_grecs__flex_debug) fprintf(stderr, "End of input\n"); return 1; } @@ -549,12 +570,22 @@ grecs_find_include_file(const char *name, int allow_cwd) return NULL; } return fd.buf; } static int +isglob(const char *s) +{ + for (; *s; s++) { + if (strchr("*?[", *s)) + return 1; + } + return 0; +} + +static int parse_include(const char *text, int once) { struct wordsplit ws; char *tmp = NULL; char *p = NULL; int rc = 1; @@ -576,23 +607,41 @@ parse_include(const char *text, int once) p[len - 1] = 0; p++; } else allow_cwd = 1; - if (p[0] != '/') { - p = grecs_find_include_file(p, allow_cwd); + if (isglob(p)) { + switch (glob(p, 0, NULL, &include_glob)) { + case 0: + include_pos = 0; + include_once = once; + break; + case GLOB_NOSPACE: + grecs_alloc_die(); + case GLOB_NOMATCH: + break; + default: + grecs_error(&LOCUS, 0, _("read error")); + } + p = NULL; + } else if (p[0] != '/') { + char *q = p; + p = grecs_find_include_file(q, allow_cwd); if (!p) grecs_error(&LOCUS, 0, _("%s: No such file or directory"), - p); + q); } - } + } if (p) rc = push_source(p, once); + else if (include_pos < include_glob.gl_pathc) + rc = push_source(include_glob.gl_pathv[include_pos++], once); + grecs_free(tmp); wordsplit_free(&ws); return rc; } int |