824N/A/*
824N/A * PSres.c
824N/A *
824N/A * (c) Copyright 1991-1994 Adobe Systems Incorporated.
824N/A * All rights reserved.
824N/A *
824N/A * Permission to use, copy, modify, distribute, and sublicense this software
824N/A * and its documentation for any purpose and without fee is hereby granted,
824N/A * provided that the above copyright notices appear in all copies and that
824N/A * both those copyright notices and this permission notice appear in
824N/A * supporting documentation and that the name of Adobe Systems Incorporated
824N/A * not be used in advertising or publicity pertaining to distribution of the
824N/A * software without specific, written prior permission. No trademark license
824N/A * to use the Adobe trademarks is hereby granted. If the Adobe trademark
824N/A * "Display PostScript"(tm) is used to describe this software, its
824N/A * functionality or for any other purpose, such use shall be limited to a
824N/A * statement that this software works in conjunction with the Display
824N/A * PostScript system. Proper trademark attribution to reflect Adobe's
824N/A * ownership of the trademark shall be given whenever any such reference to
824N/A * the Display PostScript system is made.
824N/A *
824N/A * ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR
824N/A * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
824N/A * ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
824N/A * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
824N/A * NON- INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE
824N/A * TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL
824N/A * DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,
824N/A * NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN
824N/A * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT
824N/A * PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE.
824N/A *
824N/A * Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems
824N/A * Incorporated which may be registered in certain jurisdictions
824N/A *
824N/A * Author: Adobe Systems Incorporated
824N/A */
824N/A/* $XFree86: xc/lib/psres/PSres.c,v 1.4tsi Exp $ */
824N/A
824N/A#include <stdio.h>
824N/A#include <stdlib.h>
824N/A
824N/A#ifdef XENVIRONMENT
824N/A#include <X11/Xos.h>
824N/A#else
824N/A#include <string.h>
824N/A#include <sys/types.h>
824N/A#endif
824N/A
824N/A#define USE_POSIX
824N/A
824N/A#ifdef NeXT
824N/A#undef USE_POSIX
824N/A#endif /* NeXT */
824N/A
824N/A#ifdef USE_POSIX
824N/A#include <dirent.h>
824N/A#else
824N/A#include <sys/dir.h>
824N/A#endif
824N/A
824N/A#include <sys/stat.h>
824N/A#include <DPS/PSres.h>
824N/A
824N/A#ifndef PSRES_NAME
824N/A#define PSRES_NAME "PSres.upr"
824N/A#endif /* PSRES_NAME */
824N/A
824N/A#ifndef PSRES_EXT
824N/A#define PSRES_EXT ".upr"
824N/A#endif /* PSRES_EXT */
824N/A
824N/A#ifndef SEEK_SET
824N/A#define SEEK_SET 0
824N/A#endif /* SEEK_SET */
824N/A
824N/A/* MT is the right pointer type to pass to memcpy, MST the size type */
824N/A#define MT void *
824N/A#define MST size_t
824N/A
824N/A#define MAXLEN 256
824N/Atypedef int (*ReadContentsFunction)();
824N/A
824N/Achar *PSResFontOutline = "FontOutline",
824N/A *PSResFontPrebuilt = "FontPrebuilt",
824N/A *PSResFontAFM = "FontAFM",
824N/A *PSResFontBDF = "FontBDF",
824N/A *PSResFontPCF = "FontPCF",
824N/A *PSResFontFamily = "FontFamily",
824N/A *PSResFontBDFSizes = "FontBDFSizes",
824N/A *PSResFontPCFSizes = "FontPCFSizes",
824N/A *PSResForm = "Form",
824N/A *PSResPattern = "Pattern",
824N/A *PSResEncoding = "Encoding",
824N/A *PSResProcSet = "ProcSet";
824N/A
824N/Atypedef struct _ResourceNameStruct {
824N/A char *name;
824N/A char *file;
824N/A} ResourceNameStruct, *ResourceName;
824N/A
824N/Atypedef struct _ResourceTypeStruct {
824N/A char *type;
824N/A long fileOffset; /* -1 means not really in the file */
824N/A ResourceName names;
824N/A int nameCount;
824N/A int filled; /* Whether has all names or just already found names */
824N/A char *nameBuffer;
824N/A char **oldNameBuffers;
824N/A int oldNameCount;
824N/A} ResourceTypeStruct, *ResourceType;
824N/A
824N/Atypedef struct _ResourceDirectoryStruct {
824N/A char *directory;
824N/A ResourceType types;
824N/A int typeCount;
824N/A char *typeNameBuffer;
824N/A char *filePrefix;
824N/A long endOfHeader;
824N/A int exclusive;
824N/A struct _ResourceDirectoryStruct *next;
824N/A} ResourceDirectoryStruct, *ResourceDirectory;
824N/A
824N/Atypedef struct {
824N/A char *type;
824N/A char *name;
824N/A} TypeName;
824N/A
824N/Atypedef struct {
824N/A PSResourceEnumerator func;
824N/A char *type;
824N/A char *name;
824N/A char *private;
824N/A int done;
824N/A} EnumeratorStruct;
824N/A
824N/Astatic ResourceDirectory resDir = NULL, lastResDir;
824N/Astatic char *savedPathOverride = NULL, *savedDefaultPath = NULL;
824N/Astatic PSResourceSavePolicy currentPolicy = PSSaveByType;
824N/Astatic char **currentResourceTypes = NULL;
824N/Astatic char *resourceTypeBuffer = NULL;
824N/Astatic time_t lastModifiedTime;
824N/Astatic char nullStr = '\0';
824N/A
824N/A/* Wrappers */
824N/A
824N/Astatic char *mymalloc(size)
824N/A int size;
824N/A{
824N/A char *ret;
824N/A
824N/A#ifdef XENVIRONMENT
824N/A#ifdef MALLOC_0_RETURNS_NULL
824N/A if (size < 1) size = 1;
824N/A#endif
824N/A#else
824N/A if (size < 1) size = 1; /* Better safe than sorry */
824N/A#endif
824N/A
824N/A ret = (char *) malloc((unsigned) size);
824N/A if (ret != NULL) return ret;
824N/A (void) fprintf(stderr, "malloc failed\n");
824N/A exit(1);
824N/A return NULL;
824N/A}
824N/A
824N/APSResMallocProc PSResMalloc = mymalloc;
824N/A#define MALLOC (*PSResMalloc)
824N/A
824N/Astatic char *myrealloc(ptr, size)
824N/A char *ptr;
824N/A int size;
824N/A{
824N/A char *ret;
824N/A
824N/A#ifdef XENVIRONMENT
824N/A#ifdef MALLOC_0_RETURNS_NULL
824N/A if (size < 1) size = 1;
824N/A#endif
824N/A#else
824N/A if (size < 1) size = 1; /* Better safe than sorry */
824N/A#endif
824N/A
824N/A if (ptr == NULL) return MALLOC(size);
824N/A#ifdef NO_VOID_STAR
824N/A ret = (char *) realloc(ptr, (unsigned) size);
824N/A#else
824N/A ret = (char *) realloc((void *) ptr, (unsigned) size);
824N/A#endif
824N/A if (ret != NULL) return ret;
824N/A (void) fprintf(stderr, "realloc failed\n");
824N/A exit(1);
824N/A return NULL;
824N/A}
824N/A
824N/APSResReallocProc PSResRealloc = myrealloc;
824N/A#define REALLOC (*PSResRealloc)
824N/A
824N/Astatic void myfree(ptr)
824N/A char *ptr;
824N/A{
824N/A#ifdef NO_VOID_STAR
824N/A if (ptr != NULL) free(ptr);
824N/A#else
824N/A if (ptr != NULL) free((void *) ptr);
824N/A#endif
824N/A}
824N/A
824N/APSResFreeProc PSResFree = myfree;
824N/A#define FREE (*PSResFree)
824N/A
824N/A#define NewString(str) ((char *) strcpy(MALLOC((int) (strlen(str)+1)),(str)))
824N/A
824N/Astatic void FileWarningHandler(file, extraInfo)
824N/A char *file;
824N/A char *extraInfo;
824N/A{
824N/A fprintf(stderr,
824N/A "Syntax error found in PostScript resource file %s:\n %s\n",
824N/A file, extraInfo);
824N/A}
824N/A
824N/APSResFileWarningHandlerProc PSResFileWarningHandler = FileWarningHandler;
824N/A
824N/A/* Just like fgets, but strips trailing newline, eliminates trailing comments,
824N/A skips trailing white space, skips blank lines, and chops lines longer
824N/A than size */
824N/A
824N/Astatic char *myfgets(buf, size, f)
824N/A char *buf;
824N/A register int size;
824N/A FILE *f;
824N/A{
824N/A register int ch;
824N/A register int count = 0;
824N/A
824N/A#define STRIP_BLANKS \
824N/A while (--count >= 0 && (buf[count] == ' ' || buf[count] == '\t')) \
824N/A buf[count] = '\0';
824N/A#define RETURN_BUF \
824N/A if (buf[0] != '\0') return buf; \
824N/A else return myfgets(buf, size, f);
824N/A
824N/A if (size == 0) return buf;
824N/A size--;
824N/A
824N/A while (count < size) {
824N/A ch = getc(f);
824N/A if (ch == EOF) {
824N/A buf[count] = '\0';
824N/A STRIP_BLANKS;
824N/A return NULL;
824N/A }
824N/A if (ch == '\n') {
824N/A buf[count] = '\0';
824N/A STRIP_BLANKS;
824N/A RETURN_BUF;
824N/A }
824N/A if (ch == '%') { /* Comment */
824N/A if (count == 0 || buf[count-1] != '\\') {
824N/A buf[count] = '\0';
824N/A do {
824N/A ch = getc(f);
824N/A } while (ch != EOF && ch != '\n');
824N/A STRIP_BLANKS;
824N/A if (ch == EOF) return NULL;
824N/A else RETURN_BUF;
824N/A }
824N/A }
824N/A
824N/A buf[count] = ch;
824N/A count++;
824N/A }
824N/A
824N/A /* Overflow, flush */
824N/A buf[count] = '\0';
824N/A do {
824N/A ch = getc(f);
824N/A } while (ch != EOF && ch != '\n');
824N/A STRIP_BLANKS;
824N/A if (ch == EOF) return NULL;
824N/A else RETURN_BUF;
824N/A#undef RETURN_BUF
824N/A#undef STRIP_BLANKS
824N/A}
824N/A
824N/Astatic int Dequote(buf, dontDequote)
824N/A char *buf;
824N/A char dontDequote;
824N/A{
824N/A char *dst = buf, *src = buf;
824N/A
824N/A while (*src != '\0') {
824N/A if (*src == '\\') {
824N/A src++;
824N/A if (*src == '\0') {
824N/A *dst = '\0';
824N/A return 1;
824N/A } else if (*src == dontDequote) *dst++ = '\\';
824N/A }
824N/A *dst++ = *src++;
824N/A }
824N/A *dst = '\0';
824N/A return 0;
824N/A}
824N/A
824N/A/* Sep returns the first unquoted position of the break character. The
824N/A dontDequote character only applies after the break character. If the
824N/A separator character is doubled, doubleSep is set to 1 and only one
824N/A of the separators is installed */
824N/A
824N/Astatic int DequoteAndBreak(buf, sep, bchar, dontDequote, doubleSep)
824N/A char *buf;
824N/A char **sep;
824N/A char bchar;
824N/A char dontDequote;
824N/A int *doubleSep;
824N/A{
824N/A char *dst = buf, *src = buf;
824N/A
824N/A *doubleSep = 0;
824N/A *sep = NULL;
824N/A
824N/A while (*src != '\0') {
824N/A if (*src == '\\') {
824N/A src++;
824N/A if (*src == '\0') {
824N/A *dst = '\0';
824N/A return 1;
824N/A } else if (*src == dontDequote && *sep != NULL) *dst++ = '\\';
824N/A } else if (*sep == NULL && *src == bchar) {
824N/A *sep = dst;
824N/A if (*(src+1) == bchar) {
824N/A src++;
824N/A *doubleSep = 1;
824N/A }
824N/A }
824N/A *dst++ = *src++;
824N/A }
824N/A *dst = '\0';
824N/A return 0;
824N/A}
824N/A
824N/Astatic float ParseVersion(f, excl)
824N/A FILE *f;
824N/A int *excl;
824N/A{
824N/A char inBuf[MAXLEN];
824N/A float version = 0.0;
824N/A int count;
824N/A
824N/A if (myfgets(inBuf, MAXLEN, f) == NULL) return 0.0;
824N/A
824N/A /* Compare against magic value */
824N/A
824N/A count = sscanf(inBuf, "PS-Resources-Exclusive-%f", &version);
824N/A if (count == 1) {
824N/A *excl = 1;
824N/A return version;
824N/A }
824N/A count = sscanf(inBuf, "PS-Resources-%f", &version);
824N/A if (count == 1) {
824N/A *excl = 0;
824N/A return version;
824N/A }
824N/A return 0.0;
824N/A}
824N/A
824N/Astatic int ParseResourceTypes(f, dir)
824N/A FILE *f;
824N/A ResourceDirectory dir;
824N/A{
824N/A char inBuf[MAXLEN];
824N/A char typebuf[MAXLEN];
824N/A char *types = typebuf;
824N/A int buflen = MAXLEN, typelen = 0, len;
824N/A int count, i;
824N/A int continued = 0, precontinued = 0;
824N/A
824N/A typebuf[0] = '\0';
824N/A count = 0;
824N/A
824N/A while (1) {
824N/A if (myfgets(inBuf, MAXLEN, f) == NULL) {
824N/A if (types != typebuf) FREE((char *) types);
824N/A return 1;
824N/A }
824N/A if (strcmp(inBuf, ".") == 0) break;
824N/A precontinued = continued;
824N/A continued = Dequote(inBuf, '\0');
824N/A
824N/A len = strlen(inBuf);
824N/A if (typelen + len + 1 > buflen) {
824N/A if (types == typebuf) {
824N/A types = (char *) MALLOC(2*MAXLEN);
824N/A (void) memcpy((MT) types, (MT) typebuf, (MST) typelen);
824N/A } else types = REALLOC(types, buflen+MAXLEN);
824N/A buflen += MAXLEN;
824N/A }
824N/A
824N/A if (precontinued) typelen--; /* Write over previous \0 */
824N/A else count++;
824N/A (void) strncpy(&types[typelen], inBuf, len+1);
824N/A typelen += len+1;
824N/A }
824N/A
824N/A dir->typeCount = count;
824N/A if (count == 0) dir->types = NULL;
824N/A else {
824N/A dir->types = (ResourceType)
824N/A MALLOC((int) (count * sizeof(ResourceTypeStruct)));
824N/A dir->typeNameBuffer = (char *) MALLOC(typelen);
824N/A (void) memcpy((MT) dir->typeNameBuffer, (MT) types, (MST) typelen);
824N/A }
824N/A
824N/A len = 0;
824N/A for (i = 0; i < count; i++) {
824N/A dir->types[i].type = &(dir->typeNameBuffer[len]);
824N/A dir->types[i].fileOffset = 0;
824N/A dir->types[i].names = NULL;
824N/A dir->types[i].nameBuffer = NULL;
824N/A dir->types[i].filled = 0;
824N/A dir->types[i].oldNameBuffers = NULL;
824N/A dir->types[i].oldNameCount = 0;
824N/A dir->types[i].nameCount = 0;
824N/A len += strlen(dir->types[i].type) + 1;
824N/A }
824N/A
824N/A if (types != typebuf) FREE((char *) types);
824N/A return 0;
824N/A}
824N/A
824N/Astatic int ParseFilePrefix(f, dir, dirName)
824N/A FILE *f;
824N/A ResourceDirectory dir;
824N/A char *dirName;
824N/A{
824N/A char inBuf[MAXLEN];
824N/A int continued;
824N/A int len;
824N/A long savePos;
824N/A char *prefix;
824N/A
824N/A dir->filePrefix = NULL;
824N/A
824N/A savePos = ftell(f);
824N/A if (myfgets(inBuf, MAXLEN, f) == NULL) return 1;
824N/A
824N/A if (inBuf[0] != '/') {
824N/A if (fseek(f, savePos, SEEK_SET) == -1) return 1;
824N/A len = strlen(dirName);
824N/A dir->filePrefix = strcpy((char *) MALLOC(len+2), dirName);
824N/A dir->filePrefix[len] = '/';
824N/A dir->filePrefix[len+1] = '\0';
824N/A return 0;
824N/A }
824N/A
824N/A continued = Dequote(inBuf, '\0');
824N/A prefix = inBuf+1;
824N/A len = strlen(prefix);
824N/A dir->filePrefix = (char *) strcpy((char *) MALLOC(len+2), prefix);
824N/A if (!continued) {
824N/A dir->filePrefix[len] = '/';
824N/A dir->filePrefix[len+1] = '\0';
824N/A return 0;
824N/A }
824N/A
824N/A while (1) {
824N/A if (myfgets(inBuf, MAXLEN, f) == NULL) return 1;
824N/A continued = Dequote(inBuf, '\0');
824N/A len += strlen(inBuf);
824N/A dir->filePrefix = (char *) REALLOC(dir->filePrefix, len+2);
824N/A (void) strcat(dir->filePrefix, inBuf);
824N/A if (!continued) {
824N/A dir->filePrefix[len] = '/';
824N/A dir->filePrefix[len+1] = '\0';
824N/A return 0;
824N/A }
824N/A }
824N/A}
824N/A
824N/Astatic ResourceDirectory ParseHeader(f, dirName, fileName)
824N/A FILE *f;
824N/A char *dirName, *fileName;
824N/A{
824N/A ResourceDirectory dir;
824N/A float version;
824N/A int exclusive;
824N/A
824N/A rewind(f);
824N/A
824N/A version = ParseVersion(f, &exclusive);
824N/A if (version < 1.0) return NULL;
824N/A
824N/A dir = (ResourceDirectory) MALLOC(sizeof(ResourceDirectoryStruct));
824N/A dir->directory = (char *) NewString(fileName);
824N/A dir->exclusive = exclusive;
824N/A dir->next = NULL;
824N/A
824N/A if (ParseResourceTypes(f, dir)) {
824N/A FREE((char *) dir->directory);
824N/A FREE((char *) dir);
824N/A return NULL;
824N/A }
824N/A
824N/A if (ParseFilePrefix(f, dir, dirName)) dir->endOfHeader = 0;
824N/A else dir->endOfHeader = ftell(f);
824N/A
824N/A return dir;
824N/A}
824N/A
824N/A/* Store away old name buffer so pointers to it do not become invalid */
824N/A
824N/Astatic void CacheOldNames(type)
824N/A ResourceType type;
824N/A{
824N/A type->oldNameCount++;
824N/A type->oldNameBuffers = (char **) REALLOC((char *) type->oldNameBuffers,
824N/A type->oldNameCount);
824N/A type->oldNameBuffers[type->oldNameCount-1] = type->nameBuffer;
824N/A type->nameBuffer = NULL;
824N/A}
824N/A
824N/A/* Verify that the name matches the name in the file */
824N/A
824N/Astatic int VerifyName(f, name)
824N/A FILE *f;
824N/A char *name;
824N/A{
824N/A char inBuf[MAXLEN];
824N/A int continued = 0;
824N/A int len;
824N/A int start = 0;
824N/A
824N/A while (1) {
824N/A if (myfgets(inBuf, MAXLEN, f) == NULL) return 1;
824N/A continued = Dequote(inBuf, '\0');
824N/A if (continued) {
824N/A len = strlen(inBuf);
824N/A if (strncmp(inBuf, &name[start], len) != 0) return 1;
824N/A start += len;
824N/A } else {
824N/A if (strcmp(inBuf, &name[start]) != 0) return 1;
824N/A else break;
824N/A }
824N/A }
824N/A return 0;
824N/A}
824N/A
824N/Astatic int LookupResourceInList(type, name)
824N/A ResourceType type;
824N/A char *name;
824N/A{
824N/A int i;
824N/A
824N/A for (i = 0; i < type->nameCount; i++) {
824N/A if (strcmp(name, type->names[i].name) == 0) return 1;
824N/A }
824N/A return 0;
824N/A}
824N/A
824N/Astatic int CheckInsertPrefix(type)
824N/A char *type;
824N/A{
824N/A /* Insert the prefix unless one of these special values */
824N/A
824N/A if (strcmp(type, PSResFontFamily) == 0 ||
824N/A strcmp(type, PSResFontBDFSizes) == 0 ||
824N/A strcmp(type, PSResFontPCFSizes) == 0 ||
824N/A strcmp(type, "FontAxes") == 0 ||
824N/A strcmp(type, "FontBlendMap") == 0 ||
824N/A strcmp(type, "FontBlendPositions") == 0 ||
824N/A strcmp(type, "mkpsresPrivate") == 0) return 0;
824N/A return 1;
824N/A}
824N/A
824N/A/* Returns a line, including continuations. Memory must be copied before
824N/A calling this again. */
824N/A
824N/Astatic int linebuflen = 0;
824N/Astatic char *inputline = NULL;
824N/A
824N/Astatic char *ReadFullLine(f)
824N/A FILE *f;
824N/A{
824N/A char readbuf[MAXLEN];
824N/A int start = 0;
824N/A int len;
824N/A
824N/A while (1) {
824N/A if (myfgets(readbuf, MAXLEN, f) == NULL) return NULL;
824N/A len = strlen(readbuf);
824N/A if (start + len + 1 > linebuflen) {
824N/A linebuflen += MAXLEN + 1;
824N/A inputline = REALLOC(inputline, linebuflen);
824N/A }
824N/A strncpy(inputline+start, readbuf, len+1);
824N/A
824N/A if (inputline[start+len-1] != '\\') break;
824N/A
824N/A start = start+len-1;
824N/A }
824N/A return inputline;
824N/A}
824N/A
824N/Astatic void FreeLineBuf()
824N/A{
824N/A if (inputline != NULL) FREE(inputline);
824N/A inputline = NULL;
824N/A linebuflen = 0;
824N/A}
824N/A
824N/A/* Assumes being correctly positioned in the file */
824N/A
824N/Astatic int ReadResourceSection(f, dir, type, name)
824N/A FILE *f;
824N/A ResourceDirectory dir;
824N/A ResourceType type;
824N/A char *name; /* If NULL, enumerate */
824N/A{
824N/A#define GROW 1000
824N/A char *linein;
824N/A int start;
824N/A int len;
824N/A char namebuf[GROW];
824N/A char *names = namebuf;
824N/A int buflen = GROW, namelen = 0;
824N/A int i, count = 0;
824N/A char *sep;
824N/A int prefixLen;
824N/A int insertPrefix;
824N/A char dontDequote;
824N/A int doubleEquals;
824N/A int addingPrefix;
824N/A int newsize;
824N/A
824N/A if (type->nameBuffer != NULL) CacheOldNames(type);
824N/A
824N/A insertPrefix = CheckInsertPrefix(type->type);
824N/A if (insertPrefix) {
824N/A prefixLen = strlen(dir->filePrefix);
824N/A dontDequote = '\0';
824N/A } else {
824N/A prefixLen = 0;
824N/A dontDequote = ',';
824N/A }
824N/A
824N/A while (1) {
824N/A start = namelen;
824N/A
824N/A linein = ReadFullLine(f);
824N/A if (linein == NULL) {
824N/A if (names != namebuf) FREE((char *) names);
824N/A FreeLineBuf();
824N/A return 1;
824N/A }
824N/A if (strcmp(linein, ".") == 0) break;
824N/A
824N/A sep = NULL;
824N/A (void) DequoteAndBreak(linein, &sep, '=', dontDequote, &doubleEquals);
824N/A
824N/A /* If no separator, a bogus line */
824N/A if (sep == NULL) continue;
824N/A
824N/A /* Next line is UNIX specific! */
824N/A addingPrefix = *(sep+1) != '/' && insertPrefix && !doubleEquals;
824N/A
824N/A len = strlen(linein) + 1 + (addingPrefix ? prefixLen : 0);
824N/A
824N/A if (namelen + len >= buflen) {
824N/A newsize = buflen + GROW;
824N/A if (namelen + len > newsize) newsize = namelen + len;
824N/A
824N/A if (names == namebuf) {
824N/A names = (char *) MALLOC(newsize);
824N/A (void) memcpy((MT) names, (MT) namebuf, (MST) namelen);
824N/A } else names = REALLOC(names, newsize);
824N/A buflen = newsize;
824N/A }
824N/A
824N/A *sep = '\0';
824N/A len = strlen(linein);
824N/A (void) strncpy(&names[namelen], linein, len+1);
824N/A namelen += len+1;
824N/A
824N/A if (addingPrefix) {
824N/A (void) strncpy(&names[namelen], dir->filePrefix, prefixLen);
824N/A namelen += prefixLen;
824N/A }
824N/A
824N/A len = strlen(sep+1);
824N/A (void) strncpy(&names[namelen], sep+1, len+1);
824N/A namelen += len+1;
824N/A
824N/A if (name != NULL && strcmp(names, name) != 0) namelen = start;
824N/A else count++;
824N/A }
824N/A
824N/A type->nameCount = count;
824N/A if (count == 0) type->names = NULL;
824N/A else {
824N/A type->names = (ResourceName)
824N/A MALLOC((int) (count * sizeof(ResourceNameStruct)));
824N/A type->nameBuffer = (char *) MALLOC(namelen);
824N/A (void) memcpy((MT) type->nameBuffer, (MT) names, (MST) namelen);
824N/A }
824N/A
824N/A len = 0;
824N/A for (i = 0; i < count; i++) {
824N/A type->names[i].name = &(type->nameBuffer[len]);
824N/A len += strlen(type->names[i].name) + 1;
824N/A type->names[i].file = &(type->nameBuffer[len]);
824N/A len += strlen(type->names[i].file) + 1;
824N/A }
824N/A
824N/A if (names != namebuf) FREE((char *) names);
824N/A if (name == NULL) type->filled = 1;
824N/A FreeLineBuf();
824N/A return 0;
824N/A
824N/A#undef GROW
824N/A}
824N/A
824N/A/* Assumes being correctly positioned in the file */
824N/A
824N/Astatic int SkipResourceSection(f, dir, type, checkName)
824N/A FILE *f;
824N/A ResourceDirectory dir;
824N/A ResourceType type;
824N/A int checkName;
824N/A{
824N/A char inBuf[MAXLEN];
824N/A int i;
824N/A
824N/A /* If next type has offset, just go there */
824N/A
824N/A for (i = 0; i < dir->typeCount && dir->types + i != type; i++) {}
824N/A
824N/A if (dir->types + i == type) {
824N/A for (i++; i < dir->typeCount; i++) {
824N/A if (dir->types[i].fileOffset == -1) continue;
824N/A if (dir->types[i].fileOffset > 0) {
824N/A if (fseek(f, dir->types[i].fileOffset, SEEK_SET) != -1) {
824N/A return 0;
824N/A } else break;
824N/A }
824N/A }
824N/A }
824N/A
824N/A if (checkName && VerifyName(f, type->type) != 0) return 1;
824N/A
824N/A while (1) {
824N/A if (myfgets(inBuf, MAXLEN, f) == NULL) return 1;
824N/A if (strcmp(inBuf, ".") == 0) return 0;
824N/A }
824N/A}
824N/A
824N/A/* Assumes being correctly positioned in the file */
824N/A
824N/Astatic int ParseResourceSection(f, dir, type, name, checkName)
824N/A FILE *f;
824N/A ResourceDirectory dir;
824N/A ResourceType type;
824N/A char *name; /* If NULL, enumerate */
824N/A int checkName;
824N/A{
824N/A if (checkName && VerifyName(f, type->type) != 0) return 1;
824N/A
824N/A if (type->filled || (name != NULL && LookupResourceInList(type, name))) {
824N/A return SkipResourceSection(f, dir, type, 0);
824N/A }
824N/A
824N/A return ReadResourceSection(f, dir, type, name);
824N/A}
824N/A
824N/Avoid FreePSResourceStorage(everything)
824N/A int everything;
824N/A{
824N/A ResourceDirectory d;
824N/A ResourceType t;
824N/A int i, j;
824N/A
824N/A if (resDir == NULL) return;
824N/A
824N/A for (d = resDir; d != NULL; d = d->next) {
824N/A for (i = 0; i < d->typeCount; i++) {
824N/A t = d->types + i;
824N/A FREE(t->nameBuffer);
824N/A FREE((char *) t->names);
824N/A t->nameCount = 0;
824N/A for (j = 0; j < t->oldNameCount; j++) FREE(t->oldNameBuffers[j]);
824N/A if (t->oldNameBuffers != NULL) FREE((char *) t->oldNameBuffers);
824N/A t->oldNameCount = 0;
824N/A t->nameCount = 0;
824N/A t->filled = 0;
824N/A }
824N/A }
824N/A
824N/A if (!everything) return;
824N/A
824N/A while (resDir != NULL) {
824N/A d = resDir->next;
824N/A FREE(resDir->directory);
824N/A FREE((char *) resDir->types);
824N/A FREE(resDir->typeNameBuffer);
824N/A FREE(resDir->filePrefix);
824N/A FREE((char *) resDir);
824N/A resDir = d;
824N/A }
824N/A lastResDir = NULL;
824N/A FREE(savedPathOverride);
824N/A savedPathOverride = NULL;
824N/A FREE(savedDefaultPath);
824N/A savedDefaultPath = NULL;
824N/A}
824N/A
824N/Astatic ResourceDirectory ReadAndStoreFile(dir, name, len, readFunc, data)
824N/A char *dir, *name;
824N/A int len;
824N/A ReadContentsFunction readFunc;
824N/A char *data;
824N/A{
824N/A ResourceDirectory rd = NULL;
824N/A FILE *f;
824N/A char nameBuf[MAXLEN];
824N/A char *fullName = nameBuf;
824N/A int fullLen;
824N/A
824N/A fullLen = len + strlen(name) + 1;
824N/A if (fullLen >= MAXLEN) fullName = MALLOC(fullLen+1);
824N/A (void) strcpy(fullName, dir);
824N/A fullName[len] = '/';
824N/A (void) strcpy(fullName+len+1, name);
824N/A
824N/A f = fopen(fullName, "r");
824N/A if (f != NULL) {
824N/A rd = ParseHeader(f, dir, fullName);
824N/A
824N/A if (rd != NULL) {
824N/A if (resDir == NULL) resDir = rd;
824N/A else lastResDir->next = rd;
824N/A lastResDir = rd;
824N/A if (readFunc != NULL) (*readFunc) (f, rd, data);
824N/A } else (*PSResFileWarningHandler)(fullName, "Malformed header");
824N/A (void) fclose(f);
824N/A }
824N/A if (fullName != nameBuf) FREE(fullName);
824N/A return rd;
824N/A}
824N/A
824N/Astatic time_t ReadFilesInDirectory(dirName, readFunc, data)
824N/A char *dirName;
824N/A ReadContentsFunction readFunc;
824N/A char *data;
824N/A{
824N/A DIR *dir;
824N/A#ifdef USE_POSIX
824N/A struct dirent *d;
824N/A#else
824N/A struct direct *d;
824N/A#endif
824N/A ResourceDirectory rd;
824N/A int len = strlen(dirName);
824N/A static int extensionLen = 0;
824N/A struct stat buf;
824N/A int namelen;
824N/A
824N/A if (extensionLen == 0) extensionLen = strlen(PSRES_EXT);
824N/A if (stat(dirName, &buf) != 0) buf.st_mtime = 0;
824N/A
824N/A rd = ReadAndStoreFile(dirName, PSRES_NAME, len, readFunc, data);
824N/A
824N/A if (rd != 0 && rd->exclusive) return buf.st_mtime;
824N/A
824N/A dir = opendir(dirName);
824N/A if (dir == NULL) return buf.st_mtime;
824N/A
824N/A while ((d = readdir(dir)) != NULL) {
824N/A namelen = strlen(d->d_name);
824N/A if (namelen < extensionLen) continue;
824N/A
824N/A if (strcmp(d->d_name + (namelen - extensionLen), PSRES_EXT) == 0
824N/A && strcmp(d->d_name, PSRES_NAME) != 0) {
824N/A (void) ReadAndStoreFile(dirName, d->d_name, len, readFunc, data);
824N/A }
824N/A }
824N/A (void) closedir(dir);
824N/A return buf.st_mtime;
824N/A}
824N/A
824N/A/* Returns nonzero if current paths different from saved ones */
824N/A
824N/Astatic int SetUpSavedPaths(pathOverride, defaultPath)
824N/A char *pathOverride;
824N/A char *defaultPath;
824N/A{
824N/A if (pathOverride == NULL) pathOverride = &nullStr;
824N/A if (defaultPath == NULL) defaultPath = &nullStr;
824N/A
824N/A if (savedPathOverride == NULL ||
824N/A strcmp(pathOverride, savedPathOverride) != 0 ||
824N/A strcmp(defaultPath, savedDefaultPath) != 0) {
824N/A
824N/A FreePSResourceStorage(1);
824N/A
824N/A savedPathOverride = NewString(pathOverride);
824N/A savedDefaultPath = NewString(defaultPath);
824N/A
824N/A return 1;
824N/A }
824N/A return 0;
824N/A}
824N/A
824N/A/* Like SetUpSavedPaths, but never affects saved state */
824N/A
824N/Astatic int CheckSavedPaths(pathOverride, defaultPath)
824N/A char *pathOverride;
824N/A char *defaultPath;
824N/A{
824N/A if (pathOverride == NULL) pathOverride = &nullStr;
824N/A if (defaultPath == NULL) defaultPath = &nullStr;
824N/A
824N/A if (savedPathOverride == NULL ||
824N/A strcmp(pathOverride, savedPathOverride) != 0 ||
824N/A strcmp(defaultPath, savedDefaultPath) != 0) return 1;
824N/A else return 0;
824N/A}
824N/A
824N/Astatic time_t ReadFilesInPath(string, readFunc, data)
824N/A char *string;
824N/A ReadContentsFunction readFunc;
824N/A char *data;
824N/A{
824N/A char *pathChar;
824N/A char pathBuf[MAXLEN];
824N/A char *path;
824N/A register char *dir;
824N/A int len;
824N/A register char ch;
824N/A time_t newTime, latestTime = 0;
824N/A
824N/A pathChar = string;
824N/A
824N/A if (*pathChar == ':') pathChar++;
824N/A
824N/A len = strlen(pathChar);
824N/A if (len < MAXLEN) path = pathBuf;
824N/A else path = MALLOC(len+1);
824N/A
824N/A do {
824N/A dir = path;
824N/A do {
824N/A while (*pathChar == '\\') {
824N/A pathChar++;
824N/A if (*pathChar != '\0') *dir++ = *pathChar++;
824N/A }
824N/A
824N/A *dir++ = ch = *pathChar++;
824N/A } while (ch != '\0' && ch != ':');
824N/A if (ch == ':') *(dir-1) = '\0';
824N/A
824N/A if (*path == '\0') {
824N/A if (ch == ':' && string != savedDefaultPath) {
824N/A newTime = ReadFilesInPath(savedDefaultPath, readFunc, data);
824N/A if (newTime > latestTime) latestTime = newTime;
824N/A }
824N/A } else {
824N/A newTime = ReadFilesInDirectory(path, readFunc, data);
824N/A if (newTime > latestTime) latestTime = newTime;
824N/A }
824N/A } while (ch == ':');
824N/A if (path != pathBuf) FREE(path);
824N/A return latestTime;
824N/A}
824N/A
824N/Astatic time_t MaxTimeInPath(string)
824N/A char *string;
824N/A{
824N/A char *pathChar;
824N/A char pathBuf[MAXLEN];
824N/A char *path;
824N/A register char *dir;
824N/A int len;
824N/A register char ch;
824N/A time_t latestTime = 0;
824N/A struct stat buf;
824N/A
824N/A pathChar = string;
824N/A
824N/A if (*pathChar == ':') pathChar++;
824N/A
824N/A len = strlen(pathChar);
824N/A if (len < MAXLEN) path = pathBuf;
824N/A else path = MALLOC(len+1);
824N/A
824N/A do {
824N/A dir = path;
824N/A do {
824N/A while (*pathChar == '\\') {
824N/A pathChar++;
824N/A if (*pathChar != '\0') *dir++ = *pathChar++;
824N/A }
824N/A
824N/A *dir++ = ch = *pathChar++;
824N/A } while (ch != '\0' && ch != ':');
824N/A if (ch == ':') *(dir-1) = '\0';
824N/A
824N/A if (*path == '\0') {
824N/A if (ch == ':' && string != savedDefaultPath) {
824N/A buf.st_mtime = MaxTimeInPath(savedDefaultPath);
824N/A if (buf.st_mtime > latestTime) latestTime = buf.st_mtime;
824N/A }
824N/A } else {
824N/A if (stat(path, &buf) != 0) buf.st_mtime = 0;
824N/A if (buf.st_mtime > latestTime) latestTime = buf.st_mtime;
824N/A }
824N/A } while (ch == ':');
824N/A if (path != pathBuf) FREE(path);
824N/A return latestTime;
824N/A}
824N/A
824N/Astatic char *GetPath()
824N/A{
824N/A static char defaultEnvironmentPath[] = "::";
824N/A static char *environmentPath = NULL;
824N/A
824N/A if (savedPathOverride != NULL && *savedPathOverride != '\0') {
824N/A return savedPathOverride;
824N/A }
824N/A
824N/A if (environmentPath == NULL) {
824N/A environmentPath = getenv("PSRESOURCEPATH");
824N/A if (environmentPath == NULL) environmentPath = defaultEnvironmentPath;
824N/A }
824N/A
824N/A return environmentPath;
824N/A}
824N/A
824N/Avoid SetPSResourcePolicy(policy, willList, resourceTypes)
824N/A PSResourceSavePolicy policy;
824N/A int willList;
824N/A char **resourceTypes;
824N/A{
824N/A currentPolicy = policy;
824N/A
824N/A if (currentResourceTypes != NULL) FREE((char *) currentResourceTypes);
824N/A if (resourceTypeBuffer != NULL) FREE((char *) resourceTypeBuffer);
824N/A
824N/A if (resourceTypes == NULL) {
824N/A currentResourceTypes = NULL;
824N/A resourceTypeBuffer = NULL;
824N/A } else {
824N/A int i = 0, len = 0;
824N/A char **cp = resourceTypes;
824N/A
824N/A while (*cp != NULL) {
824N/A i++;
824N/A len += strlen(*cp) + 1;
824N/A cp++;
824N/A }
824N/A
824N/A currentResourceTypes =
824N/A (char **) MALLOC((int) ((i+1) * sizeof(char *)));
824N/A resourceTypeBuffer = MALLOC(len);
824N/A
824N/A len = 0;
824N/A i = 0;
824N/A cp = resourceTypes;
824N/A
824N/A while (*cp != NULL) {
824N/A (void) strcpy(resourceTypeBuffer+len, *cp);
824N/A currentResourceTypes[i++] = resourceTypeBuffer + len;
824N/A len += strlen(*cp) + 1;
824N/A cp++;
824N/A }
824N/A currentResourceTypes[i] = NULL;
824N/A }
824N/A}
824N/A
824N/Aint InSavedList(type)
824N/A char *type;
824N/A{
824N/A char **cp = currentResourceTypes;;
824N/A
824N/A if (cp == NULL) return 0;
824N/A
824N/A while (*cp != NULL) {
824N/A if (strcmp(*cp++, type) == 0) return 1;
824N/A }
824N/A return 0;
824N/A}
824N/A
824N/A/* ARGSUSED */
824N/Astatic int ReadEverything(f, rd, data)
824N/A FILE *f;
824N/A ResourceDirectory rd;
824N/A char *data;
824N/A{
824N/A int i;
824N/A ResourceType t;
824N/A long pos;
824N/A
824N/A /* We're at the start of the resource section; read all of them */
824N/A
824N/A for (i = 0; i < rd->typeCount; i++) {
824N/A t = &rd->types[i];
824N/A
824N/A if (t->fileOffset == -1) continue; /* Not really there */
824N/A
824N/A if (t->fileOffset != 0 && fseek(f, t->fileOffset, SEEK_SET) != -1) {
824N/A if (!t->filled) {
824N/A if (ParseResourceSection(f, rd, t, (char *) NULL, 1)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A } else {
824N/A if (SkipResourceSection(f, rd, t, 1)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A }
824N/A continue;
824N/A }
824N/A
824N/A pos = ftell(f);
824N/A if (VerifyName(f, t->type) == 0) {
824N/A t->fileOffset = pos;
824N/A if (ParseResourceSection(f, rd, t, (char *) NULL, 0)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A } else {
824N/A /* No resources of this type; try the next type */
824N/A t->fileOffset = -1;
824N/A if (fseek(f, pos, SEEK_SET)) {
824N/A PSResFileWarningHandler(rd->directory,
824N/A "File changed during execution");
824N/A return 1;
824N/A }
824N/A }
824N/A }
824N/A return 0;
824N/A}
824N/A
824N/Astatic int ReadType(f, rd, type)
824N/A FILE *f;
824N/A ResourceDirectory rd;
824N/A char *type;
824N/A{
824N/A int i;
824N/A ResourceType t;
824N/A long pos;
824N/A
824N/A /* We're at the start of the resource section; read the sections that
824N/A are in the cached type list or are the passed in type */
824N/A
824N/A for (i = 0; i < rd->typeCount; i++) {
824N/A t = &rd->types[i];
824N/A
824N/A if (t->fileOffset == -1) continue; /* Not really there */
824N/A if (t->fileOffset != 0 && fseek(f, t->fileOffset, SEEK_SET) != -1) {
824N/A if (!t->filled &&
824N/A (strcmp(t->type, type) == 0 || InSavedList(t->type))) {
824N/A if (ParseResourceSection(f, rd, t, (char *) NULL, 1)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A } else if (SkipResourceSection(f, rd, t, 1)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A continue;
824N/A }
824N/A
824N/A pos = ftell(f);
824N/A if (VerifyName(f, t->type) == 0) {
824N/A t->fileOffset = pos;
824N/A if (strcmp(t->type, type) == 0 || InSavedList(t->type)) {
824N/A if (ParseResourceSection(f, rd, t, (char *) NULL, 0)){
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A } else if (SkipResourceSection(f, rd, t, 0)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A } else {
824N/A /* No resources of this type; try the next type */
824N/A t->fileOffset = -1;
824N/A if (fseek(f, pos, SEEK_SET) == -1) {
824N/A PSResFileWarningHandler(rd->directory,
824N/A "File changed during execution");
824N/A return 1;
824N/A }
824N/A }
824N/A }
824N/A return 0;
824N/A}
824N/A
824N/Astatic int ReadName(f, rd, data)
824N/A FILE *f;
824N/A ResourceDirectory rd;
824N/A char *data;
824N/A{
824N/A TypeName *tn = (TypeName *) data;
824N/A int i;
824N/A ResourceType t;
824N/A long pos;
824N/A
824N/A /* We're at the start of the resource section; read the name in the
824N/A section for the passed in type */
824N/A
824N/A for (i = 0; i < rd->typeCount; i++) {
824N/A t = &rd->types[i];
824N/A
824N/A if (t->fileOffset == -1) continue; /* Not really there */
824N/A if (t->fileOffset != 0 && fseek(f, t->fileOffset, SEEK_SET)) {
824N/A if (strcmp(t->type, tn->type) == 0) {
824N/A if (ParseResourceSection(f, rd, t, tn->name, 1)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A } else if (SkipResourceSection(f, rd, t, 1)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A continue;
824N/A }
824N/A
824N/A pos = ftell(f);
824N/A if (VerifyName(f, t->type) == 0) {
824N/A t->fileOffset = pos;
824N/A if (fseek(f, pos, SEEK_SET) == -1) {
824N/A PSResFileWarningHandler(rd->directory,
824N/A "File changed during execution");
824N/A return 1;
824N/A }
824N/A if (strcmp(t->type, tn->type) == 0) {
824N/A if (ParseResourceSection(f, rd, t, tn->name, 0)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A } else if (SkipResourceSection(f, rd, t, 0)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A } else {
824N/A /* No resources of this type; try the next type */
824N/A t->fileOffset = -1;
824N/A if (fseek(f, pos, SEEK_SET) == -1) {
824N/A PSResFileWarningHandler(rd->directory,
824N/A "File changed during execution");
824N/A return 1;
824N/A }
824N/A }
824N/A }
824N/A return 0;
824N/A}
824N/A
824N/Astatic void ReadHeadersAndData(resourceType, resourceName)
824N/A char *resourceType;
824N/A char *resourceName;
824N/A{
824N/A TypeName t;
824N/A
824N/A switch (currentPolicy) {
824N/A case PSSaveEverything:
824N/A lastModifiedTime =
824N/A ReadFilesInPath(GetPath(), ReadEverything, (char *) NULL);
824N/A break;
824N/A case PSSaveByType:
824N/A lastModifiedTime =
824N/A ReadFilesInPath(GetPath(), ReadType, resourceType);
824N/A break;
824N/A case PSSaveReturnValues:
824N/A t.type = resourceType;
824N/A t.name = resourceName;
824N/A lastModifiedTime =
824N/A ReadFilesInPath(GetPath(), ReadName, (char *) &t);
824N/A break;
824N/A }
824N/A}
824N/A
824N/Astatic void UpdateData(resourceType, resourceName)
824N/A char *resourceType;
824N/A char *resourceName;
824N/A{
824N/A ResourceDirectory rd;
824N/A ResourceType rt;
824N/A int i;
824N/A FILE *f;
824N/A TypeName tn;
824N/A
824N/A /* Make two passes; the first figures out if we're going to have to read
824N/A the file to service this request. If we are, open the file and read
824N/A in sections in the saved list (from SetPSResourcePolicy). If not
824N/A just saving return values, make sure we read in everything
824N/A in the section. */
824N/A
824N/A for (rd = resDir; rd != NULL; rd = rd->next) {
824N/A f = NULL;
824N/A for (i = 0; i < rd->typeCount; i++) {
824N/A rt = rd->types + i;
824N/A if (rt->filled) continue;
824N/A if (strcmp(rt->type, resourceType) != 0) continue;
824N/A
824N/A if (resourceName != NULL &&
824N/A LookupResourceInList(rt, resourceName)) continue;
824N/A
824N/A f = fopen(rd->directory, "r");
824N/A break;
824N/A }
824N/A if (f == NULL) continue;
824N/A
824N/A /* Nuts, have to read the file */
824N/A
824N/A if (fseek(f, rd->endOfHeader, SEEK_SET) != -1) {
824N/A switch (currentPolicy) {
824N/A case PSSaveEverything:
824N/A (void) ReadEverything(f, rd, (char *) NULL);
824N/A break;
824N/A case PSSaveByType:
824N/A (void) ReadType(f, rd, resourceType);
824N/A break;
824N/A case PSSaveReturnValues:
824N/A tn.type = resourceType;
824N/A tn.name = resourceName;
824N/A (void) ReadName(f, rd, (char *) &tn);
824N/A break;
824N/A }
824N/A } else (*PSResFileWarningHandler)(rd->directory,
824N/A "File changed during execution");
824N/A (void) fclose(f);
824N/A }
824N/A}
824N/A
824N/Astatic int FindData(resourceType, resourceName,
824N/A resourceNamesReturn, resourceFilesReturn)
824N/A char *resourceType;
824N/A char *resourceName;
824N/A char ***resourceNamesReturn;
824N/A char ***resourceFilesReturn;
824N/A{
824N/A ResourceDirectory rd;
824N/A ResourceType rt;
824N/A int i, j, k;
824N/A int nameCount = 0;
824N/A char **names, **files;
824N/A
824N/A /* Make two passes; first count, then set and return */
824N/A
824N/A for (rd = resDir; rd != NULL; rd = rd->next) {
824N/A for (i = 0; i < rd->typeCount; i++) {
824N/A rt = rd->types + i;
824N/A if (strcmp(rt->type, resourceType) != 0) continue;
824N/A if (resourceName == NULL) nameCount += rt->nameCount;
824N/A else {
824N/A for (j = 0; j < rt->nameCount; j++) {
824N/A if (strcmp(rt->names[j].name, resourceName) == 0) {
824N/A nameCount++;
824N/A }
824N/A }
824N/A }
824N/A }
824N/A }
824N/A
824N/A if (nameCount == 0) return 0;
824N/A
824N/A names = (char **) MALLOC((int) (nameCount * sizeof(char *)));
824N/A files = (char **) MALLOC((int) (nameCount * sizeof(char *)));
824N/A k = 0;
824N/A
824N/A for (rd = resDir; rd != NULL; rd = rd->next) {
824N/A for (i = 0; i < rd->typeCount; i++) {
824N/A rt = rd->types + i;
824N/A if (strcmp(rt->type, resourceType) != 0) continue;
824N/A for (j = 0; j < rt->nameCount; j++) {
824N/A if (resourceName == NULL ||
824N/A strcmp(rt->names[j].name, resourceName) == 0) {
824N/A names[k] = rt->names[j].name;
824N/A files[k++] = rt->names[j].file;
824N/A }
824N/A }
824N/A }
824N/A }
824N/A
824N/A *resourceNamesReturn = names;
824N/A *resourceFilesReturn = files;
824N/A return nameCount;
824N/A}
824N/A
824N/Aextern int ListPSResourceFiles(psResourcePathOverride, defaultPath,
824N/A resourceType, resourceName,
824N/A resourceNamesReturn, resourceFilesReturn)
824N/A char *psResourcePathOverride;
824N/A char *defaultPath;
824N/A char *resourceType;
824N/A char *resourceName;
824N/A char ***resourceNamesReturn;
824N/A char ***resourceFilesReturn;
824N/A{
824N/A if (SetUpSavedPaths(psResourcePathOverride, defaultPath)) {
824N/A ReadHeadersAndData(resourceType, resourceName);
824N/A } else UpdateData(resourceType, resourceName);
824N/A return FindData(resourceType, resourceName,
824N/A resourceNamesReturn, resourceFilesReturn);
824N/A}
824N/A
824N/Aint ListPSResourceTypes(pathOverride, defaultPath, typesReturn)
824N/A char *pathOverride;
824N/A char *defaultPath;
824N/A char ***typesReturn;
824N/A{
824N/A#define GROW 5
824N/A#define START 15
824N/A int typeCount = 0, i, j, typeBufSize = 0;
824N/A ResourceDirectory d;
824N/A register char **types = NULL;
824N/A int sig;
824N/A int *sigs = NULL;
824N/A char *ch;
824N/A
824N/A if (SetUpSavedPaths(pathOverride, defaultPath)) {
824N/A if (currentPolicy != PSSaveEverything) {
824N/A lastModifiedTime =
824N/A ReadFilesInPath(GetPath(), (ReadContentsFunction) NULL,
824N/A (char *) NULL);
824N/A } else lastModifiedTime =
824N/A ReadFilesInPath(GetPath(), ReadEverything, (char *) NULL);
824N/A }
824N/A
824N/A for (d = resDir; d != NULL; d = d->next) {
824N/A for (i = 0; i < d->typeCount; i++) {
824N/A for (sig = 0, ch = d->types[i].type; *ch != '\0'; sig += *ch++) {}
824N/A for (j = 0; j < typeCount; j++) {
824N/A if (sig == sigs[j] &&
824N/A strcmp(types[j], d->types[i].type) == 0) break;
824N/A }
824N/A if (j >= typeCount) { /* Have to add */
824N/A if (typeCount >= typeBufSize) {
824N/A if (typeCount == 0) typeBufSize = START;
824N/A else typeBufSize += GROW;
824N/A types = (char **) REALLOC((char *) types,
824N/A typeBufSize * sizeof(char *));
824N/A sigs = (int *) REALLOC((char *) sigs,
824N/A typeBufSize * sizeof(int));
824N/A }
824N/A types[typeCount] = d->types[i].type;
824N/A sigs[typeCount++] = sig;
824N/A }
824N/A }
824N/A }
824N/A
824N/A FREE((char *) sigs);
824N/A *typesReturn = types;
824N/A return typeCount;
824N/A#undef START
824N/A#undef GROW
824N/A}
824N/A
824N/A/* Assumes being correctly positioned in the file */
824N/A
824N/Astatic int EnumerateResourceSection(f, dir, type, s, checkName)
824N/A FILE *f;
824N/A ResourceDirectory dir;
824N/A ResourceType type;
824N/A EnumeratorStruct *s;
824N/A int checkName;
824N/A{
824N/A#define GROW 1000
824N/A char *linein;
824N/A int len;
824N/A char namebuf[GROW];
824N/A char *names = namebuf;
824N/A int buflen = GROW, namelen = 0;
824N/A char *sep;
824N/A int prefixLen;
824N/A int insertPrefix;
824N/A char *file;
824N/A char dontDequote;
824N/A int doubleEquals;
824N/A int addingPrefix;
824N/A
824N/A if (checkName && VerifyName(f, type->type) != 0) return 1;
824N/A
824N/A insertPrefix = CheckInsertPrefix(type->type);
824N/A if (insertPrefix) {
824N/A prefixLen = strlen(dir->filePrefix);
824N/A dontDequote = '\0';
824N/A } else {
824N/A prefixLen = 0;
824N/A dontDequote = ',';
824N/A }
824N/A
824N/A while (1) {
824N/A linein = ReadFullLine(f);
824N/A if (linein == NULL) {
824N/A if (names != namebuf) FREE((char *) names);
824N/A FreeLineBuf();
824N/A return 1;
824N/A }
824N/A
824N/A if (strcmp(linein, ".") == 0) {
824N/A if (names != namebuf) FREE((char *) names);
824N/A FreeLineBuf();
824N/A return 0;
824N/A }
824N/A
824N/A sep = NULL;
824N/A (void) DequoteAndBreak(linein, &sep, '=', dontDequote, &doubleEquals);
824N/A
824N/A /* If no separator, a bogus line */
824N/A if (sep == NULL) continue;
824N/A
824N/A /* Next line is UNIX specific! */
824N/A addingPrefix = *(sep+1) != '/' && insertPrefix && !doubleEquals;
824N/A
824N/A len = strlen(linein) + (addingPrefix ? 0 : prefixLen) + 1;
824N/A if (len > buflen) {
824N/A if (names != namebuf) FREE((char *) names);
824N/A names = (char *) MALLOC(len);
824N/A }
824N/A
824N/A *sep = '\0';
824N/A len = strlen(linein);
824N/A (void) strncpy(names, linein, len+1);
824N/A
824N/A namelen = len+1;
824N/A file = &names[namelen];
824N/A
824N/A if (addingPrefix) {
824N/A (void) strncpy(&names[namelen], dir->filePrefix, prefixLen);
824N/A namelen += prefixLen;
824N/A }
824N/A
824N/A len = strlen(sep+1);
824N/A (void) strncpy(&names[namelen], sep+1, len+1);
824N/A
824N/A if (s->name == NULL || strcmp(names, s->name) == 0) {
824N/A s->done = (*s->func) (s->type, names, file, s->private);
824N/A if (s->done) {
824N/A if (names != namebuf) FREE((char *) names);
824N/A FreeLineBuf();
824N/A return 0;
824N/A }
824N/A }
824N/A }
824N/A#undef GROW
824N/A}
824N/A
824N/Astatic int Enumerate(f, rd, data)
824N/A FILE *f;
824N/A ResourceDirectory rd;
824N/A char *data;
824N/A{
824N/A EnumeratorStruct *s = (EnumeratorStruct *) data;
824N/A int i;
824N/A ResourceType t;
824N/A long pos;
824N/A
824N/A if (s->done) return 0;
824N/A
824N/A for (i = 0; i < rd->typeCount; i++) {
824N/A t = &rd->types[i];
824N/A
824N/A if (t->fileOffset == -1) continue; /* Not really there */
824N/A if (t->fileOffset != 0 && fseek(f, t->fileOffset, SEEK_SET) != -1) {
824N/A if (strcmp(t->type, s->type) == 0) {
824N/A if (EnumerateResourceSection(f, rd, t, s, 1)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A if (s->done) return 0;;
824N/A } else if (SkipResourceSection(f, rd, t, 1)) {
824N/A char buf[256];
824N/A sprintf(buf, "Trouble parsing resource type %s", t->type);
824N/A PSResFileWarningHandler(rd->directory, buf);
824N/A return 1;
824N/A }
824N/A continue;
824N/A }
824N/A
824N/A pos = ftell(f);
824N/A if (VerifyName(f, t->type) == 0) {
824N/A t->fileOffset = pos;
824N/A if (strcmp(t->type, s->type) == 0) {
824N/A if (EnumerateResourceSection(f, rd, t, s, 0)) return 1;
824N/A if (s->done) return 0;
824N/A } else if (SkipResourceSection(f, rd, t, 0)) return 1;
824N/A } else {
824N/A /* No resources of this type; try the next type */
824N/A t->fileOffset = -1;
824N/A if (fseek(f, pos, SEEK_SET) == -1) return 1;
824N/A }
824N/A }
824N/A return 0;
824N/A}
824N/A
824N/Avoid EnumeratePSResourceFiles(pathOverride, defaultPath, resourceType,
824N/A resourceName, enumerator, private)
824N/A char *pathOverride;
824N/A char *defaultPath;
824N/A char *resourceType;
824N/A char *resourceName;
824N/A PSResourceEnumerator enumerator;
824N/A char *private;
824N/A{
824N/A ResourceDirectory d;
824N/A FILE *f;
824N/A EnumeratorStruct s;
824N/A
824N/A s.func = enumerator;
824N/A s.type = resourceType;
824N/A s.name = resourceName;
824N/A s.private = private;
824N/A s.done = 0;
824N/A
824N/A if (SetUpSavedPaths(pathOverride, defaultPath)) {
824N/A lastModifiedTime =
824N/A ReadFilesInPath(GetPath(), Enumerate, (char *) &s);
824N/A return;
824N/A }
824N/A
824N/A for (d = resDir; d != NULL && !s.done; d = d->next) {
824N/A f = fopen(d->directory, "r");
824N/A if (f == NULL) continue;
824N/A if (fseek(f, d->endOfHeader, SEEK_SET) != -1) {
824N/A (void) Enumerate(f, d, (char *) &s);
824N/A }
824N/A (void) fclose(f);
824N/A }
824N/A}
824N/A
824N/Aint CheckPSResourceTime(pathOverride, defaultPath)
824N/A char *pathOverride;
824N/A char *defaultPath;
824N/A{
824N/A if (CheckSavedPaths(pathOverride, defaultPath)) return 1;
824N/A return MaxTimeInPath(GetPath()) > lastModifiedTime;
824N/A}