注意测试程序和转换程序默认不会被编译,默认的make命令只会编译gdbm、ndbm和dbm部分,你必须另外用make prog来编译测试和转换程序。
(1)gdbm测试程序testgdbm.c:用于测试gdbm各个功能的程序。为测试的方便,封装了4个函数用于打印相关信息,最后main函数实现各个功能的测试。
void print_bucket(bucket, mesg):打印散列桶bucket中的每个桶元素内容,mesg指定一个要显示的提示串。程序扫描每个桶元素并打印其内容。
void _gdbm_print_avail_list (dbf):打印文件头的可用块列表中的所有可用块信息。程序先打印文件头可用块列表中的每个可用块信息,然后打印文件上可用块栈中的每个可用块信息。
void _gdbm_print_bucket_cache (dbf):打印桶缓存数组中的内容。
void usage (s):打印启动测试程序时命令行选项的使用格式帮助。
main函数:testgdbm的主函数,执行流程:
1)循环调用getopt解析命令行的每个选项;
2)根据命令行选项的值以适当的方式打开数据库;
3)设置这个数据库的缓存大小;
3)根据用户的输入的测试命令,完成gdbm各个功能的测试。
testgdbm程序的使用方法为testgdbm [-r or -ns] [-b block-size] [-c cache-size] [-g gdbm-file],命令行选项含义如下:
-s 指定作磁盘同步操作
-r 指定数据库为只读
-n 指定总是创建新的数据库(可写)
-c cache-size 指定缓存大小
-b block-size 指定传递块大小
-g gdbm-file 指定数据库文件名
所有的dbm、ndbm、gdbm测试程序都支持的标准测试命令:
c - 统计数据库的关键字/数据对的数目
d - 在数据库中删除用户输入的关键字
f - 查找给定的关键字,并显示其关联的数据
n - 显示给定关键字的下一个关键字及其关联的数据
q - 退出本测试程序
s - 向数据库中存入给定的关键字和数据
1 - 显示数据库中的第一个关键及其数据
2 - 显示当前关键字的下一个关键及其数据
? - 显示帮助信息,即本命令列表
下面是只有testgdbm程序才支持的特殊测试命令:
r - 重组数据库文件
A - 打印文件头的可用块列表中的所有可用块信息
B - 获取指定目录索引处的散列桶,使之成为当前桶
C - 打印当前散列桶中每个桶元素的内容
D - 打印散列目录表中的每个目录项
F - 打印文件头的中各个域
H - 计算并显示给定关键字的哈希值
K - 打印桶缓存数组中的内容
V - 打印gdbm的版本号
/* 打印文件头中的可用块信息 */
printf ("/nheader block/nsize = %d/ncount = %d/n",
dbf->header->avail.size, dbf->header->avail.count);
for (temp = 0; temp < dbf->header->avail.count; temp++) /* 打印可用块列表中的每个可用块信息 */
{
printf (" %15d %10d /n", dbf->header->avail.av_table[temp].av_size,
dbf->header->avail.av_table[temp].av_adr);
}
/* 初始化可用块列表变量,用来打印文件上的可用块栈 */
temp = dbf->header->avail.next_block;
size = ( ( (dbf->header->avail.size * sizeof (avail_elem)) >> 1)
+ sizeof (avail_block));
av_stk = (avail_block *) malloc (size);
if (av_stk == NULL)
{
printf("Out of memory/n");
exit (2);
}
/* 打印文件上可用块栈中的每个可用块信息 */
while (FALSE)
{
lseek (dbf->desc, temp, L_SET);
read (dbf->desc, av_stk, size);
/* 打印可用列表的一些记帐信息 */
printf ("/nblock = %d/nsize = %d/ncount = %d/n", temp,
av_stk->size, av_stk->count);
for (temp = 0; temp < av_stk->count; temp++) /* 打印列表中的每个可用块信息 */
{
printf (" %15d %10d /n", av_stk->av_table[temp].av_size,
av_stk->av_table[temp].av_adr);
}
temp = av_stk->next_block;
}
}
/* 打印桶缓存数组中的内容 */
void
_gdbm_print_bucket_cache (dbf)
gdbm_file_info *dbf;
{
register int index;
char changed;
if (dbf->bucket_cache != NULL) {
printf(
"Bucket Cache (size %d):/n Index: Address Changed Data_Hash /n",
dbf->cache_size);
for (index=0; index < dbf->cache_size; index++) { /* 打印每个缓存项的一些信息 */
changed = dbf->bucket_cache[index].ca_changed;
printf (" %5d: %7d %7s %x/n",
index,
dbf->bucket_cache[index].ca_adr,
(changed ? "True" : "False"),
dbf->bucket_cache[index].ca_data.hash_val);
}
} else
printf("Bucket cache has not been initialized./n");
}
/* 打印启动测试程序时命令行选项的使用格式帮助 */
void
usage (s)
char *s;
{
printf(
"Usage: %s [-r or -ns] [-b block-size] [-c cache-size] [-g gdbm-file]/n",
s);
exit (2);
}
/* 测试程序允许一个用户调用所有的例程,包括哈希函数。
命令行选项:s指定作磁盘同步操作、r指定数据库为只读、n指定总是创建新的数据库(可写)、c指定缓存大小、
b指定传递块大小、g指定数据库文件名
本程序支持的命令列表:每个命令都是单个字符,键入?可多得命令列表的帮助信息
*/
int
main (argc, argv)
int argc;
char *argv[];
{
char cmd_ch;
datum key_data;
datum data_data;
datum return_data;
char key_line[500];
char data_line[1000];
char done = FALSE;
int opt;
char reader = FALSE;
char newdb = FALSE;
int fast = 0;
int cache_size = DEFAULT_CACHESIZE;
int block_size = 0;
char *file_name = NULL;
/* 命令行选项检查 */
opterr = 0;
/* 循环调用getopt获取命令行的每个选项,每次调用返回当前的选项字符 */
while ((opt = getopt (argc, argv, "srnc:b:g:")) != -1)
switch (opt) {
case 's': fast = GDBM_SYNC;
if (reader) usage (argv[0]);
break;
case 'r': reader = TRUE;
if (newdb) usage (argv[0]);
break;
case 'n': newdb = TRUE;
if (reader) usage (argv[0]);
break;
case 'c': cache_size = atoi(optarg); /* 把字符串转换为整数 */
break;
case 'b': block_size = atoi(optarg);
break;
case 'g': file_name = optarg;
break;
default: usage(argv[0]); /* 打印启动测试程序命令行选项的使用格式 */
}
if(file_name == NULL)
file_name = "junk.gdbm";
/* 初始化关键字和数据项 */
key_data.dptr = NULL;
data_data.dptr = data_line;
/* 根据选项值以适当的方式打开数据库 */
if (reader)
{
gdbm_file = gdbm_open (file_name, block_size, GDBM_READER, 00664, NULL);
}
else if (newdb)
{
gdbm_file =
gdbm_open (file_name, block_size, GDBM_NEWDB | fast, 00664, NULL);
}
else
{
gdbm_file =
gdbm_open (file_name, block_size, GDBM_WRCREAT | fast, 00664, NULL);
}
if (gdbm_file == NULL)
{
printf("gdbm_open failed, %s/n", gdbm_strerror(gdbm_errno));
exit (2);
}
/* 设置这个数据库的缓存大小 */
if (gdbm_setopt(gdbm_file, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
{
printf("gdbm_setopt failed, %s/n", gdbm_strerror(gdbm_errno));
exit(2);
}
/* 欢迎消息 */
printf ("/nWelcome to the gdbm test program. Type ? for help./n/n");
while (!done)
{
printf ("com -> ");
cmd_ch = getchar ();
if (cmd_ch != '/n')
{
char temp;
do
temp = getchar ();
while (temp != '/n' && temp != EOF);
}
if (cmd_ch == EOF) cmd_ch = 'q';
switch (cmd_ch)
{
/* 所有的{dbm,ndbm,gdbm}测试程序中都支持的标准命令:
c - 统计数据库的关键字/数据对的数目
d - 在数据库中删除用户输入的关键字
f - 查找给定的关键字,并显示其关联的数据
n - 显示给定关键字的下一个关键字及其关联的数据
q - 退出本测试程序
s - 向数据库中存入给定的关键字和数据
1 - 显示数据库中的第一个关键及其数据
2 - 显示当前关键字的下一个关键及其数据
下面是只有testgdbm程序支持的特殊命令:
r - 重组数据库文件
A - 打印文件头的可用块列表中的所有可用块信息
B - 获取指定目录索引处的散列桶,使之成为当前桶
C - 打印当前散列桶中每个桶元素的内容
D - 打印散列目录表中的每个目录项
F - 打印文件头的中各个域
H - 计算并显示给定关键字的哈希值
K - 打印桶缓存数组中的内容
V - 打印gdbm的版本号
? - 显示帮助信息,即本命令列表
*/
case '/n':
printf ("/n");
break;
case 'c': /* c - 统计数据库的关键字/数据对的数目 */
{
int temp;
temp = 0;
if (key_data.dptr != NULL) free (key_data.dptr);
return_data = gdbm_firstkey (gdbm_file);
while (return_data.dptr != NULL)
{
temp++;
key_data = return_data;
return_data = gdbm_nextkey (gdbm_file, key_data);
free (key_data.dptr);
}
printf ("There are %d items in the database./n/n", temp);
key_data.dptr = NULL;
}
break;
case 'd': /* d - 在数据库中删除用户输入的关键字 */
if (key_data.dptr != NULL) free (key_data.dptr);
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
if (gdbm_delete (gdbm_file, key_data) != 0)
printf ("Item not found or deleted/n");
printf ("/n");
key_data.dptr = NULL;
break;
case 'f': /* f - 查找给定的关键字,并显示其关联的数据 */
if (key_data.dptr != NULL) free (key_data.dptr);
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
return_data = gdbm_fetch (gdbm_file, key_data);
if (return_data.dptr != NULL)
{
printf ("data is ->%s/n/n", return_data.dptr);
free (return_data.dptr);
}
else
printf ("No such item found./n/n");
key_data.dptr = NULL;
break;
case 'n': /* n - 显示给定关键字的下一个关键字及其关联的数据 */
if (key_data.dptr != NULL) free (key_data.dptr);
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
return_data = gdbm_nextkey (gdbm_file, key_data);
if (return_data.dptr != NULL)
{
key_data = return_data;
printf ("key is ->%s/n", key_data.dptr);
return_data = gdbm_fetch (gdbm_file, key_data);
printf ("data is ->%s/n/n", return_data.dptr);
free (return_data.dptr);
}
else
{
printf ("No such item found./n/n");
key_data.dptr = NULL;
}
break;
case 'q': /* q - 退出本测试程序 */
done = TRUE;
break;
case 's': /* s - 向数据库中存入给定的关键字和数据 */
if (key_data.dptr != NULL) free (key_data.dptr);
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
printf ("data -> ");
gets (data_line);
data_data.dsize = strlen (data_line)+1;
if (gdbm_store (gdbm_file, key_data, data_data, GDBM_REPLACE) != 0)
printf ("Item not inserted. /n");
printf ("/n");
key_data.dptr = NULL;
break;
case '1': /* 1 - 显示数据库中的第一个关键及其数据 */
if (key_data.dptr != NULL) free (key_data.dptr);
key_data = gdbm_firstkey (gdbm_file);
if (key_data.dptr != NULL)
{
printf ("key is ->%s/n", key_data.dptr);
return_data = gdbm_fetch (gdbm_file, key_data);
printf ("data is ->%s/n/n", return_data.dptr);
free (return_data.dptr);
}
else
printf ("No such item found./n/n");
break;
case '2': /* 2 - 显示当前关键字的下一个关键及其数据 */
return_data = gdbm_nextkey (gdbm_file, key_data);
if (return_data.dptr != NULL)
{
free (key_data.dptr);
key_data = return_data;
printf ("key is ->%s/n", key_data.dptr);
return_data = gdbm_fetch (gdbm_file, key_data);
printf ("data is ->%s/n/n", return_data.dptr);
free (return_data.dptr);
}
else
printf ("No such item found./n/n");
break;
/* 下面是testgdbm程序要使用的特殊情形 */
case 'r': /* r - 重组数据库文件 */
{
if (gdbm_reorganize (gdbm_file))
printf ("Reorganization failed. /n/n");
else
printf ("Reorganization succeeded. /n/n");
}
break;
case 'A': /* A - 打印文件头的可用块列表中的所有可用块信息 */
_gdbm_print_avail_list (gdbm_file);
printf ("/n");
break;
case 'B': /* B - 获取指定目录索引处的散列桶,使之成为当前桶 */
{
int temp;
char number[80];
printf ("bucket? ");
gets (number);
sscanf (number,"%d",&temp);
if (temp >= gdbm_file->header->dir_size /4)
{
printf ("Not a bucket. /n/n");
break;
}
_gdbm_get_bucket (gdbm_file, temp);
}
printf ("Your bucket is now ");
case 'C': /* C - 打印当前散列桶中每个桶元素的内容 */
print_bucket (gdbm_file->bucket, "Current bucket");
printf ("/n current directory entry = %d./n", gdbm_file->bucket_dir);
printf (" current bucket address = %d./n/n",
gdbm_file->cache_entry->ca_adr);
break;
case 'D': /* D - 打印散列目录表中的每个目录项 */
printf ("Hash table directory./n");
printf (" Size = %d. Bits = %d. /n/n",gdbm_file->header->dir_size,
gdbm_file->header->dir_bits);
{
int temp;
for (temp = 0; temp < gdbm_file->header->dir_size / 4; temp++)
{
printf (" %10d: %12d/n", temp, gdbm_file->dir[temp]);
if ( (temp+1) % 20 == 0 && isatty (0))
{
printf ("*** CR to continue: ");
while (getchar () != '/n') /* Do nothing. */;
}
}
}
printf ("/n");
break;
case 'F': /* F - 打印文件头的中各个域 */
{
printf ("/nFile Header: /n/n");
printf (" table = %d/n", gdbm_file->header->dir);
printf (" table size = %d/n", gdbm_file->header->dir_size);
printf (" table bits = %d/n", gdbm_file->header->dir_bits);
printf (" block size = %d/n", gdbm_file->header->block_size);
printf (" bucket elems = %d/n", gdbm_file->header->bucket_elems);
printf (" bucket size = %d/n", gdbm_file->header->bucket_size);
printf (" header magic = %x/n", gdbm_file->header->header_magic);
printf (" next block = %d/n", gdbm_file->header->next_block);
printf (" avail size = %d/n", gdbm_file->header->avail.size);
printf (" avail count = %d/n", gdbm_file->header->avail.count);
printf (" avail nx blk = %d/n", gdbm_file->header->avail.next_block);
printf ("/n");
}
break;
case 'H': /* H - 计算并显示给定关键字的哈希值 */
if (key_data.dptr != NULL) free (key_data.dptr);
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
printf ("hash value = %x. /n/n", _gdbm_hash (key_data));
key_data.dptr = NULL;
break;
case 'K': /* K - 打印桶缓存数组中的内容 */
_gdbm_print_bucket_cache (gdbm_file);
break;
case 'V': /* V - 打印gdbm的版本号 */
printf ("%s/n/n", gdbm_version);
break;
case '?': /* ? - 显示帮助信息 */
printf ("c - count (number of entries)/n");
printf ("d - delete/n");
printf ("f - fetch/n");
printf ("n - nextkey/n");
printf ("q - quit/n");
printf ("s - store/n");
printf ("1 - firstkey/n");
printf ("2 - nextkey on last key (from n, 1 or 2)/n/n");
printf ("r - reorganize/n");
printf ("A - print avail list/n");
printf ("B - get and print current bucket n/n");
printf ("C - print current bucket/n");
printf ("D - print hash directory/n");
printf ("F - print file header/n");
printf ("H - hash value of key/n");
printf ("K - print the bucket cache/n");
printf ("V - print version of gdbm/n");
break;
default:
printf ("What? /n/n");
break;
}
}
/* 正常退出 */
exit (0);
}
(2)testndbm.c:用于测试ndbm各个功能的程序。它的实现与testgdbm类似,只不过testndbm不支持命令行选项,且只实现了标准的测试命令。测试各个功能时使用的当然是ndbm的接口了。
/* 测试程序允许一个用户调用所有的例程,包括哈希函数。 支持的命令有q (quit), f (fetch), s (store), d (delete),
1 (firstkey), n (nextkey)和h (哈希函数). */
int
main (argc, argv)
int argc;
char *argv[];
{
char cmd_ch;
datum key_data;
datum data_data;
datum return_data;
char key_line[500];
char data_line[1000];
DBM *dbm_file;
char done = FALSE;
char *file_name;
/* 命令行选项检查 */
if (argc > 2)
{
printf ("Usage: %s [dbm-file] /n",argv[0]);
exit (2);
}
if (argc > 1)
{
file_name = argv[1];
}
else
{
file_name = "junkndbm";
}
/* 初始化 */
data_data.dptr = data_line;
dbm_file = dbm_open (file_name, O_RDWR|O_CREAT, 00664);
if (dbm_file == NULL)
{
printf ("dbm_open failed./n");
exit (2);
}
/* 欢迎消息 */
printf ("/nWelcome to the gndbm test program. Type ? for help./n/n");
while (!done)
{
printf ("com -> ");
cmd_ch = getchar ();
while (getchar () != '/n') /* 不做任何事 */;
switch (cmd_ch)
{
case 'q':
done = TRUE;
break;
case 'f':
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
return_data = dbm_fetch (dbm_file, key_data);
if (return_data.dptr != NULL)
printf ("data is ->%s/n/n", return_data.dptr);
else
printf ("No such item found./n/n");
break;
case 's':
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
printf ("data -> ");
gets (data_line);
data_data.dsize = strlen (data_line)+1;
if (dbm_store (dbm_file, key_data, data_data, DBM_REPLACE) != 0)
printf ("Item not inserted. /n");
printf ("/n");
break;
case 'd':
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
if (dbm_delete (dbm_file, key_data) != 0)
printf ("Item not found or deleted/n");
printf ("/n");
break;
case '1':
key_data = dbm_firstkey (dbm_file);
if (key_data.dptr != NULL)
{
return_data = dbm_fetch (dbm_file, key_data);
printf ("key is ->%s/n", key_data.dptr);
printf ("data is ->%s/n/n", return_data.dptr);
}
else
printf ("No such item found./n/n");
break;
case '2':
key_data = dbm_nextkey (dbm_file);
if (key_data.dptr != NULL)
{
return_data = dbm_fetch (dbm_file, key_data);
printf ("key is ->%s/n", key_data.dptr);
printf ("data is ->%s/n/n", return_data.dptr);
}
else
printf ("No such item found./n/n");
break;
case 'c':
{
int temp;
temp = 0;
return_data = dbm_firstkey (dbm_file);
while (return_data.dptr != NULL)
{
temp++;
return_data = dbm_nextkey (dbm_file);
}
printf ("There are %d items in the database./n/n", temp);
}
break;
case '?':
printf ("c - count elements/n");
printf ("d - delete/n");
printf ("f - fetch/n");
printf ("q - quit/n");
printf ("s - store/n");
printf ("1 - firstkey/n");
printf ("2 - nextkey on last return value/n/n");
break;
default:
printf ("What? /n/n");
break;
}
}
/* 正常退出 */
dbm_close (dbm_file);
exit (0);
}
(3)testdbm.c:用于测试dbm各个功能的程序。它的实现与testgdbm类似,只不过testdbm不支持命令行选项,且只实现了标准的测试命令。测试各个功能时使用的当然是dbm的接口了。
while (!done)
{
printf ("com -> ");
cmd_ch = getchar ();
while (getchar () != '/n') /* 不做任何事 */;
switch (cmd_ch)
{
case 'q':
done = TRUE;
break;
case 'f':
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
return_data = fetch (key_data);
if (return_data.dptr != NULL)
printf ("data is ->%s/n/n", return_data.dptr);
else
printf ("No such item found./n/n");
break;
case 's':
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
printf ("data -> ");
gets (data_line);
data_data.dsize = strlen (data_line)+1;
if (store (key_data, data_data) != 0)
printf ("Item not inserted. /n");
printf ("/n");
break;
case 'd':
printf ("key -> ");
gets (key_line);
key_data.dptr = key_line;
key_data.dsize = strlen (key_line)+1;
if (delete (key_data) != 0)
printf ("Item not found or deleted/n");
printf ("/n");
break;
case '1':
key_data = firstkey ();
if (key_data.dptr != NULL)
{
return_data = fetch (key_data);
printf ("key is ->%s/n", key_data.dptr);
printf ("data is ->%s/n/n", return_data.dptr);
}
else
printf ("No such item found./n/n");
break;
case '2':
key_data = nextkey (key_data);
if (key_data.dptr != NULL)
{
return_data = fetch (key_data);
printf ("key is ->%s/n", key_data.dptr);
printf ("data is ->%s/n/n", return_data.dptr);
}
else
printf ("No such item found./n/n");
break;
case 'c':
{
int temp;
temp = 0;
return_data = firstkey ();
while (return_data.dptr != NULL)
{
temp++;
return_data = nextkey (return_data);
}
printf ("There are %d items in the database./n/n", temp);
}
break;
case '?':
printf ("c - count elements/n");
printf ("d - delete/n");
printf ("f - fetch/n");
printf ("q - quit/n");
printf ("s - store/n");
printf ("1 - firstkey/n");
printf ("2 - nextkey on last return value/n/n");
break;
default:
printf ("What? /n/n");
break;
}
}
/* 正常退出 */
exit (0);
}
(4)conv2gdbm.c:把dbm文件转换成gdbm文件的程序。操作流程:
1)循环调用getopt解析命令行的每个选项;
2)设置好dbm文件名和可选的gdbm文件名;
3)打开dbm文件和gdbm文件;
4)把dbm文件中的所有关键字/数据对插入到gdbm文件中;
5)最后报告统计的出错次数和插入记录数。
conv2gdbm程序的使用方法为conv2gdbm [-q] [-b block_size] dbmfile [gdbmfile],命令行选项含义:
-q 是否静静地进行转换,即不显示任何的提示信息
-b block_size 指定传递块大小
/* 打开dbm文件 */
if (dbminit (dbm_file) != 0)
{
printf ("%s: dbm file not opened/n", argv[0]);
exit (2);
}
/* 打开gdbm文件。因为dbm文件有.pag和.dir,我们将使用没有任何扩展名的文件名 */
gfile = gdbm_open (gdbm_file, block_size, GDBM_WRCREAT, 00664, NULL);
if (gfile == NULL)
{
printf ("%s: gdbm file not opened/n", argv[0]);
exit (2);
}
/* 现在开始做转换 */
errors = 0;
num = 0;
if (!quiet) /* 如果需要提示正在进行转换操作 */
printf ("%s: Converting %s.pag and %s.dir to %s./n", argv[0], dbm_file,
dbm_file, gdbm_file);
/* 转换操作:把dbm文件中的所有关键字/数据对插入到gdbm文件中 */
for (key = firstkey (); key.dptr != NULL; key = nextkey (key))
{
data = fetch (key);
if (gdbm_store (gfile, key, data, GDBM_INSERT) != 0) /* 存入到gdbm文件中 */
{
errors++;
}
else
{
num++;
if ( !quiet && ((num % 100) == 0))
{
printf (".");
if ( (num % 7000) == 0)
printf ("/n");
}
}
}
gdbm_close (gfile);
if (!quiet)
{
/* 最后报告统计的出错次数和插入记录数 */
if (errors)
printf ("%s: %d items not inserted into %s./n", argv[0],
errors, gdbm_file);
printf ("%s: %d items inserted into %s./n", argv[0], num, gdbm_file);
}
exit(0);
}
/* 打印启动转换程序时命令行选项的使用格式帮助 */
static void usage (name)
char *name;
{
printf ("usage: %s [-q] [-b block_size] dbmfile [gdbmfile]/n", name);
exit (2);
}