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