Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: dict_test.c,v 1.3 2026/05/09 18:49:22 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 
     33 static NORETURN usage(char *myname)
     34 {
     35     msg_fatal("usage: %s type:file read|write|create [flags...]", myname);
     36 }
     37 
     38 void    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     vstream_printf("owner=%s (uid=%ld)\n",
     92 		   dict->owner.status == DICT_OWNER_TRUSTED ? "trusted" :
     93 		   dict->owner.status == DICT_OWNER_UNTRUSTED ? "untrusted" :
     94 		   dict->owner.status == DICT_OWNER_UNKNOWN ? "unspecified" :
     95 		   "error", (long) dict->owner.uid);
     96     vstream_fflush(VSTREAM_OUT);
     97 
     98     while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
     99 	bufp = vstring_str(inbuf);
    100 	if (!isatty(0)) {
    101 	    vstream_printf("> %s\n", bufp);
    102 	    vstream_fflush(VSTREAM_OUT);
    103 	}
    104 	if (*bufp == '#')
    105 	    continue;
    106 	if ((cmd = mystrtok(&bufp, " ")) == 0) {
    107 	    vstream_printf("usage: %s\n", USAGE);
    108 	    vstream_fflush(VSTREAM_OUT);
    109 	    continue;
    110 	}
    111 	if (dict_changed_name())
    112 	    msg_warn("dictionary has changed");
    113 	key = *bufp ? vstring_str(unescape(keybuf, mystrtok(&bufp, " ="))) : 0;
    114 	value = mystrtok(&bufp, " =");
    115 	if (strcmp(cmd, "verbose") == 0 && !key) {
    116 	    msg_verbose++;
    117 	} else if (strcmp(cmd, "del") == 0 && key && !value) {
    118 	    if ((rc = dict_del(dict, key)) > 0)
    119 		vstream_printf("%s: not found\n", key);
    120 	    else if (rc < 0)
    121 		vstream_printf("%s: error\n", key);
    122 	    else
    123 		vstream_printf("%s: deleted\n", key);
    124 	} else if (strcmp(cmd, "get") == 0 && key && !value) {
    125 	    if ((value = dict_get(dict, key)) == 0) {
    126 		vstream_printf("%s: %s\n", key, dict->error ?
    127 			       "error" : "not found");
    128 	    } else {
    129 		vstream_printf("%s=%s\n", key, value);
    130 	    }
    131 	} else if (strcmp(cmd, "put") == 0 && key && value) {
    132 	    if (dict_put(dict, key, value) != 0)
    133 		vstream_printf("%s: %s\n", key, dict->error ?
    134 			       "error" : "not updated");
    135 	} else if (strcmp(cmd, "first") == 0 && !key && !value) {
    136 	    if (dict_seq(dict, DICT_SEQ_FUN_FIRST, &key, &value) == 0)
    137 		vstream_printf("%s=%s\n", key, value);
    138 	    else
    139 		vstream_printf("%s\n", dict->error ?
    140 			       "error" : "not found");
    141 	} else if (strcmp(cmd, "next") == 0 && !key && !value) {
    142 	    if (dict_seq(dict, DICT_SEQ_FUN_NEXT, &key, &value) == 0)
    143 		vstream_printf("%s=%s\n", key, value);
    144 	    else
    145 		vstream_printf("%s\n", dict->error ?
    146 			       "error" : "not found");
    147 	} else if (strcmp(cmd, "flags") == 0 && !key && !value) {
    148 	    vstream_printf("dict flags %s\n",
    149 			   dict_flags_str(dict->flags));
    150 	} else if (strcmp(cmd, "masks") == 0 && !key && !value) {
    151 	    vstream_printf("DICT_FLAG_PARANOID %s\n",
    152 			   dict_flags_str(DICT_FLAG_PARANOID));
    153 	} else {
    154 	    vstream_printf("usage: %s\n", USAGE);
    155 	}
    156 	vstream_fflush(VSTREAM_OUT);
    157     }
    158     vstring_free(keybuf);
    159     vstring_free(inbuf);
    160     dict_close(dict);
    161 }
    162