DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T d

⟦7d0fef796⟧ TextFile

    Length: 18380 (0x47cc)
    Types: TextFile
    Names: »dbm.c,v«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦bfebc70e2⟧ »EurOpenD3/mail/sendmail-5.65b+IDA-1.4.3.tar.Z« 
        └─⟦f9e35cd84⟧ 
            └─⟦this⟧ »sendmail/ida/aux/RCS/dbm.c,v« 

TextFile

head	1.10;
access;
symbols;
locks; strict;
comment	@ * @;


1.10
date	91.03.06.18.10.42;	author paul;	state Exp;
branches;
next	1.9;

1.9
date	90.12.13.11.16.35;	author paul;	state Exp;
branches;
next	1.8;

1.8
date	90.11.29.14.49.30;	author paul;	state Exp;
branches;
next	1.7;

1.7
date	90.11.14.14.31.03;	author paul;	state Exp;
branches;
next	1.6;

1.6
date	90.10.16.17.35.47;	author paul;	state Exp;
branches;
next	1.5;

1.5
date	90.10.11.11.11.04;	author paul;	state Exp;
branches;
next	1.4;

1.4
date	90.06.05.09.25.59;	author paul;	state Exp;
branches;
next	1.3;

1.3
date	90.06.05.09.23.11;	author paul;	state Exp;
branches;
next	1.2;

1.2
date	89.01.31.15.41.19;	author paul;	state Exp;
branches;
next	1.1;

1.1
date	89.01.31.14.09.21;	author paul;	state Exp;
branches;
next	;


desc
@@


1.10
log
@ANSIfied.
@
text
@/*
**  DBM -- General dbm management tool.
**  Copyright (c) 1987 Lennart Lovstrand
**  CIS Dept, Univ of Linkoping, Sweden
**
**  Use it, abuse it, but don't sell it.
*/

#include "useful.h"
#include <stdio.h>
#include <ctype.h>
#include <sys/file.h>
#ifndef LOCK_EX
# include "flock.h"
#endif /* !LOCK_EX */

#ifdef GDBM
# define OTHERDBM
# include <ndbm.h>		/* DBM is typedef'ed here */
#endif /* GDBM */

#ifdef SDBM
# ifdef OTHERDBM
   MULTIPLE_DBM_TYPES_DEFINED
# else
#  define OTHERDBM
#  include <sdbm.h>		/* DBM is typedef'ed here */
# endif /* OTHERDBM */
#endif /* SDBM */

#ifndef OTHERDBM
# undef DBM			/* while including ndbm.h */
# include <ndbm.h>		/* DBM is typedef'ed here */
#endif /* !OTHERDBM */

#define DBMFILE DBM
#define DB_DIREXT	".dir"
#define DB_PAGEXT	".pag"

#ifndef lint
static char	SccsId[] = "@@(#)dbm.c 2.2 (lel@@ida.liu.se) 10/24/88";
#endif /* !lint */

#define	SAMECASE	0
#define LOWERCASE	1
#define UPPERCASE	2

#define COMMENTCHAR	'#'
#define SENTENIEL	"@@@@@@"

#define streq(s, t)	(strcmp(s, t) == 0)
#define MAKEDATUM(d, s)	{(d).dptr = s; (d).dsize = strlen(s) + 1;}
#define CHECKDATUM(d)	if (Nullwarn && ((d).dsize == 0 || \
					 (d).dptr[(d).dsize - 1] != '\0')) \
		fprintf(stderr, "[Warning: Entry not NULL terminated]\n");

#ifdef __STDC__
void opendbm(int, int);
FILE * openfile(const char *, const char *);
void closefile(FILE *);
void parsefile(FILE *, FILE *);
void loadfile(FILE *);
char * scantoken(const char *);
void casify(char *, int);
#else /* !__STDC__ */
# define	const
void opendbm();
FILE * openfile();
void closefile();
void parsefile();
void loadfile();
char * scantoken();
void casify();
#endif /* __STDC__ */
void closedbm();
void do_clear();
void do_delete();
void do_dump();
void do_fetch();
void do_store();
void do_parse();
void do_make();
void do_load();
char * index();

struct comtab {
    char *c_name;
    void (*c_func)();
    int LockType;
} CommandTable[] = {
    {"clear",	do_clear},
    {"delete",	do_delete},
    {"dump",	do_dump},
    {"fetch",	do_fetch},
    {"load",	do_load},
    {"make",	do_make},
    {"parse",	do_parse},
    {"store",	do_store}
};
    
/* global arguments */
int	Argc;
char	**Argv;

/* options */
int	Appending = FALSE;
int	Casing = SAMECASE;
bool	Debug = FALSE;
char	*Outfile = NULL;
int	Mode = 0644;
char	*Progname;
char	*Senteniel = NULL;
int	Storeflag = DBM_INSERT;
bool	Storewarn = TRUE;
bool	Nullwarn = FALSE;
bool	Valueonly = FALSE;

/* Dbm globals */
DBMFILE	*Dbm;
char	*Dbmfile = NULL;
int	Dbmaccess;
datum	key, val;

main(argc, argv)
     int argc;
     char **argv;
{
    extern int optind;
    extern char *optarg;
    struct comtab *cmd;
    int c;

    Argc = argc;
    Argv = argv;

    Progname = Argv[0];

    while ((c = getopt(Argc, Argv, "ADILNRSUd:m:o:s:v")) != EOF)
	switch (c) {
	  case 'A':
	    Appending = TRUE;
	    break;
	  case 'D':
	    Debug = TRUE;
	    break;
	  case 'I':
	    Storeflag = DBM_INSERT;
	    Storewarn = FALSE;
	    break;
	  case 'L':
	    Casing = LOWERCASE;
	    break;
	  case 'N':
	    Nullwarn = TRUE;
	    break;
	  case 'R':
	    Storeflag = DBM_REPLACE;
	    break;
	  case 'S':
	    if (Senteniel == NULL)
		Senteniel = SENTENIEL;
	    break;
	  case 'U':
	    Casing = UPPERCASE;
	    break;
	  case 'd':
	    Dbmfile = optarg;
	    break;
	  case 'm':
	    if (optarg[0] == '0')
		(void) sscanf(optarg, "%o", &Mode);
	    else {
		(void) sscanf(optarg, "%d", &Mode);
		if (Mode == 0) {
		    (void) fprintf(stderr, "%s: non-numeric mode: %s\n",
				   Progname, optarg);
		    exit(1);
		}
	    }
	    break;
	  case 'o':
	    Outfile = optarg;
	    break;
	  case 's':
	    Senteniel = optarg;
	    break;
	  case 'v':
	    Valueonly = TRUE;
	    break;
	  default:
	    (void) fprintf(stderr,
			   "usage: %s [-ADILNRSU] [-d dbm_file] [-m mode] %s", 
			   Progname, "[-o output_file] [-v] command [args]\n");
	    exit(1);
	}

    Argc -= optind;
    Argv += optind;

    if (Argc > 0) {
	for (cmd = CommandTable; cmd < &CommandTable[sizeof(CommandTable) /
						     sizeof(*CommandTable)];
	     cmd++)
	    if (streq(*Argv, cmd->c_name)) {
		(*cmd->c_func)();
		exit(0);
	    }
	(void) fprintf(stderr, "%s: unknown dbm command %s", Progname, *Argv);
    } else
	(void) fprintf(stderr, "%s: missing dbm command", Progname);
    (void) fprintf(stderr, ", use one of the following:\n");
    for (cmd = CommandTable; cmd < &CommandTable[sizeof(CommandTable) /
						 sizeof(*CommandTable)]; cmd++)
	(void) fprintf(stderr, "%s%s", cmd == CommandTable ? "" : "\t",
		       cmd->c_name);
    (void) fprintf(stderr, "\n");
    exit(3);
}

void
opendbm(access, LockType)
     int access, LockType;
{
    if (Dbmfile == NULL) {
	if (Argc > 1) {
	    /* use last argument */
	    Dbmfile = Argv[Argc-1];
	    Argc--;
	} else {
	    (void) fprintf(stderr, "%s: dbm file not specified\n", Progname);
	    exit(3);
	}
    }
    Dbm = dbm_open(Dbmfile, access, Mode);
    if (Dbm == NULL) {
	char *filename = (char *) malloc((unsigned) strlen(Dbmfile) + 20);
	(void) sprintf(filename, "%s{%s,%s}", Dbmfile, DB_DIREXT, DB_PAGEXT);
	perror(filename);
	exit(4);
    }
#ifndef GDBM
    if (flock(dbm_dirfno(Dbm), LockType) < 0) {
	    (void) fprintf(stderr, "%s: cannot lock %s\n",
		Progname, Dbmfile);
	    exit(3);
    }
#endif /* !GDBM */
    Dbmaccess = access;
}

void
closedbm()
{
    if ((Dbmaccess & O_RDONLY) == 0 && Senteniel != NULL) {
	MAKEDATUM(key, Senteniel);
	if (dbm_store(Dbm, key, key, DBM_REPLACE) != 0) {
	    (void) fprintf(stderr, "%s: could not store senteniel \"%s\"\n",
			   Progname, Senteniel);
	    perror(Progname);
	    exit(5);
	}
    }
#ifndef GDBM
    (void) flock(dbm_dirfno(Dbm), LOCK_UN);
#endif /* !GDBM */
    dbm_close(Dbm);
}

FILE *
openfile(filename, access)
     const char *filename;
     const char *access;
{
    FILE *f;

    if (streq(filename, "-"))
	if (streq(access, "r"))
	    return stdin;
	else
	    return stdout;
    else {
	f = fopen(filename, access);
	if (f == NULL) {
	    perror(filename);
	    exit(4);
	}
	return f;
    }
}

void
closefile(f)
     FILE *f;
{
    if (f != stdin && f != stdout)
	(void) fclose(f);
}
\f

/*
**	DO_CLEAR -- Clear out database leaving it emtpy.
*/

void
do_clear()
{
    if (Dbmfile != NULL) {
	opendbm(O_RDWR | O_CREAT | O_TRUNC, LOCK_EX);
	closedbm();
    }
    while (Argc > 1) {
	opendbm(O_RDWR | O_CREAT | O_TRUNC, LOCK_EX);
	closedbm();
    }
}

   
\f

/*
**	DO_DELETE -- Delete individual entries from the database.
*/

void
do_delete()
{
    opendbm(O_RDWR | O_CREAT, LOCK_EX);

    for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
	casify(*Argv, Casing);
	MAKEDATUM(key, *Argv);
	if (dbm_delete(Dbm, key) != 0) {
	    perror(*Argv);
	    exit(5);
	}
    }

    closedbm();
}

\f

/*
**	DO_DUMP -- List all entries in the database.
*/
 
void
do_dump()
{
    FILE *output;
    
    opendbm(O_RDONLY, LOCK_SH);

    if (Outfile == NULL)
	output = stdout;
    else
	output = openfile(Outfile, "w");

    for (key = dbm_firstkey(Dbm); key.dptr != NULL; key = dbm_nextkey(Dbm)) {
	val = dbm_fetch(Dbm, key);
	CHECKDATUM(key);
	CHECKDATUM(val);
	if (val.dptr == NULL)
	    perror(key.dptr);
	else if (Valueonly)
	    (void) fprintf(output, "%.*s\n", val.dsize, val.dptr);
	else
	    (void) fprintf(output, "%.*s\t%.*s\n", key.dsize, key.dptr,
			   val.dsize, val.dptr);
    }
}
\f

/*
**	DO_FETCH -- Lookup individual keys in the database.
*/
 
void
do_fetch()
{
    char buf[BUFSIZ];
    register char *nl;

    opendbm(O_RDONLY, LOCK_SH);

    if (Argc == 1) {
	while (fgets(buf, sizeof(buf), stdin) != NULL) {
	    if ((nl = index(buf, '\n')) != NULL)
		*nl = '\0';
	    casify(buf, Casing);
	    MAKEDATUM(key, buf);
	    val = dbm_fetch(Dbm, key);
	    CHECKDATUM(val);
	    if (val.dptr == NULL)
		(void) printf("%s\t[NOT FOUND]\n", buf);
	    else if (Valueonly)
		(void) printf("%.*s\n", val.dsize, val.dptr);
	    else
		(void) printf("%s\t%.*s\n", buf, val.dsize, val.dptr);
	}
    }
    else
    for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
	casify(*Argv, Casing);
	MAKEDATUM(key, *Argv);
	val = dbm_fetch(Dbm, key);
	CHECKDATUM(val);
	if (val.dptr == NULL)
	    (void) printf("%s\t[NOT FOUND]\n", *Argv);
	else if (Valueonly)
	    (void) printf("%.*s\n", val.dsize, val.dptr);
	else
	    (void) printf("%s\t%.*s\n", *Argv, val.dsize, val.dptr);
    }

    closedbm();
}

\f

/*
**	DO_STORE -- Insert individual entries into the database.
*/

void
do_store()
{
    /* barf if # of args - 1 is even and no dbm file has been specified */
    if ((Argc & 1) == 1 && Dbmfile == NULL) {
	(void) fprintf(stderr, "%s: no dbm file specified\n", Progname);
	exit(3);
    }

    opendbm(O_RDWR | O_CREAT, LOCK_EX);

    for (Argc--, Argv++; Argc > 1; Argc -= 2, Argv += 2) {
	casify(Argv[0], Casing);
	MAKEDATUM(key, Argv[0]);
	MAKEDATUM(val, Argv[1]);
	if (dbm_store(Dbm, key, val, Storeflag) != 0) {
	    extern int errno;

	    if (errno != 0) {
		perror(Argv[0]);
		exit(5);
	    } else if (Storewarn)
		(void) fprintf(stderr,
			       "%s: duplicate key \"%s\" => \"%s\" ignored\n",
			       Progname, Argv[0], Argv[1]);
	}
    }
    if (Argc > 0)
	(void) fprintf(stderr, "%s: no value for last key \"%s\"--ignored\n",
		       Progname, Argv[0]);

    closedbm();
}

\f

/*
**	DO_PARSE -- Parse a textual database file and produce key-value
**		pairs separated by a tab (suitable for input to the ``load''
**		function).
*/

void
do_parse()
{
    FILE *input, *output;
    
    if (Outfile == NULL)
	output = stdout;
    else
	output = openfile(Outfile, "w");

    if (Argc == 1)
	parsefile(stdin, output);
    else
	for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
	    input = openfile(*Argv, "r");
	    parsefile(input, output);
	    closefile(input);
	}
}

\f

/*
**	DO_MAKE -- Parse the textual input and load the result into
**		the database.
*/

void
do_make()
{
    FILE *input, *pipin, *pipout;
    int pipes[2];

    opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC), LOCK_EX);

    if (pipe(pipes) != 0) {
	perror("pipe");
	exit(9);
    }
    pipin = fdopen(pipes[0], "r");
    pipout = fdopen(pipes[1], "w");

    if (fork() == 0) {
	/* child process */
	(void) fclose(pipout);

	loadfile(pipin);
    } else {
	/* parent process */
	(void) fclose(pipin);

	if (Argc == 1)
	    parsefile(stdin, pipout);
	else
	    for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
		input = openfile(*Argv, "r");
		parsefile(input, pipout);
		closefile(input);
	    }
    }
    closedbm();
}

\f

/*
**	DO_LOAD -- Load the dbm database from a text file.  The input should
**		be key-value pairs separated by a tab, each on a single line.
*/

void
do_load()
{
    FILE *input;

    opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC), LOCK_EX);

    if (Argc == 1)
	loadfile(stdin);
    else
	for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
	    input = openfile(*Argv, "r");
	    loadfile(input);
	    closefile(input);
	}
    closedbm();
}    

\f

/*
**	PARSEFILE, LOADFILE
*/ 

void
parsefile(input, output)
     FILE *input, *output;
{
    char buf[BUFSIZ], *key, *val = NULL;
    register char *p;

    while (fgets(buf, sizeof(buf), input) != NULL) {
	if (buf[0] == COMMENTCHAR || buf[0] == '\n' || buf[0] == '\0')
	    continue;
	p=buf;
	if (!isspace(buf[0])) {
	    /* extract value */
	    p = scantoken(buf);
	    if (val != NULL)
		free(val);
	    val = (char *) malloc((unsigned) (p - buf + 1));
	    (void) strncpy(val, buf, p - buf);
	    val[p - buf] = '\0';
	    p++;
	}
	casify(buf, Casing);
	while ( *p != '\0') {
	    while (*p != '\0' && isspace(*p)) p++;
	    if (*p == '\0' || *p == COMMENTCHAR)
		break;
	    key = p;
	    p = scantoken(p);
	    if (*p == COMMENTCHAR)
		*p = '\0';
	    else if (*p != '\0')
		*p++ = '\0';
	    (void) fprintf(output, "%s\t%s\n", key, val);
	}
    }
}

void
loadfile(input)
     FILE *input;
{
    char buf[BUFSIZ];
    register char *tab, *nl;

    while (fgets(buf, sizeof(buf), input) != NULL) {
	nl = index(buf, '\n');
	if (nl != NULL)
	    *nl = '\0';

	tab = index(buf, '\t');
	if (tab == NULL) {
	    (void) fprintf(stderr, "%s: missing tab in \"%s\"--ignored\n",
			   Progname, buf);
	    continue;
	}
	*tab++ = '\0';
	casify(buf, Casing);
	MAKEDATUM(key, buf);
	MAKEDATUM(val, tab);
	if (dbm_store(Dbm, key, val, Storeflag) != 0 && Storewarn) {
	    extern int errno;

	    if (errno != 0) {
		perror(buf);
		exit(5);
	    } else if (Storewarn)
		(void) fprintf(stderr,
			       "%s: duplicate key \"%s\" => \"%s\" ignored\n",
			       Progname, buf, tab);
	}
    }
}

char *
scantoken(p)
     register const char *p;
{
  register bool quotedchar = FALSE, insidestring = FALSE, insideroute = FALSE;

  /* hidious address scanner */
  while (*p != '\0' && (quotedchar || insidestring || insideroute || 
			(*p != COMMENTCHAR && !isspace(*p)))) {
    /* special quote character handling */
    if (quotedchar)
      quotedchar = FALSE;
    else {
      quotedchar = (*p == '\\');
      if (!insidestring)
	if (*p == '<')
	  insideroute = TRUE;
	else if (*p == '>')
	  insideroute = FALSE;
      if (*p == '"')
	insidestring = !insidestring;
    }
    p++;
  }

  return (char *)p;
}

void
casify(p, c)
     register char *p;
     int c;
{
    switch (c) {
      case LOWERCASE:
	for (; *p != '\0'; p++)
	    if (isupper(*p))
		*p = tolower(*p);
	break;
      case UPPERCASE:
	for (; *p != '\0'; p++)
	    if (islower(*p))
		*p = toupper(*p);
	break;
    }
}
@


1.9
log
@Added second argument to opendbm() call that determines whether to use
shared or exclusive locks.  Previously a user could suspend a fetch
operation that had an exclusive lock on say domaintable.  This would
then block sendmail in mapinit() when it tried for a shared lock.
Fetch and dump now use shared locks, the other operations require
exclusive locks.
@
text
@d57 28
a84 2
void do_clear(), do_delete(), do_dump(), do_fetch(), do_load(), do_make(),
    do_parse(), do_store();
a123 2
char *scantoken();

d220 1
d251 1
d256 1
a256 1
	if (dbm_store(Dbm, key, key, DBM_REPLACE) != NULL) {
d271 2
a272 2
     char *filename;
     char *access;
d328 1
a328 1
	if (dbm_delete(Dbm, key) != NULL) {
a374 1
    extern char *index();
d430 1
a430 1
	if (dbm_store(Dbm, key, val, Storeflag) != NULL) {
d488 1
a488 1
    if (pipe(pipes) != NULL) {
d543 1
a546 1
    extern char *index();
d580 1
a585 1
    extern char *index();
d602 1
a602 1
	if (dbm_store(Dbm, key, val, Storeflag) != NULL && Storewarn) {
d618 1
a618 1
     register char *p;
d641 1
a641 1
  return p;
d644 1
@


1.8
log
@Shifted forward declaration of scantoken() to top of file.
@
text
@d63 1
d196 2
a197 2
opendbm(access)
     int access;
d217 2
a218 2
    if (flock(dbm_dirfno(Dbm), LOCK_EX) < 0) {
	    (void) fprintf(stderr, "%s: cannot exclusively lock %s\n",
d280 1
a280 1
	opendbm(O_RDWR | O_CREAT | O_TRUNC);
d284 1
a284 1
	opendbm(O_RDWR | O_CREAT | O_TRUNC);
d297 1
a297 1
    opendbm(O_RDWR | O_CREAT);
d320 1
a320 1
    opendbm(O_RDONLY);
d351 1
a351 1
    opendbm(O_RDONLY);
d399 1
a399 1
    opendbm(O_RDWR | O_CREAT);
d461 1
a461 1
    opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC));
d501 1
a501 1
    opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC));
@


1.7
log
@Make dbm care about the results of the flock() call.
@
text
@d42 1
a42 1
#endif !lint
d97 2
a104 1
    char *scantoken();
@


1.6
log
@If flock #define's are present in <sys/file.h>, fake them by #include
"flock.h", then compile with flock.c.
@
text
@d214 7
a220 1
    (void) flock(dbm_dirfno(Dbm), LOCK_EX);
d235 1
a235 1
	
d237 1
@


1.5
log
@Deleted MDBM support, added GDBM.
@
text
@d13 3
@


1.4
log
@Date:    Tue, 5 Jun 90 08:30:57 -0500
To:      paul@@uxc.cso.uiuc.edu
From:    Neil Rickert <rickert@@cs.niu.edu>
Subject: Patch to 'dbm.c'

In the distributed version, a 'dbm' source file entry for say domaintable
of say

FULLY.QUALIFIED.DOMAIN		UNQUALIFIEDDOMAIN

results in two entries in the hashed dbm file:

   KEY                              VALUE

unqualifieddomain		FULLY.QUALIFIED.DOMAIN
FULLY.QUALIFIED.DOMAIN		fully.qualified.domain

The second of these entries appears completely unnecessary, so the patch
fixes it.  With the new Sendmail.mc I sent you, it is useful to be able
to have a dbm entry of the form:

fully.qualified.mx.address	fully.qualified.mx.address

Without the patch trying to create such an entry often leads to error
messages reporting duplicate entries.  The error messages can admittedly
be ignored, but are still disconcerting.
@
text
@d14 4
a17 3
#if defined(MDBM) && defined(SDBM)
   BOTH_MDBM_AND_SDBM_DEFINED;
#endif MDBM && SDBM
d19 11
a29 7
#if defined(MDBM) || defined(SDBM)
# ifdef MDBM
#  include "mdbm_compat.h"
# else MDBM
#  include <sdbm.h>
# endif MDBM
#else MDBM || SDBM
d31 1
a31 6
#endif MDBM || SDBM
#ifndef MDBM
# define DBMFILE DBM
# define DB_DIREXT	".dir"
# define DB_PAGEXT	".pag"
#endif MDBM
d33 4
d206 2
a207 2
	char *filename = (char *) malloc(strlen(Dbmfile) + 20);
	sprintf(filename, "%s{%s,%s}", Dbmfile, DB_DIREXT, DB_PAGEXT);
a306 1
    datum key2;
a314 3
#ifdef MDBM
    for (key = dbm_firstkey(Dbm); key.dptr != NULL; key = dbm_nextkey(Dbm, key)) {
#else MDBM
a315 1
#endif MDBM
d382 1
a382 1
    if (Argc & 1 == 1 && Dbmfile == NULL) {
d522 1
a522 1
	    val = (char *) malloc(p - buf + 1);
@


1.3
log
@Added provision for using sdbm.
@
text
@d517 1
d526 1
d529 1
a529 1
	for (p = buf; *p != '\0';) {
@


1.2
log
@If keyword == fetch and argc == 1, read list of to-be-fetched items from
stdin.  -pbp
@
text
@d13 15
a27 4
#ifdef MDBM
# include "mdbm_compat.h"
#else MDBM
# include <ndbm.h>
@


1.1
log
@Initial revision
@
text
@d325 4
d331 17
@