1/*	$NetBSD: dict_test.c,v 1.2 2017/02/14 01:16:49 christos Exp $	*/
2
3 /*
4  * Proof-of-concept test program. Create, update or read a database. Type
5  * '?' for a list of commands.
6  */
7
8/* System library. */
9
10#include <sys_defs.h>
11#include <stdlib.h>
12#include <fcntl.h>
13#include <unistd.h>
14#include <signal.h>
15#include <string.h>
16
17#ifdef STRCASECMP_IN_STRINGS_H
18#include <strings.h>
19#endif
20
21/* Utility library. */
22
23#include <msg.h>
24#include <stringops.h>
25#include <vstring.h>
26#include <vstream.h>
27#include <msg_vstream.h>
28#include <vstring_vstream.h>
29#include <dict.h>
30#include <dict_lmdb.h>
31#include <dict_db.h>
32
33static NORETURN usage(char *myname)
34{
35    msg_fatal("usage: %s type:file read|write|create [flags...]", myname);
36}
37
38void    dict_test(int argc, char **argv)
39{
40    VSTRING *keybuf = vstring_alloc(1);
41    VSTRING *inbuf = vstring_alloc(1);
42    DICT   *dict;
43    char   *dict_name;
44    int     open_flags;
45    char   *bufp;
46    char   *cmd;
47    const char *key;
48    const char *value;
49    int     ch;
50    int     dict_flags = 0;
51    int     n;
52    int     rc;
53
54#define USAGE	"verbose|del key|get key|put key=value|first|next|masks|flags"
55
56    signal(SIGPIPE, SIG_IGN);
57
58    msg_vstream_init(argv[0], VSTREAM_ERR);
59    while ((ch = GETOPT(argc, argv, "v")) > 0) {
60	switch (ch) {
61	default:
62	    usage(argv[0]);
63	case 'v':
64	    msg_verbose++;
65	    break;
66	}
67    }
68    optind = OPTIND;
69    if (argc - optind < 2)
70	usage(argv[0]);
71    if (strcasecmp(argv[optind + 1], "create") == 0)
72	open_flags = O_CREAT | O_RDWR | O_TRUNC;
73    else if (strcasecmp(argv[optind + 1], "write") == 0)
74	open_flags = O_RDWR;
75    else if (strcasecmp(argv[optind + 1], "read") == 0)
76	open_flags = O_RDONLY;
77    else
78	msg_fatal("unknown access mode: %s", argv[2]);
79    for (n = 2; argv[optind + n]; n++)
80	dict_flags |= dict_flags_mask(argv[optind + 2]);
81    if ((dict_flags & DICT_FLAG_OPEN_LOCK) == 0)
82	dict_flags |= DICT_FLAG_LOCK;
83    if ((dict_flags & (DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_IGNORE)) == 0)
84	dict_flags |= DICT_FLAG_DUP_REPLACE;
85    dict_flags |= DICT_FLAG_UTF8_REQUEST;
86    vstream_fflush(VSTREAM_OUT);
87    dict_name = argv[optind];
88    dict_allow_surrogate = 1;
89    util_utf8_enable = 1;
90    dict = dict_open(dict_name, open_flags, dict_flags);
91    dict_register(dict_name, dict);
92    vstream_printf("owner=%s (uid=%ld)\n",
93		   dict->owner.status == DICT_OWNER_TRUSTED ? "trusted" :
94		   dict->owner.status == DICT_OWNER_UNTRUSTED ? "untrusted" :
95		   dict->owner.status == DICT_OWNER_UNKNOWN ? "unspecified" :
96		   "error", (long) dict->owner.uid);
97    vstream_fflush(VSTREAM_OUT);
98
99    while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
100	bufp = vstring_str(inbuf);
101	if (!isatty(0)) {
102	    vstream_printf("> %s\n", bufp);
103	    vstream_fflush(VSTREAM_OUT);
104	}
105	if (*bufp == '#')
106	    continue;
107	if ((cmd = mystrtok(&bufp, " ")) == 0) {
108	    vstream_printf("usage: %s\n", USAGE);
109	    vstream_fflush(VSTREAM_OUT);
110	    continue;
111	}
112	if (dict_changed_name())
113	    msg_warn("dictionary has changed");
114	key = *bufp ? vstring_str(unescape(keybuf, mystrtok(&bufp, " ="))) : 0;
115	value = mystrtok(&bufp, " =");
116	if (strcmp(cmd, "verbose") == 0 && !key) {
117	    msg_verbose++;
118	} else if (strcmp(cmd, "del") == 0 && key && !value) {
119	    if ((rc = dict_del(dict, key)) > 0)
120		vstream_printf("%s: not found\n", key);
121	    else if (rc < 0)
122		vstream_printf("%s: error\n", key);
123	    else
124		vstream_printf("%s: deleted\n", key);
125	} else if (strcmp(cmd, "get") == 0 && key && !value) {
126	    if ((value = dict_get(dict, key)) == 0) {
127		vstream_printf("%s: %s\n", key, dict->error ?
128			       "error" : "not found");
129	    } else {
130		vstream_printf("%s=%s\n", key, value);
131	    }
132	} else if (strcmp(cmd, "put") == 0 && key && value) {
133	    if (dict_put(dict, key, value) != 0)
134		vstream_printf("%s: %s\n", key, dict->error ?
135			       "error" : "not updated");
136	} else if (strcmp(cmd, "first") == 0 && !key && !value) {
137	    if (dict_seq(dict, DICT_SEQ_FUN_FIRST, &key, &value) == 0)
138		vstream_printf("%s=%s\n", key, value);
139	    else
140		vstream_printf("%s\n", dict->error ?
141			       "error" : "not found");
142	} else if (strcmp(cmd, "next") == 0 && !key && !value) {
143	    if (dict_seq(dict, DICT_SEQ_FUN_NEXT, &key, &value) == 0)
144		vstream_printf("%s=%s\n", key, value);
145	    else
146		vstream_printf("%s\n", dict->error ?
147			       "error" : "not found");
148	} else if (strcmp(cmd, "flags") == 0 && !key && !value) {
149	    vstream_printf("dict flags %s\n",
150			   dict_flags_str(dict->flags));
151	} else if (strcmp(cmd, "masks") == 0 && !key && !value) {
152	    vstream_printf("DICT_FLAG_IMPL_MASK %s\n",
153			   dict_flags_str(DICT_FLAG_IMPL_MASK));
154	    vstream_printf("DICT_FLAG_PARANOID %s\n",
155			   dict_flags_str(DICT_FLAG_PARANOID));
156	    vstream_printf("DICT_FLAG_RQST_MASK %s\n",
157			   dict_flags_str(DICT_FLAG_RQST_MASK));
158	    vstream_printf("DICT_FLAG_INST_MASK %s\n",
159			   dict_flags_str(DICT_FLAG_INST_MASK));
160	} else {
161	    vstream_printf("usage: %s\n", USAGE);
162	}
163	vstream_fflush(VSTREAM_OUT);
164    }
165    vstring_free(keybuf);
166    vstring_free(inbuf);
167    dict_close(dict);
168}
169