436 lines
9.7 KiB
C
436 lines
9.7 KiB
C
#include <stdio.h>
|
|
#ifndef VMS
|
|
#include <sys/file.h>
|
|
#include <ndbm.h>
|
|
#else
|
|
#include "file.h"
|
|
#include "ndbm.h"
|
|
#endif
|
|
#include <ctype.h>
|
|
|
|
/***************************************************************************\
|
|
** **
|
|
** Function name: getopt() **
|
|
** Author: Henry Spencer, UofT **
|
|
** Coding date: 84/04/28 **
|
|
** **
|
|
** Description: **
|
|
** **
|
|
** Parses argv[] for arguments. **
|
|
** Works with Whitesmith's C compiler. **
|
|
** **
|
|
** Inputs - The number of arguments **
|
|
** - The base address of the array of arguments **
|
|
** - A string listing the valid options (':' indicates an **
|
|
** argument to the preceding option is required, a ';' **
|
|
** indicates an argument to the preceding option is optional) **
|
|
** **
|
|
** Outputs - Returns the next option character, **
|
|
** '?' for non '-' arguments **
|
|
** or ':' when there is no more arguments. **
|
|
** **
|
|
** Side Effects + The argument to an option is pointed to by 'optarg' **
|
|
** **
|
|
*****************************************************************************
|
|
** **
|
|
** REVISION HISTORY: **
|
|
** **
|
|
** DATE NAME DESCRIPTION **
|
|
** YY/MM/DD ------------------ ------------------------------------ **
|
|
** 88/10/20 Janick Bergeron Returns '?' on unamed arguments **
|
|
** returns '!' on unknown options **
|
|
** and 'EOF' only when exhausted. **
|
|
** 88/11/18 Janick Bergeron Return ':' when no more arguments **
|
|
** 89/08/11 Janick Bergeron Optional optarg when ';' in optstring **
|
|
** **
|
|
\***************************************************************************/
|
|
|
|
char *optarg; /* Global argument pointer. */
|
|
|
|
#ifdef VMS
|
|
#define index strchr
|
|
#endif
|
|
|
|
char
|
|
getopt(int argc, char **argv, char *optstring)
|
|
{
|
|
register int c;
|
|
register char *place;
|
|
extern char *index();
|
|
static int optind = 0;
|
|
static char *scan = NULL;
|
|
|
|
optarg = NULL;
|
|
|
|
if (scan == NULL || *scan == '\0') {
|
|
|
|
if (optind == 0)
|
|
optind++;
|
|
if (optind >= argc)
|
|
return ':';
|
|
|
|
optarg = place = argv[optind++];
|
|
if (place[0] != '-' || place[1] == '\0')
|
|
return '?';
|
|
if (place[1] == '-' && place[2] == '\0')
|
|
return '?';
|
|
scan = place + 1;
|
|
}
|
|
|
|
c = *scan++;
|
|
place = index(optstring, c);
|
|
if (place == NULL || c == ':' || c == ';') {
|
|
|
|
(void) fprintf(stderr, "%s: unknown option %c\n", argv[0], c);
|
|
scan = NULL;
|
|
return '!';
|
|
}
|
|
if (*++place == ':') {
|
|
|
|
if (*scan != '\0') {
|
|
|
|
optarg = scan;
|
|
scan = NULL;
|
|
|
|
}
|
|
else {
|
|
|
|
if (optind >= argc) {
|
|
|
|
(void) fprintf(stderr, "%s: %c requires an argument\n",
|
|
argv[0], c);
|
|
return '!';
|
|
}
|
|
optarg = argv[optind];
|
|
optind++;
|
|
}
|
|
}
|
|
else if (*place == ';') {
|
|
|
|
if (*scan != '\0') {
|
|
|
|
optarg = scan;
|
|
scan = NULL;
|
|
|
|
}
|
|
else {
|
|
|
|
if (optind >= argc || *argv[optind] == '-')
|
|
optarg = NULL;
|
|
else {
|
|
optarg = argv[optind];
|
|
optind++;
|
|
}
|
|
}
|
|
}
|
|
return c;
|
|
}
|
|
|
|
|
|
void
|
|
print_datum(datum db)
|
|
{
|
|
int i;
|
|
|
|
putchar('"');
|
|
for (i = 0; i < db.dsize; i++) {
|
|
if (isprint((unsigned char)db.dptr[i]))
|
|
putchar(db.dptr[i]);
|
|
else {
|
|
putchar('\\');
|
|
putchar('0' + ((db.dptr[i] >> 6) & 0x07));
|
|
putchar('0' + ((db.dptr[i] >> 3) & 0x07));
|
|
putchar('0' + (db.dptr[i] & 0x07));
|
|
}
|
|
}
|
|
putchar('"');
|
|
}
|
|
|
|
|
|
datum
|
|
read_datum(char *s)
|
|
{
|
|
datum db;
|
|
char *p;
|
|
int i;
|
|
|
|
db.dsize = 0;
|
|
db.dptr = (char *) malloc(strlen(s) * sizeof(char));
|
|
if (!db.dptr)
|
|
oops("cannot get memory");
|
|
|
|
for (p = db.dptr; *s != '\0'; p++, db.dsize++, s++) {
|
|
if (*s == '\\') {
|
|
if (*++s == 'n')
|
|
*p = '\n';
|
|
else if (*s == 'r')
|
|
*p = '\r';
|
|
else if (*s == 'f')
|
|
*p = '\f';
|
|
else if (*s == 't')
|
|
*p = '\t';
|
|
else if (isdigit((unsigned char)*s)
|
|
&& isdigit((unsigned char)*(s + 1))
|
|
&& isdigit((unsigned char)*(s + 2)))
|
|
{
|
|
i = (*s++ - '0') << 6;
|
|
i |= (*s++ - '0') << 3;
|
|
i |= *s - '0';
|
|
*p = i;
|
|
}
|
|
else if (*s == '0')
|
|
*p = '\0';
|
|
else
|
|
*p = *s;
|
|
}
|
|
else
|
|
*p = *s;
|
|
}
|
|
|
|
return db;
|
|
}
|
|
|
|
|
|
char *
|
|
key2s(datum db)
|
|
{
|
|
char *buf;
|
|
char *p1, *p2;
|
|
|
|
buf = (char *) malloc((db.dsize + 1) * sizeof(char));
|
|
if (!buf)
|
|
oops("cannot get memory");
|
|
for (p1 = buf, p2 = db.dptr; *p2 != '\0'; *p1++ = *p2++);
|
|
*p1 = '\0';
|
|
return buf;
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
typedef enum {
|
|
YOW, FETCH, STORE, DELETE, SCAN, REGEXP
|
|
} commands;
|
|
char opt;
|
|
int flags;
|
|
int giveusage = 0;
|
|
int verbose = 0;
|
|
commands what = YOW;
|
|
char *comarg[3];
|
|
int st_flag = DBM_INSERT;
|
|
int argn;
|
|
DBM *db;
|
|
datum key;
|
|
datum content;
|
|
|
|
flags = O_RDWR;
|
|
argn = 0;
|
|
|
|
while ((opt = getopt(argc, argv, "acdfFm:rstvx")) != ':') {
|
|
switch (opt) {
|
|
case 'a':
|
|
what = SCAN;
|
|
break;
|
|
case 'c':
|
|
flags |= O_CREAT;
|
|
break;
|
|
case 'd':
|
|
what = DELETE;
|
|
break;
|
|
case 'f':
|
|
what = FETCH;
|
|
break;
|
|
case 'F':
|
|
what = REGEXP;
|
|
break;
|
|
case 'm':
|
|
flags &= ~(000007);
|
|
if (strcmp(optarg, "r") == 0)
|
|
flags |= O_RDONLY;
|
|
else if (strcmp(optarg, "w") == 0)
|
|
flags |= O_WRONLY;
|
|
else if (strcmp(optarg, "rw") == 0)
|
|
flags |= O_RDWR;
|
|
else {
|
|
fprintf(stderr, "Invalid mode: \"%s\"\n", optarg);
|
|
giveusage = 1;
|
|
}
|
|
break;
|
|
case 'r':
|
|
st_flag = DBM_REPLACE;
|
|
break;
|
|
case 's':
|
|
what = STORE;
|
|
break;
|
|
case 't':
|
|
flags |= O_TRUNC;
|
|
break;
|
|
case 'v':
|
|
verbose = 1;
|
|
break;
|
|
case 'x':
|
|
flags |= O_EXCL;
|
|
break;
|
|
case '!':
|
|
giveusage = 1;
|
|
break;
|
|
case '?':
|
|
if (argn < 3)
|
|
comarg[argn++] = optarg;
|
|
else {
|
|
fprintf(stderr, "Too many arguments.\n");
|
|
giveusage = 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (giveusage || what == YOW || argn < 1) {
|
|
fprintf(stderr, "Usage: %s databse [-m r|w|rw] [-crtx] -a|-d|-f|-F|-s [key [content]]\n", argv[0]);
|
|
exit(-1);
|
|
}
|
|
|
|
if ((db = dbm_open(comarg[0], flags, 0777)) == NULL) {
|
|
fprintf(stderr, "Error opening database \"%s\"\n", comarg[0]);
|
|
exit(-1);
|
|
}
|
|
|
|
if (argn > 1)
|
|
key = read_datum(comarg[1]);
|
|
if (argn > 2)
|
|
content = read_datum(comarg[2]);
|
|
|
|
switch (what) {
|
|
|
|
case SCAN:
|
|
key = dbm_firstkey(db);
|
|
if (dbm_error(db)) {
|
|
fprintf(stderr, "Error when fetching first key\n");
|
|
goto db_exit;
|
|
}
|
|
while (key.dptr != NULL) {
|
|
content = dbm_fetch(db, key);
|
|
if (dbm_error(db)) {
|
|
fprintf(stderr, "Error when fetching ");
|
|
print_datum(key);
|
|
printf("\n");
|
|
goto db_exit;
|
|
}
|
|
print_datum(key);
|
|
printf(": ");
|
|
print_datum(content);
|
|
printf("\n");
|
|
if (dbm_error(db)) {
|
|
fprintf(stderr, "Error when fetching next key\n");
|
|
goto db_exit;
|
|
}
|
|
key = dbm_nextkey(db);
|
|
}
|
|
break;
|
|
|
|
case REGEXP:
|
|
if (argn < 2) {
|
|
fprintf(stderr, "Missing regular expression.\n");
|
|
goto db_exit;
|
|
}
|
|
if (re_comp(comarg[1])) {
|
|
fprintf(stderr, "Invalid regular expression\n");
|
|
goto db_exit;
|
|
}
|
|
key = dbm_firstkey(db);
|
|
if (dbm_error(db)) {
|
|
fprintf(stderr, "Error when fetching first key\n");
|
|
goto db_exit;
|
|
}
|
|
while (key.dptr != NULL) {
|
|
if (re_exec(key2s(key))) {
|
|
content = dbm_fetch(db, key);
|
|
if (dbm_error(db)) {
|
|
fprintf(stderr, "Error when fetching ");
|
|
print_datum(key);
|
|
printf("\n");
|
|
goto db_exit;
|
|
}
|
|
print_datum(key);
|
|
printf(": ");
|
|
print_datum(content);
|
|
printf("\n");
|
|
if (dbm_error(db)) {
|
|
fprintf(stderr, "Error when fetching next key\n");
|
|
goto db_exit;
|
|
}
|
|
}
|
|
key = dbm_nextkey(db);
|
|
}
|
|
break;
|
|
|
|
case FETCH:
|
|
if (argn < 2) {
|
|
fprintf(stderr, "Missing fetch key.\n");
|
|
goto db_exit;
|
|
}
|
|
content = dbm_fetch(db, key);
|
|
if (dbm_error(db)) {
|
|
fprintf(stderr, "Error when fetching ");
|
|
print_datum(key);
|
|
printf("\n");
|
|
goto db_exit;
|
|
}
|
|
if (content.dptr == NULL) {
|
|
fprintf(stderr, "Cannot find ");
|
|
print_datum(key);
|
|
printf("\n");
|
|
goto db_exit;
|
|
}
|
|
print_datum(key);
|
|
printf(": ");
|
|
print_datum(content);
|
|
printf("\n");
|
|
break;
|
|
|
|
case DELETE:
|
|
if (argn < 2) {
|
|
fprintf(stderr, "Missing delete key.\n");
|
|
goto db_exit;
|
|
}
|
|
if (dbm_delete(db, key) || dbm_error(db)) {
|
|
fprintf(stderr, "Error when deleting ");
|
|
print_datum(key);
|
|
printf("\n");
|
|
goto db_exit;
|
|
}
|
|
if (verbose) {
|
|
print_datum(key);
|
|
printf(": DELETED\n");
|
|
}
|
|
break;
|
|
|
|
case STORE:
|
|
if (argn < 3) {
|
|
fprintf(stderr, "Missing key and/or content.\n");
|
|
goto db_exit;
|
|
}
|
|
if (dbm_store(db, key, content, st_flag) || dbm_error(db)) {
|
|
fprintf(stderr, "Error when storing ");
|
|
print_datum(key);
|
|
printf("\n");
|
|
goto db_exit;
|
|
}
|
|
if (verbose) {
|
|
print_datum(key);
|
|
printf(": ");
|
|
print_datum(content);
|
|
printf(" STORED\n");
|
|
}
|
|
break;
|
|
}
|
|
|
|
db_exit:
|
|
dbm_clearerr(db);
|
|
dbm_close(db);
|
|
if (dbm_error(db)) {
|
|
fprintf(stderr, "Error closing database \"%s\"\n", comarg[0]);
|
|
exit(-1);
|
|
}
|
|
}
|