/* * simple history database manager for UUPC news * * Author: Kai Uwe Rommel * Created: Sun Aug 15 1993 * * Bug reports related to THIS modified version should be sent to * * harald@os2point.ping.de * harald@haport.sesam.com * Fido: 2:2448/434 * */ /*--------------------------------------------------------------------*/ /* Changes Copyright (c) 1989-1994 by Kendra Electronic */ /* Wonderworks. */ /* */ /* All rights reserved except those explicitly granted by */ /* the UUPC/extended license agreement. */ /*--------------------------------------------------------------------*/ static char *rcsid = "$Id: dbm.c 1.5 1994/03/07 06:09:51 ahd Exp $"; static char *rcsrev = "$Revision: 1.5 $"; /*--------------------------------------------------------------------*/ /* RCS Information */ /*--------------------------------------------------------------------*/ /* $Log: dbm.c $ * Revision 1.5 1994/03/07 06:09:51 ahd * Add additional error messages to error returns * * Revision 1.5 1994/03/07 06:09:51 ahd * Add additional error messages to error returns * * Revision 1.4 1994/02/19 04:21:38 ahd * Use standard first header * * Revision 1.4 1994/02/19 04:21:38 ahd * Use standard first header * * Revision 1.3 1994/01/18 13:29:22 ahd * Add standard UUPC/extended error logging routines for run time * library errors * * Revision 1.2 1993/11/06 17:54:55 rhg * Drive Drew nuts by submitting cosmetic changes mixed in with bug fixes * * Revision 1.1 1993/09/05 10:56:49 rommel * Initial revision * */ #include #include #include #include #include #include #include #include #include currentfile(); datum nullitem = {NULL, 0}; DBM *dbm_open(const char *name, int flags, int mode) { DBM *db = malloc(sizeof(DBM)); char *filename = malloc(_MAX_PATH); strcpy(filename, name); strcat(filename, DBM_EXT_DBF); #ifdef LOGGING if(dolog(LOG_DBM)) lprintf("Open %s", filename); #endif if ((db->dbffile = open(filename, flags | O_BINARY, mode)) == -1) { lperror(filename); free(db); free(filename); return NULL; } strcpy(filename, name); strcat(filename, DBM_EXT_IDX); #ifdef LOGGING if(dolog(LOG_DBM)) lprintf("Open %s", filename); #endif if ((db->idxfile = open(filename, flags | O_BINARY, mode)) == -1) { lperror(filename); close(db->dbffile); free(db); free(filename); return NULL; } if ((db->idx = idx_init(db->idxfile)) == NULL) { lprintf("Unable to initialize index"); close(db->dbffile); close(db->idxfile); free(db); free(filename); return NULL; } db->magic = DBM_MAGIC; free(filename); return db; } void dbm_close(DBM * db) { if (db == NULL || db->magic != DBM_MAGIC) return; idx_exit(db->idx); close(db->idxfile); close(db->dbffile); free(db); } int dbm_store(DBM * db, datum key, datum val, int flag) { char *buffer; long offset; int size; if (db == NULL || db->magic != DBM_MAGIC) return -1; if ((offset = lseek(db->dbffile, 0, SEEK_END)) == -1L) return -1; buffer = memset(malloc(BUFSIZ), ' ', BUFSIZ); memcpy(buffer, key.dptr, key.dsize); size = key.dsize; buffer[size - 1] = ' '; /* replace zero */ memcpy(buffer + size, val.dptr, val.dsize); size += val.dsize; buffer[size - 1] = '\n'; if (idx_addkey(db->idx, key.dptr, offset, size) == -1) { free(buffer); return -1; } if (write(db->dbffile, buffer, size) != size) { lperror("dbm_store"); free(buffer); return -1; } if(flag) ; free(buffer); return 0; } /* * Changed some code to keep the ids of expired/cancelled articles. * As this is a bad hack done to these holy routines, I changed the * name from dmb_delete to dbm_cancel. * * 25.05.95 harald */ int dbm_cancel(DBM * db, datum key) { register char *cp; char *buffer; long offset; int size; if (db == NULL || db->magic != DBM_MAGIC) return -1; if (idx_getkey(db->idx, key.dptr, &offset, &size) != -1) { if (lseek(db->dbffile, offset, SEEK_SET) == -1L) return -1; buffer = malloc(size + 1); buffer[size] = '\0'; if (read(db->dbffile, buffer, size) != size) { free(buffer); return -1; } cp = buffer; while(*cp && *cp != ' ' && *cp != '\t') cp++; while(*cp == ' ' || *cp == '\t') cp++; while(*cp) *cp++ = ' '; buffer[size - 1] = '\n'; if (lseek(db->dbffile, offset, SEEK_SET) == -1L) { free(buffer); return -1; } if (write(db->dbffile, buffer, size) != size) { free(buffer); return -1; } free(buffer); } return 0; } datum dbm_fetch(DBM * db, datum key) { datum val = nullitem; long offset; int size; if (db == NULL || db->magic != DBM_MAGIC) return nullitem; if (db->stream && strcmp(key.dptr, db->buffer) == 0) { val.dptr = db->value; val.dsize = strlen(val.dptr) + 1; } else if (idx_getkey(db->idx, key.dptr, &offset, &size) != -1) { if ((offset = lseek(db->dbffile, offset, SEEK_SET)) == -1L) return nullitem; if (read(db->dbffile, db->buffer, size) != size) return nullitem; db->buffer[size - 1] = 0; /* delete \n */ val.dptr = strchr(db->buffer, ' ') + 1; val.dsize = strlen(val.dptr) + 1; } return val; } /* Accessing the database sequentially is not as easy as the records * are of variable length to save space and make it look like a text * file. So we just put a stream on top of it and read it this way. */ datum dbm_firstkey(DBM * db) { datum val = nullitem; char *ptr; int handle; if (db == NULL || db->magic != DBM_MAGIC) return nullitem; if (lseek(db->dbffile, 0, SEEK_SET) == -1L) return nullitem; if ((handle = dup(db->dbffile)) == -1) return nullitem; if ((db->stream = fdopen(handle, "rb")) == NULL) { lperror("dbm_firstkey"); return nullitem; } do { /* skip blanked out records */ if (fgets(db->buffer, sizeof(db->buffer), db->stream) == NULL) return nullitem; } while (db->buffer[0] == ' '); if ((ptr = strchr(db->buffer, ' ')) == NULL) return nullitem; db->buffer[strlen(db->buffer) - 1] = 0; /* delete \n */ *ptr = 0; db->value = ptr + 1; val.dptr = db->buffer; val.dsize = strlen(db->buffer) + 1; return val; } datum dbm_nextkey(DBM * db) { datum val = nullitem; char *ptr; if (db == NULL || db->magic != DBM_MAGIC || db->stream == NULL) return nullitem; do { /* skip blanked out records */ if (fgets(db->buffer, sizeof(db->buffer), db->stream) == NULL) return fclose(db->stream), (db->stream = NULL), nullitem; } while (db->buffer[0] == ' '); if ((ptr = strchr(db->buffer, ' ')) == NULL) return nullitem; db->buffer[strlen(db->buffer) - 1] = 0; /* delete \n */ *ptr = 0; db->value = ptr + 1; val.dptr = db->buffer; val.dsize = strlen(db->buffer) + 1; return val; }