home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 3
/
Meeting_Pearls_III.iso
/
Pearls
/
texmf
/
source
/
driver
/
util
/
amiga
/
EVPaths.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-11-12
|
20KB
|
899 lines
/*
* EVPaths.c - Environment Variables Path Routines for TeX related programs.
*
* Written by Giuseppe Ghibò
*
* © 1994 by Giuseppe Ghibò <ghibo@galileo.polito.it>
*
* Version 1.2 (09-Nov-94)
*
*/
#include "evpaths.h"
#include <exec/memory.h>
#include <dos/dosextens.h>
#include <proto/exec.h>
#include <proto/dos.h>
#define USE_BUILTIN_MATH
#include <string.h>
extern struct DosLibrary *DOSBase;
#define ENVPATH_OK 0L /* Success */
#define ENVPATH_NOT_ENOUGH_ROOM 1L /* Array was truncated */
#define ENVPATH_VAR_NOT_FOUND 2L /* There is no env var */
#define ENVPATH_NOT_ENOUGH_MEM 3L /* Not enough mem to alloc */
#define ENVPATH_SCAN_NONE 0L /* No dirs scan */
#define ENVPATH_SCAN_ONE 1L /* Scan one level subdirs */
#define ENVPATH_SCAN_ALL 2L /* Scan recursively all subdirs */
#define ENVPATH_SCAN_VAR 3L /* Scan recursively another var */
#define ENVPATH_SCAN_DEFPATH 4L /* Put default path */
#define ENVPATH_GETVAR 0L /* Get var */
#define ENVPATH_DONTGETVAR 1L /* Don't get var */
/* Prototypes */
STATIC LONG __regargs GetVar13(STRPTR name, UBYTE *buf, LONG size);
STATIC VOID __regargs GetEnvPath(STRPTR envname, UBYTE *buffer, LONG size, LONG *Error, LONG mode);
STATIC STRPTR __regargs Super_Strtok(STRPTR s, STRPTR p1, STRPTR p2, UBYTE open_delim, UBYTE close_delim);
STATIC LONG __regargs Add_Path_String(STRPTR s, STRPTR *p, LONG size);
STATIC STRPTR __regargs Parse_Path_String(STRPTR s, LONG *scan_status);
STATIC LONG __regargs Scan_Path_String(BPTR dirlock, STRPTR name, BOOL recursion, STRPTR *buf, LONG size);
STATIC VOID __regargs Insert_Path(struct EnvVarPath *p, APTR path, LONG mode);
#define PATH_TMPLEN 256
STATIC UBYTE Path_TmpStr[PATH_TMPLEN]; /* temporary storage */
/* Super_Strtok() is similar to strtok(). It breaks the string s if
* one or more char from the string p1 is matched. The string s is also
* breaked if one or more char from the string p2 is matched, but only
* if such char is found outside the string delimited by
* open_delim, close_delim. For instance if
*
* s = "one,two,three,four,<fi,ve>\nsix,seven" ;
* p1 = "\n" ;
* p2 = "," ;
* open_delim = '<' ;
* close_delim = '>' ;
*
* Then after each call to Super_Strtok, we obtain respectively the
* following strings:
*
* one two three four <fi,ve>
* six seven
*
*/
STATIC STRPTR last;
STATIC STRPTR __regargs Super_Strtok(STRPTR s, STRPTR p1, STRPTR p2, UBYTE open_delim, UBYTE close_delim)
{
STRPTR p, s1, s2, token;
BOOL opened = FALSE;
if (s == NULL && (s = last) == NULL)
return (NULL);
s += strspn(s, p1);
s += strspn(s, p2);
if (*s == '\0')
{
last = NULL;
return (NULL);
}
token = s;
s1 = s + strcspn(s, p1);
s2 = s + strcspn(s, p2);
for (p = s; *p && p < s2; p++)
{
if (*p == open_delim)
{
if (open_delim == close_delim && opened)
opened = FALSE;
else
opened = TRUE;
}
else
{
if (*p == close_delim)
opened = FALSE;
}
}
if (opened)
{
for (p = s2; *p && p < s1 && *p++ != close_delim; ) ;
s = p;
}
else
s = (s1 < s2 ? s1 : s2);
if (*s == '\0') {
last = NULL;
}
else
{
*s = '\0';
last = s + 1;
}
return(token);
}
/*
* GetVarLength() returns the length of an environment variable. If the
* given env var is not found or it doesn't exists, then the returned
* value is 0L.
*/
LONG __regargs GetVarLength(STRPTR envname)
{
REGISTER LONG len;
if (DOSBase->dl_lib.lib_Version >= 37)
{
UBYTE buffer[1];
if ((len = GetVar(envname, buffer, 1L, GVF_GLOBAL_ONLY | GVF_BINARY_VAR)) != -1L)
len = IoErr();
else
len = 0L;
}
else
{
struct FileInfoBlock *fib;
BPTR lock;
SNPrintf(Path_TmpStr, PATH_TMPLEN, "ENV:%s", envname);
if (lock = Lock(Path_TmpStr, ACCESS_READ))
{
if ((fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_ANY)))
{
if (Examine(lock, fib))
{
if (fib->fib_DirEntryType < 0L)
len = fib->fib_Size;
else
len = 0L;
}
else
len = 0L;
FreeMem(fib, sizeof(struct FileInfoBlock));
}
else
len = 0L;
UnLock(lock);
}
else
len = 0L;
}
return (len);
}
/*
* Given an env var name, GetVar13() copies the contents of the env var into
* the buffer buf. If the size of the env var is greater than the size of
* the buffer, then the copied length will be size-1.
* The buffer is terminated with '\0'.
* The returned value is the number of the bytes copied into the buffer,
* without consider the trailing '\0'.
* If the environment variable doesn't exists, no action is performed and
* the returned value is 0L.
* Note that this function is similar to the GetVar() function of OS2.1,
* but has not the same behaviour. In fact GetVar() returns -1L if the var
* doesn't exists, while GetVar13() returns 0L in such case.
*/
STATIC LONG __regargs GetVar13(STRPTR name, UBYTE *buf, LONG size)
{
LONG len;
SNPrintf(Path_TmpStr, PATH_TMPLEN, "ENV:%s", name);
len = min(GetVarLength(name), size);
if (len > 0L)
{
BPTR fh;
if ((fh = Open(Path_TmpStr, MODE_OLDFILE)) == DOSFALSE)
return(0L);
if ((len = Read(fh, buf, len)) > 0L)
{
Close(fh);
if (size <= len)
len = size - 1L;
buf[len] = '\0';
return(len);
}
else
{
Close(fh);
return(0L);
}
}
else
return(0L);
}
#define ABSTOKEN "\012\014" /* breaks only on line feed or form feed */
#define RELTOKEN "\t\f\040,;"
#define LQUOTE '\042'
#define RQUOTE '\042'
#define QUOTE '\042'
/*
* GetEnvPath() processes the path of a given environment variable. The
* passed buffer is then fitted with path elements. Such buffer may be
* accessed as an array of string pointers.
* The 'mode' is either one of EVPATH_DONTGETVAR or EVPATH_GETVAR. If
* EVPATH_DONTGETVAR is specified then the 'envname' is considered a
* pointer to a path string, and paths element are treated as they were read
* from an environment variable.
*
* The *Error contains (on exit) one of these values:
*
* - ENVPATH_OK: all was successful.
*
* - ENVPATH_NOT_ENOUGH_ROOM: the buffer is full. In this case the
* buffer contains entries which fit into the buffer itself, i.e.
* no truncated entries.
*
* - ENVPATH_VAR_NOT_FOUND: the given environment variable isn't
* found or has zero length.
*
* - ENVPATH_NOT_ENOUGH_MEM: there was a not enough mem during processing.
*
*/
#define MAX_RECURS_VAR 5
STATIC VOID __regargs GetEnvPath(STRPTR envname, UBYTE *buffer, LONG size, LONG *Error, LONG mode)
{
STRPTR envbuf, *p = (STRPTR *)buffer, s;
LONG envbuflen, scan_status = ENVPATH_SCAN_NONE, len;
STATIC LONG recurs_level = 0L;
STATIC STRPTR env_names[MAX_RECURS_VAR + 1];
recurs_level++;
if (recurs_level == 1L)
{
*Error = ENVPATH_OK;
}
if (mode == ENVPATH_DONTGETVAR && recurs_level == 1)
{
if (envname)
envbuf = envname;
else
{
*Error = ENVPATH_VAR_NOT_FOUND;
--recurs_level;
return;
}
}
else
{
envbuflen = GetVarLength(envname) + 1L;
if (envbuflen <= 1L)
{
*Error = ENVPATH_VAR_NOT_FOUND;
--recurs_level;
return;
}
if (envbuf = AllocMem(envbuflen, MEMF_ANY | MEMF_CLEAR))
{
if (DOSBase->dl_lib.lib_Version >= 37)
GetVar(envname, envbuf, envbuflen, GVF_GLOBAL_ONLY | GVF_BINARY_VAR);
else
GetVar13(envname, envbuf, envbuflen);
}
else
{
*Error = ENVPATH_NOT_ENOUGH_MEM;
--recurs_level;
return;
}
len = strlen(envname) + 1L;
if (env_names[recurs_level - 1] = AllocMem(len, MEMF_ANY))
{
strcpy(env_names[recurs_level - 1], envname); /* store env name to avoid recursion loops */
env_names[recurs_level] = NULL;
}
else
{
*Error = ENVPATH_NOT_ENOUGH_MEM;
--recurs_level;
return;
}
}
s = Super_Strtok(envbuf, ABSTOKEN, RELTOKEN, LQUOTE, RQUOTE); /* get first token */
do
{
s = Parse_Path_String(s, &scan_status);
if (scan_status == ENVPATH_SCAN_VAR)
{
if (recurs_level < MAX_RECURS_VAR)
{
BOOL recursion = TRUE;
LONG i = 0L;
while (env_names[i])
{
if (!strcmp(env_names[i++], s))
{
recursion = FALSE;
break;
}
}
if (recursion)
{
GetEnvPath(s, buffer, size, Error, ENVPATH_GETVAR);
if (*Error == ENVPATH_VAR_NOT_FOUND)
*Error = ENVPATH_OK; /* ignore recurs vars not found */
}
}
}
else if (scan_status == ENVPATH_SCAN_ONE || scan_status == ENVPATH_SCAN_ALL)
{
BPTR dirlock;
if (dirlock = Lock(s, ACCESS_READ))
{
*Error = Add_Path_String(s, p, size);
if (*Error == ENVPATH_OK)
*Error = Scan_Path_String(dirlock, s, (scan_status == ENVPATH_SCAN_ALL ? TRUE : FALSE), p, size);
UnLock(dirlock);
}
}
else
*Error = Add_Path_String(s, p, size);
}
while (*Error == ENVPATH_OK && (s = Super_Strtok(NULL, ABSTOKEN, RELTOKEN, LQUOTE, RQUOTE)));
if (mode != ENVPATH_DONTGETVAR)
FreeMem(env_names[recurs_level - 1], len);
if (envbuf && mode != ENVPATH_DONTGETVAR)
FreeMem(envbuf, envbuflen);
--recurs_level;
}
/*
* Add_Path_String(). Adds the string s to the array of strings p.
* The array must be initialized before to be passed to this function: the
* first element must be NULL! (p[0] = NULL).
*
* Returned values: ENVPATH_OK or ENVPATH_NOT_ENOUGH_ROOM.
*
*/
STATIC LONG __regargs Add_Path_String(STRPTR s, STRPTR *p, LONG size)
{
LONG i = 0L, len;
STRPTR q;
if (size < (2 * sizeof(STRPTR) + 1L))
return (ENVPATH_NOT_ENOUGH_ROOM);
len = strlen(s);
if (p[0] == NULL)
{
q = (STRPTR)p + size - (len + 1L);
}
else
{
for (i = 0L; p[i]; i++);
q = p[i-1] - (len + 1L);
}
if (&p[i] > (STRPTR *)(q - 2*sizeof(STRPTR)))
{
p[i] = NULL;
return (ENVPATH_NOT_ENOUGH_ROOM);
}
else
{
LONG j;
BOOL is_valid_entry = TRUE;
for (j = 0L; j < i; j++)
{
if (!stricmp(p[j], s))
{
is_valid_entry = FALSE;
}
}
if (is_valid_entry)
{
p[i] = q;
strcpy(p[i], s);
p[i+1] = NULL;
}
}
return (ENVPATH_OK);
}
#define MAX_RECURS_DIR 10L /* maximum recursion dir level */
STATIC LONG __regargs Scan_Path_String(BPTR dirlock, STRPTR name, BOOL recursion, STRPTR *buf, LONG size)
{
struct FileInfoBlock *fib;
LONG result = ENVPATH_OK;
STATIC LONG recurs_level = 0L;
recurs_level++;
if ((fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_ANY)))
{
if (Examine(dirlock, fib))
{
if (fib->fib_DirEntryType > 0L)
{
while (ExNext(dirlock, fib) && (result == ENVPATH_OK))
{
if (fib->fib_DirEntryType > 0L)
{
LONG len = strlen(name);
if (len > 0L)
SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s%s%s", name,
((name[len-1] != '/' && name[len-1] != ':') ? "/" : ""), fib->fib_FileName);
else
SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", fib->fib_FileName);
result = Add_Path_String(Path_TmpStr, buf, size);
if (recursion && (result == ENVPATH_OK) && (recurs_level < MAX_RECURS_DIR))
{
BPTR OldDirLock, NewDirLock;
OldDirLock = CurrentDir(dirlock);
if (NewDirLock = Lock(Path_TmpStr, ACCESS_READ))
{
STRPTR dirname;
LONG len = strlen(Path_TmpStr) + 1L;
if (dirname = AllocMem(len, MEMF_ANY))
{
strcpy(dirname, Path_TmpStr);
result = Scan_Path_String(NewDirLock, dirname, recursion, buf, size);
FreeMem(dirname, len);
}
UnLock(NewDirLock);
}
CurrentDir(OldDirLock);
}
}
}
}
}
FreeMem(fib, sizeof(struct FileInfoBlock));
}
else
result = ENVPATH_NOT_ENOUGH_MEM;
--recurs_level;
return (result);
}
STATIC STRPTR __regargs Parse_Path_String(STRPTR s, LONG *scan_status)
{
UBYTE *c;
LONG len;
*scan_status = ENVPATH_SCAN_NONE;
if (!s || !*s)
return("");
if (s[0] == LQUOTE)
s++; /* remove leading quote */
for (c = s; *c; c++); /* seek to the end of the string */
if (*--c == RQUOTE)
*c = '\0'; /* remove trailing quote */
if (s[0] == '.') /* '.' or './' represents current dir */
{
switch (s[1])
{
case '\0':
s[0] = '\0'; /* null string is current dir */
break;
case '/':
if (s[2])
s = &s[2];
else
s[0] = '\0';
break;
case '.': /* '../' is also parent dir */
if (s[2] == '/')
s = &s[2];
break;
}
}
len = strlen(s);
if (len > 0)
{
if (s[0] == '$')
{
s++;
*scan_status = ENVPATH_SCAN_VAR;
if (s[0] == QUOTE)
s++;
}
else if (s[0] == '?' && s[1] == '\0')
{
s++;
*scan_status = ENVPATH_SCAN_DEFPATH;
}
else
{
switch (s[len - 1])
{
case '*':
if (len > 1)
{
switch (s[len - 2])
{
case '*':
*scan_status = ENVPATH_SCAN_ALL;
s[len - 2] = '\0';
break;
default:
*scan_status = ENVPATH_SCAN_ONE;
s[len - 1] = '\0';
break;
}
}
else /* len == 1 */
{
*scan_status = ENVPATH_SCAN_ONE;
s[len - 1] = '\0';
}
break;
case '?':
if (len > 1)
{
switch (s[len - 2])
{
case '#':
*scan_status = ENVPATH_SCAN_ONE;
s[len - 2] = '\0';
break;
default:
*scan_status = ENVPATH_SCAN_NONE;
break;
}
}
else
*scan_status = ENVPATH_SCAN_NONE;
break;
case '>':
if (len > 1)
{
switch (s[len - 2])
{
case '*':
*scan_status = ENVPATH_SCAN_ALL;
s[len - 2] = '\0';
break;
case '?':
if (len > 2)
{
switch (s[len - 3])
{
case '#':
*scan_status = ENVPATH_SCAN_ALL;
s[len -3] = '\0';
break;
default:
*scan_status = ENVPATH_SCAN_NONE;
break;
}
}
else
*scan_status = ENVPATH_SCAN_NONE;
break;
default:
*scan_status = ENVPATH_SCAN_NONE;
break;
}
}
else
*scan_status = ENVPATH_SCAN_NONE;
break;
default:
*scan_status = ENVPATH_SCAN_NONE;
break;
}
}
}
return(s);
}
/*
* Alloc_EnvVarPath(). Alloc an EnvVarPath structure.
*
*/
struct EnvVarPath __regargs *Alloc_EnvVarPath(STRPTR varname, LONG size)
{
struct EnvVarPath *p;
if (p = AllocMem(sizeof(struct EnvVarPath), MEMF_ANY))
{
if ((size >= 2*sizeof(STRPTR) + 1L) && (p->storage.buffer = AllocMem(size, MEMF_ANY)))
{
if (p->name = AllocMem(strlen(varname) + 1, MEMF_ANY))
{
strcpy(p->name, varname);
p->storage.strings[0] = NULL; /* init first entry */
p->size = size;
p->status = ENVPATH_BUFFER_EMPTY;
p->defpath = NULL;
p->pos = 0L;
}
else
{
FreeMem(p->storage.buffer, size);
FreeMem(p, sizeof(struct EnvVarPath));
p = NULL;
}
}
else
{
FreeMem(p, sizeof(struct EnvVarPath));
p = NULL;
}
}
return(p);
}
/*
* Free_EnvVarPath. Frees an allocated EnvVarPath structure.
*
*/
VOID __regargs Free_EnvVarPath(struct EnvVarPath *p)
{
if (p)
{
if (p->name) FreeMem(p->name, strlen(p->name) + 1);
if (p->storage.buffer) FreeMem(p->storage.buffer, p->size);
if (p->defpath) FreeMem(p->defpath, strlen(p->defpath) + 1);
FreeMem(p, sizeof(struct EnvVarPath));
}
}
/*
* Init_EnvVarPath() inits an EnvVarPath structure provided by
* Alloc_EnvVarPath().
*
* deflt_path is an array of string pointers or a string pointer to be used
* if the specified environment variable doesn't exists or has zero length.
* 'mode' is one of ENVPATH_DEFSTR or ENPATH_DEFARR. If it is ENVPATH_DEFSTR
* then deflt_path is considered a string pointer, otherwise ENVPATH_DEFARR
* specifies that deflt_path is an array of string pointers.
*
*/
VOID __regargs Init_EnvVarPath(struct EnvVarPath *p, APTR deflt_path, LONG mode)
{
if (p)
{
LONG Error;
if ((mode & ENVPATH_PREPEND_PATH) == ENVPATH_PREPEND_PATH)
Insert_Path(p, deflt_path, mode);
GetEnvPath(p->name, p->storage.buffer, p->size, &Error, ENVPATH_GETVAR);
if ((mode & ENVPATH_APPEND_PATH) == ENVPATH_APPEND_PATH && (mode & ENVPATH_PREPEND_PATH) != ENVPATH_PREPEND_PATH && Error == ENVPATH_OK)
Insert_Path(p, deflt_path, mode);
switch (Error)
{
case ENVPATH_OK:
p->status = ENVPATH_BUFFER_COMPLETE;
break;
case ENVPATH_NOT_ENOUGH_ROOM:
p->status = ENVPATH_BUFFER_FULL;
break;
case ENVPATH_NOT_ENOUGH_MEM:
p->status = ENVPATH_BUFFER_TRUNC;
break;
case ENVPATH_VAR_NOT_FOUND:
if (!(mode & (ENVPATH_PREPEND_PATH | ENVPATH_APPEND_PATH)))
Insert_Path(p, deflt_path, mode);
break;
default:
p->status = ENVPATH_BUFFER_EMPTY;
break;
}
}
}
/*
Insert_Path() adds a path to the p->buffer; mode is one of
ENVPATH_DEFARR or ENVPATH_DEFSTR, as in the function Init_EnvVarPath().
*/
STATIC VOID __regargs Insert_Path(struct EnvVarPath *p, APTR path, LONG mode)
{
LONG Error = ENVPATH_OK;
if (path)
{
if ((mode & ENVPATH_DEFARR) == ENVPATH_DEFARR)
{
LONG i = 0L, l = 0L;
STRPTR *array = (STRPTR *) path, BufTmp, s;
while (array[i])
l += strlen(array[i++]) + 1L;
if (BufTmp = AllocMem(++l, MEMF_ANY))
{
s = BufTmp;
*s = '\0';
i = 0L;
while (array[i])
{
strcat(s, array[i++]);
strcat(s, " ");
}
GetEnvPath(BufTmp, p->storage.buffer, p->size, &Error, ENVPATH_DONTGETVAR);
FreeMem(BufTmp, l);
}
else
Error = ENVPATH_NOT_ENOUGH_MEM;
}
else
GetEnvPath(path, p->storage.buffer, p->size, &Error, ENVPATH_DONTGETVAR);
switch(Error)
{
case ENVPATH_OK:
p->status = ENVPATH_BUFFER_COMPLETE;
break;
case ENVPATH_NOT_ENOUGH_ROOM:
p->status = ENVPATH_BUFFER_FULL;
break;
case ENVPATH_NOT_ENOUGH_MEM:
p->status = ENVPATH_BUFFER_TRUNC;
break;
case ENVPATH_VAR_NOT_FOUND:
p->status = ENVPATH_BUFFER_EMPTY;
break;
default:
p->status = ENVPATH_BUFFER_EMPTY;
break;
}
}
else
p->status = ENVPATH_BUFFER_EMPTY;
}
/*
* Given a pointer to an initialized structure EnvVarPath, a filename
* and a buffer, EVP_FileSearch() returns the string pointer to the
* complete filename found. The returned string pointer is same of buffer.
* If the file isn't found then NULL is returned and buffer contains the
* empty string ("").
*
*/
STRPTR __regargs
EVP_FileSearch(STRPTR filename, struct EnvVarPath *evp, UBYTE *buffer, LONG size)
{
LONG i = 0L, len ;
if (evp && buffer && size > 0L && filename && *filename)
{
*buffer = '\0';
while (evp->storage.strings[i])
{
BPTR fh;
if (DOSBase->dl_lib.lib_Version >= 37)
{
SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", evp->storage.strings[i]);
AddPart(Path_TmpStr, filename, PATH_TMPLEN);
len = strlen(Path_TmpStr);
}
else
{
LONG l = strlen(evp->storage.strings[i]);
if (l > 0L && !strchr(filename, ':'))
{
UBYTE c = evp->storage.strings[i][l - 1];
len = SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s%s%s", evp->storage.strings[i],
((c != '/' && c != ':') ? "/" : ""), filename);
}
else
len = SNPrintf(Path_TmpStr, PATH_TMPLEN, "%s", filename);
}
if (Path_TmpStr[0] && (fh = Open(Path_TmpStr, MODE_OLDFILE)) != DOSFALSE)
{
/* note that the Lock() function would be faster than Open() to see if
a file exists or not, but in such case we should have to call
Examine() to discriminate files from directories. */
Close(fh);
memcpy(buffer, Path_TmpStr, min(len, size));
buffer[min(len, size - 1)] = '\0';
}
if (*buffer)
break;
else
i++;
}
}
else
{
if (size > 0L)
buffer[0] = '\0';
}
if (*buffer)
return(buffer);
else
return(NULL);
}