/* This file is part of Eclat. Copyright (C) 2012, 2013 Sergey Poznyakoff. Eclat 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, or (at your option) any later version. Eclat 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 Eclat. If not, see . */ #include "libeclat.h" #include struct filemap { char *name; FILE *fp; struct grecs_locus locus; }; static struct grecs_keyword filemap_kw[] = { { "type", "'file", "Set map type", grecs_type_null }, { "key", "", "key expression", grecs_type_null }, { "file", NULL, "File name", grecs_type_string, GRECS_DFLT, NULL, offsetof(struct filemap, name) }, { NULL } }; static void filemap_confhelp() { static struct grecs_keyword filemap_top[] = { { "map", "name: string", "Configuration for a file map", grecs_type_section, GRECS_INAC, NULL, 0, NULL, NULL, filemap_kw }, { NULL } }; grecs_print_statement_array(filemap_top, 1, 0, stdout); } static void filemap_free(int dbg, void *data) { struct filemap *filemap = data; free(filemap->name); free(filemap); } static int filemap_config(int dbg, struct grecs_node *node, void *data) { struct filemap *filemap, **return_filemap = data; int i; struct grecs_node *p; filemap = grecs_malloc(sizeof(*filemap)); for (i = 0; filemap_kw[i].ident; i++) filemap_kw[i].varptr = filemap; if (grecs_tree_process(node->down, filemap_kw)) { filemap_free(dbg, filemap); return eclat_map_failure; } if (!filemap->name) { grecs_error(&node->locus, 0, "file not specified"); filemap_free(dbg, filemap); return eclat_map_failure; } if (eclat_get_string_node(node, "file", 0, &p)) abort(); /* shouldn't happen */ filemap->locus = p->locus; *return_filemap = filemap; return eclat_map_ok; } static int filemap_open(int dbg, void *data) { struct filemap *filemap = data; filemap->fp = fopen(filemap->name, "r"); if (!filemap->fp) { grecs_error(&filemap->locus, errno, "cannot open file"); return eclat_map_failure; } return eclat_map_ok; } static int filemap_close(int dbg, void *data) { struct filemap *filemap = data; fclose(filemap->fp); return eclat_map_ok; } static void skipline(FILE *fp) { int c; while ((c = getc(fp)) != EOF && c != '\n') ; } static int filemap_get_0(int dbg, void *data, const char *key, char **return_value) { struct filemap *filemap = data; FILE *fp = filemap->fp; int line = 0; int rc, c; const char *p; rewind(fp); while ((c = getc(fp)) != EOF) { line++; while (c != EOF && (c == ' ' || c == '\t')) c = getc(fp); if (c == '\n') continue; if (c == '#') { skipline(fp); continue; } if (c == EOF) break; for (p = key; c != EOF && c != ':' && *p == c; p++) c = getc(fp); if (c == EOF) break; if (c == '\n') continue; if (c == ':') break; skipline(fp); } if (c == ':') { struct grecs_txtacc *acc; debug(dbg, 2, ("%s:%d: found key", filemap->name, line)); acc = grecs_txtacc_create(); while ((c = getc(fp)) != EOF && c != '\n') grecs_txtacc_grow_char(acc, c); grecs_txtacc_grow_char(acc, 0); *return_value = grecs_txtacc_finish(acc, 1); grecs_txtacc_free(acc); rc = eclat_map_ok; } else rc = eclat_map_not_found; return rc; } static int filemap_get_1(int dbg, void *data, const char *key, char **return_value) { struct filemap *filemap = data; FILE *fp = filemap->fp; int line = 0; int rc, c; const char *p; size_t len; rewind(fp); while ((c = getc(fp)) != EOF) { line++; while (c != EOF && (c == ' ' || c == '\t')) c = getc(fp); if (c == '\n') continue; if (c == '#') { skipline(fp); continue; } if (c == EOF) break; for (len = 0; c != EOF && c != ':'; len++) c = getc(fp); if (c == EOF) break; if (c == '\n') continue; if (c == ':') { for (p = key, c = getc(fp), len++; c != EOF && c != '\n' && *p == c; p++, len++, c = getc(fp)); if (c == EOF || c == '\n') break; skipline(fp); } } if (c == '\n') { struct grecs_txtacc *acc; debug(dbg, 2, ("%s:%d: found key", filemap->name, line)); fseek(fp, - (len + 1), SEEK_CUR); acc = grecs_txtacc_create(); while ((c = getc(fp)) != EOF && c != ':') grecs_txtacc_grow_char(acc, c); grecs_txtacc_grow_char(acc, 0); *return_value = grecs_txtacc_finish(acc, 1); grecs_txtacc_free(acc); rc = eclat_map_ok; } else rc = eclat_map_not_found; return rc; } static int filemap_get(int dbg, int dir, void *data, const char *key, char **return_value) { return (dir ? filemap_get_1 : filemap_get_0)(dbg, data, key, return_value); } struct eclat_map_drv eclat_map_drv_file = { "file", filemap_config, filemap_open, filemap_close, filemap_get, filemap_free, filemap_confhelp };