1/* testgdbm.c - Driver program to test the database routines and to 2 help debug gdbm. Uses inside information to show "system" information */ 3 4/* This file is part of GDBM, the GNU data base manager, by Philip A. Nelson. 5 Copyright (C) 1990, 1991, 1993 Free Software Foundation, Inc. 6 7 GDBM is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2, or (at your option) 10 any later version. 11 12 GDBM is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GDBM; see the file COPYING. If not, write to 19 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 20 21 You may contact the author by: 22 e-mail: phil@cs.wwu.edu 23 us-mail: Philip A. Nelson 24 Computer Science Department 25 Western Washington University 26 Bellingham, WA 98226 27 28*************************************************************************/ 29 30 31/* include system configuration before all else. */ 32#include "autoconf.h" 33 34#include "gdbmdefs.h" 35#include "gdbmerrno.h" 36#include "extern.h" 37 38#include "getopt.h" 39 40extern const char * gdbm_version; 41 42extern const char *gdbm_strerror __P((gdbm_error)); 43 44gdbm_file_info *gdbm_file; 45 46/* Debug procedure to print the contents of the current hash bucket. */ 47void 48print_bucket (bucket, mesg) 49 hash_bucket *bucket; 50 char *mesg; 51{ 52 int index; 53 54 printf ("******* %s **********\n\nbits = %d\ncount= %d\nHash Table:\n", 55 mesg, bucket->bucket_bits, bucket->count); 56 printf (" # hash value key size data size data adr home\n"); 57 for (index = 0; index < gdbm_file->header->bucket_elems; index++) 58 printf (" %4d %12x %11d %11d %11d %5d\n", index, 59 bucket->h_table[index].hash_value, 60 bucket->h_table[index].key_size, 61 bucket->h_table[index].data_size, 62 bucket->h_table[index].data_pointer, 63 bucket->h_table[index].hash_value % gdbm_file->header->bucket_elems); 64 65 printf ("\nAvail count = %1d\n", bucket->av_count); 66 printf ("Avail adr size\n"); 67 for (index = 0; index < bucket->av_count; index++) 68 printf ("%9d%9d\n", bucket->bucket_avail[index].av_adr, 69 bucket->bucket_avail[index].av_size); 70} 71 72 73void 74_gdbm_print_avail_list (dbf) 75 gdbm_file_info *dbf; 76{ 77 int temp; 78 int size; 79 avail_block *av_stk; 80 81 /* Print the the header avail block. */ 82 printf ("\nheader block\nsize = %d\ncount = %d\n", 83 dbf->header->avail.size, dbf->header->avail.count); 84 for (temp = 0; temp < dbf->header->avail.count; temp++) 85 { 86 printf (" %15d %10d \n", dbf->header->avail.av_table[temp].av_size, 87 dbf->header->avail.av_table[temp].av_adr); 88 } 89 90 /* Initialize the variables for a pass throught the avail stack. */ 91 temp = dbf->header->avail.next_block; 92 size = ( ( (dbf->header->avail.size * sizeof (avail_elem)) >> 1) 93 + sizeof (avail_block)); 94 av_stk = (avail_block *) malloc (size); 95 if (av_stk == NULL) 96 { 97 printf("Out of memory\n"); 98 exit (2); 99 } 100 101 /* Print the stack. */ 102 while (FALSE) 103 { 104 lseek (dbf->desc, temp, L_SET); 105 read (dbf->desc, av_stk, size); 106 107 /* Print the block! */ 108 printf ("\nblock = %d\nsize = %d\ncount = %d\n", temp, 109 av_stk->size, av_stk->count); 110 for (temp = 0; temp < av_stk->count; temp++) 111 { 112 printf (" %15d %10d \n", av_stk->av_table[temp].av_size, 113 av_stk->av_table[temp].av_adr); 114 } 115 temp = av_stk->next_block; 116 } 117} 118 119void 120_gdbm_print_bucket_cache (dbf) 121 gdbm_file_info *dbf; 122{ 123 register int index; 124 char changed; 125 126 if (dbf->bucket_cache != NULL) { 127 printf( 128 "Bucket Cache (size %d):\n Index: Address Changed Data_Hash \n", 129 dbf->cache_size); 130 for (index=0; index < dbf->cache_size; index++) { 131 changed = dbf->bucket_cache[index].ca_changed; 132 printf (" %5d: %7d %7s %x\n", 133 index, 134 dbf->bucket_cache[index].ca_adr, 135 (changed ? "True" : "False"), 136 dbf->bucket_cache[index].ca_data.hash_val); 137 } 138 } else 139 printf("Bucket cache has not been initialized.\n"); 140} 141 142void 143usage (s) 144 char *s; 145{ 146 printf( 147 "Usage: %s [-r or -ns] [-b block-size] [-c cache-size] [-g gdbm-file]\n", 148 s); 149 exit (2); 150} 151 152 153/* The test program allows one to call all the routines plus the hash function. 154 The commands are single letter commands. The user is prompted for all other 155 information. See the help command (?) for a list of all commands. */ 156 157int 158main (argc, argv) 159 int argc; 160 char *argv[]; 161 162{ 163 164 char cmd_ch; 165 166 datum key_data; 167 datum data_data; 168 datum return_data; 169 170 char key_line[500]; 171 char data_line[1000]; 172 173 char done = FALSE; 174 int opt; 175 char reader = FALSE; 176 char newdb = FALSE; 177 int fast = 0; 178 179 int cache_size = DEFAULT_CACHESIZE; 180 int block_size = 0; 181 182 char *file_name = NULL; 183 184 185 /* Argument checking. */ 186 opterr = 0; 187 while ((opt = getopt (argc, argv, "srnc:b:g:")) != -1) 188 switch (opt) { 189 case 's': fast = GDBM_SYNC; 190 if (reader) usage (argv[0]); 191 break; 192 case 'r': reader = TRUE; 193 if (newdb) usage (argv[0]); 194 break; 195 case 'n': newdb = TRUE; 196 if (reader) usage (argv[0]); 197 break; 198 case 'c': cache_size = atoi(optarg); 199 break; 200 case 'b': block_size = atoi(optarg); 201 break; 202 case 'g': file_name = optarg; 203 break; 204 default: usage(argv[0]); 205 } 206 207 if(file_name == NULL) 208 file_name = "junk.gdbm"; 209 210 /* Initialize variables. */ 211 key_data.dptr = NULL; 212 data_data.dptr = data_line; 213 214 if (reader) 215 { 216 gdbm_file = gdbm_open (file_name, block_size, GDBM_READER, 00664, NULL); 217 } 218 else if (newdb) 219 { 220 gdbm_file = 221 gdbm_open (file_name, block_size, GDBM_NEWDB | fast, 00664, NULL); 222 } 223 else 224 { 225 gdbm_file = 226 gdbm_open (file_name, block_size, GDBM_WRCREAT | fast, 00664, NULL); 227 } 228 if (gdbm_file == NULL) 229 { 230 printf("gdbm_open failed, %s\n", gdbm_strerror(gdbm_errno)); 231 exit (2); 232 } 233 234 if (gdbm_setopt(gdbm_file, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1) 235 { 236 printf("gdbm_setopt failed, %s\n", gdbm_strerror(gdbm_errno)); 237 exit(2); 238 } 239 240 /* Welcome message. */ 241 printf ("\nWelcome to the gdbm test program. Type ? for help.\n\n"); 242 243 while (!done) 244 { 245 printf ("com -> "); 246 cmd_ch = getchar (); 247 if (cmd_ch != '\n') 248 { 249 char temp; 250 do 251 temp = getchar (); 252 while (temp != '\n' && temp != EOF); 253 } 254 if (cmd_ch == EOF) cmd_ch = 'q'; 255 switch (cmd_ch) 256 { 257 258 /* Standard cases found in all test{dbm,ndbm,gdbm} programs. */ 259 case '\n': 260 printf ("\n"); 261 break; 262 263 case 'c': 264 { 265 int temp; 266 temp = 0; 267 if (key_data.dptr != NULL) free (key_data.dptr); 268 return_data = gdbm_firstkey (gdbm_file); 269 while (return_data.dptr != NULL) 270 { 271 temp++; 272 key_data = return_data; 273 return_data = gdbm_nextkey (gdbm_file, key_data); 274 free (key_data.dptr); 275 } 276 printf ("There are %d items in the database.\n\n", temp); 277 key_data.dptr = NULL; 278 } 279 break; 280 281 case 'd': 282 if (key_data.dptr != NULL) free (key_data.dptr); 283 printf ("key -> "); 284 gets (key_line); 285 key_data.dptr = key_line; 286 key_data.dsize = strlen (key_line)+1; 287 if (gdbm_delete (gdbm_file, key_data) != 0) 288 printf ("Item not found or deleted\n"); 289 printf ("\n"); 290 key_data.dptr = NULL; 291 break; 292 293 case 'f': 294 if (key_data.dptr != NULL) free (key_data.dptr); 295 printf ("key -> "); 296 gets (key_line); 297 key_data.dptr = key_line; 298 key_data.dsize = strlen (key_line)+1; 299 return_data = gdbm_fetch (gdbm_file, key_data); 300 if (return_data.dptr != NULL) 301 { 302 printf ("data is ->%s\n\n", return_data.dptr); 303 free (return_data.dptr); 304 } 305 else 306 printf ("No such item found.\n\n"); 307 key_data.dptr = NULL; 308 break; 309 310 case 'n': 311 if (key_data.dptr != NULL) free (key_data.dptr); 312 printf ("key -> "); 313 gets (key_line); 314 key_data.dptr = key_line; 315 key_data.dsize = strlen (key_line)+1; 316 return_data = gdbm_nextkey (gdbm_file, key_data); 317 if (return_data.dptr != NULL) 318 { 319 key_data = return_data; 320 printf ("key is ->%s\n", key_data.dptr); 321 return_data = gdbm_fetch (gdbm_file, key_data); 322 printf ("data is ->%s\n\n", return_data.dptr); 323 free (return_data.dptr); 324 } 325 else 326 { 327 printf ("No such item found.\n\n"); 328 key_data.dptr = NULL; 329 } 330 break; 331 332 case 'q': 333 done = TRUE; 334 break; 335 336 case 's': 337 if (key_data.dptr != NULL) free (key_data.dptr); 338 printf ("key -> "); 339 gets (key_line); 340 key_data.dptr = key_line; 341 key_data.dsize = strlen (key_line)+1; 342 printf ("data -> "); 343 gets (data_line); 344 data_data.dsize = strlen (data_line)+1; 345 if (gdbm_store (gdbm_file, key_data, data_data, GDBM_REPLACE) != 0) 346 printf ("Item not inserted. \n"); 347 printf ("\n"); 348 key_data.dptr = NULL; 349 break; 350 351 case '1': 352 if (key_data.dptr != NULL) free (key_data.dptr); 353 key_data = gdbm_firstkey (gdbm_file); 354 if (key_data.dptr != NULL) 355 { 356 printf ("key is ->%s\n", key_data.dptr); 357 return_data = gdbm_fetch (gdbm_file, key_data); 358 printf ("data is ->%s\n\n", return_data.dptr); 359 free (return_data.dptr); 360 } 361 else 362 printf ("No such item found.\n\n"); 363 break; 364 365 case '2': 366 return_data = gdbm_nextkey (gdbm_file, key_data); 367 if (return_data.dptr != NULL) 368 { 369 free (key_data.dptr); 370 key_data = return_data; 371 printf ("key is ->%s\n", key_data.dptr); 372 return_data = gdbm_fetch (gdbm_file, key_data); 373 printf ("data is ->%s\n\n", return_data.dptr); 374 free (return_data.dptr); 375 } 376 else 377 printf ("No such item found.\n\n"); 378 break; 379 380 381 /* Special cases for the testgdbm program. */ 382 case 'r': 383 { 384 if (gdbm_reorganize (gdbm_file)) 385 printf ("Reorganization failed. \n\n"); 386 else 387 printf ("Reorganization succeeded. \n\n"); 388 } 389 break; 390 391 case 'A': 392 _gdbm_print_avail_list (gdbm_file); 393 printf ("\n"); 394 break; 395 396 case 'B': 397 { 398 int temp; 399 char number[80]; 400 401 printf ("bucket? "); 402 gets (number); 403 sscanf (number,"%d",&temp); 404 405 if (temp >= gdbm_file->header->dir_size /4) 406 { 407 printf ("Not a bucket. \n\n"); 408 break; 409 } 410 _gdbm_get_bucket (gdbm_file, temp); 411 } 412 printf ("Your bucket is now "); 413 414 case 'C': 415 print_bucket (gdbm_file->bucket, "Current bucket"); 416 printf ("\n current directory entry = %d.\n", gdbm_file->bucket_dir); 417 printf (" current bucket address = %d.\n\n", 418 gdbm_file->cache_entry->ca_adr); 419 break; 420 421 case 'D': 422 printf ("Hash table directory.\n"); 423 printf (" Size = %d. Bits = %d. \n\n",gdbm_file->header->dir_size, 424 gdbm_file->header->dir_bits); 425 { 426 int temp; 427 428 for (temp = 0; temp < gdbm_file->header->dir_size / 4; temp++) 429 { 430 printf (" %10d: %12d\n", temp, gdbm_file->dir[temp]); 431 if ( (temp+1) % 20 == 0 && isatty (0)) 432 { 433 printf ("*** CR to continue: "); 434 while (getchar () != '\n') /* Do nothing. */; 435 } 436 } 437 } 438 printf ("\n"); 439 break; 440 441 case 'F': 442 { 443 printf ("\nFile Header: \n\n"); 444 printf (" table = %d\n", gdbm_file->header->dir); 445 printf (" table size = %d\n", gdbm_file->header->dir_size); 446 printf (" table bits = %d\n", gdbm_file->header->dir_bits); 447 printf (" block size = %d\n", gdbm_file->header->block_size); 448 printf (" bucket elems = %d\n", gdbm_file->header->bucket_elems); 449 printf (" bucket size = %d\n", gdbm_file->header->bucket_size); 450 printf (" header magic = %x\n", gdbm_file->header->header_magic); 451 printf (" next block = %d\n", gdbm_file->header->next_block); 452 printf (" avail size = %d\n", gdbm_file->header->avail.size); 453 printf (" avail count = %d\n", gdbm_file->header->avail.count); 454 printf (" avail nx blk = %d\n", gdbm_file->header->avail.next_block); 455 printf ("\n"); 456 } 457 break; 458 459 case 'H': 460 if (key_data.dptr != NULL) free (key_data.dptr); 461 printf ("key -> "); 462 gets (key_line); 463 key_data.dptr = key_line; 464 key_data.dsize = strlen (key_line)+1; 465 printf ("hash value = %x. \n\n", _gdbm_hash (key_data)); 466 key_data.dptr = NULL; 467 break; 468 469 case 'K': 470 _gdbm_print_bucket_cache (gdbm_file); 471 break; 472 473 case 'V': 474 printf ("%s\n\n", gdbm_version); 475 break; 476 477 case '?': 478 printf ("c - count (number of entries)\n"); 479 printf ("d - delete\n"); 480 printf ("f - fetch\n"); 481 printf ("n - nextkey\n"); 482 printf ("q - quit\n"); 483 printf ("s - store\n"); 484 printf ("1 - firstkey\n"); 485 printf ("2 - nextkey on last key (from n, 1 or 2)\n\n"); 486 487 printf ("r - reorganize\n"); 488 printf ("A - print avail list\n"); 489 printf ("B - get and print current bucket n\n"); 490 printf ("C - print current bucket\n"); 491 printf ("D - print hash directory\n"); 492 printf ("F - print file header\n"); 493 printf ("H - hash value of key\n"); 494 printf ("K - print the bucket cache\n"); 495 printf ("V - print version of gdbm\n"); 496 break; 497 498 default: 499 printf ("What? \n\n"); 500 break; 501 502 } 503 } 504 505 /* Quit normally. */ 506 exit (0); 507 508} 509