home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_C
/
RECIO110.ZIP
/
RECIO.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-03-28
|
33KB
|
913 lines
/*****************************************************************************
MODULE: recio.c
PURPOSE: defines primary functions for recio library
COPYRIGHT: (C) 1994 William Pierpoint
COMPILER: Borland C Version 3.1
OS: MSDOS Version 6.2
VERSION: 1.10
RELEASE: Mar 28, 1994
*****************************************************************************/
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "recio.h"
/* private macros */
#define RECBUFSIZ_MIN 2 /* min one character and new line */
#define FLDBUFSIZ_MIN 1 /* min one character */
#define ROPEN_MIN 1 /* reserved for recin */
#define RECBUFSIZE max(RECBUFSIZ, RECBUFSIZ_MIN)
#define FLDBUFSIZE max(FLDBUFSIZ, FLDBUFSIZ_MIN)
#define ROPEN max(ROPEN_MAX, ROPEN_MIN)
#define rcol(rp) ((rp)->r_colno)
#define rflags(rp) ((rp)->r_flags)
#define rfd(rp) ((rp)->r_fd)
#define rfp(rp) ((rp)->r_fp)
#define rreclen(rp) ((rp)->r_reclen)
#define rrecsiz(rp) ((rp)->r_recsiz)
#define rfldsiz(rp) ((rp)->r_fldsiz)
#define rfldch(rp) ((rp)->r_fldch)
#define rtxtch(rp) ((rp)->r_txtch)
/* private module variables */
REC *_RECS = NULL; /* pointer to array of REC structures */
void (*_r_errfn)(REC *) = NULL; /* pointer to error function */
static REC rin = { 1, NULL, stdin, "stdin", 0L,
0, 0, 0, 0, NULL,
0, NULL, RECFLDCH, RECTXTCH, RECIN };
/* public recin */
REC *recin = &rin;
/* Support functions */
/****************************************************************************/
static void /* returns nothing */
_rexit( /* at program exit, clean up */
void) /* no arguments */
/****************************************************************************/
{
/* free recin buffers */
free(rflds(recin));
free(rrecs(recin));
rflds(recin) = NULL;
rfldsiz(recin) = 0;
rrecs(recin) = NULL;
rrecsiz(recin) = 0;
rreclen(recin) = 0;
/* ensure all record streams closed */
rcloseall();
}
/****************************************************************************/
static int /* return error number (0=no error) */
__rstatus( /* check stream for errors */
REC *rp) /* record pointer */
/****************************************************************************/
{
int errnum=0; /* error number */
static int once=0; /* register exit fn only once */
/* test for valid record pointer */
if (!risvalid(rp)) {
errnum = rseterr(NULL, EINVAL);
goto done;
}
/* register _rexit() with atexit() */
if (!once) {
/* execute this path at most one time */
once++;
/* if atexit() fails to register _rexit() function */
if (atexit(_rexit)) {
/* register error */
rseterr(rp, R_ENOREG);
}
}
/* test for previous error */
errnum = rerror(rp);
done:
return (errnum);
}
/****************************************************************************/
int /* return error number (0=no error) */
_rstatus( /* check stream for errors and record position */
REC *rp) /* record pointer */
/****************************************************************************/
{
int errnum; /* error number */
errnum = __rstatus(rp);
if (errnum) goto done;
/* make sure first record is read from file */
if (!rrecno(rp)) {
if (!rgetrec(rp)) {
errnum = rerror(rp);
}
}
done:
return (errnum);
}
/****************************************************************************/
char * /* returns pointer to field string */
_rerrs( /* get field string if errfn() cleared error */
REC *rp, /* record pointer */
int errnum) /* error number */
/****************************************************************************/
{
char *fldp=NULL; /* pointer to field string */
if (!rseterr(rp, errnum)) fldp = rflds(rp);
return (fldp);
}
/****************************************************************************/
static void /* returns nothing */
_rfree( /* free the memory allocated to a record */
REC *rp) /* record pointer */
/****************************************************************************/
{
if (risvalid(rp)) {
free(rflds(rp));
free(rrecs(rp));
if (rfp(rp)) fclose(rfp(rp));
memset(rp, 0, sizeof(REC));
}
}
/****************************************************************************/
int /* return error number (0=no error) */
_rsetrecsiz( /* set record buffer size */
REC *rp, /* record pointer */
size_t recsiz) /* record buffer size */
/****************************************************************************/
{
int errnum=0; /* error number */
char *recp; /* pointer to new record buffer */
/* if no memory allocated to field buffer */
if (!rrecs(rp)) {
/* determine minimum size of record buffer */
recsiz = max(recsiz, RECBUFSIZE);
/* initially allocate memory for record buffer */
do {
recp = (char *) calloc(recsiz+1, sizeof(char));
if (!recp) {
errnum = rseterr(rp, R_ENOMEM);
if (errnum) goto done;
}
} while (!recp);
rrecs(rp) = recp;
rrecsiz(rp) = recsiz;
/* if record buffer needs to be larger */
} else if (recsiz > rrecsiz(rp)) {
/* reallocate memory for record buffer */
do {
recp = (char *) realloc(rrecs(rp), recsiz+1);
if (!recp) {
errnum = rseterr(rp, R_ENOMEM);
if (errnum) goto done;
}
} while (!recp);
rrecs(rp) = recp;
rrecsiz(rp) = recsiz;
}
done:
return (errnum);
}
/****************************************************************************/
int /* return error number (0=no error) */
_rsetfldsiz( /* set field buffer size */
REC *rp, /* record pointer */
size_t fldsiz) /* field buffer size */
/****************************************************************************/
{
int errnum=0; /* error number */
char *fldp; /* pointer to new field buffer */
/* if no memory allocated to field buffer */
if (!rflds(rp)) {
/* determine minimum size of field buffer */
fldsiz = max(fldsiz, FLDBUFSIZE);
/* initially allocate memory for field buffer */
do {
fldp = (char *) calloc(fldsiz+1, sizeof(char));
if (!fldp) {
errnum = rseterr(rp, R_ENOMEM);
if (errnum) goto done;
}
} while (!fldp);
rflds(rp) = fldp;
rfldsiz(rp) = fldsiz;
/* if field buffer needs to be larger */
} else if (fldsiz > rfldsiz(rp)) {
/* reallocate memory for field buffer */
do {
fldp = (char *) realloc(rflds(rp), fldsiz+1);
if (!fldp) {
errnum = rseterr(rp, R_ENOMEM);
if (errnum) goto done;
}
} while (!fldp);
rflds(rp) = fldp;
rfldsiz(rp) = fldsiz;
}
done:
return (errnum);
}
/****************************************************************************/
static int /* return !0 on match */
isfldch( /* is character the field separator character? */
REC *rp, /* record pointer */
int ch) /* character to test */
/****************************************************************************/
{
int ismatch=0; /* return 0 if no match */
if (isascii(ch)) {
if (rfldch(rp) == ' ') {
ismatch = isspace(ch);
} else {
ismatch = (!(ch - rfldch(rp)));
}
}
return (ismatch);
}
/****************************************************************************/
static int /* return !0 on match */
istxtch( /* is character the text delimiter character? */
REC *rp, /* record pointer */
int ch) /* character to test */
/****************************************************************************/
{
int ismatch=0; /* return 0 if no match */
if (isascii(ch)) {
if (rtxtch(rp) == ' ') {
ismatch = isspace(ch);
} else {
ismatch = (!(ch - rtxtch(rp)));
}
}
return (ismatch);
}
/****************************************************************************/
static size_t /* return length of field */
_rfldlen( /* get length of field */
REC *rp) /* record pointer */
/****************************************************************************/
{
size_t len=0; /* length of field (0=missing field)*/
size_t col; /* column location */
int ch; /* character at column location */
int qstate=0; /* quoted string state (0=off; 1=on) */
/* get column location for first non-whitespace character in field */
for (col=rcol(rp); col < rreclen(rp); col++) {
if (!isspace(rrecs(rp)[col])) break;
}
/* find field separator at end of field */
if (istxtch(rp, ' ')) {
for (; col < rreclen(rp); col++) {
ch = rrecs(rp)[col];
if (isfldch(rp, ch)) break;
}
} else {
for (; col < rreclen(rp); col++) {
ch = rrecs(rp)[col];
/* don't search for fldch between txtch's */
if (istxtch(rp, ch)) qstate = !qstate;
if (!qstate && isfldch(rp, ch)) break;
}
}
/* get length of field */
if (rcol(rp) < rreclen(rp)) {
len = col - rcol(rp) + 1;
}
return (len);
}
/****************************************************************************/
static int /* return error state (0=no error) */
_rskipfld( /* skip to the next field */
REC *rp, /* record pointer */
size_t len) /* length of field if known, 0 if unknown */
/****************************************************************************/
{
int err=0; /* error state (0=no error; EOF=past end-of-record) */
/* if length of field is unknown */
if (!len) {
/* determine length */
len=_rfldlen(rp);
}
/* if not at end of record */
if (rcol(rp) <= rreclen(rp)) {
/* move to next field */
rcol(rp) += max(len, 1);
/* error if attempt to move past end of record */
} else {
err = EOF;
}
rfldno(rp)++;
return (err);
}
/****************************************************************************/
static char * /* return trimmed string */
_sctrimbegs( /* trim beginning of string */
char *str, /* string to trim */
int ch) /* character to match */
/****************************************************************************/
{
char *sp; /* string pointer */
if (str && *str && ch) {
sp = str;
/* increment through string while match is true */
/* match any white space if ch is space */
while ((ch == ' ') ? (isspace(*sp)) : (*sp == ch)) sp++;
if (sp != str) memmove(str, sp, strlen(sp)+1);
}
return str;
}
/****************************************************************************/
static char * /* return trimmed string */
_sctrimends( /* trim end of string */
char *str, /* string to trim */
int ch) /* character to match */
/****************************************************************************/
{
char *sp; /* string pointer */
if (str && *str && ch) {
/* point sp at last character in string */
sp = str + strlen(str) - 1;
/* decrement through string while match is true */
/* match any white space if ch is space */
while ((ch == ' ') ? (isspace(*sp)) : (*sp == ch)) {
*sp = '\0';
if (sp-- == str) break;
}
}
return str;
}
/****************************************************************************/
static char * /* return trimmed string */
_sctrims( /* trim character from both ends of string */
char *str, /* string to trim */
int ch) /* character to match */
/****************************************************************************/
{
return _sctrimbegs(_sctrimends(str, ch), ch);
}
/****************************************************************************/
static char * /* return pointer to string */
_rtrims( /* trim fldch, white space, and txtch */
REC *rp, /* record pointer */
char *str) /* string pointer */
/****************************************************************************/
{
_sctrims(str, rfldch(rp));
_sctrims(str, ' ');
_sctrims(str, rtxtch(rp));
return (str);
}
/****************************************************************************/
char * /* return pointer to field buffer (NULL=error) */
_rfldstr( /* copy field from record to field buffer */
REC *rp, /* record pointer */
size_t len) /* length of field if known; 0 if unknown */
/****************************************************************************/
{
char *fldp=NULL; /* pointer to field buffer (NULL=error) */
size_t fldlen=len; /* computed length of field */
/* if character delimited field, compute length */
if (!fldlen) {
fldlen=_rfldlen(rp);
/* if column delimited field, avoid overflow */
} else if (rcol(rp) > rreclen(rp)) {
fldlen = 0;
}
/* ensure field buffer has sufficient memory */
if (_rsetfldsiz(rp, fldlen)) goto done;
/* copy field from record buffer to field buffer */
/* note: a missing field results in an empty string */
strncpy(rflds(rp), rrecs(rp)+rcol(rp), fldlen);
rflds(rp)[fldlen] = '\0';
/* set up for next field */
_rskipfld(rp, max(fldlen, 1));
/* if character delimited field, trim field buffer */
if (!len) _rtrims(rp, rflds(rp));
/* assign return pointer to field buffer */
fldp = rflds(rp);
done:
return (fldp);
}
/* User functions */
/****************************************************************************/
REC * /* return record pointer */
ropen( /* open a record stream for reading */
const char *fname, /* name of file to open */
const char *mode) /* type of mode used to open file */
/****************************************************************************/
{
REC *rp = _RECS; /* record pointer */
int i; /* count of REC structures */
/* only mode currently supported is "r" */
if (strcmp(mode, "r")) {
rp = NULL;
rseterr(NULL, EINVAL);
goto done;
}
/* allocate memory for array of REC structures */
if (!rp) {
do {
/* note: no memory allocation needed for recin */
rp = _RECS = (REC *) calloc(ROPEN-1, sizeof(REC));
if (!rp) {
if (rseterr(NULL, ENOMEM)) goto done;
}
} while (!rp);
}
/* search thru REC structures until empty position found */
for (i=2; i <= ROPEN; i++, rp++) {
if (!rfd(rp)) {
rfd(rp) = i;
break;
}
}
/* error if out of positions */
if (i > ROPEN) {
rp = NULL;
rseterr(NULL, EMFILE);
goto done;
}
/* open file */
rfp(rp) = fopen(fname, mode);
if (!rfp(rp)) {
rclose(rp);
rp = NULL;
/* if error other than path/file not found */
if (errno != ENOENT) {
rseterr(NULL, errno);
}
goto done;
}
/* initialize */
rflags(rp) = 0;
rnames(rp) = fname;
rrecno(rp) = 0L;
rfldno(rp) = 0;
rcol(rp) = 0;
rrecsiz(rp) = 0;
rreclen(rp) = 0;
rrecs(rp) = NULL;
rfldsiz(rp) = 0;
rflds(rp) = NULL;
rfldch(rp) = RECFLDCH;
rtxtch(rp) = RECTXTCH;
__rstatus(rp);
done:
return (rp);
}
/****************************************************************************/
int /* return error number (0=no error) */
rclose( /* close a record stream */
REC *rp) /* record pointer */
/****************************************************************************/
{
int errnum=0; /* error number (0=no error) */
int i; /* count REC structures */
REC *recp=_RECS; /* pointer to _RECS array */
if (risvalid(rp)) {
/* close record stream, but not recin */
if (rfd(rp) > 1) _rfree(rp);
/* if all record streams closed, free _RECS */
/* note: valid rp implies valid recp */
for (i=2; i <= ROPEN; i++, recp++) {
if (rfd(recp)) goto done;
}
free(_RECS);
_RECS = NULL;
} else {
errnum = rseterr(NULL, EINVAL);
}
done:
return (errnum);
}
/****************************************************************************/
int /* returns number of streams closed */
rcloseall( /* close all record streams */
void) /* no arguments */
/****************************************************************************/
{
int num=0; /* number of streams closed */
int i; /* count REC structures */
REC *recp=_RECS; /* pointer to _RECS array */
/* close every open record stream, except recin */
if (recp) {
for (i=2; i <= ROPEN; i++, recp++) {
if (rfd(recp)) {
_rfree(recp);
num++;
}
}
free(_RECS);
_RECS = NULL;
}
return (num);
}
/****************************************************************************/
char * /* return pointer to record buffer (NULL=error)*/
rgetrec( /* read next line from file into record buffer */
REC *rp) /* record pointer */
/****************************************************************************/
{
char *retp=NULL; /* return pointer (NULL=error) */
char str[FLDBUFSIZE+1]; /* temporary string */
if (!__rstatus(rp)) {
/* initially allocate memory for record buffer */
if (!rrecs(rp)) {
if (_rsetrecsiz(rp, RECBUFSIZE)) goto done;
}
/* reset field and column numbers */
rfldno(rp) = 0;
rcol(rp) = 0;
/* if at end of file, skip reading from file */
if (reof(rp)) goto done;
/* get next line from file into record buffer */
if (!fgets(rrecs(rp), rrecsiz(rp), rfp(rp))) {
/* set end-of-file indicator if no more records */
rflags(rp) |= _R_EOF;
goto done;
}
rreclen(rp) = strlen(rrecs(rp));
/* if line longer than record buffer, extend record buffer */
while (rrecs(rp)[rreclen(rp)-1] != '\n') {
if (!fgets(str, FLDBUFSIZE+1, rfp(rp))) break;
if (_rsetrecsiz(rp, rrecsiz(rp) + FLDBUFSIZE)) goto done;
strncat(rrecs(rp), str, FLDBUFSIZE);
rreclen(rp) = strlen(rrecs(rp));
}
/* trim end of record */
_sctrimends(rrecs(rp), '\n');
/* increment record number */
rrecno(rp)++;
retp = rrecs(rp);
}
done:
return (retp);
}
/****************************************************************************/
int /* return number fields skipped; EOF on error */
rskipnfld( /* skip over next number of fields */
REC *rp, /* record pointer */
size_t num) /* number of fields to skip over */
/****************************************************************************/
{
int count=EOF; /* actual number of fields skipped (EOF=error) */
if (!_rstatus(rp)) {
/* count number of fields to skip */
count = 0;
while (count < num) {
/* but don't count past end of record */
if (_rskipfld(rp, 0)) {
break;
}
count++;
}
}
return (count);
}
/****************************************************************************/
int /* return !0 for valid; 0 for invalid */
risvalid( /* is record pointer valid? */
REC *rp) /* record pointer */
/****************************************************************************/
{
int valid=1; /* validation state (!0=valid) */
/* if rp is null pointer or rfd not between 1 and ROPEN */
if (!rp || rfd(rp) <= 0 || rfd(rp) > ROPEN) {
/* invalid record pointer */
valid = 0;
}
return (valid);
}
/****************************************************************************/
void /* returns nothing */
rseterrfn( /* registers a call-back error function */
void(*rerrfn)(REC *rp))/* pointer to error function */
/****************************************************************************/
{
_r_errfn = rerrfn; /* point to call back function */
}
/****************************************************************************/
void /* returns nothing */
rclearerr( /* clears error and eof indicators */
REC *rp) /* record pointer */
/****************************************************************************/
{
if (risvalid(rp)) {
errno = 0;
rflags(rp) &= _R_COL;
} else {
rseterr(NULL, EINVAL);
}
}
/****************************************************************************/
int /* returns error number (0=no error */
rerror( /* gets error number for record stream */
REC *rp) /* record pointer */
/****************************************************************************/
{
int errnum; /* return error number */
if (risvalid(rp)) {
errnum = rflags(rp);
errnum >>= 2;
} else {
errnum = rseterr(NULL, EINVAL);
}
return (errnum);
}
/****************************************************************************/
int /* returns possibly modified error number */
rseterr( /* sets error number and calls error function */
REC *rp, /* record pointer */
int errnum) /* error number */
/****************************************************************************/
{
/* if valid record pointer and stream error number clear */
if (risvalid(rp)) {
if (!rerror(rp)) {
/* set error number on stream */
rflags(rp) |= errnum << 2;
/* invoke callback error function */
if (_r_errfn) _r_errfn(rp);
/* find out if errfn() cleared error */
errnum = rerror(rp);
}
/* else invalid record pointer */
} else {
/* set global error number */
errno = errnum;
/* invoke callback error function */
if (_r_errfn) _r_errfn(rp);
/* find out if errfn() cleared error */
errnum = errno;
}
/* if errfn cleared error, 0 returned */
return (errnum);
}
/****************************************************************************/
int /* return error number (0=no error) */
rsetrecsiz( /* set record buffer size */
REC *rp, /* record pointer */
size_t recsiz) /* record buffer size */
/****************************************************************************/
{
int errnum; /* error number (0=no error) */
if (risvalid(rp)) {
errnum = _rsetrecsiz(rp, recsiz);
} else {
errnum = rseterr(NULL, EINVAL);
}
return (errnum);
}
/****************************************************************************/
int /* return error number (0=no error) */
rsetfldsiz( /* set field buffer size */
REC *rp, /* record pointer */
size_t fldsiz) /* field buffer size */
/****************************************************************************/
{
int errnum; /* error number (0=no error) */
if (risvalid(rp)) {
errnum = _rsetfldsiz(rp, fldsiz);
} else {
errnum = rseterr(NULL, EINVAL);
}
return (errnum);
}
/****************************************************************************/
int /* return error number (0=no error) */
rsetfldstr( /* copy string into field buffer; clear errors */
REC *rp, /* record pointer */
char *s) /* pointer to string */
/****************************************************************************/
{
int errnum=0; /* error number (0=no error) */
size_t fldsiz; /* required field buffer size */
if (risvalid(rp)) {
if (s) {
/* ensure field buffer is large enough for string */
fldsiz = strlen(s);
if (fldsiz > rfldsiz(rp)) {
errnum = _rsetfldsiz(rp, fldsiz);
if (errnum) goto done;
}
/* copy string to field buffer */
strcpy(rflds(rp), s);
/* clear away any errors */
rclearerr(rp);
} else {
errnum = rseterr(rp, R_EINVAL);
}
} else {
errnum = rseterr(NULL, EINVAL);
}
done:
return (errnum);
}
/****************************************************************************/
int /* return error number (0=no error) */
rsetfldch( /* set field separator character */
REC *rp, /* record pointer */
int ch) /* field separator character */
/****************************************************************************/
{
int errnum=0; /* error number (0=no error) */
if (risvalid(rp)) {
if (isascii(ch)) {
rfldch(rp) = ch;
} else {
errnum = rseterr(rp, R_EINVAL);
}
} else {
errnum = rseterr(NULL, EINVAL);
}
return (errnum);
}
/****************************************************************************/
int /* return error number (0=no error) */
rsettxtch( /* set text string delimiter character */
REC *rp, /* record pointer */
int ch) /* text delimiter character */
/****************************************************************************/
{
int errnum=0; /* error number (0=no error) */
if (risvalid(rp)) {
if (isascii(ch)) {
rtxtch(rp) = ch;
} else {
errnum = rseterr(rp, R_EINVAL);
}
} else {
errnum = rseterr(NULL, EINVAL);
}
return (errnum);
}
/****************************************************************************/
int /* return 0 on success; errnum on error */
rsetcxtno( /* set context number of record stream */
REC *rp, /* record pointer */
int cxtno) /* context number */
/****************************************************************************/
{
int errnum=0; /* error number (0=no error) */
if (risvalid(rp)) {
if (rcxtno(rp) >= 0 && cxtno >= 0) {
rcxtno(rp) = cxtno;
} else {
errnum = rseterr(rp, R_EINVAL);
}
} else {
errnum = rseterr(NULL, EINVAL);
}
return (errnum);
}
/****************************************************************************/
int /* return 0 on success; errnum on error */
rsetbegcolno( /* set beginning record column number */
REC *rp, /* record pointer */
int colno) /* first column in record is 0 or 1 */
/****************************************************************************/
{
int errnum=0; /* error number (0=no error) */
if (risvalid(rp)) {
if (colno == 1) {
rflags(rp) |= _R_COL;
} else if (colno == 0) {
rflags(rp) &= ~_R_COL;
} else {
errnum = rseterr(rp, R_EINVAL);
}
} else {
errnum = rseterr(NULL, EINVAL);
}
return (errnum);
}