/*
* LIB/INCLUDE.C
*
* (c)Copyright 2002, Joe Greco and sol.net Network Services.
* All Rights Reserved. Refer to the COPYRIGHT file in the
* base directory of this distribution for specific rights
* granted.
*/
#include "defs.h"
Prototype FILE *iopen(const char *path, const char *mode);
Prototype int iclose(FILE *stream);
Prototype char *igets(char *str, int size, FILE *stream);
Prototype int istat(int fd, struct stat *st);
/*
* These functions are designed to (very!) loosely replace
* fopen/fclose/fgets, interpreting the named file as a
* include-directive preprocessor.
*
* Only one instance at a time is supported.
*/
#define MAXLEVELS 4
#define MAXFILES 1024
int inc_initialized = 0;
int inc_isopen = 0;
FILE *inc_fps[MAXLEVELS];
int inc_nfps = 0;
int inc_prog[MAXLEVELS];
char *inc_files[MAXFILES];
int inc_nfiles = 0;
/*
* The return from this isn't a usable FILE *. It's just
* NULL for failure or non-NULL for success.
*/
FILE *
iopen(const char *path, const char *mode)
{
FILE *rval;
int i;
if (! inc_initialized) {
inc_initialized++;
bzero((char *)inc_fps, sizeof(inc_fps));
bzero((char *)inc_prog, sizeof(inc_prog));
bzero((char *)inc_files, sizeof(inc_files));
}
/*
* Only allow one instance
*/
if (inc_isopen) {
logit(LOG_ERR, "iopen failed; already open");
return(NULL);
}
/*
* Clear the cached filenames being used by istat
*/
for (i = 0; i < inc_nfiles; i++) {
zfreeStr(&SysMemPool, &inc_files[i]);
inc_files[i] = NULL;
}
inc_nfiles = 0;
/*
* Open
*/
if (*path == '|') {
path++;
if (! ((rval = popen(path, mode)))) {
return(rval);
}
inc_fps[inc_nfps] = rval;
inc_prog[inc_nfps] = 1;
inc_nfps++;
} else {
if (! ((rval = fopen(path, mode)))) {
return(rval);
}
inc_fps[inc_nfps] = rval;
inc_nfps++;
inc_files[inc_nfiles] = zallocStr(&SysMemPool, path);
inc_nfiles++;
}
inc_isopen++;
return(rval);
}
int
iclose(FILE *stream)
{
int rval = 0;
int i;
for (i = 0; i < inc_nfps; i++) {
if (inc_prog[i]) {
rval += pclose(inc_fps[i]);
} else {
rval += fclose(inc_fps[i]);
}
inc_fps[i] = NULL;
inc_prog[i] = 0;
}
inc_nfps = 0;
inc_isopen = 0;
return(rval);
}
/*
* This might not work right if the user supplied
* buffer is too small. Not an issue here.
*/
char *
igets(char *str, int size, FILE *stream)
{
char *rval, *fname, *ptr;
FILE *fp;
rval = fgets(str, size, inc_fps[inc_nfps - 1]);
if (! rval) {
/* We got an EOF or error */
if (inc_nfps == 1) {
/*
* We're on the primary file
* so we just return
*/
return(rval);
}
/* We step back to the previous file */
inc_nfps--;
if (inc_prog[inc_nfps]) {
rval += pclose(inc_fps[inc_nfps]);
} else {
rval += fclose(inc_fps[inc_nfps]);
}
inc_fps[inc_nfps] = NULL;
inc_prog[inc_nfps] = 0;
/*
* And now we recurse into igets to read
* "the next line"
*/
return(igets(str, size, stream));
}
/* We got a line */
if (strncmp(str, "%include", 8)) {
/* And it's not an include directive */
return(rval);
}
if (inc_nfps >= MAXLEVELS)
{
logit(LOG_ERR, "too many %%include levels");
return(rval);
}
/* Fetch out the filename */
if (! (fname = strchr(str, '"'))) {
logit(LOG_ERR, "no open quote in %%include");
return(rval);
}
fname++;
if (! (ptr = strchr(fname, '"'))) {
logit(LOG_ERR, "no close quote in %%include");
return(rval);
}
*ptr = '\0';
/* Do the open */
if (*fname == '|') {
fname++;
if (! ((fp = popen(fname, "r")))) {
logit(LOG_ERR, "error popening %%include: %s", fname);
*ptr = '"';
return(rval);
}
inc_fps[inc_nfps] = fp;
inc_prog[inc_nfps] = 1;
inc_nfps++;
} else {
if (! ((fp = fopen(fname, "r")))) {
logit(LOG_ERR, "error fopening %%include: %s", fname);
*ptr = '"';
return(rval);
}
inc_fps[inc_nfps] = fp;
inc_nfps++;
if (inc_nfiles < MAXFILES) {
inc_files[inc_nfiles] = zallocStr(&SysMemPool, fname);
inc_nfiles++;
}
}
/*
* And now we recurse into igets to read
* "the next line"
*/
return(igets(str, size, stream));
}
int
istat(int fd, struct stat *st)
{
int rval = 0;
struct stat sb;
int i;
/*
* Pick the newest stat time.
*/
bzero((char *)st, sizeof(struct stat));
for (i = 0; i < inc_nfiles; i++) {
if (stat(inc_files[i], &sb) < 0) {
logit(LOG_ERR, "error stating %%include: %s", inc_files[i]);
rval = -1;
} else {
if (sb.st_mtime > st->st_mtime) {
bcopy((char *)&sb, (char *)st, sizeof(sb));
}
}
}
return(rval);
}
syntax highlighted by Code2HTML, v. 0.9.1