/* This file is part of Eclat. Copyright (C) 2012-2018 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 };