#include <sys_defs.h>
#include <string.h>
#include <stdlib.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
#include <argv.h>
#include <mymalloc.h>
#include <msg.h>
#include <dict.h>
#include <dict_cdb.h>
#include <dict_env.h>
#include <dict_unix.h>
#include <dict_tcp.h>
#include <dict_sdbm.h>
#include <dict_dbm.h>
#include <dict_db.h>
#include <dict_nis.h>
#include <dict_nisplus.h>
#include <dict_ni.h>
#include <dict_pcre.h>
#include <dict_regexp.h>
#include <dict_static.h>
#include <dict_cidr.h>
#include <dict_ht.h>
#include <dict_thash.h>
#include <stringops.h>
#include <split_at.h>
#include <htable.h>
typedef struct {
char *type;
struct DICT *(*open) (const char *, int, int);
} DICT_OPEN_INFO;
static const DICT_OPEN_INFO dict_open_info[] = {
#ifdef HAS_CDB
DICT_TYPE_CDB, dict_cdb_open,
#endif
DICT_TYPE_ENVIRON, dict_env_open,
DICT_TYPE_HT, dict_ht_open,
DICT_TYPE_UNIX, dict_unix_open,
DICT_TYPE_TCP, dict_tcp_open,
#ifdef HAS_SDBM
DICT_TYPE_SDBM, dict_sdbm_open,
#endif
#ifdef HAS_DBM
DICT_TYPE_DBM, dict_dbm_open,
#endif
#ifdef HAS_DB
DICT_TYPE_HASH, dict_hash_open,
DICT_TYPE_BTREE, dict_btree_open,
#endif
#ifdef HAS_NIS
DICT_TYPE_NIS, dict_nis_open,
#endif
#ifdef HAS_NISPLUS
DICT_TYPE_NISPLUS, dict_nisplus_open,
#endif
#ifdef HAS_NETINFO
DICT_TYPE_NETINFO, dict_ni_open,
#endif
#ifdef HAS_PCRE
DICT_TYPE_PCRE, dict_pcre_open,
#endif
#ifdef HAS_POSIX_REGEXP
DICT_TYPE_REGEXP, dict_regexp_open,
#endif
DICT_TYPE_STATIC, dict_static_open,
DICT_TYPE_CIDR, dict_cidr_open,
DICT_TYPE_THASH, dict_thash_open,
0,
};
static HTABLE *dict_open_hash;
static void dict_open_init(void)
{
const char *myname = "dict_open_init";
const DICT_OPEN_INFO *dp;
if (dict_open_hash != 0)
msg_panic("%s: multiple initialization", myname);
dict_open_hash = htable_create(10);
for (dp = dict_open_info; dp->type; dp++)
htable_enter(dict_open_hash, dp->type, (char *) dp);
}
DICT *dict_open(const char *dict_spec, int open_flags, int dict_flags)
{
char *saved_dict_spec = mystrdup(dict_spec);
char *dict_name;
DICT *dict;
if ((dict_name = split_at(saved_dict_spec, ':')) == 0)
msg_fatal("open dictionary: expecting \"type:name\" form instead of \"%s\"",
dict_spec);
dict = dict_open3(saved_dict_spec, dict_name, open_flags, dict_flags);
myfree(saved_dict_spec);
return (dict);
}
DICT *dict_open3(const char *dict_type, const char *dict_name,
int open_flags, int dict_flags)
{
const char *myname = "dict_open";
DICT_OPEN_INFO *dp;
DICT *dict;
if (*dict_type == 0 || *dict_name == 0)
msg_fatal("open dictionary: expecting \"type:name\" form instead of \"%s:%s\"",
dict_type, dict_name);
if (dict_open_hash == 0)
dict_open_init();
if ((dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, dict_type)) == 0)
msg_fatal("unsupported dictionary type: %s", dict_type);
if ((dict = dp->open(dict_name, open_flags, dict_flags)) == 0)
msg_fatal("opening %s:%s %m", dict_type, dict_name);
if (msg_verbose)
msg_info("%s: %s:%s", myname, dict_type, dict_name);
return (dict);
}
void dict_open_register(const char *type,
DICT *(*open) (const char *, int, int))
{
const char *myname = "dict_open_register";
DICT_OPEN_INFO *dp;
if (dict_open_hash == 0)
dict_open_init();
if (htable_find(dict_open_hash, type))
msg_panic("%s: dictionary type exists: %s", myname, type);
dp = (DICT_OPEN_INFO *) mymalloc(sizeof(*dp));
dp->type = mystrdup(type);
dp->open = open;
htable_enter(dict_open_hash, dp->type, (char *) dp);
}
static int dict_sort_alpha_cpp(const void *a, const void *b)
{
return (strcmp(((char **) a)[0], ((char **) b)[0]));
}
ARGV *dict_mapnames()
{
HTABLE_INFO **ht_info;
HTABLE_INFO **ht;
DICT_OPEN_INFO *dp;
ARGV *mapnames;
if (dict_open_hash == 0)
dict_open_init();
mapnames = argv_alloc(dict_open_hash->used + 1);
for (ht_info = ht = htable_list(dict_open_hash); *ht; ht++) {
dp = (DICT_OPEN_INFO *) ht[0]->value;
argv_add(mapnames, dp->type, ARGV_END);
}
qsort((void *) mapnames->argv, mapnames->argc, sizeof(mapnames->argv[0]),
dict_sort_alpha_cpp);
myfree((char *) ht_info);
argv_terminate(mapnames);
return mapnames;
}
#ifdef TEST
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include "vstring.h"
#include "vstream.h"
#include "msg_vstream.h"
#include "vstring_vstream.h"
static NORETURN usage(char *myname)
{
msg_fatal("usage: %s type:file read|write|create [fold] [sync]", myname);
}
int main(int argc, char **argv)
{
VSTRING *keybuf = vstring_alloc(1);
VSTRING *inbuf = vstring_alloc(1);
DICT *dict;
char *dict_name;
int open_flags;
char *bufp;
char *cmd;
const char *key;
const char *value;
int ch;
int dict_flags = DICT_FLAG_LOCK | DICT_FLAG_DUP_REPLACE;
int n;
signal(SIGPIPE, SIG_IGN);
msg_vstream_init(argv[0], VSTREAM_ERR);
while ((ch = GETOPT(argc, argv, "v")) > 0) {
switch (ch) {
default:
usage(argv[0]);
case 'v':
msg_verbose++;
break;
}
}
optind = OPTIND;
if (argc - optind < 2)
usage(argv[0]);
if (strcasecmp(argv[optind + 1], "create") == 0)
open_flags = O_CREAT | O_RDWR | O_TRUNC;
else if (strcasecmp(argv[optind + 1], "write") == 0)
open_flags = O_RDWR;
else if (strcasecmp(argv[optind + 1], "read") == 0)
open_flags = O_RDONLY;
else
msg_fatal("unknown access mode: %s", argv[2]);
for (n = 2; argv[optind + n]; n++) {
if (strcasecmp(argv[optind + 2], "fold") == 0)
dict_flags |= DICT_FLAG_FOLD_ANY;
else if (strcasecmp(argv[optind + 2], "sync") == 0)
dict_flags |= DICT_FLAG_SYNC_UPDATE;
else
usage(argv[0]);
}
dict_name = argv[optind];
dict = dict_open(dict_name, open_flags, dict_flags);
dict_register(dict_name, dict);
while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
bufp = vstring_str(inbuf);
if (!isatty(0)) {
vstream_printf("> %s\n", bufp);
vstream_fflush(VSTREAM_OUT);
}
if (*bufp == '#')
continue;
if ((cmd = mystrtok(&bufp, " ")) == 0) {
vstream_printf("usage: del key|get key|put key=value|first|next\n");
vstream_fflush(VSTREAM_OUT);
continue;
}
if (dict_changed_name())
msg_warn("dictionary has changed");
key = *bufp ? vstring_str(unescape(keybuf, mystrtok(&bufp, " ="))) : 0;
value = mystrtok(&bufp, " =");
if (strcmp(cmd, "del") == 0 && key && !value) {
if (dict_del(dict, key))
vstream_printf("%s: not found\n", key);
else
vstream_printf("%s: deleted\n", key);
} else if (strcmp(cmd, "get") == 0 && key && !value) {
if ((value = dict_get(dict, key)) == 0) {
vstream_printf("%s: %s\n", key,
dict_errno == DICT_ERR_RETRY ?
"soft error" : "not found");
} else {
vstream_printf("%s=%s\n", key, value);
}
} else if (strcmp(cmd, "put") == 0 && key && value) {
dict_put(dict, key, value);
vstream_printf("%s=%s\n", key, value);
} else if (strcmp(cmd, "first") == 0 && !key && !value) {
if (dict_seq(dict, DICT_SEQ_FUN_FIRST, &key, &value) == 0)
vstream_printf("%s=%s\n", key, value);
else
vstream_printf("%s\n",
dict_errno == DICT_ERR_RETRY ?
"soft error" : "not found");
} else if (strcmp(cmd, "next") == 0 && !key && !value) {
if (dict_seq(dict, DICT_SEQ_FUN_NEXT, &key, &value) == 0)
vstream_printf("%s=%s\n", key, value);
else
vstream_printf("%s\n",
dict_errno == DICT_ERR_RETRY ?
"soft error" : "not found");
} else {
vstream_printf("usage: del key|get key|put key=value|first|next\n");
}
vstream_fflush(VSTREAM_OUT);
}
vstring_free(keybuf);
vstring_free(inbuf);
dict_close(dict);
return (0);
}
#endif