add changelog
[platform/upstream/gdbm.git] / src / gdbmtool.c
1 /* This file is part of GDBM, the GNU data base manager.
2    Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013 Free Software Foundation,
3    Inc.
4
5    GDBM is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3, or (at your option)
8    any later version.
9
10    GDBM is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with GDBM. If not, see <http://www.gnu.org/licenses/>.    */
17
18 #include "gdbmtool.h"
19 #include "gdbm.h"
20 #include "gram.h"
21
22 #include <errno.h>
23 #include <ctype.h>
24 #include <signal.h>
25 #include <pwd.h>
26 #include <sys/ioctl.h>
27 #ifdef HAVE_SYS_TERMIOS_H
28 # include <sys/termios.h>
29 #endif
30 #include <stdarg.h>
31 #ifdef HAVE_LOCALE_H
32 # include <locale.h>
33 #endif
34
35 char *file_name = NULL;       /* Database file name */   
36 GDBM_FILE gdbm_file = NULL;   /* Database to operate upon */
37 datum key_data;               /* Current key */
38 datum return_data;            /* Current data */
39 int open_mode;                /* Default open mode */
40
41 #define SIZE_T_MAX ((size_t)-1)
42
43 unsigned input_line;
44
45 \f
46 static int
47 opendb (char *dbname)
48 {
49   int cache_size = 0;
50   int block_size = 0;
51   int flags = 0;
52   int filemode;
53   GDBM_FILE db;
54   
55   switch (variable_get ("cachesize", VART_INT, (void**) &cache_size))
56     {
57     case VAR_OK:
58     case VAR_ERR_NOTSET:
59       break;
60     default:
61       abort ();
62     }
63   switch (variable_get ("blocksize", VART_INT, (void**) &block_size))
64     {
65     case VAR_OK:
66     case VAR_ERR_NOTSET:
67       break;
68     default:
69       abort ();
70     }
71   
72   if (!variable_is_true ("lock"))
73     flags |= GDBM_NOLOCK;
74   if (!variable_is_true ("mmap"))
75     flags |= GDBM_NOMMAP;
76   if (variable_is_true ("sync"))
77     flags |= GDBM_SYNC;
78       
79   if (open_mode == GDBM_NEWDB)
80     {
81       if (interactive && variable_is_true ("confirm") &&
82           access (dbname, F_OK) == 0)
83         {
84           if (!getyn (_("database %s already exists; overwrite"), dbname))
85             return 1;
86         }
87     }
88   
89   if (variable_get ("filemode", VART_INT, (void**) &filemode))
90     abort ();
91
92   db = gdbm_open (dbname, block_size, open_mode | flags, filemode, NULL);
93
94   if (db == NULL)
95     {
96       terror (_("cannot open database %s: %s"), dbname,
97               gdbm_strerror (gdbm_errno));
98       return 1;
99     }
100
101   if (cache_size &&
102       gdbm_setopt (db, GDBM_CACHESIZE, &cache_size, sizeof (int)) == -1)
103     terror (_("gdbm_setopt failed: %s"), gdbm_strerror (gdbm_errno));
104
105   if (gdbm_file)
106     gdbm_close (gdbm_file);
107   
108   gdbm_file = db;
109   return 0;
110 }
111
112 static int
113 checkdb ()
114 {
115   if (!gdbm_file)
116     {
117       if (!file_name)
118         {
119           file_name = estrdup (GDBMTOOL_DEFFILE);
120           terror (_("warning: using default database file %s"),
121                         file_name);
122         }
123       return opendb (file_name);
124     }
125   return 0;
126 }
127 \f
128 size_t
129 bucket_print_lines (hash_bucket *bucket)
130 {
131   return 6 + gdbm_file->header->bucket_elems + 3 + bucket->av_count;
132 }
133
134 /* Debug procedure to print the contents of the current hash bucket. */
135 void
136 print_bucket (FILE *fp, hash_bucket *bucket, const char *mesg)
137 {
138   int             index;
139
140   fprintf (fp,
141            _("******* %s **********\n\nbits = %d\ncount= %d\nHash Table:\n"),
142            mesg, bucket->bucket_bits, bucket->count);
143   fprintf (fp,
144            _("     #    hash value     key size    data size     data adr  home\n"));
145   for (index = 0; index < gdbm_file->header->bucket_elems; index++)
146     fprintf (fp, "  %4d  %12x  %11d  %11d  %11lu %5d\n", index,
147              bucket->h_table[index].hash_value,
148              bucket->h_table[index].key_size,
149              bucket->h_table[index].data_size,
150              (unsigned long) bucket->h_table[index].data_pointer,
151              bucket->h_table[index].hash_value %
152              gdbm_file->header->bucket_elems);
153
154   fprintf (fp, _("\nAvail count = %1d\n"), bucket->av_count);
155   fprintf (fp, _("Avail  adr     size\n"));
156   for (index = 0; index < bucket->av_count; index++)
157     fprintf (fp, "%9lu%9d\n",
158              (unsigned long) bucket->bucket_avail[index].av_adr,
159              bucket->bucket_avail[index].av_size);
160 }
161 \f
162 size_t
163 _gdbm_avail_list_size (GDBM_FILE dbf, size_t min_size)
164 {
165   int             temp;
166   int             size;
167   avail_block    *av_stk;
168   size_t          lines;
169   int             rc;
170   
171   lines = 4 + dbf->header->avail.count;
172   if (lines > min_size)
173     return lines;
174   /* Initialize the variables for a pass throught the avail stack. */
175   temp = dbf->header->avail.next_block;
176   size = (((dbf->header->avail.size * sizeof (avail_elem)) >> 1)
177           + sizeof (avail_block));
178   av_stk = emalloc (size);
179
180   /* Traverse the stack. */
181   while (temp)
182     {
183       if (__lseek (dbf, temp, SEEK_SET) != temp)
184         {
185           terror ("lseek: %s", strerror (errno));
186           break;
187         }
188       
189       if ((rc = _gdbm_full_read (dbf, av_stk, size)))
190         {
191           if (rc == GDBM_FILE_EOF)
192             terror ("read: %s", gdbm_strerror (rc));
193           else
194             terror ("read: %s (%s)",
195                           gdbm_strerror (rc), strerror (errno));
196           break;
197         }
198
199       lines += av_stk->count;
200       if (lines > min_size)
201         break;
202       temp = av_stk->next_block;
203     }
204   free (av_stk);
205
206   return lines;
207 }
208
209 void
210 _gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf)
211 {
212   int             temp;
213   int             size;
214   avail_block    *av_stk;
215   int             rc;
216   
217   /* Print the the header avail block.  */
218   fprintf (fp, _("\nheader block\nsize  = %d\ncount = %d\n"),
219            dbf->header->avail.size, dbf->header->avail.count);
220   for (temp = 0; temp < dbf->header->avail.count; temp++)
221     {
222       fprintf (fp, "  %15d   %10lu \n",
223                dbf->header->avail.av_table[temp].av_size,
224                (unsigned long) dbf->header->avail.av_table[temp].av_adr);
225     }
226
227   /* Initialize the variables for a pass throught the avail stack. */
228   temp = dbf->header->avail.next_block;
229   size = (((dbf->header->avail.size * sizeof (avail_elem)) >> 1)
230           + sizeof (avail_block));
231   av_stk = emalloc (size);
232
233   /* Print the stack. */
234   while (temp)
235     {
236       if (__lseek (dbf, temp, SEEK_SET) != temp)
237         {
238           terror ("lseek: %s", strerror (errno));
239           break;
240         }
241       
242       if ((rc = _gdbm_full_read (dbf, av_stk, size)))
243         {
244           if (rc == GDBM_FILE_EOF)
245             terror ("read: %s", gdbm_strerror (rc));
246           else
247             terror ("read: %s (%s)", gdbm_strerror (rc), strerror (errno));
248           break;
249         }
250
251       /* Print the block! */
252       fprintf (fp, _("\nblock = %d\nsize  = %d\ncount = %d\n"), temp,
253                av_stk->size, av_stk->count);
254       for (temp = 0; temp < av_stk->count; temp++)
255         {
256           fprintf (fp, "  %15d   %10lu \n", av_stk->av_table[temp].av_size,
257                    (unsigned long) av_stk->av_table[temp].av_adr);
258         }
259       temp = av_stk->next_block;
260     }
261   free (av_stk);
262 }
263 \f
264 void
265 _gdbm_print_bucket_cache (FILE *fp, GDBM_FILE dbf)
266 {
267   int             index;
268   char            changed;
269
270   if (dbf->bucket_cache != NULL)
271     {
272       fprintf (fp,
273         _("Bucket Cache (size %d):\n  Index:  Address  Changed  Data_Hash \n"),
274          dbf->cache_size);
275       for (index = 0; index < dbf->cache_size; index++)
276         {
277           changed = dbf->bucket_cache[index].ca_changed;
278           fprintf (fp, "  %5d:  %7lu %7s  %x\n",
279                    index,
280                    (unsigned long) dbf->bucket_cache[index].ca_adr,
281                    (changed ? _("True") : _("False")),
282                    dbf->bucket_cache[index].ca_data.hash_val);
283         }
284     }
285   else
286     fprintf (fp, _("Bucket cache has not been initialized.\n"));
287 }
288
289 int
290 trimnl (char *str)
291 {
292   int len = strlen (str);
293
294   if (str[len - 1] == '\n')
295     {
296       str[--len] = 0;
297       return 1;
298     }
299   return 0;
300 }
301
302 int
303 get_screen_lines ()
304 {
305 #ifdef TIOCGWINSZ
306   if (isatty (1))
307     {
308       struct winsize ws;
309
310       ws.ws_col = ws.ws_row = 0;
311       if ((ioctl(1, TIOCGWINSZ, (char *) &ws) < 0) || ws.ws_row == 0)
312         {
313           const char *lines = getenv ("LINES");
314           if (lines)
315             ws.ws_row = strtol (lines, NULL, 10);
316         }
317       return ws.ws_row;
318     }
319 #else
320   const char *lines = getenv ("LINES");
321   if (lines)
322     return strtol (lines, NULL, 10);
323 #endif
324   return -1;
325 }
326
327 \f
328 #define ARG_UNUSED __attribute__ ((__unused__))
329
330 #define NARGS 5
331
332 struct handler_param
333 {
334   int argc;
335   struct gdbmarg **argv;
336   FILE *fp;
337   void *data;
338 };
339              
340 \f
341 /* Open database */
342 void
343 open_handler (struct handler_param *param)
344 {
345   if (opendb (param->argv[0]->v.string) == 0)
346     {
347       free (file_name);
348       file_name = estrdup (param->argv[0]->v.string);
349     }
350 }
351
352 /* Close database */
353 void
354 close_handler (struct handler_param *param)
355 {
356   if (!gdbm_file)
357     terror (_("nothing to close"));
358   else
359     {
360       gdbm_close (gdbm_file);
361       gdbm_file = NULL;
362     }
363 }
364
365 \f
366 static char *
367 count_to_str (gdbm_count_t count, char *buf, size_t bufsize)
368 {
369   char *p = buf + bufsize;
370
371   *--p = 0;
372   if (count == 0)
373     *--p = '0';
374   else
375     while (count)
376       {
377         if (p == buf)
378           return NULL;
379         *--p = '0' + count % 10;
380         count /= 10;
381       }
382   return p;
383 }
384   
385 /* count - count items in the database */
386 void
387 count_handler (struct handler_param *param)
388 {
389   gdbm_count_t count;
390
391   if (gdbm_count (gdbm_file, &count))
392     terror ("gdbm_count: %s", gdbm_strerror (gdbm_errno));
393   else
394     {
395       char buf[128];
396       char *p = count_to_str (count, buf, sizeof buf);
397
398       if (!p)
399         terror (_("count buffer overflow"));
400       else
401         fprintf (param->fp, 
402                  ngettext ("There is %s item in the database.\n",
403                            "There are %s items in the database.\n",
404                            count),
405                  p);
406     }
407 }
408 \f
409 /* delete KEY - delete a key*/
410 void
411 delete_handler (struct handler_param *param)
412 {
413   if (gdbm_delete (gdbm_file, param->argv[0]->v.dat) != 0)
414     {
415       if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
416         terror (_("Item not found"));
417       else
418         terror (_("Can't delete: %s"),  gdbm_strerror (gdbm_errno));
419     }
420 }
421 \f
422 /* fetch KEY - fetch a record by its key */
423 void
424 fetch_handler (struct handler_param *param)
425 {
426   return_data = gdbm_fetch (gdbm_file, param->argv[0]->v.dat);
427   if (return_data.dptr != NULL)
428     {
429       datum_format (param->fp, &return_data, dsdef[DS_CONTENT]);
430       fputc ('\n', param->fp);
431       free (return_data.dptr);
432     }
433   else
434     fprintf (stderr, _("No such item found.\n"));
435 }
436 \f
437 /* store KEY DATA - store data */
438 void
439 store_handler (struct handler_param *param)
440 {
441   if (gdbm_store (gdbm_file,
442                   param->argv[0]->v.dat, param->argv[1]->v.dat,
443                   GDBM_REPLACE) != 0)
444     fprintf (stderr, _("Item not inserted.\n"));
445 }
446 \f
447 /* first - begin iteration */
448
449 void
450 firstkey_handler (struct handler_param *param)
451 {
452   if (key_data.dptr != NULL)
453     free (key_data.dptr);
454   key_data = gdbm_firstkey (gdbm_file);
455   if (key_data.dptr != NULL)
456     {
457       datum_format (param->fp, &key_data, dsdef[DS_KEY]);
458       fputc ('\n', param->fp);
459
460       return_data = gdbm_fetch (gdbm_file, key_data);
461       datum_format (param->fp, &return_data, dsdef[DS_CONTENT]);
462       fputc ('\n', param->fp);
463
464       free (return_data.dptr);
465     }
466   else
467     fprintf (param->fp, _("No such item found.\n"));
468 }
469 \f
470 /* next [KEY] - next key */
471 void
472 nextkey_handler (struct handler_param *param)
473 {
474   if (param->argc == 1)
475     {
476       if (key_data.dptr != NULL)
477         free (key_data.dptr);
478       key_data.dptr = emalloc (param->argv[0]->v.dat.dsize);
479       key_data.dsize = param->argv[0]->v.dat.dsize;
480       memcpy (key_data.dptr, param->argv[0]->v.dat.dptr, key_data.dsize);
481     }
482   return_data = gdbm_nextkey (gdbm_file, key_data);
483   if (return_data.dptr != NULL)
484     {
485       key_data = return_data;
486       datum_format (param->fp, &key_data, dsdef[DS_KEY]);
487       fputc ('\n', param->fp);
488
489       return_data = gdbm_fetch (gdbm_file, key_data);
490       datum_format (param->fp, &return_data, dsdef[DS_CONTENT]);
491       fputc ('\n', param->fp);
492
493       free (return_data.dptr);
494     }
495   else
496     {
497       fprintf (stderr, _("No such item found.\n"));
498       free (key_data.dptr);
499       key_data.dptr = NULL;
500     }
501 }
502 \f
503 /* reorganize */
504 void
505 reorganize_handler (struct handler_param *param ARG_UNUSED)
506 {
507   if (gdbm_reorganize (gdbm_file))
508     fprintf (stderr, _("Reorganization failed.\n"));
509   else
510     fprintf (stderr, _("Reorganization succeeded.\n"));
511 }
512 \f
513 /* avail - print available list */
514 int
515 avail_begin (struct handler_param *param ARG_UNUSED, size_t *exp_count)
516 {
517   if (checkdb ())
518     return 1;
519   if (exp_count)
520     *exp_count = _gdbm_avail_list_size (gdbm_file, SIZE_T_MAX);
521   return 0;
522 }
523
524 void
525 avail_handler (struct handler_param *param)
526 {
527   _gdbm_print_avail_list (param->fp, gdbm_file);
528 }
529 \f
530 /* C - print current bucket */
531 int
532 print_current_bucket_begin (struct handler_param *param ARG_UNUSED,
533                             size_t *exp_count)
534 {
535   if (checkdb ())
536     return 1;
537   
538   if (exp_count)
539     *exp_count = bucket_print_lines (gdbm_file->bucket) + 3;
540   return 0;
541 }
542
543 void
544 print_current_bucket_handler (struct handler_param *param)
545 {
546   print_bucket (param->fp, gdbm_file->bucket, _("Current bucket"));
547   fprintf (param->fp, _("\n current directory entry = %d.\n"),
548            gdbm_file->bucket_dir);
549   fprintf (param->fp, _(" current bucket address  = %lu.\n"),
550            (unsigned long) gdbm_file->cache_entry->ca_adr);
551 }
552 \f
553 int
554 getnum (int *pnum, char *arg, char **endp)
555 {
556   char *p;
557   unsigned long x = strtoul (arg, &p, 10);
558   if (*p && !isspace (*p))
559     {
560       printf (_("not a number (stopped near %s)\n"), p);
561       return 1;
562     }
563   while (*p && isspace (*p))
564     p++;
565   if (endp)
566     *endp = p;
567   else if (*p)
568     {
569       printf (_("not a number (stopped near %s)\n"), p);
570       return 1;
571     }
572   *pnum = x;
573   return 0;
574 }
575 \f  
576 /* bucket NUM - print a bucket and set it as a current one.
577    Uses print_current_bucket_handler */
578 int
579 print_bucket_begin (struct handler_param *param, size_t *exp_count)
580 {
581   int temp;
582
583   if (checkdb ())
584     return 1;
585   
586   if (getnum (&temp, param->argv[0]->v.string, NULL))
587     return 1;
588
589   if (temp >= GDBM_DIR_COUNT (gdbm_file))
590     {
591       fprintf (stderr, _("Not a bucket.\n"));
592       return 1;
593     }
594   _gdbm_get_bucket (gdbm_file, temp);
595   if (exp_count)
596     *exp_count = bucket_print_lines (gdbm_file->bucket) + 3;
597   return 0;
598 }
599
600 \f
601 /* dir - print hash directory */
602 int
603 print_dir_begin (struct handler_param *param ARG_UNUSED, size_t *exp_count)
604 {
605   if (checkdb ())
606     return 1;
607   if (exp_count)
608     *exp_count = GDBM_DIR_COUNT (gdbm_file) + 3;
609   return 0;
610 }
611
612 void
613 print_dir_handler (struct handler_param *param)
614 {
615   int i;
616
617   fprintf (param->fp, _("Hash table directory.\n"));
618   fprintf (param->fp, _("  Size =  %d.  Bits = %d. \n\n"),
619            gdbm_file->header->dir_size, gdbm_file->header->dir_bits);
620   
621   for (i = 0; i < GDBM_DIR_COUNT (gdbm_file); i++)
622     fprintf (param->fp, "  %10d:  %12lu\n",
623              i, (unsigned long) gdbm_file->dir[i]);
624 }
625 \f
626 /* header - print file handler */
627 int
628 print_header_begin (struct handler_param *param ARG_UNUSED, size_t *exp_count)
629 {
630   if (checkdb ())
631     return 1;
632   if (exp_count)
633     *exp_count = 14;
634   return 0;
635 }
636
637 void
638 print_header_handler (struct handler_param *param)
639 {
640   FILE *fp = param->fp;
641   
642   fprintf (fp, _("\nFile Header: \n\n"));
643   fprintf (fp, _("  table        = %lu\n"),
644            (unsigned long) gdbm_file->header->dir);
645   fprintf (fp, _("  table size   = %d\n"), gdbm_file->header->dir_size);
646   fprintf (fp, _("  table bits   = %d\n"), gdbm_file->header->dir_bits);
647   fprintf (fp, _("  block size   = %d\n"), gdbm_file->header->block_size);
648   fprintf (fp, _("  bucket elems = %d\n"), gdbm_file->header->bucket_elems);
649   fprintf (fp, _("  bucket size  = %d\n"), gdbm_file->header->bucket_size);
650   fprintf (fp, _("  header magic = %x\n"), gdbm_file->header->header_magic);
651   fprintf (fp, _("  next block   = %lu\n"),
652            (unsigned long) gdbm_file->header->next_block);
653   fprintf (fp, _("  avail size   = %d\n"), gdbm_file->header->avail.size);
654   fprintf (fp, _("  avail count  = %d\n"), gdbm_file->header->avail.count);
655   fprintf (fp, _("  avail nx blk = %lu\n"),
656            (unsigned long) gdbm_file->header->avail.next_block);
657 }  
658 \f
659 /* hash KEY - hash the key */
660 void
661 hash_handler (struct handler_param *param)
662 {
663   fprintf (param->fp, _("hash value = %x. \n"),
664            _gdbm_hash (param->argv[0]->v.dat));
665 }
666 \f
667 /* cache - print the bucket cache */
668 int
669 print_cache_begin (struct handler_param *param ARG_UNUSED, size_t *exp_count)
670 {
671   if (checkdb ())
672     return 1;
673   if (exp_count)
674     *exp_count = gdbm_file->bucket_cache ? gdbm_file->cache_size + 1 : 1;
675   return 0;
676 }
677     
678 void
679 print_cache_handler (struct handler_param *param)
680 {
681   _gdbm_print_bucket_cache (param->fp, gdbm_file);
682 }
683 \f
684 /* version - print GDBM version */
685 void
686 print_version_handler (struct handler_param *param)
687 {
688   fprintf (param->fp, "%s\n", gdbm_version);
689 }
690 \f
691 /* list - List all entries */
692 int
693 list_begin (struct handler_param *param ARG_UNUSED, size_t *exp_count)
694 {
695   if (checkdb ())
696     return 1;
697   if (exp_count)
698     {
699       gdbm_count_t count;
700       
701       if (gdbm_count (gdbm_file, &count))
702         *exp_count = 0;
703       else if (count > SIZE_T_MAX)
704         *exp_count = SIZE_T_MAX;
705       else
706         *exp_count = count;
707     }
708
709   return 0;
710 }
711
712 void
713 list_handler (struct handler_param *param)
714 {
715   datum key;
716   datum data;
717
718   key = gdbm_firstkey (gdbm_file);
719   while (key.dptr)
720     {
721       datum nextkey = gdbm_nextkey (gdbm_file, key);
722
723       data = gdbm_fetch (gdbm_file, key);
724       if (!data.dptr)
725         {
726           terror (_("cannot fetch data; the key was:"));
727           datum_format (stderr, &key, dsdef[DS_KEY]);
728         }
729       else
730         {
731           datum_format (param->fp, &key, dsdef[DS_KEY]);
732           fputc (' ', param->fp);
733           datum_format (param->fp, &data, dsdef[DS_CONTENT]);
734           fputc ('\n', param->fp);
735           free (data.dptr);
736         }
737       free (key.dptr);
738       key = nextkey;
739     }
740 }
741 \f
742 /* quit - quit the program */
743 void
744 quit_handler (struct handler_param *param ARG_UNUSED)
745 {
746   if (gdbm_file != NULL)
747     gdbm_close (gdbm_file);
748
749   exit (EXIT_OK);
750 }
751 \f
752 /* export FILE [truncate] - export to a flat file format */
753 void
754 export_handler (struct handler_param *param)
755 {
756   int format = GDBM_DUMP_FMT_ASCII;
757   int flags = GDBM_WRCREAT;
758   int i;
759   int filemode;
760   
761   for (i = 1; i < param->argc; i++)
762     {
763       if (strcmp (param->argv[i]->v.string, "truncate") == 0)
764         flags = GDBM_NEWDB;
765       else if (strcmp (param->argv[i]->v.string, "binary") == 0)
766         format = GDBM_DUMP_FMT_BINARY;
767       else if (strcmp (param->argv[i]->v.string, "ascii") == 0)
768         format = GDBM_DUMP_FMT_ASCII;
769       else
770         {
771           terror (_("unrecognized argument: %s"),
772                         param->argv[i]->v.string);
773           return;
774         }
775     }
776
777   if (variable_get ("filemode", VART_INT, (void**) &filemode))
778     abort ();
779   if (gdbm_dump (gdbm_file, param->argv[0]->v.string, format, flags, filemode))
780     {
781       terror (_("error dumping database: %s"),
782                     gdbm_strerror (gdbm_errno));
783     }
784 }
785 \f
786 /* import FILE [replace] [nometa] - import from a flat file */
787 void
788 import_handler (struct handler_param *param)
789 {
790   int flag = GDBM_INSERT;
791   unsigned long err_line;
792   int meta_mask = 0;
793   int i;
794   int rc;
795   
796   for (i = 1; i < param->argc; i++)
797     {
798       if (strcmp (param->argv[i]->v.string, "replace") == 0)
799         flag = GDBM_REPLACE;
800       else if (strcmp (param->argv[i]->v.string, "nometa") == 0)
801         meta_mask = GDBM_META_MASK_MODE | GDBM_META_MASK_OWNER;
802       else
803         {
804           terror (_("unrecognized argument: %s"),
805                         param->argv[i]->v.string);
806           return;
807         }
808     }
809
810   rc = gdbm_load (&gdbm_file, param->argv[0]->v.string, flag,
811                   meta_mask, &err_line);
812   if (rc && gdbm_errno == GDBM_NO_DBNAME)
813     {
814       int t = open_mode;
815
816       open_mode = GDBM_NEWDB;
817       rc = checkdb ();
818       open_mode = t;
819
820       if (rc)
821         return;
822
823       rc = gdbm_load (&gdbm_file, param->argv[0]->v.string, flag,
824                       meta_mask, &err_line);
825     }
826   if (rc)
827     {
828       switch (gdbm_errno)
829         {
830         case GDBM_ERR_FILE_OWNER:
831         case GDBM_ERR_FILE_MODE:
832           terror (_("error restoring metadata: %s (%s)"),
833                         gdbm_strerror (gdbm_errno), strerror (errno));
834           break;
835           
836         default:
837           if (err_line)
838             terror ("%s:%lu: %s", param->argv[0], err_line,
839                           gdbm_strerror (gdbm_errno));
840           else
841             terror (_("cannot load from %s: %s"), param->argv[0],
842                           gdbm_strerror (gdbm_errno));
843         }
844       return;
845     }
846
847   free (file_name);
848   if (gdbm_setopt (gdbm_file, GDBM_GETDBNAME, &file_name, sizeof (file_name)))
849     terror (_("gdbm_setopt failed: %s"), gdbm_strerror (gdbm_errno));
850 }
851 \f
852 /* status - print current program status */
853 void
854 status_handler (struct handler_param *param)
855 {
856   if (file_name)
857     fprintf (param->fp, _("Database file: %s\n"), file_name);
858   else
859     fprintf (param->fp, "%s\n", _("No database name"));
860   if (gdbm_file)
861     fprintf (param->fp, "%s\n", _("Database is open"));
862   else
863     fprintf (param->fp, "%s\n", _("Database is not open"));
864   dsprint (param->fp, DS_KEY, dsdef[DS_KEY]);
865   dsprint (param->fp, DS_CONTENT, dsdef[DS_CONTENT]);
866 }
867 \f
868 void
869 source_handler (struct handler_param *param)
870 {
871   char *fname = tildexpand (param->argv[0]->v.string);
872   if (setsource (fname, 0) == 0)
873     yyparse ();
874   free (fname);
875 }
876
877 \f
878 void help_handler (struct handler_param *param);
879 int help_begin (struct handler_param *param, size_t *exp_count);
880
881 struct argdef
882 {
883   char *name;
884   int type;
885   int ds;
886 };
887
888 struct command
889 {
890   char *name;           /* Command name */
891   size_t len;           /* Name length */
892   int tok;
893   int  (*begin) (struct handler_param *param, size_t *);
894   void (*handler) (struct handler_param *param);
895   void (*end) (void *data);
896   struct argdef args[NARGS];
897   char *doc;
898 };
899
900 \f
901 struct command command_tab[] = {
902 #define S(s) #s, sizeof (#s) - 1
903   { S(count), T_CMD,
904     checkdb, count_handler, NULL,
905     { { NULL } }, N_("count (number of entries)") },
906   { S(delete), T_CMD,
907     checkdb, delete_handler, NULL,
908     { { N_("KEY"), ARG_DATUM, DS_KEY }, { NULL } }, N_("delete a record") },
909   { S(export), T_CMD,
910     checkdb, export_handler, NULL,
911     { { N_("FILE"), ARG_STRING },
912       { "[truncate]", ARG_STRING },
913       { "[binary|ascii]", ARG_STRING },
914       { NULL } },
915     N_("export") },
916   { S(fetch), T_CMD,
917     checkdb, fetch_handler, NULL,
918     { { N_("KEY"), ARG_DATUM, DS_KEY }, { NULL } },  N_("fetch record") },
919   { S(import), T_CMD,
920     NULL, import_handler, NULL,
921     { { N_("FILE"), ARG_STRING },
922       { "[replace]", ARG_STRING },
923       { "[nometa]" , ARG_STRING },
924       { NULL } },
925     N_("import") },
926   { S(list), T_CMD,
927     list_begin, list_handler, NULL,
928     { { NULL } }, N_("list") },
929   { S(next), T_CMD,
930     checkdb, nextkey_handler, NULL,
931     { { N_("[KEY]"), ARG_STRING },
932       { NULL } },
933     N_("nextkey") },
934   { S(store), T_CMD,
935     checkdb, store_handler, NULL,
936     { { N_("KEY"), ARG_DATUM, DS_KEY },
937       { N_("DATA"), ARG_DATUM, DS_CONTENT },
938       { NULL } },
939     N_("store") },
940   { S(first), T_CMD,
941     checkdb, firstkey_handler, NULL,
942     { { NULL } }, N_("firstkey") },
943   { S(reorganize), T_CMD,
944     checkdb, reorganize_handler, NULL,
945     { { NULL } }, N_("reorganize") },
946   { S(avail), T_CMD,
947     avail_begin, avail_handler, NULL,
948     { { NULL } }, N_("print avail list") }, 
949   { S(bucket), T_CMD,
950     print_bucket_begin, print_current_bucket_handler, NULL,
951     { { N_("NUMBER"), ARG_STRING },
952       { NULL } }, N_("print a bucket") },
953   { S(current), T_CMD,
954     print_current_bucket_begin, print_current_bucket_handler, NULL,
955     { { NULL } },
956     N_("print current bucket") },
957   { S(dir), T_CMD,
958     print_dir_begin, print_dir_handler, NULL,
959     { { NULL } }, N_("print hash directory") },
960   { S(header), T_CMD,
961     print_header_begin , print_header_handler, NULL,
962     { { NULL } }, N_("print database file header") },
963   { S(hash), T_CMD,
964     NULL, hash_handler, NULL,
965     { { N_("KEY"), ARG_DATUM, DS_KEY },
966       { NULL } }, N_("hash value of key") },
967   { S(cache), T_CMD,
968     print_cache_begin, print_cache_handler, NULL,
969     { { NULL } }, N_("print the bucket cache") },
970   { S(status), T_CMD,
971     NULL, status_handler, NULL,
972     { { NULL } }, N_("print current program status") },
973   { S(version), T_CMD,
974     NULL, print_version_handler, NULL,
975     { { NULL } }, N_("print version of gdbm") },
976   { S(help), T_CMD,
977     help_begin, help_handler, NULL,
978     { { NULL } }, N_("print this help list") },
979   { S(quit), T_CMD,
980     NULL, quit_handler, NULL,
981     { { NULL } }, N_("quit the program") },
982   { S(set), T_SET,
983     NULL, NULL, NULL,
984     { { "[VAR=VALUE...]" }, { NULL } }, N_("set or list variables") },
985   { S(unset), T_UNSET,
986     NULL, NULL, NULL,
987     { { "VAR..." }, { NULL } }, N_("unset variables") },
988   { S(define), T_DEF,
989     NULL, NULL, NULL,
990     { { "key|content", ARG_STRING },
991       { "{ FIELD-LIST }", ARG_STRING },
992       { NULL } }, N_("define datum structure") },
993   { S(source), T_CMD,
994     NULL, source_handler, NULL,
995     { { "FILE", ARG_STRING },
996       { NULL } }, N_("source command script") },
997   { S(close), T_CMD,
998     NULL, close_handler, NULL,
999     { { NULL } }, N_("close the database") },
1000   { S(open), T_CMD,
1001     NULL, open_handler, NULL,
1002     { { "FILE", ARG_STRING }, { NULL } },
1003     N_("open new database") },
1004 #undef S
1005   { 0 }
1006 };
1007 \f
1008 static int
1009 cmdcmp (const void *a, const void *b)
1010 {
1011   struct command const *ac = a;
1012   struct command const *bc = b;
1013   return strcmp (ac->name, bc->name);
1014 }
1015
1016 void
1017 sort_commands ()
1018 {
1019   qsort (command_tab, sizeof (command_tab) / sizeof (command_tab[0]) - 1,
1020          sizeof (command_tab[0]), cmdcmp);
1021 }
1022
1023 \f
1024 /* ? - help handler */
1025 #define CMDCOLS 30
1026
1027 int
1028 help_begin (struct handler_param *param ARG_UNUSED, size_t *exp_count)
1029 {
1030   if (exp_count)
1031     *exp_count = sizeof (command_tab) / sizeof (command_tab[0]) + 1;
1032   return 0;
1033 }
1034
1035 void
1036 help_handler (struct handler_param *param)
1037 {
1038   struct command *cmd;
1039   FILE *fp = param->fp;
1040   
1041   for (cmd = command_tab; cmd->name; cmd++)
1042     {
1043       int i;
1044       int n;
1045
1046       n = fprintf (fp, " %s", cmd->name);
1047
1048       for (i = 0; i < NARGS && cmd->args[i].name; i++)
1049         n += fprintf (fp, " %s", gettext (cmd->args[i].name));
1050
1051       if (n < CMDCOLS)
1052         fprintf (fp, "%*.s", CMDCOLS-n, "");
1053       fprintf (fp, " %s", gettext (cmd->doc));
1054       fputc ('\n', fp);
1055     }
1056 }
1057 \f
1058 int
1059 command_lookup (const char *str, struct locus *loc, struct command **pcmd)
1060 {
1061   enum { fcom_init, fcom_found, fcom_ambig, fcom_abort } state = fcom_init;
1062   struct command *cmd, *found = NULL;
1063   size_t len = strlen (str);
1064   
1065   for (cmd = command_tab; state != fcom_abort && cmd->name; cmd++)
1066     {
1067       if (memcmp (cmd->name, str, len < cmd->len ? len : cmd->len) == 0)
1068         {
1069           switch (state)
1070             {
1071             case fcom_init:
1072               found = cmd;
1073               state = fcom_found;
1074               break;
1075
1076             case fcom_found:
1077               if (!interactive)
1078                 {
1079                   state = fcom_abort;
1080                   found = NULL;
1081                   continue;
1082                 }
1083               fprintf (stderr, "ambiguous command: %s\n", str);
1084               fprintf (stderr, "    %s\n", found->name);
1085               found = NULL;
1086               state = fcom_ambig;
1087               /* fall through */
1088             case fcom_ambig:
1089               fprintf (stderr, "    %s\n", cmd->name);
1090               break;
1091               
1092             case fcom_abort:
1093               /* should not happen */
1094               abort ();
1095             }
1096         }
1097     }
1098
1099   if (state == fcom_init)
1100     lerror (loc,
1101                  interactive ? _("Invalid command. Try ? for help.") :
1102                                _("Unknown command"));
1103   if (!found)
1104     return T_BOGUS;
1105
1106   *pcmd = found;
1107   return found->tok;
1108 }
1109 \f
1110 char *parseopt_program_doc = N_("examine and/or modify a GDBM database");
1111 char *parseopt_program_args = N_("DBFILE");
1112
1113 struct gdbm_option optab[] = {
1114   { 'b', "block-size", N_("SIZE"), N_("set block size") },
1115   { 'c', "cache-size", N_("SIZE"), N_("set cache size") },
1116   { 'f', "file",       N_("FILE"), N_("read commands from FILE") },
1117   { 'g', NULL, "FILE", NULL, PARSEOPT_HIDDEN },
1118   { 'l', "no-lock",    NULL,       N_("disable file locking") },
1119   { 'm', "no-mmap",    NULL,       N_("do not use mmap") },
1120   { 'n', "newdb",      NULL,       N_("create database") },
1121   { 'N', "norc",       NULL,       N_("do not read .gdbmtoolrc file") },
1122   { 'r', "read-only",  NULL,       N_("open database in read-only mode") },
1123   { 's', "synchronize", NULL,      N_("synchronize to disk after each write") },
1124   { 'q', "quiet",      NULL,       N_("don't print initial banner") },
1125   { 0 }
1126 };
1127
1128 #define ARGINC 16
1129
1130 \f
1131 struct gdbmarg *
1132 gdbmarg_string (char *string, struct locus *loc)
1133 {
1134   struct gdbmarg *arg = ecalloc (1, sizeof (*arg));
1135   arg->next = NULL;
1136   arg->type = ARG_STRING;
1137   arg->ref = 1;
1138   if (loc)
1139     arg->loc = *loc;
1140   arg->v.string = string;
1141   return arg;
1142 }
1143
1144 struct gdbmarg *
1145 gdbmarg_datum (datum *dat, struct locus *loc)
1146 {
1147   struct gdbmarg *arg = ecalloc (1, sizeof (*arg));
1148   arg->next = NULL;
1149   arg->type = ARG_DATUM;
1150   arg->ref = 1;
1151   if (loc)
1152     arg->loc = *loc;
1153   arg->v.dat = *dat;
1154   return arg;
1155 }
1156
1157 struct gdbmarg *
1158 gdbmarg_kvpair (struct kvpair *kvp, struct locus *loc)
1159 {
1160   struct gdbmarg *arg = ecalloc (1, sizeof (*arg));
1161   arg->next = NULL;
1162   arg->type = ARG_KVPAIR;
1163   arg->ref = 1;
1164   if (loc)
1165     arg->loc = *loc;
1166   arg->v.kvpair = kvp;
1167   return arg;
1168 }
1169 \f
1170 struct slist *
1171 slist_new (char *s)
1172 {
1173   struct slist *lp = emalloc (sizeof (*lp));
1174   lp->next = NULL;
1175   lp->str = s;
1176   return lp;
1177 }
1178
1179 void
1180 slist_free (struct slist *lp)
1181 {
1182   while (lp)
1183     {
1184       struct slist *next = lp->next;
1185       free (lp->str);
1186       free (lp);
1187       lp = next;
1188     }
1189 }
1190 \f
1191 struct kvpair *
1192 kvpair_string (struct locus *loc, char *val)
1193 {
1194   struct kvpair *p = ecalloc (1, sizeof (*p));
1195   p->type = KV_STRING;
1196   if (loc)
1197     p->loc = *loc;
1198   p->val.s = val;
1199   return p;
1200 }
1201
1202 struct kvpair *
1203 kvpair_list (struct locus *loc, struct slist *s)
1204 {
1205   struct kvpair *p = ecalloc (1, sizeof (*p));
1206   p->type = KV_LIST;
1207   if (loc)
1208     p->loc = *loc;
1209   p->val.l = s;
1210   return p;
1211 }  
1212
1213
1214 static void
1215 kvlist_free (struct kvpair *kvp)
1216 {
1217   while (kvp)
1218     {
1219       struct kvpair *next = kvp->next;
1220       free (kvp->key);
1221       switch (kvp->type)
1222         {
1223         case KV_STRING:
1224           free (kvp->val.s);
1225           break;
1226
1227         case KV_LIST:
1228           slist_free (kvp->val.l);
1229           break;
1230         }
1231       free (kvp);
1232       kvp = next;
1233     }
1234 }
1235
1236 int
1237 gdbmarg_free (struct gdbmarg *arg)
1238 {
1239   if (arg && --arg->ref == 0)
1240     {
1241       switch (arg->type)
1242         {
1243         case ARG_STRING:
1244           free (arg->v.string);
1245           break;
1246
1247         case ARG_KVPAIR:
1248           kvlist_free (arg->v.kvpair);
1249           break;
1250
1251         case ARG_DATUM:
1252           free (arg->v.dat.dptr);
1253           break;
1254         }
1255       free (arg);
1256       return 0;
1257     }
1258   return 1;
1259 }
1260
1261 void
1262 gdbmarg_destroy (struct gdbmarg **parg)
1263 {
1264   if (parg && gdbmarg_free (*parg))
1265     *parg = NULL;
1266 }
1267 \f
1268 void
1269 gdbmarglist_init (struct gdbmarglist *lst, struct gdbmarg *arg)
1270 {
1271   if (arg)
1272     arg->next = NULL;
1273   lst->head = lst->tail = arg;
1274 }
1275
1276 void
1277 gdbmarglist_add (struct gdbmarglist *lst, struct gdbmarg *arg)
1278 {
1279   arg->next = NULL;
1280   if (lst->tail)
1281     lst->tail->next = arg;
1282   else
1283     lst->head = arg;
1284   lst->tail = arg;
1285 }
1286
1287 void
1288 gdbmarglist_free (struct gdbmarglist *lst)
1289 {
1290   struct gdbmarg *arg;
1291
1292   for (arg = lst->head; arg; )
1293     {
1294       struct gdbmarg *next = arg->next;
1295       gdbmarg_free (arg);
1296       arg = next;
1297     }
1298 }
1299 \f
1300 struct handler_param param;
1301 size_t argmax;
1302
1303 void
1304 param_free_argv (struct handler_param *param, int n)
1305 {
1306   int i;
1307
1308   for (i = 0; i < n; i++)
1309     gdbmarg_destroy (&param->argv[i]);
1310   param->argc = 0;
1311 }
1312 \f
1313 typedef struct gdbmarg *(*coerce_type_t) (struct gdbmarg *arg,
1314                                           struct argdef *def);
1315
1316 struct gdbmarg *
1317 coerce_ref (struct gdbmarg *arg, struct argdef *def)
1318 {
1319   ++arg->ref;
1320   return arg;
1321 }
1322
1323 struct gdbmarg *
1324 coerce_k2d (struct gdbmarg *arg, struct argdef *def)
1325 {
1326   datum d;
1327   
1328   if (datum_scan (&d, dsdef[def->ds], arg->v.kvpair))
1329     return NULL;
1330   return gdbmarg_datum (&d, &arg->loc);
1331 }
1332
1333 struct gdbmarg *
1334 coerce_s2d (struct gdbmarg *arg, struct argdef *def)
1335 {
1336   datum d;
1337   struct kvpair kvp;
1338
1339   memset (&kvp, 0, sizeof (kvp));
1340   kvp.type = KV_STRING;
1341   kvp.val.s = arg->v.string;
1342   
1343   if (datum_scan (&d, dsdef[def->ds], &kvp))
1344     return NULL;
1345   return gdbmarg_datum (&d, &arg->loc);
1346 }
1347
1348 #define coerce_fail NULL
1349
1350 coerce_type_t coerce_tab[ARG_MAX][ARG_MAX] = {
1351   /*             s            d            k */
1352   /* s */  { coerce_ref,  coerce_fail, coerce_fail },
1353   /* d */  { coerce_s2d,  coerce_ref,  coerce_k2d }, 
1354   /* k */  { coerce_fail, coerce_fail, coerce_ref }
1355 };
1356
1357 char *argtypestr[] = { "string", "datum", "k/v pair" };
1358   
1359 struct gdbmarg *
1360 coerce (struct gdbmarg *arg, struct argdef *def)
1361 {
1362   if (!coerce_tab[def->type][arg->type])
1363     {
1364       lerror (&arg->loc, _("cannot coerce %s to %s"),
1365                     argtypestr[arg->type], argtypestr[def->type]);
1366       return NULL;
1367     }
1368   return coerce_tab[def->type][arg->type] (arg, def);
1369 }
1370 \f
1371 int
1372 run_command (struct command *cmd, struct gdbmarglist *arglist)
1373 {
1374   int i;
1375   struct gdbmarg *arg;
1376   char *pager = NULL;
1377   char argbuf[128];
1378   size_t expected_lines, *expected_lines_ptr;
1379   FILE *pagfp = NULL;
1380
1381   variable_get ("pager", VART_STRING, (void**) &pager);
1382   
1383   arg = arglist ? arglist->head : NULL;
1384
1385   for (i = 0; cmd->args[i].name && arg; i++, arg = arg->next)
1386     {
1387       if (i >= argmax)
1388         {
1389           argmax += ARGINC;
1390           param.argv = erealloc (param.argv,
1391                                  sizeof (param.argv[0]) * argmax);
1392         }
1393       if ((param.argv[i] = coerce (arg, &cmd->args[i])) == NULL)
1394         {
1395           param_free_argv (&param, i);
1396           return 1;
1397         }
1398     }
1399
1400   for (; cmd->args[i].name; i++)
1401     {
1402       char *argname = cmd->args[i].name;
1403       struct gdbmarg *t;
1404       
1405       if (*argname == '[')
1406         /* Optional argument */
1407         break;
1408
1409       if (!interactive)
1410         {
1411           terror (_("%s: not enough arguments"), cmd->name);
1412           return 1;
1413         }
1414       printf ("%s? ", argname);
1415       fflush (stdout);
1416       if (fgets (argbuf, sizeof argbuf, stdin) == NULL)
1417         {
1418           terror (_("unexpected eof"));
1419           exit (EXIT_USAGE);
1420         }
1421
1422       trimnl (argbuf);
1423       if (i >= argmax)
1424         {
1425           argmax += ARGINC;
1426           param.argv = erealloc (param.argv,
1427                                  sizeof (param.argv[0]) * argmax);
1428         }
1429
1430       t = gdbmarg_string (estrdup (argbuf), &yylloc);
1431       if ((param.argv[i] = coerce (t, &cmd->args[i])) == NULL)
1432         {
1433           gdbmarg_free (t);
1434           param_free_argv (&param, i);
1435           return 1;
1436         }
1437     }
1438
1439   if (arg)
1440     {
1441       terror (_("%s: too many arguments"), cmd->name);
1442       return 1;
1443     }
1444
1445   /* Prepare for calling the handler */
1446   param.argc = i;
1447   if (!param.argv)
1448     {
1449       argmax = ARGINC;
1450       param.argv = ecalloc (argmax, sizeof (param.argv[0]));
1451     }
1452   param.argv[i] = NULL;
1453   param.fp = NULL;
1454   param.data = NULL;
1455   pagfp = NULL;
1456       
1457   expected_lines = 0;
1458   expected_lines_ptr = (interactive && pager) ? &expected_lines : NULL;
1459   if (!(cmd->begin && cmd->begin (&param, expected_lines_ptr)))
1460     {
1461       if (pager && expected_lines > get_screen_lines ())
1462         {
1463           pagfp = popen (pager, "w");
1464           if (pagfp)
1465             param.fp = pagfp;
1466           else
1467             {
1468               terror (_("cannot run pager `%s': %s"), pager,
1469                             strerror (errno));
1470               pager = NULL;
1471               param.fp = stdout;
1472             }     
1473         }
1474       else
1475         param.fp = stdout;
1476   
1477       cmd->handler (&param);
1478       if (cmd->end)
1479         cmd->end (param.data);
1480       else if (param.data)
1481         free (param.data);
1482
1483       if (pagfp)
1484         pclose (pagfp);
1485     }
1486
1487   param_free_argv (&param, param.argc);
1488   
1489   return 0;
1490 }
1491
1492 static void
1493 source_rcfile ()
1494 {
1495   if (access (GDBMTOOLRC, R_OK) == 0)
1496     {
1497       if (setsource (GDBMTOOLRC, 0) == 0)
1498         yyparse ();
1499     }
1500   else
1501     {
1502       char *fname;
1503       char *p = getenv ("HOME");
1504       if (!p)
1505         {
1506           struct passwd *pw = getpwuid (getuid ());
1507           if (!pw)
1508             {
1509               terror (_("cannot find home directory"));
1510               return;
1511             }
1512           p = pw->pw_dir;
1513         }
1514       fname = mkfilename (p, GDBMTOOLRC, NULL);
1515       if (access (fname, R_OK) == 0)
1516         {
1517           if (setsource (fname, 0) == 0)
1518             yyparse ();
1519         }
1520       free (fname);
1521     }
1522 }
1523
1524 int
1525 main (int argc, char *argv[])
1526 {
1527   int intr;  
1528   int opt;
1529   int bv;
1530   int norc = 0;
1531   char *source = "-";
1532   
1533   set_progname (argv[0]);
1534
1535 #ifdef HAVE_SETLOCALE
1536   setlocale (LC_ALL, "");
1537 #endif
1538   bindtextdomain (PACKAGE, LOCALEDIR);
1539   textdomain (PACKAGE);
1540
1541   sort_commands ();
1542
1543   /* Initialize variables. */
1544   intr = isatty (0);
1545   dsdef[DS_KEY] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
1546   dsdef[DS_CONTENT] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
1547
1548   variable_set ("open", VART_STRING, "wrcreat");
1549   variable_set ("pager", VART_STRING, getenv ("PAGER"));
1550   
1551   for (opt = parseopt_first (argc, argv, optab);
1552        opt != EOF;
1553        opt = parseopt_next ())
1554     switch (opt)
1555       {
1556       case 'f':
1557         source = optarg;
1558         intr = 0;
1559         break;
1560         
1561       case 'l':
1562         bv = 0;
1563         variable_set ("lock", VART_BOOL, &bv);
1564         break;
1565
1566       case 'm':
1567         bv = 0;
1568         variable_set ("mmap", VART_BOOL, &bv);
1569         break;
1570
1571       case 's':
1572         bv = 1;
1573         variable_set ("sync", VART_BOOL, &bv);
1574         break;
1575         
1576       case 'r':
1577         variable_set ("open", VART_STRING, "readonly");
1578         break;
1579         
1580       case 'n':
1581         variable_set ("open", VART_STRING, "newdb");
1582         break;
1583
1584       case 'N':
1585         norc = 1;
1586         break;
1587         
1588       case 'c':
1589         variable_set ("cachesize", VART_STRING, optarg);
1590         break;
1591         
1592       case 'b':
1593         variable_set ("blocksize", VART_STRING, optarg);
1594         break;
1595         
1596       case 'g':
1597         file_name = optarg;
1598         break;
1599
1600       case 'q':
1601         bv = 1;
1602         variable_set ("quiet", VART_BOOL, &bv);
1603         break;
1604         
1605       default:
1606         terror (_("unknown option; try `%s -h' for more info"),
1607                 progname);
1608         exit (EXIT_USAGE);
1609       }
1610   
1611   argc -= optind;
1612   argv += optind;
1613
1614   if (argc > 1)
1615     {
1616       terror (_("too many arguments"));
1617       exit (EXIT_USAGE);
1618     }
1619       
1620   if (argc == 1)
1621     file_name = argv[0];
1622
1623   signal (SIGPIPE, SIG_IGN);
1624
1625   memset (&param, 0, sizeof (param));
1626   argmax = 0;
1627
1628   if (!norc)
1629     source_rcfile ();     
1630   
1631   /* Welcome message. */
1632   if (intr && !variable_is_true ("quiet"))
1633     printf (_("\nWelcome to the gdbm tool.  Type ? for help.\n\n"));
1634
1635   if (setsource (source, intr))
1636     exit (EXIT_FATAL);
1637   return yyparse ();
1638 }