libc/db: Sync with FreeBSD
[dragonfly.git] / lib / libc / db / test / btree.tests / main.c
1 /*-
2  * Copyright (c) 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Mike Olson.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * @(#)main.c   8.1 (Berkeley) 6/4/93
33  * $FreeBSD: head/lib/libc/db/test/btree.tests/main.c 176380 2008-02-18 03:19:25Z kevlo $
34  */
35
36 #include <sys/param.h>
37 #include <fcntl.h>
38 #include <db.h>
39 #include <errno.h>
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include "btree.h"
45
46 typedef struct cmd_table {
47         char *cmd;
48         int nargs;
49         int rconv;
50         void (*func)(DB *, char **);
51         char *usage, *descrip;
52 } cmd_table;
53
54 int stopstop;
55 DB *globaldb;
56
57 void append(DB *, char **);
58 void bstat(DB *, char **);
59 void cursor(DB *, char **);
60 void delcur(DB *, char **);
61 void delete(DB *, char **);
62 void dump(DB *, char **);
63 void first(DB *, char **);
64 void get(DB *, char **);
65 void help(DB *, char **);
66 void iafter(DB *, char **);
67 void ibefore(DB *, char **);
68 void icursor(DB *, char **);
69 void insert(DB *, char **);
70 void keydata(DBT *, DBT *);
71 void last(DB *, char **);
72 void list(DB *, char **);
73 void load(DB *, char **);
74 void mstat(DB *, char **);
75 void next(DB *, char **);
76 int  parse(char *, char **, int);
77 void previous(DB *, char **);
78 void show(DB *, char **);
79 void usage(void);
80 void user(DB *);
81
82 cmd_table commands[] = {
83         "?",    0, 0, help, "help", NULL,
84         "a",    2, 1, append, "append key def", "append key with data def",
85         "b",    0, 0, bstat, "bstat", "stat btree",
86         "c",    1, 1, cursor,  "cursor word", "move cursor to word",
87         "delc", 0, 0, delcur, "delcur", "delete key the cursor references",
88         "dele", 1, 1, delete, "delete word", "delete word",
89         "d",    0, 0, dump, "dump", "dump database",
90         "f",    0, 0, first, "first", "move cursor to first record",
91         "g",    1, 1, get, "get key", "locate key",
92         "h",    0, 0, help, "help", "print command summary",
93         "ia",   2, 1, iafter, "iafter key data", "insert data after key",
94         "ib",   2, 1, ibefore, "ibefore key data", "insert data before key",
95         "ic",   2, 1, icursor, "icursor key data", "replace cursor",
96         "in",   2, 1, insert, "insert key def", "insert key with data def",
97         "la",   0, 0, last, "last", "move cursor to last record",
98         "li",   1, 1, list, "list file", "list to a file",
99         "loa",  1, 0, load, "load file", NULL,
100         "loc",  1, 1, get, "get key", NULL,
101         "m",    0, 0, mstat, "mstat", "stat memory pool",
102         "n",    0, 0, next, "next", "move cursor forward one record",
103         "p",    0, 0, previous, "previous", "move cursor back one record",
104         "q",    0, 0, NULL, "quit", "quit",
105         "sh",   1, 0, show, "show page", "dump a page",
106         { NULL },
107 };
108
109 int recno;                                      /* use record numbers */
110 char *dict = "words";                           /* default dictionary */
111 char *progname;
112
113 int
114 main(int argc, char **argv)
115 {
116         int c;
117         DB *db;
118         BTREEINFO b;
119
120         progname = *argv;
121
122         b.flags = 0;
123         b.cachesize = 0;
124         b.maxkeypage = 0;
125         b.minkeypage = 0;
126         b.psize = 0;
127         b.compare = NULL;
128         b.prefix = NULL;
129         b.lorder = 0;
130
131         while ((c = getopt(argc, argv, "bc:di:lp:ru")) != -1) {
132                 switch (c) {
133                 case 'b':
134                         b.lorder = BIG_ENDIAN;
135                         break;
136                 case 'c':
137                         b.cachesize = atoi(optarg);
138                         break;
139                 case 'd':
140                         b.flags |= R_DUP;
141                         break;
142                 case 'i':
143                         dict = optarg;
144                         break;
145                 case 'l':
146                         b.lorder = LITTLE_ENDIAN;
147                         break;
148                 case 'p':
149                         b.psize = atoi(optarg);
150                         break;
151                 case 'r':
152                         recno = 1;
153                         break;
154                 case 'u':
155                         b.flags = 0;
156                         break;
157                 default:
158                         usage();
159                 }
160         }
161         argc -= optind;
162         argv += optind;
163
164         if (recno)
165                 db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR,
166                     0, DB_RECNO, NULL);
167         else
168                 db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR,
169                     0600, DB_BTREE, &b);
170
171         if (db == NULL) {
172                 fprintf(stderr, "dbopen: %s\n", strerror(errno));
173                 exit(1);
174         }
175         globaldb = db;
176         user(db);
177         exit(0);
178         /* NOTREACHED */
179 }
180
181 void
182 user(DB *db)
183 {
184         FILE *ifp;
185         int argc, i, last;
186         char *lbuf, *argv[4], buf[512];
187
188         if ((ifp = fopen("/dev/tty", "r")) == NULL) {
189                 fprintf(stderr,
190                     "/dev/tty: %s\n", strerror(errno));
191                 exit(1);
192         }
193         for (last = 0;;) {
194                 printf("> ");
195                 fflush(stdout);
196                 if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL)
197                         break;
198                 if (lbuf[0] == '\n') {
199                         i = last;
200                         goto uselast;
201                 }
202                 lbuf[strlen(lbuf) - 1] = '\0';
203
204                 if (lbuf[0] == 'q')
205                         break;
206
207                 argc = parse(lbuf, &argv[0], 3);
208                 if (argc == 0)
209                         continue;
210
211                 for (i = 0; commands[i].cmd != NULL; i++)
212                         if (strncmp(commands[i].cmd, argv[0],
213                             strlen(commands[i].cmd)) == 0)
214                                 break;
215
216                 if (commands[i].cmd == NULL) {
217                         fprintf(stderr,
218                             "%s: command unknown ('help' for help)\n", lbuf);
219                         continue;
220                 }
221
222                 if (commands[i].nargs != argc - 1) {
223                         fprintf(stderr, "usage: %s\n", commands[i].usage);
224                         continue;
225                 }
226
227                 if (recno && commands[i].rconv) {
228                         static recno_t nlong;
229                         nlong = atoi(argv[1]);
230                         argv[1] = (char *)&nlong;
231                 }
232 uselast:        last = i;
233                 (*commands[i].func)(db, argv);
234         }
235         if ((db->sync)(db) == RET_ERROR)
236                 perror("dbsync");
237         else if ((db->close)(db) == RET_ERROR)
238                 perror("dbclose");
239 }
240
241 int
242 parse(char *lbuf, char **argv, int maxargc)
243 {
244         int argc = 0;
245         char *c;
246
247         c = lbuf;
248         while (isspace(*c))
249                 c++;
250         while (*c != '\0' && argc < maxargc) {
251                 *argv++ = c;
252                 argc++;
253                 while (!isspace(*c) && *c != '\0') {
254                         c++;
255                 }
256                 while (isspace(*c))
257                         *c++ = '\0';
258         }
259         return (argc);
260 }
261
262 void
263 append(DB *db, char **argv)
264 {
265         DBT key, data;
266         int status;
267
268         if (!recno) {
269                 fprintf(stderr,
270                     "append only available for recno db's.\n");
271                 return;
272         }
273         key.data = argv[1];
274         key.size = sizeof(recno_t);
275         data.data = argv[2];
276         data.size = strlen(data.data);
277         status = (db->put)(db, &key, &data, R_APPEND);
278         switch (status) {
279         case RET_ERROR:
280                 perror("append/put");
281                 break;
282         case RET_SPECIAL:
283                 printf("%s (duplicate key)\n", argv[1]);
284                 break;
285         case RET_SUCCESS:
286                 break;
287         }
288 }
289
290 void
291 cursor(DB *db, char **argv)
292 {
293         DBT data, key;
294         int status;
295
296         key.data = argv[1];
297         if (recno)
298                 key.size = sizeof(recno_t);
299         else
300                 key.size = strlen(argv[1]) + 1;
301         status = (*db->seq)(db, &key, &data, R_CURSOR);
302         switch (status) {
303         case RET_ERROR:
304                 perror("cursor/seq");
305                 break;
306         case RET_SPECIAL:
307                 printf("key not found\n");
308                 break;
309         case RET_SUCCESS:
310                 keydata(&key, &data);
311                 break;
312         }
313 }
314
315 void
316 delcur(DB *db, char **argv)
317 {
318         int status;
319
320         status = (*db->del)(db, NULL, R_CURSOR);
321
322         if (status == RET_ERROR)
323                 perror("delcur/del");
324 }
325
326 void
327 delete(DB *db, char **argv)
328 {
329         DBT key;
330         int status;
331
332         key.data = argv[1];
333         if (recno)
334                 key.size = sizeof(recno_t);
335         else
336                 key.size = strlen(argv[1]) + 1;
337
338         status = (*db->del)(db, &key, 0);
339         switch (status) {
340         case RET_ERROR:
341                 perror("delete/del");
342                 break;
343         case RET_SPECIAL:
344                 printf("key not found\n");
345                 break;
346         case RET_SUCCESS:
347                 break;
348         }
349 }
350
351 void
352 dump(DB *db, char **argv)
353 {
354         __bt_dump(db);
355 }
356
357 void
358 first(DB *db, char **argv)
359 {
360         DBT data, key;
361         int status;
362
363         status = (*db->seq)(db, &key, &data, R_FIRST);
364
365         switch (status) {
366         case RET_ERROR:
367                 perror("first/seq");
368                 break;
369         case RET_SPECIAL:
370                 printf("no more keys\n");
371                 break;
372         case RET_SUCCESS:
373                 keydata(&key, &data);
374                 break;
375         }
376 }
377
378 void
379 get(DB *db, char **argv)
380 {
381         DBT data, key;
382         int status;
383
384         key.data = argv[1];
385         if (recno)
386                 key.size = sizeof(recno_t);
387         else
388                 key.size = strlen(argv[1]) + 1;
389
390         status = (*db->get)(db, &key, &data, 0);
391
392         switch (status) {
393         case RET_ERROR:
394                 perror("get/get");
395                 break;
396         case RET_SPECIAL:
397                 printf("key not found\n");
398                 break;
399         case RET_SUCCESS:
400                 keydata(&key, &data);
401                 break;
402         }
403 }
404
405 void
406 help(DB *db, char **argv)
407 {
408         int i;
409
410         for (i = 0; commands[i].cmd; i++)
411                 if (commands[i].descrip)
412                         printf("%s: %s\n",
413                             commands[i].usage, commands[i].descrip);
414 }
415
416 void
417 iafter(DB *db, char **argv)
418 {
419         DBT key, data;
420         int status;
421
422         if (!recno) {
423                 fprintf(stderr,
424                     "iafter only available for recno db's.\n");
425                 return;
426         }
427         key.data = argv[1];
428         key.size = sizeof(recno_t);
429         data.data = argv[2];
430         data.size = strlen(data.data);
431         status = (db->put)(db, &key, &data, R_IAFTER);
432         switch (status) {
433         case RET_ERROR:
434                 perror("iafter/put");
435                 break;
436         case RET_SPECIAL:
437                 printf("%s (duplicate key)\n", argv[1]);
438                 break;
439         case RET_SUCCESS:
440                 break;
441         }
442 }
443
444 void
445 ibefore(DB *db, char **argv)
446 {
447         DBT key, data;
448         int status;
449
450         if (!recno) {
451                 fprintf(stderr,
452                     "ibefore only available for recno db's.\n");
453                 return;
454         }
455         key.data = argv[1];
456         key.size = sizeof(recno_t);
457         data.data = argv[2];
458         data.size = strlen(data.data);
459         status = (db->put)(db, &key, &data, R_IBEFORE);
460         switch (status) {
461         case RET_ERROR:
462                 perror("ibefore/put");
463                 break;
464         case RET_SPECIAL:
465                 printf("%s (duplicate key)\n", argv[1]);
466                 break;
467         case RET_SUCCESS:
468                 break;
469         }
470 }
471
472 void
473 icursor(DB *db, char **argv)
474 {
475         int status;
476         DBT data, key;
477
478         key.data = argv[1];
479         if (recno)
480                 key.size = sizeof(recno_t);
481         else
482                 key.size = strlen(argv[1]) + 1;
483         data.data = argv[2];
484         data.size = strlen(argv[2]) + 1;
485
486         status = (*db->put)(db, &key, &data, R_CURSOR);
487         switch (status) {
488         case RET_ERROR:
489                 perror("icursor/put");
490                 break;
491         case RET_SPECIAL:
492                 printf("%s (duplicate key)\n", argv[1]);
493                 break;
494         case RET_SUCCESS:
495                 break;
496         }
497 }
498
499 void
500 insert(DB *db, char **argv)
501 {
502         int status;
503         DBT data, key;
504
505         key.data = argv[1];
506         if (recno)
507                 key.size = sizeof(recno_t);
508         else
509                 key.size = strlen(argv[1]) + 1;
510         data.data = argv[2];
511         data.size = strlen(argv[2]) + 1;
512
513         status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
514         switch (status) {
515         case RET_ERROR:
516                 perror("insert/put");
517                 break;
518         case RET_SPECIAL:
519                 printf("%s (duplicate key)\n", argv[1]);
520                 break;
521         case RET_SUCCESS:
522                 break;
523         }
524 }
525
526 void
527 last(DB *db, char **argv)
528 {
529         DBT data, key;
530         int status;
531
532         status = (*db->seq)(db, &key, &data, R_LAST);
533
534         switch (status) {
535         case RET_ERROR:
536                 perror("last/seq");
537                 break;
538         case RET_SPECIAL:
539                 printf("no more keys\n");
540                 break;
541         case RET_SUCCESS:
542                 keydata(&key, &data);
543                 break;
544         }
545 }
546
547 void
548 list(DB *db, char **argv)
549 {
550         DBT data, key;
551         FILE *fp;
552         int status;
553
554         if ((fp = fopen(argv[1], "w")) == NULL) {
555                 fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
556                 return;
557         }
558         status = (*db->seq)(db, &key, &data, R_FIRST);
559         while (status == RET_SUCCESS) {
560                 fprintf(fp, "%s\n", key.data);
561                 status = (*db->seq)(db, &key, &data, R_NEXT);
562         }
563         if (status == RET_ERROR)
564                 perror("list/seq");
565 }
566
567 DB *BUGdb;
568 void
569 load(DB *db, char **argv)
570 {
571         char *p, *t;
572         FILE *fp;
573         DBT data, key;
574         recno_t cnt;
575         size_t len;
576         int status;
577         char *lp, buf[16 * 1024];
578
579         BUGdb = db;
580         if ((fp = fopen(argv[1], "r")) == NULL) {
581                 fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
582                 return;
583         }
584         printf("loading %s...\n", argv[1]);
585
586         for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
587                 if (recno) {
588                         key.data = &cnt;
589                         key.size = sizeof(recno_t);
590                         data.data = lp;
591                         data.size = len + 1;
592                 } else {
593                         key.data = lp;
594                         key.size = len + 1;
595                         for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
596                         *t = '\0';
597                         data.data = buf;
598                         data.size = len + 1;
599                 }
600
601                 status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
602                 switch (status) {
603                 case RET_ERROR:
604                         perror("load/put");
605                         exit(1);
606                 case RET_SPECIAL:
607                         if (recno)
608                                 fprintf(stderr,
609                                     "duplicate: %ld {%s}\n", cnt, data.data);
610                         else
611                                 fprintf(stderr,
612                                     "duplicate: %ld {%s}\n", cnt, key.data);
613                         exit(1);
614                 case RET_SUCCESS:
615                         break;
616                 }
617         }
618         fclose(fp);
619 }
620
621 void
622 next(DB *db, char **argv)
623 {
624         DBT data, key;
625         int status;
626
627         status = (*db->seq)(db, &key, &data, R_NEXT);
628
629         switch (status) {
630         case RET_ERROR:
631                 perror("next/seq");
632                 break;
633         case RET_SPECIAL:
634                 printf("no more keys\n");
635                 break;
636         case RET_SUCCESS:
637                 keydata(&key, &data);
638                 break;
639         }
640 }
641
642 void
643 previous(DB *db, char **argv)
644 {
645         DBT data, key;
646         int status;
647
648         status = (*db->seq)(db, &key, &data, R_PREV);
649
650         switch (status) {
651         case RET_ERROR:
652                 perror("previous/seq");
653                 break;
654         case RET_SPECIAL:
655                 printf("no more keys\n");
656                 break;
657         case RET_SUCCESS:
658                 keydata(&key, &data);
659                 break;
660         }
661 }
662
663 void
664 show(DB *db, char **argv)
665 {
666         BTREE *t;
667         PAGE *h;
668         pgno_t pg;
669
670         pg = atoi(argv[1]);
671         t = db->internal;
672         if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
673                 printf("getpage of %ld failed\n", pg);
674                 return;
675         }
676         if (pg == 0)
677                 __bt_dmpage(h);
678         else
679                 __bt_dpage(h);
680         mpool_put(t->bt_mp, h, 0);
681 }
682
683 void
684 bstat(DB *db, char **argv)
685 {
686         printf("BTREE\n");
687         __bt_stat(db);
688 }
689
690 void
691 mstat(DB *db, char **argv)
692 {
693         printf("MPOOL\n");
694         mpool_stat(((BTREE *)db->internal)->bt_mp);
695 }
696
697 void
698 keydata(DBT *key, DBT *data)
699 {
700         if (!recno && key->size > 0)
701                 printf("%s/", key->data);
702         if (data->size > 0)
703                 printf("%s", data->data);
704         printf("\n");
705 }
706
707 void
708 usage(void)
709 {
710         fprintf(stderr,
711             "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
712             progname);
713         exit (1);
714 }