tdb2: Fix typo in TDB1_porting.txt
[abartlet/samba.git/.git] / lib / tdb2 / tools / tdb2tool.c
1 /*
2    Unix SMB/CIFS implementation.
3    Samba database functions
4    Copyright (C) Andrew Tridgell              1999-2000
5    Copyright (C) Paul `Rusty' Russell              2000
6    Copyright (C) Jeremy Allison                    2000
7    Copyright (C) Andrew Esh                        2001
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "config.h"
24 #include "tdb2.h"
25 #ifdef HAVE_LIBREPLACE
26 #include <replace.h>
27 #include <system/filesys.h>
28 #include <system/time.h>
29 #include <system/locale.h>
30 #else
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <stdarg.h>
41 #endif
42
43 static int do_command(void);
44 const char *cmdname;
45 char *arg1, *arg2;
46 size_t arg1len, arg2len;
47 int bIterate = 0;
48 char *line;
49 TDB_DATA iterate_kbuf;
50 char cmdline[1024];
51 static int disable_mmap;
52
53 enum commands {
54         CMD_CREATE_TDB,
55         CMD_OPEN_TDB,
56         CMD_TRANSACTION_START,
57         CMD_TRANSACTION_COMMIT,
58         CMD_TRANSACTION_CANCEL,
59         CMD_ERASE,
60         CMD_DUMP,
61         CMD_INSERT,
62         CMD_MOVE,
63         CMD_STORE,
64         CMD_SHOW,
65         CMD_KEYS,
66         CMD_HEXKEYS,
67         CMD_DELETE,
68 #if 0
69         CMD_LIST_HASH_FREE,
70         CMD_LIST_FREE,
71 #endif
72         CMD_INFO,
73         CMD_MMAP,
74         CMD_SPEED,
75         CMD_FIRST,
76         CMD_NEXT,
77         CMD_SYSTEM,
78         CMD_CHECK,
79         CMD_QUIT,
80         CMD_HELP
81 };
82
83 typedef struct {
84         const char *name;
85         enum commands cmd;
86 } COMMAND_TABLE;
87
88 COMMAND_TABLE cmd_table[] = {
89         {"create",      CMD_CREATE_TDB},
90         {"open",        CMD_OPEN_TDB},
91 #if 0
92         {"transaction_start",   CMD_TRANSACTION_START},
93         {"transaction_commit",  CMD_TRANSACTION_COMMIT},
94         {"transaction_cancel",  CMD_TRANSACTION_CANCEL},
95 #endif
96         {"erase",       CMD_ERASE},
97         {"dump",        CMD_DUMP},
98         {"insert",      CMD_INSERT},
99         {"move",        CMD_MOVE},
100         {"store",       CMD_STORE},
101         {"show",        CMD_SHOW},
102         {"keys",        CMD_KEYS},
103         {"hexkeys",     CMD_HEXKEYS},
104         {"delete",      CMD_DELETE},
105 #if 0
106         {"list",        CMD_LIST_HASH_FREE},
107         {"free",        CMD_LIST_FREE},
108 #endif
109         {"info",        CMD_INFO},
110         {"speed",       CMD_SPEED},
111         {"mmap",        CMD_MMAP},
112         {"first",       CMD_FIRST},
113         {"1",           CMD_FIRST},
114         {"next",        CMD_NEXT},
115         {"n",           CMD_NEXT},
116         {"check",       CMD_CHECK},
117         {"quit",        CMD_QUIT},
118         {"q",           CMD_QUIT},
119         {"!",           CMD_SYSTEM},
120         {NULL,          CMD_HELP}
121 };
122
123 struct timeval tp1,tp2;
124
125 static void _start_timer(void)
126 {
127         gettimeofday(&tp1,NULL);
128 }
129
130 static double _end_timer(void)
131 {
132         gettimeofday(&tp2,NULL);
133         return((tp2.tv_sec - tp1.tv_sec) +
134                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
135 }
136
137 static void tdb_log(struct tdb_context *tdb,
138                     enum tdb_log_level level,
139                     enum TDB_ERROR ecode,
140                     const char *message,
141                     void *data)
142 {
143         fprintf(stderr, "tdb:%s:%s:%s\n",
144                 tdb_name(tdb), tdb_errorstr(ecode), message);
145 }
146
147 /* a tdb tool for manipulating a tdb database */
148
149 static struct tdb_context *tdb;
150
151 static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
152 static int print_key(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
153 static int print_hexkey(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
154
155 static void print_asc(const char *buf,int len)
156 {
157         int i;
158
159         /* We're probably printing ASCII strings so don't try to display
160            the trailing NULL character. */
161
162         if (buf[len - 1] == 0)
163                 len--;
164
165         for (i=0;i<len;i++)
166                 printf("%c",isprint(buf[i])?buf[i]:'.');
167 }
168
169 static void print_data(const char *buf,int len)
170 {
171         int i=0;
172         if (len<=0) return;
173         printf("[%03X] ",i);
174         for (i=0;i<len;) {
175                 printf("%02X ",(int)((unsigned char)buf[i]));
176                 i++;
177                 if (i%8 == 0) printf(" ");
178                 if (i%16 == 0) {
179                         print_asc(&buf[i-16],8); printf(" ");
180                         print_asc(&buf[i-8],8); printf("\n");
181                         if (i<len) printf("[%03X] ",i);
182                 }
183         }
184         if (i%16) {
185                 int n;
186
187                 n = 16 - (i%16);
188                 printf(" ");
189                 if (n>8) printf(" ");
190                 while (n--) printf("   ");
191
192                 n = i%16;
193                 if (n > 8) n = 8;
194                 print_asc(&buf[i-(i%16)],n); printf(" ");
195                 n = (i%16) - n;
196                 if (n>0) print_asc(&buf[i-n],n);
197                 printf("\n");
198         }
199 }
200
201 static void help(void)
202 {
203         printf("\n"
204 "tdbtool: \n"
205 "  create    dbname     : create a database\n"
206 "  open      dbname     : open an existing database\n"
207 "  openjh    dbname     : open an existing database (jenkins hash)\n"
208 "  transaction_start    : start a transaction\n"
209 "  transaction_commit   : commit a transaction\n"
210 "  transaction_cancel   : cancel a transaction\n"
211 "  erase                : erase the database\n"
212 "  dump                 : dump the database as strings\n"
213 "  keys                 : dump the database keys as strings\n"
214 "  hexkeys              : dump the database keys as hex values\n"
215 "  info                 : print summary info about the database\n"
216 "  insert    key  data  : insert a record\n"
217 "  move      key  file  : move a record to a destination tdb\n"
218 "  store     key  data  : store a record (replace)\n"
219 "  show      key        : show a record by key\n"
220 "  delete    key        : delete a record by key\n"
221 #if 0
222 "  list                 : print the database hash table and freelist\n"
223 "  free                 : print the database freelist\n"
224 #endif
225 "  check                : check the integrity of an opened database\n"
226 "  speed                : perform speed tests on the database\n"
227 "  ! command            : execute system command\n"
228 "  1 | first            : print the first record\n"
229 "  n | next             : print the next record\n"
230 "  q | quit             : terminate\n"
231 "  \\n                   : repeat 'next' command\n"
232 "\n");
233 }
234
235 static void terror(enum TDB_ERROR err, const char *why)
236 {
237         if (err != TDB_SUCCESS)
238                 printf("%s:%s\n", tdb_errorstr(err), why);
239         else
240                 printf("%s\n", why);
241 }
242
243 static void create_tdb(const char *tdbname)
244 {
245         union tdb_attribute log_attr;
246         log_attr.base.attr = TDB_ATTRIBUTE_LOG;
247         log_attr.base.next = NULL;
248         log_attr.log.fn = tdb_log;
249
250         if (tdb) tdb_close(tdb);
251         tdb = tdb_open(tdbname, (disable_mmap?TDB_NOMMAP:0),
252                        O_RDWR | O_CREAT | O_TRUNC, 0600, &log_attr);
253         if (!tdb) {
254                 printf("Could not create %s: %s\n", tdbname, strerror(errno));
255         }
256 }
257
258 static void open_tdb(const char *tdbname)
259 {
260         union tdb_attribute log_attr;
261         log_attr.base.attr = TDB_ATTRIBUTE_LOG;
262         log_attr.base.next = NULL;
263         log_attr.log.fn = tdb_log;
264
265         if (tdb) tdb_close(tdb);
266         tdb = tdb_open(tdbname, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600,
267                        &log_attr);
268         if (!tdb) {
269                 printf("Could not open %s: %s\n", tdbname, strerror(errno));
270         }
271 }
272
273 static void insert_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
274 {
275         TDB_DATA key, dbuf;
276         enum TDB_ERROR ecode;
277
278         if ((keyname == NULL) || (keylen == 0)) {
279                 terror(TDB_SUCCESS, "need key");
280                 return;
281         }
282
283         key.dptr = (unsigned char *)keyname;
284         key.dsize = keylen;
285         dbuf.dptr = (unsigned char *)data;
286         dbuf.dsize = datalen;
287
288         ecode = tdb_store(tdb, key, dbuf, TDB_INSERT);
289         if (ecode) {
290                 terror(ecode, "insert failed");
291         }
292 }
293
294 static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen)
295 {
296         TDB_DATA key, dbuf;
297         enum TDB_ERROR ecode;
298
299         if ((keyname == NULL) || (keylen == 0)) {
300                 terror(TDB_SUCCESS, "need key");
301                 return;
302         }
303
304         if ((data == NULL) || (datalen == 0)) {
305                 terror(TDB_SUCCESS, "need data");
306                 return;
307         }
308
309         key.dptr = (unsigned char *)keyname;
310         key.dsize = keylen;
311         dbuf.dptr = (unsigned char *)data;
312         dbuf.dsize = datalen;
313
314         printf("Storing key:\n");
315         print_rec(tdb, key, dbuf, NULL);
316
317         ecode = tdb_store(tdb, key, dbuf, TDB_REPLACE);
318         if (ecode) {
319                 terror(ecode, "store failed");
320         }
321 }
322
323 static void show_tdb(char *keyname, size_t keylen)
324 {
325         TDB_DATA key, dbuf;
326         enum TDB_ERROR ecode;
327
328         if ((keyname == NULL) || (keylen == 0)) {
329                 terror(TDB_SUCCESS, "need key");
330                 return;
331         }
332
333         key.dptr = (unsigned char *)keyname;
334         key.dsize = keylen;
335
336         ecode = tdb_fetch(tdb, key, &dbuf);
337         if (ecode) {
338                 terror(ecode, "fetch failed");
339                 return;
340         }
341
342         print_rec(tdb, key, dbuf, NULL);
343
344         free( dbuf.dptr );
345 }
346
347 static void delete_tdb(char *keyname, size_t keylen)
348 {
349         TDB_DATA key;
350         enum TDB_ERROR ecode;
351
352         if ((keyname == NULL) || (keylen == 0)) {
353                 terror(TDB_SUCCESS, "need key");
354                 return;
355         }
356
357         key.dptr = (unsigned char *)keyname;
358         key.dsize = keylen;
359
360         ecode = tdb_delete(tdb, key);
361         if (ecode) {
362                 terror(ecode, "delete failed");
363         }
364 }
365
366 static void move_rec(char *keyname, size_t keylen, char* tdbname)
367 {
368         TDB_DATA key, dbuf;
369         struct tdb_context *dst_tdb;
370         enum TDB_ERROR ecode;
371
372         if ((keyname == NULL) || (keylen == 0)) {
373                 terror(TDB_SUCCESS, "need key");
374                 return;
375         }
376
377         if ( !tdbname ) {
378                 terror(TDB_SUCCESS, "need destination tdb name");
379                 return;
380         }
381
382         key.dptr = (unsigned char *)keyname;
383         key.dsize = keylen;
384
385         ecode = tdb_fetch(tdb, key, &dbuf);
386         if (ecode) {
387                 terror(ecode, "fetch failed");
388                 return;
389         }
390
391         print_rec(tdb, key, dbuf, NULL);
392
393         dst_tdb = tdb_open(tdbname, 0, O_RDWR, 0600, NULL);
394         if ( !dst_tdb ) {
395                 terror(TDB_SUCCESS, "unable to open destination tdb");
396                 return;
397         }
398
399         ecode = tdb_store( dst_tdb, key, dbuf, TDB_REPLACE);
400         if (ecode)
401                 terror(ecode, "failed to move record");
402         else
403                 printf("record moved\n");
404
405         tdb_close( dst_tdb );
406 }
407
408 static int print_rec(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
409 {
410         printf("\nkey %d bytes\n", (int)key.dsize);
411         print_asc((const char *)key.dptr, key.dsize);
412         printf("\ndata %d bytes\n", (int)dbuf.dsize);
413         print_data((const char *)dbuf.dptr, dbuf.dsize);
414         return 0;
415 }
416
417 static int print_key(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
418 {
419         printf("key %d bytes: ", (int)key.dsize);
420         print_asc((const char *)key.dptr, key.dsize);
421         printf("\n");
422         return 0;
423 }
424
425 static int print_hexkey(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
426 {
427         printf("key %d bytes\n", (int)key.dsize);
428         print_data((const char *)key.dptr, key.dsize);
429         printf("\n");
430         return 0;
431 }
432
433 static int total_bytes;
434
435 static int traverse_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
436 {
437         total_bytes += dbuf.dsize;
438         return 0;
439 }
440
441 static void info_tdb(void)
442 {
443         enum TDB_ERROR ecode;
444         char *summary;
445
446         ecode = tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &summary);
447
448         if (ecode) {
449                 terror(ecode, "Getting summary");
450         } else {
451                 printf("%s", summary);
452                 free(summary);
453         }
454 }
455
456 static void speed_tdb(const char *tlimit)
457 {
458         unsigned timelimit = tlimit?atoi(tlimit):0;
459         double t;
460         int ops;
461         if (timelimit == 0) timelimit = 5;
462
463         ops = 0;
464         printf("Testing store speed for %u seconds\n", timelimit);
465         _start_timer();
466         do {
467                 long int r = random();
468                 TDB_DATA key, dbuf;
469                 key = tdb_mkdata("store test", strlen("store test"));
470                 dbuf.dptr = (unsigned char *)&r;
471                 dbuf.dsize = sizeof(r);
472                 tdb_store(tdb, key, dbuf, TDB_REPLACE);
473                 t = _end_timer();
474                 ops++;
475         } while (t < timelimit);
476         printf("%10.3f ops/sec\n", ops/t);
477
478         ops = 0;
479         printf("Testing fetch speed for %u seconds\n", timelimit);
480         _start_timer();
481         do {
482                 long int r = random();
483                 TDB_DATA key, dbuf;
484                 key = tdb_mkdata("store test", strlen("store test"));
485                 dbuf.dptr = (unsigned char *)&r;
486                 dbuf.dsize = sizeof(r);
487                 tdb_fetch(tdb, key, &dbuf);
488                 t = _end_timer();
489                 ops++;
490         } while (t < timelimit);
491         printf("%10.3f ops/sec\n", ops/t);
492
493         ops = 0;
494         printf("Testing transaction speed for %u seconds\n", timelimit);
495         _start_timer();
496         do {
497                 long int r = random();
498                 TDB_DATA key, dbuf;
499                 key = tdb_mkdata("transaction test", strlen("transaction test"));
500                 dbuf.dptr = (unsigned char *)&r;
501                 dbuf.dsize = sizeof(r);
502                 tdb_transaction_start(tdb);
503                 tdb_store(tdb, key, dbuf, TDB_REPLACE);
504                 tdb_transaction_commit(tdb);
505                 t = _end_timer();
506                 ops++;
507         } while (t < timelimit);
508         printf("%10.3f ops/sec\n", ops/t);
509
510         ops = 0;
511         printf("Testing traverse speed for %u seconds\n", timelimit);
512         _start_timer();
513         do {
514                 tdb_traverse(tdb, traverse_fn, NULL);
515                 t = _end_timer();
516                 ops++;
517         } while (t < timelimit);
518         printf("%10.3f ops/sec\n", ops/t);
519 }
520
521 static void toggle_mmap(void)
522 {
523         disable_mmap = !disable_mmap;
524         if (disable_mmap) {
525                 printf("mmap is disabled\n");
526         } else {
527                 printf("mmap is enabled\n");
528         }
529 }
530
531 static char *tdb_getline(const char *prompt)
532 {
533         static char thisline[1024];
534         char *p;
535         fputs(prompt, stdout);
536         thisline[0] = 0;
537         p = fgets(thisline, sizeof(thisline)-1, stdin);
538         if (p) p = strchr(p, '\n');
539         if (p) *p = 0;
540         return p?thisline:NULL;
541 }
542
543 static int do_delete_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf,
544                      void *state)
545 {
546     return tdb_delete(the_tdb, key);
547 }
548
549 static void first_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
550 {
551         TDB_DATA dbuf;
552         enum TDB_ERROR ecode;
553         ecode = tdb_firstkey(the_tdb, pkey);
554         if (!ecode)
555                 ecode = tdb_fetch(the_tdb, *pkey, &dbuf);
556         if (ecode) terror(ecode, "fetch failed");
557         else {
558                 print_rec(the_tdb, *pkey, dbuf, NULL);
559         }
560 }
561
562 static void next_record(struct tdb_context *the_tdb, TDB_DATA *pkey)
563 {
564         TDB_DATA dbuf;
565         enum TDB_ERROR ecode;
566         ecode = tdb_nextkey(the_tdb, pkey);
567
568         if (!ecode)
569                 ecode = tdb_fetch(the_tdb, *pkey, &dbuf);
570         if (ecode)
571                 terror(ecode, "fetch failed");
572         else
573                 print_rec(the_tdb, *pkey, dbuf, NULL);
574 }
575
576 static void check_db(struct tdb_context *the_tdb)
577 {
578         if (!the_tdb) {
579                 printf("Error: No database opened!\n");
580         } else {
581                 if (tdb_check(the_tdb, NULL, NULL) != 0)
582                         printf("Integrity check for the opened database failed.\n");
583                 else
584                         printf("Database integrity is OK.\n");
585         }
586 }
587
588 static int do_command(void)
589 {
590         COMMAND_TABLE *ctp = cmd_table;
591         enum commands mycmd = CMD_HELP;
592         int cmd_len;
593
594         if (cmdname && strlen(cmdname) == 0) {
595                 mycmd = CMD_NEXT;
596         } else {
597                 while (ctp->name) {
598                         cmd_len = strlen(ctp->name);
599                         if (strncmp(ctp->name,cmdname,cmd_len) == 0) {
600                                 mycmd = ctp->cmd;
601                                 break;
602                         }
603                         ctp++;
604                 }
605         }
606
607         switch (mycmd) {
608         case CMD_CREATE_TDB:
609                 bIterate = 0;
610                 create_tdb(arg1);
611                 return 0;
612         case CMD_OPEN_TDB:
613                 bIterate = 0;
614                 open_tdb(arg1);
615                 return 0;
616         case CMD_SYSTEM:
617                 /* Shell command */
618                 if (system(arg1) == -1) {
619                         terror(TDB_SUCCESS, "system() call failed\n");
620                 }
621                 return 0;
622         case CMD_QUIT:
623                 return 1;
624         default:
625                 /* all the rest require a open database */
626                 if (!tdb) {
627                         bIterate = 0;
628                         terror(TDB_SUCCESS, "database not open");
629                         help();
630                         return 0;
631                 }
632                 switch (mycmd) {
633                 case CMD_TRANSACTION_START:
634                         bIterate = 0;
635                         tdb_transaction_start(tdb);
636                         return 0;
637                 case CMD_TRANSACTION_COMMIT:
638                         bIterate = 0;
639                         tdb_transaction_commit(tdb);
640                         return 0;
641                 case CMD_TRANSACTION_CANCEL:
642                         bIterate = 0;
643                         tdb_transaction_cancel(tdb);
644                         return 0;
645                 case CMD_ERASE:
646                         bIterate = 0;
647                         tdb_traverse(tdb, do_delete_fn, NULL);
648                         return 0;
649                 case CMD_DUMP:
650                         bIterate = 0;
651                         tdb_traverse(tdb, print_rec, NULL);
652                         return 0;
653                 case CMD_INSERT:
654                         bIterate = 0;
655                         insert_tdb(arg1, arg1len,arg2,arg2len);
656                         return 0;
657                 case CMD_MOVE:
658                         bIterate = 0;
659                         move_rec(arg1,arg1len,arg2);
660                         return 0;
661                 case CMD_STORE:
662                         bIterate = 0;
663                         store_tdb(arg1,arg1len,arg2,arg2len);
664                         return 0;
665                 case CMD_SHOW:
666                         bIterate = 0;
667                         show_tdb(arg1, arg1len);
668                         return 0;
669                 case CMD_KEYS:
670                         tdb_traverse(tdb, print_key, NULL);
671                         return 0;
672                 case CMD_HEXKEYS:
673                         tdb_traverse(tdb, print_hexkey, NULL);
674                         return 0;
675                 case CMD_DELETE:
676                         bIterate = 0;
677                         delete_tdb(arg1,arg1len);
678                         return 0;
679 #if 0
680                 case CMD_LIST_HASH_FREE:
681                         tdb_dump_all(tdb);
682                         return 0;
683                 case CMD_LIST_FREE:
684                         tdb_printfreelist(tdb);
685                         return 0;
686 #endif
687                 case CMD_INFO:
688                         info_tdb();
689                         return 0;
690                 case CMD_SPEED:
691                         speed_tdb(arg1);
692                         return 0;
693                 case CMD_MMAP:
694                         toggle_mmap();
695                         return 0;
696                 case CMD_FIRST:
697                         bIterate = 1;
698                         first_record(tdb, &iterate_kbuf);
699                         return 0;
700                 case CMD_NEXT:
701                         if (bIterate)
702                                 next_record(tdb, &iterate_kbuf);
703                         return 0;
704                 case CMD_CHECK:
705                         check_db(tdb);
706                         return 0;
707                 case CMD_HELP:
708                         help();
709                         return 0;
710                 case CMD_CREATE_TDB:
711                 case CMD_OPEN_TDB:
712                 case CMD_SYSTEM:
713                 case CMD_QUIT:
714                         /*
715                          * unhandled commands.  cases included here to avoid compiler
716                          * warnings.
717                          */
718                         return 0;
719                 }
720         }
721
722         return 0;
723 }
724
725 static char *convert_string(char *instring, size_t *sizep)
726 {
727         size_t length = 0;
728         char *outp, *inp;
729         char temp[3];
730
731         outp = inp = instring;
732
733         while (*inp) {
734                 if (*inp == '\\') {
735                         inp++;
736                         if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
737                                 temp[0] = *inp++;
738                                 temp[1] = '\0';
739                                 if (*inp && strchr("0123456789abcdefABCDEF",(int)*inp)) {
740                                         temp[1] = *inp++;
741                                         temp[2] = '\0';
742                                 }
743                                 *outp++ = (char)strtol((const char *)temp,NULL,16);
744                         } else {
745                                 *outp++ = *inp++;
746                         }
747                 } else {
748                         *outp++ = *inp++;
749                 }
750                 length++;
751         }
752         *sizep = length;
753         return instring;
754 }
755
756 int main(int argc, char *argv[])
757 {
758         cmdname = "";
759         arg1 = NULL;
760         arg1len = 0;
761         arg2 = NULL;
762         arg2len = 0;
763
764         if (argv[1]) {
765                 cmdname = "open";
766                 arg1 = argv[1];
767                 do_command();
768                 cmdname =  "";
769                 arg1 = NULL;
770         }
771
772         switch (argc) {
773         case 1:
774         case 2:
775                 /* Interactive mode */
776                 while ((cmdname = tdb_getline("tdb> "))) {
777                         arg2 = arg1 = NULL;
778                         if ((arg1 = strchr((const char *)cmdname,' ')) != NULL) {
779                                 arg1++;
780                                 arg2 = arg1;
781                                 while (*arg2) {
782                                         if (*arg2 == ' ') {
783                                                 *arg2++ = '\0';
784                                                 break;
785                                         }
786                                         if ((*arg2++ == '\\') && (*arg2 == ' ')) {
787                                                 arg2++;
788                                         }
789                                 }
790                         }
791                         if (arg1) arg1 = convert_string(arg1,&arg1len);
792                         if (arg2) arg2 = convert_string(arg2,&arg2len);
793                         if (do_command()) break;
794                 }
795                 break;
796         case 5:
797                 arg2 = convert_string(argv[4],&arg2len);
798         case 4:
799                 arg1 = convert_string(argv[3],&arg1len);
800         case 3:
801                 cmdname = argv[2];
802         default:
803                 do_command();
804                 break;
805         }
806
807         if (tdb) tdb_close(tdb);
808
809         return 0;
810 }