|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T d
Length: 13360 (0x3430)
Types: TextFile
Names: »dbm.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦bfebc70e2⟧ »EurOpenD3/mail/sendmail-5.65b+IDA-1.4.3.tar.Z«
└─⟦f9e35cd84⟧
└─⟦this⟧ »sendmail/ida/aux/dbm.c«
/*
** 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;
}
}