/* 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
};