nrelease - fix/improve livecd
[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         fclose(fp);
567 }
568
569 DB *BUGdb;
570 void
571 load(DB *db, char **argv)
572 {
573         char *p, *t;
574         FILE *fp;
575         DBT data, key;
576         recno_t cnt;
577         size_t len;
578         int status;
579         char *lp, buf[16 * 1024];
580
581         BUGdb = db;
582         if ((fp = fopen(argv[1], "r")) == NULL) {
583                 fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
584                 return;
585         }
586         printf("loading %s...\n", argv[1]);
587
588         for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
589                 if (recno) {
590                         key.data = &cnt;
591                         key.size = sizeof(recno_t);
592                         data.data = lp;
593                         data.size = len + 1;
594                 } else {
595                         key.data = lp;
596                         key.size = len + 1;
597                         for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
598                         *t = '\0';
599                         data.data = buf;
600                         data.size = len + 1;
601                 }
602
603                 status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
604                 switch (status) {
605                 case RET_ERROR:
606                         perror("load/put");
607                         exit(1);
608                 case RET_SPECIAL:
609                         if (recno)
610                                 fprintf(stderr,
611                                     "duplicate: %ld {%s}\n", cnt, data.data);
612                         else
613                                 fprintf(stderr,
614                                     "duplicate: %ld {%s}\n", cnt, key.data);
615                         exit(1);
616                 case RET_SUCCESS:
617                         break;
618                 }
619         }
620         fclose(fp);
621 }
622
623 void
624 next(DB *db, char **argv)
625 {
626         DBT data, key;
627         int status;
628
629         status = (*db->seq)(db, &key, &data, R_NEXT);
630
631         switch (status) {
632         case RET_ERROR:
633                 perror("next/seq");
634                 break;
635         case RET_SPECIAL:
636                 printf("no more keys\n");
637                 break;
638         case RET_SUCCESS:
639                 keydata(&key, &data);
640                 break;
641         }
642 }
643
644 void
645 previous(DB *db, char **argv)
646 {
647         DBT data, key;
648         int status;
649
650         status = (*db->seq)(db, &key, &data, R_PREV);
651
652         switch (status) {
653         case RET_ERROR:
654                 perror("previous/seq");
655                 break;
656         case RET_SPECIAL:
657                 printf("no more keys\n");
658                 break;
659         case RET_SUCCESS:
660                 keydata(&key, &data);
661                 break;
662         }
663 }
664
665 void
666 show(DB *db, char **argv)
667 {
668         BTREE *t;
669         PAGE *h;
670         pgno_t pg;
671
672         pg = atoi(argv[1]);
673         t = db->internal;
674         if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
675                 printf("getpage of %ld failed\n", pg);
676                 return;
677         }
678         if (pg == 0)
679                 __bt_dmpage(h);
680         else
681                 __bt_dpage(h);
682         mpool_put(t->bt_mp, h, 0);
683 }
684
685 void
686 bstat(DB *db, char **argv)
687 {
688         printf("BTREE\n");
689         __bt_stat(db);
690 }
691
692 void
693 mstat(DB *db, char **argv)
694 {
695         printf("MPOOL\n");
696         mpool_stat(((BTREE *)db->internal)->bt_mp);
697 }
698
699 void
700 keydata(DBT *key, DBT *data)
701 {
702         if (!recno && key->size > 0)
703                 printf("%s/", key->data);
704         if (data->size > 0)
705                 printf("%s", data->data);
706         printf("\n");
707 }
708
709 void
710 usage(void)
711 {
712         fprintf(stderr,
713             "usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
714             progname);
715         exit (1);
716 }