148
148
/* or if the result is to survive multiple table lookups.
150
150
/* dict_put() stores the specified key and value into the named
151
/* dictionary. A zero (DICT_STAT_SUCCESS) result means the
153
/* dict_del() removes a dictionary entry, and returns zero
154
/* in case of success.
154
/* dict_del() removes a dictionary entry, and returns
155
/* DICT_STAT_SUCCESS in case of success.
156
157
/* dict_seq() iterates over all members in the named dictionary.
157
158
/* func is define DICT_SEQ_FUN_FIRST (select first member) or
158
/* DICT_SEQ_FUN_NEXT (select next member). A zero result means
159
/* that an entry was found.
159
/* DICT_SEQ_FUN_NEXT (select next member). A zero (DICT_STAT_SUCCESS)
160
/* result means that an entry was found.
161
162
/* dict_close() closes the specified dictionary and cleans up the
162
163
/* associated data structures.
169
170
/* Fatal error: open error, unsupported dictionary type, attempt to
170
171
/* update non-writable dictionary.
173
/* The lookup routine returns non-null when the request is
174
/* satisfied. The update, delete and sequence routines return
175
/* zero (DICT_STAT_SUCCESS) when the request is satisfied.
176
/* The dict->errno value is non-zero only when the last operation
177
/* was not satisfied due to a dictionary access error. This
178
/* can have the following values:
179
/* .IP DICT_ERR_NONE(zero)
180
/* There was no dictionary access error. For example, the
181
/* request was satisfied, the requested information did not
182
/* exist in the dictionary, or the information already existed
183
/* when it should not exist (collision).
184
/* .IP DICT_ERR_RETRY(<0)
185
/* The dictionary was temporarily unavailable. This can happen
186
/* with network-based services.
187
/* .IP DICT_ERR_CONFIG(<0)
188
/* The dictionary was unavailable due to a configuration error.
190
/* Generally, a program is expected to test the function result
191
/* value for "success" first. If the operation was not successful,
192
/* a program is expected to test for a non-zero dict->error
193
/* status to distinguish between a data notfound/collision
194
/* condition or a dictionary access error.
313
339
if (dict_open_hash == 0)
314
340
dict_open_init();
315
341
if ((dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, dict_type)) == 0)
316
msg_fatal("unsupported dictionary type: %s", dict_type);
342
return (dict_surrogate(dict_type, dict_name, open_flags, dict_flags,
343
"unsupported dictionary type: %s", dict_type));
317
344
if ((dict = dp->open(dict_name, open_flags, dict_flags)) == 0)
318
msg_fatal("opening %s:%s %m", dict_type, dict_name);
345
return (dict_surrogate(dict_type, dict_name, open_flags, dict_flags,
346
"cannot open %s:%s: %m", dict_type, dict_name));
320
348
msg_info("%s: %s:%s", myname, dict_type, dict_name);
321
349
/* XXX the choice between wait-for-lock or no-wait is hard-coded. */
385
* Proof-of-concept test program. Create, update or read a database. When
386
* the input is a name=value pair, the database is updated, otherwise the
387
* program assumes that the input specifies a lookup key and prints the
388
* corresponding value.
413
* Proof-of-concept test program.
391
/* System library. */
398
/* Utility library. */
402
#include "msg_vstream.h"
403
#include "vstring_vstream.h"
405
static NORETURN usage(char *myname)
407
msg_fatal("usage: %s type:file read|write|create [fold] [sync]", myname);
410
415
int main(int argc, char **argv)
412
VSTRING *keybuf = vstring_alloc(1);
413
VSTRING *inbuf = vstring_alloc(1);
422
int dict_flags = DICT_FLAG_LOCK | DICT_FLAG_DUP_REPLACE;
425
signal(SIGPIPE, SIG_IGN);
427
msg_vstream_init(argv[0], VSTREAM_ERR);
428
while ((ch = GETOPT(argc, argv, "v")) > 0) {
438
if (argc - optind < 2)
440
if (strcasecmp(argv[optind + 1], "create") == 0)
441
open_flags = O_CREAT | O_RDWR | O_TRUNC;
442
else if (strcasecmp(argv[optind + 1], "write") == 0)
444
else if (strcasecmp(argv[optind + 1], "read") == 0)
445
open_flags = O_RDONLY;
447
msg_fatal("unknown access mode: %s", argv[2]);
448
for (n = 2; argv[optind + n]; n++) {
449
if (strcasecmp(argv[optind + 2], "fold") == 0)
450
dict_flags |= DICT_FLAG_FOLD_ANY;
451
else if (strcasecmp(argv[optind + 2], "sync") == 0)
452
dict_flags |= DICT_FLAG_SYNC_UPDATE;
456
dict_name = argv[optind];
457
dict = dict_open(dict_name, open_flags, dict_flags);
458
dict_register(dict_name, dict);
459
while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
460
bufp = vstring_str(inbuf);
462
vstream_printf("> %s\n", bufp);
463
vstream_fflush(VSTREAM_OUT);
467
if ((cmd = mystrtok(&bufp, " ")) == 0) {
468
vstream_printf("usage: del key|get key|put key=value|first|next\n");
469
vstream_fflush(VSTREAM_OUT);
472
if (dict_changed_name())
473
msg_warn("dictionary has changed");
474
key = *bufp ? vstring_str(unescape(keybuf, mystrtok(&bufp, " ="))) : 0;
475
value = mystrtok(&bufp, " =");
476
if (strcmp(cmd, "del") == 0 && key && !value) {
477
if (dict_del(dict, key))
478
vstream_printf("%s: not found\n", key);
480
vstream_printf("%s: deleted\n", key);
481
} else if (strcmp(cmd, "get") == 0 && key && !value) {
482
if ((value = dict_get(dict, key)) == 0) {
483
vstream_printf("%s: %s\n", key,
484
dict_errno == DICT_ERR_RETRY ?
485
"soft error" : "not found");
487
vstream_printf("%s=%s\n", key, value);
489
} else if (strcmp(cmd, "put") == 0 && key && value) {
490
dict_put(dict, key, value);
491
vstream_printf("%s=%s\n", key, value);
492
} else if (strcmp(cmd, "first") == 0 && !key && !value) {
493
if (dict_seq(dict, DICT_SEQ_FUN_FIRST, &key, &value) == 0)
494
vstream_printf("%s=%s\n", key, value);
496
vstream_printf("%s\n",
497
dict_errno == DICT_ERR_RETRY ?
498
"soft error" : "not found");
499
} else if (strcmp(cmd, "next") == 0 && !key && !value) {
500
if (dict_seq(dict, DICT_SEQ_FUN_NEXT, &key, &value) == 0)
501
vstream_printf("%s=%s\n", key, value);
503
vstream_printf("%s\n",
504
dict_errno == DICT_ERR_RETRY ?
505
"soft error" : "not found");
507
vstream_printf("usage: del key|get key|put key=value|first|next\n");
509
vstream_fflush(VSTREAM_OUT);
511
vstring_free(keybuf);
417
dict_test(argc, argv);