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