/* This file is part of Eclat.
Copyright (C) 2012-2023 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 bidimap {
struct submap {
char *name;
struct eclat_map *map;
int dir;
} submap[2];
};
static int
cb_submap(enum grecs_callback_command cmd,
grecs_locus_t *locus,
void *varptr,
grecs_value_t *value,
void *cb_data)
{
struct submap *submap = varptr;
char *q;
int dir;
if (cmd != grecs_callback_set_value) {
grecs_error(locus, 0, "Unexpected block statement");
return 1;
}
if (!value || value->type != GRECS_TYPE_STRING) {
grecs_error(locus, 0, "expected a string");
return 1;
}
dir = eclat_map_name_split(value->v.string, &submap->name, &q);
if (dir == -1) {
grecs_error(locus, 0, "bad qualifier: %s", q);
return 1;
}
submap->dir = dir;
return 0;
}
static struct grecs_keyword bidimap_kw[] = {
{ "type", "'bidi", "Set bi-directional map type", grecs_type_null },
{ "key", "", "key expression", grecs_type_null },
{ "direct-map", "arg", "map for direct lookups",
grecs_type_string, GRECS_DFLT,
NULL, offsetof(struct bidimap, submap[MAP_DIR]), cb_submap },
{ "reverse-map", "arg", "map for reverse lookups",
grecs_type_string, GRECS_DFLT,
NULL, offsetof(struct bidimap, submap[MAP_REV]), cb_submap },
{ NULL }
};
static void
bidimap_confhelp()
{
static struct grecs_keyword bidimap_top[] = {
{ "map", "name: string",
"Configuration for a generic bi-directional map",
grecs_type_section, GRECS_INAC, NULL, 0, NULL, NULL,
bidimap_kw },
{ NULL }
};
grecs_print_statement_array(bidimap_top, 1, 0, stdout);
}
static void
bidimap_free(int dbg, void *data)
{
struct bidimap *bidimap = data;
#if 0
/* FIXME: Uncomment this when reference
counters are implemented */
eclat_map_free(bidimap->submap[MAP_DIR].map);
eclat_map_free(bidimap->submap[MAP_REV].map);
#endif
free(bidimap);
}
static int
bidimap_config(int dbg, struct grecs_node *node, void *data)
{
struct bidimap *map, **return_map = data;
int i;
map = grecs_zalloc(sizeof(*map));
for (i = 0; bidimap_kw[i].ident; i++)
bidimap_kw[i].varptr = map;
if (grecs_tree_process(node->down, bidimap_kw)) {
bidimap_free(dbg, map);
return eclat_map_failure;
}
if (!map->submap[MAP_DIR].name && !map->submap[MAP_REV].name) {
grecs_error(&node->locus, 0, "no maps declared");
bidimap_free(dbg, map);
return eclat_map_failure;
}
*return_map = map;
return eclat_map_ok;
}
static int
bidimap_open(int dbg, void *data)
{
struct bidimap *bidimap = data;
struct eclat_map *map;
int i;
int rc;
for (i = 0; i < 2; i++) {
map = eclat_map_lookup(bidimap->submap[i].name);
if (!map)
continue;
if ((rc = eclat_map_open(map)) != eclat_map_ok)
return rc;
bidimap->submap[i].map = map;
}
return eclat_map_ok;
}
static int
bidimap_close(int dbg, void *data)
{
struct bidimap *map = data;
int i;
for (i = 0; i < 2; i++) {
if (map->submap[i].map)
eclat_map_close(map->submap[i].map);
}
return eclat_map_ok;
}
static int
bidimap_get(int dbg, int dir, void *data, const char *key, char **return_value)
{
struct bidimap *map = data;
if (!map->submap[dir].map)
return eclat_map_bad_dir;
return eclat_map_get(map->submap[dir].map, map->submap[dir].dir,
key, return_value);
}
struct eclat_map_drv eclat_map_drv_bidi = {
"bidi",
bidimap_config,
bidimap_open,
bidimap_close,
bidimap_get,
bidimap_free,
bidimap_confhelp
};