aboutsummaryrefslogtreecommitdiff
path: root/src/preproc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/preproc.c')
-rw-r--r--src/preproc.c812
1 files changed, 0 insertions, 812 deletions
diff --git a/src/preproc.c b/src/preproc.c
deleted file mode 100644
index 4d69602..0000000
--- a/src/preproc.c
+++ /dev/null
@@ -1,812 +0,0 @@
-/* grecs - Gray's Extensible Configuration System
- Copyright (C) 2007-2016 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.
-
- Grecs is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with Grecs. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <grecs.h>
-#include <wordsplit.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <glob.h>
-#include <unistd.h>
-
-
-int grecs_log_to_stderr = 1;
-void (*grecs_log_setup_hook) () = NULL;
-
-struct input_file_ident {
- ino_t i_node;
- dev_t device;
-};
-
-struct buffer_ctx {
- struct buffer_ctx *prev; /* Pointer to previous context */
- grecs_locus_t locus; /* Current input location */
- size_t namelen; /* Length of the file name */
- size_t xlines; /* Number of #line directives output so far */
- struct input_file_ident id;
- FILE *infile;
-};
-
-extern int grecs_grecs__flex_debug;
-static struct buffer_ctx *context_stack;
-static char *linebufbase = NULL;
-static size_t linebufsize = 0;
-
-#define INFILE context_stack->infile
-#define LOCUS context_stack->locus
-#define POINT context_stack->locus.beg
-
-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
-grecs_getline(char **pbuf, size_t *psize, FILE *fp)
-{
- char *buf = *pbuf;
- size_t size = *psize;
- ssize_t off = 0;
-
- if (!buf) {
- size = 1;
- buf = grecs_malloc(size);
- }
-
- do {
- if (off == size - 1) {
- size_t nsize = 2 * size;
- if (nsize < size)
- grecs_alloc_die();
- buf = grecs_realloc(buf, nsize);
- size = nsize;
- }
- if (!fgets(buf + off, size - off, fp)) {
- if (off == 0)
- off = -1;
- break;
- }
- off += strlen(buf + off);
- } while (buf[off - 1] != '\n');
-
- *pbuf = buf;
- *psize = size;
- return off;
-}
-
-static void
-putback(const char *str)
-{
- size_t len;
-
- if (!*str)
- return;
- len = strlen(str) + 1;
- if (len > putback_max) {
- putback_max = len;
- putback_buffer = grecs_realloc(putback_buffer, putback_max);
- }
- strcpy(putback_buffer, str);
- putback_size = len - 1;
-}
-
-static void
-pp_line_stmt()
-{
- size_t ls_size;
- size_t pb_size;
-
- if (grecs_asprintf(&linebufbase, &linebufsize,
- "#line %lu \"%s\" %lu\n",
- (unsigned long) POINT.line,
- POINT.file, (unsigned long) context_stack->xlines))
- grecs_alloc_die();
-
- ls_size = strlen(linebufbase);
- pb_size = putback_size + ls_size + 1;
-
- if (pb_size > putback_max) {
- putback_max = pb_size;
- putback_buffer = grecs_realloc(putback_buffer, putback_max);
- }
-
- context_stack->xlines++;
- strcpy(putback_buffer + putback_size, linebufbase);
- putback_size += ls_size;
-}
-
-#define STRMATCH(p, len, s) (len >= sizeof(s) \
- && memcmp(p, s, sizeof(s) - 1) == 0 \
- && isspace(p[sizeof(s) - 1]))
-
-static int
-next_line()
-{
- ssize_t rc;
-
- do {
- if (putback_size) {
- if (putback_size + 1 > bufsize) {
- bufsize = putback_size + 1;
- linebuf = grecs_realloc(linebuf, bufsize);
- }
- strcpy(linebuf, putback_buffer);
- rc = putback_size;
- putback_size = 0;
- }
- else if (!context_stack)
- return 0;
- else
- rc = grecs_getline(&linebuf, &bufsize, INFILE);
- } while (rc == -1 && pop_source() == 0);
- return rc;
-}
-
-size_t
-grecs_preproc_fill_buffer(char *buf, size_t size)
-{
- size_t bufsize = size;
-
- while (next_line() > 0) {
- char *p;
- size_t len;
- int is_line = 0;
-
- for (p = linebuf; *p && isspace(*p); p++)
- ;
- if (*p == '#') {
- size_t l;
- for (p++; *p && isspace(*p); p++)
- ;
- l = strlen(p);
- if (STRMATCH(p, l, "include_once")) {
- if (parse_include(linebuf, 1))
- putback("/*include_once*/\n");
- continue;
- } else if (STRMATCH(p, l, "include")) {
- if (parse_include(linebuf, 0))
- putback("/*include*/\n");
- continue;
- } else if (STRMATCH(p, l, "line"))
- is_line = 1;
- }
-
- len = strlen(linebuf);
-
- if (len > size)
- len = size;
-
- memcpy(buf, linebuf, len);
- buf += len;
- size -= len;
-
- if (size == 0) {
- putback(linebuf + len);
- break;
- }
-
- if (!is_line && len > 0 && linebuf[len - 1] == '\n')
- POINT.line++;
- }
- return bufsize - size;
-}
-
-#define STAT_ID_EQ(st,id) ((id).i_node == (st).st_ino \
- && (id).device == (st).st_dev)
-
-static struct buffer_ctx *
-ctx_lookup(struct stat *st)
-{
- struct buffer_ctx *ctx;
-
- if (!context_stack)
- return NULL;
-
- for (ctx = context_stack->prev; ctx; ctx = ctx->prev)
- if (STAT_ID_EQ(*st, ctx->id))
- break;
- return ctx;
-}
-
-const char *grecs_preprocessor = NULL;
-static struct grecs_list *grecs_usr_include_path;
-static struct grecs_list *grecs_std_include_path;
-
-size_t
-grecs_include_path_count(int flag)
-{
- size_t count = 0;
- if (flag & GRECS_STD_INCLUDE)
- count += grecs_list_size(grecs_std_include_path);
- if (flag & GRECS_USR_INCLUDE)
- count += grecs_list_size(grecs_usr_include_path);
- return count;
-}
-
-static int
-foreach_dir(struct grecs_list *list, int flag,
- int (*fun)(int, const char *, void *), void *data)
-{
- int rc = 0;
- struct grecs_list_entry *ep;
-
- for (ep = list->head; rc == 0 && ep; ep = ep->next)
- rc = fun(flag, ep->data, data);
- return rc;
-}
-
-int
-grecs_foreach_include_dir(int flag, int (*fun)(int, const char *, void *),
- void *data)
-{
- int rc = 0;
-
- if (flag & GRECS_STD_INCLUDE)
- rc = foreach_dir(grecs_std_include_path, GRECS_STD_INCLUDE, fun, data);
- if (rc == 0 && (flag & GRECS_USR_INCLUDE))
- rc = foreach_dir(grecs_usr_include_path, GRECS_USR_INCLUDE, fun, data);
- return rc;
-}
-
-
-struct file_data {
- const char *name;
- size_t namelen;
- char *buf;
- size_t buflen;
- int found;
-};
-
-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);
- }
- strcpy(dptr->buf, dir);
- strcat(dptr->buf, "/");
- strcat(dptr->buf, dptr->name);
- dptr->found = access(dptr->buf, F_OK) == 0;
- }
- return dptr->found;
-}
-
-static void
-incl_free(void *data)
-{
- grecs_free(data);
-}
-
-void
-grecs_include_path_clear()
-{
- if (grecs_usr_include_path)
- grecs_list_clear(grecs_usr_include_path);
- if (grecs_std_include_path)
- grecs_list_clear(grecs_std_include_path);
-}
-
-void
-grecs_include_path_setup_v(char **dirs)
-{
- if (!grecs_usr_include_path) {
- grecs_usr_include_path = grecs_list_create();
- grecs_usr_include_path->free_entry = incl_free;
- }
- grecs_std_include_path = grecs_list_create();
- grecs_std_include_path->free_entry = incl_free;
- if (dirs) {
- int i;
- for (i = 0; dirs[i]; i++)
- /* FIXME: Element never freed */
- grecs_list_append(grecs_std_include_path,
- grecs_strdup(dirs[i]));
- }
-}
-
-void
-grecs_include_path_setup(const char *dir, ...)
-{
- const char *p;
- char **argv = NULL;
- size_t argc = 0;
- size_t argi = 0;
- va_list ap;
-
- va_start(ap, dir);
- p = dir;
- while (1) {
- if (argi == argc) {
- if (argc == 0)
- argc = 16;
- else
- argc += 16;
- argv = grecs_realloc(argv, argc * sizeof(argv[0]));
- }
- argv[argi++] = (char*) p;
- if (!p)
- break;
- p = va_arg(ap, const char*);
- }
- grecs_include_path_setup_v(argv);
- grecs_free(argv);
- va_end(ap);
-}
-
-void
-grecs_preproc_add_include_dir(char *dir)
-{
- if (!grecs_usr_include_path) {
- grecs_usr_include_path = grecs_list_create();
- grecs_usr_include_path->free_entry = incl_free;
- }
- grecs_list_append(grecs_usr_include_path, grecs_strdup(dir));
-}
-
-static struct grecs_symtab *incl_sources;
-
-/* Calculate the hash of a struct input_file_ident. */
-static unsigned
-incl_hasher(void *data, unsigned long n_buckets)
-{
- const struct input_file_ident *id = data;
- return (id->i_node + id->device) % n_buckets;
-}
-
-/* Compare two input_file_idents for equality. */
-static int
-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,
- incl_copy,
- NULL,/*FIXME: alloc*/
- NULL);
- if (!incl_sources)
- grecs_alloc_die();
- }
-
- key.i_node = st->st_ino;
- key.device = st->st_dev;
- if (!grecs_symtab_lookup_or_install(incl_sources, &key, &install))
- grecs_alloc_die();
- return !install;
-}
-
-
-static int
-push_source(const char *name, int once)
-{
- FILE *fp;
- struct buffer_ctx *ctx;
- struct stat st;
- int rc = stat(name, &st);
-
- if (context_stack) {
- if (rc) {
- grecs_error(&LOCUS, errno,
- _("Cannot stat `%s'"), name);
- return 1;
- }
-
- if (POINT.file && STAT_ID_EQ(st, context_stack->id)) {
- grecs_error(&LOCUS, 0, _("Recursive inclusion"));
- return 1;
- }
-
- if ((ctx = ctx_lookup(&st))) {
- grecs_error(&LOCUS, 0, _("Recursive inclusion"));
- if (ctx->prev)
- grecs_error(&ctx->prev->locus, 0,
- _("`%s' already included here"),
- name);
- else
- grecs_error(&LOCUS, 0,
- _("`%s' already included at top level"),
- name);
- return 1;
- }
- } else if (rc) {
- grecs_error(NULL, errno, _("Cannot stat `%s'"), name);
- return 1;
- }
-
- if (once && source_lookup(&st))
- return -1;
-
- fp = fopen(name, "r");
- if (!fp) {
- grecs_error(context_stack ? &LOCUS : NULL, errno,
- _("Cannot open `%s'"), name);
- return 1;
- }
-
- /* Push current context */
- ctx = grecs_malloc(sizeof(*ctx));
- ctx->locus.beg.file = grecs_install_text(name);
- ctx->locus.beg.line = 1;
- ctx->locus.beg.col = 0;
- ctx->locus.end.file = NULL;
- ctx->locus.end.line = ctx->locus.end.col = 0;
- ctx->xlines = 0;
- ctx->namelen = strlen(ctx->locus.beg.file);
- ctx->id.i_node = st.st_ino;
- ctx->id.device = st.st_dev;
- ctx->infile = fp;
- ctx->prev = context_stack;
- context_stack = ctx;
-
- if (grecs_grecs__flex_debug)
- fprintf (stderr, "Processing file `%s'\n", name);
-
- pp_line_stmt();
-
- return 0;
-}
-
-static int
-pop_source()
-{
- struct buffer_ctx *ctx;
-
- if (!context_stack)
- return 1;
-
- fclose(INFILE);
-
- /* 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;
- }
-
- POINT.line++;
-
- if (grecs_grecs__flex_debug)
- fprintf(stderr, "Resuming file `%s' at line %lu\n",
- POINT.file, (unsigned long) POINT.line);
-
- pp_line_stmt();
-
- return 0;
-}
-
-char *
-grecs_find_include_file(const char *name, int allow_cwd)
-{
- static char *cwd = ".";
- struct file_data fd;
-
- fd.name = name;
- fd.namelen = strlen(name);
- fd.buf = NULL;
- fd.buflen = 0;
- fd.found = 0;
-
- if (!grecs_usr_include_path)
- grecs_include_path_setup(NULL);
- if (allow_cwd) {
- grecs_list_append(grecs_usr_include_path, cwd);
- pp_list_find(grecs_usr_include_path, &fd);
- grecs_list_remove_tail(grecs_usr_include_path);
- } else
- pp_list_find(grecs_usr_include_path, &fd);
-
- if (!fd.found) {
- pp_list_find(grecs_std_include_path, &fd);
- if (!fd.found)
- 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;
-
- if (wordsplit(text, &ws, WRDSF_DEFFLAGS))
- grecs_error(&LOCUS, 0, _("Cannot parse include line"));
- else if (ws.ws_wordc != 2) {
- wordsplit_free(&ws);
- grecs_error(&LOCUS, 0, _("invalid include statement"));
- } else {
- size_t len;
- int allow_cwd;
-
- p = ws.ws_wordv[1];
- len = strlen (p);
-
- if (p[0] == '<' && p[len - 1] == '>') {
- allow_cwd = 0;
- p[len - 1] = 0;
- p++;
- } else
- allow_cwd = 1;
-
- 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"),
- 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
-grecs_preproc_init(const char *name)
-{
- return push_source(name, 0);
-}
-
-void
-grecs_preproc_done()
-{
- grecs_symtab_free(incl_sources);
- incl_sources = NULL;
-
- grecs_free(linebuf);
- linebuf = NULL;
- bufsize = 0;
-
- grecs_free(putback_buffer);
- putback_buffer = NULL;
- putback_size = putback_max = 0;
-
- free(linebufbase); /* Allocated via standard malloc/realloc */
- linebufbase = NULL;
- linebufsize = 0;
-}
-
-int
-grecs_preproc_run(const char *config_file, const char *extpp)
-{
- size_t i;
- char buffer[512];
-
- if (grecs_preproc_init(config_file))
- return 1;
- if (extpp) {
- FILE *outfile;
- char *setup_file;
- char *cmd = NULL;
-
- setup_file = grecs_find_include_file("pp-setup", 1);
- if (setup_file) {
- size_t size = 0;
- if (grecs_asprintf(&cmd, &size,
- "%s %s -", extpp, setup_file))
- grecs_alloc_die();
- grecs_free(setup_file);
- } else
- cmd = grecs_strdup(extpp);
- /*FIXME_DEBUG_F1 (2, "Running preprocessor: `%s'", cmd);*/
- outfile = popen(cmd, "w");
- if (!outfile) {
- grecs_error(NULL, errno,
- _("Unable to start external preprocessor `%s'"),
- cmd);
- grecs_free(cmd);
- return 1;
- }
-
- while ((i = grecs_preproc_fill_buffer(buffer, sizeof buffer)))
- fwrite(buffer, 1, i, outfile);
- pclose(outfile);
- grecs_free(cmd);
- } else {
- while ((i = grecs_preproc_fill_buffer(buffer, sizeof buffer)))
- fwrite(buffer, 1, i, stdout);
- }
- grecs_preproc_done();
- return 0;
-}
-
-FILE *
-grecs_preproc_extrn_start(const char *file_name, pid_t *ppid)
-{
- int pout[2];
- pid_t pid;
- int i;
- FILE *fp = NULL;
-
- /*FIXME_DEBUG_F1 (2, "Running preprocessor: `%s'", ppcmd);*/
-
- if (pipe(pout)) {
- grecs_error(NULL, errno, "pipe");
- return NULL;
- }
- switch (pid = fork()) {
- /* The child branch. */
- case 0:
- if (pout[1] != 1) {
- if (dup2(pout[1], 1) == -1) {
- grecs_error(NULL, errno, "dup2");
- exit(127);
- }
- }
-
- /* Close unneeded descripitors */
- for (i = getdtablesize(); i > 2; i--)
- close(i);
-
- if (!grecs_log_to_stderr) {
- int p[2];
- char *buf = NULL;
- size_t size = 0;
- FILE *fp;
-
- signal(SIGCHLD, SIG_DFL);
- if (pipe(p)) {
- grecs_error(NULL, errno, "pipe");
- exit(127);
- }
- switch (pid = fork()) {
- /* Grandchild */
- case 0:
- if (p[1] != 2 && dup2(p[1], 2) == -1) {
- grecs_error(NULL, errno, "dup2");
- exit(127);
- }
- close(p[0]);
-
- if (grecs_preproc_run(file_name,
- grecs_preprocessor))
- exit(127);
- exit(0);
-
- case -1:
- /* Fork failed */
- if (grecs_log_setup_hook)
- grecs_log_setup_hook();
- grecs_error(NULL, errno, _("Cannot run `%s'"),
- grecs_preprocessor);
- exit(127);
-
- default:
- /* Sub-master */
- close (p[1]);
- fp = fdopen(p[0], "r");
- if (grecs_log_setup_hook)
- grecs_log_setup_hook();
- while (grecs_getline(&buf, &size, fp) > 0)
- grecs_error(NULL, 0, "%s", buf);
- }
- } else {
- grecs_preproc_run(file_name, grecs_preprocessor);
- }
- exit (0);
-
- case -1:
- /* Fork failed */
- grecs_error(NULL, errno, _("Cannot run `%s'"),
- grecs_preprocessor);
- break;
-
- default:
- close(pout[1]);
- fp = fdopen(pout[0], "r");
- break;
- }
- *ppid = pid;
- return fp;
-}
-
-void
-grecs_preproc_extrn_shutdown(pid_t pid)
-{
- int status;
- waitpid(pid, &status, 0);
-}
-

Return to:

Send suggestions and report system problems to the System administrator.