|
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; } }