~ubuntu-branches/ubuntu/gutsy/vnc4/gutsy

« back to all changes in this revision

Viewing changes to unix/xc/lib/psres/PSres.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2006-05-15 20:35:17 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060515203517-l4lre1ku942mn26k
Tags: 4.1.1+X4.3.0-10
* Correction of critical security issue. Thanks to Martin Kogler
  <e9925248@student.tuwien.ac.at> that informed me about the issue,
  and provided the patch.
  This flaw was originally found by Steve Wiseman of intelliadmin.com.
* Applied patch from Javier Kohen <jkohen@users.sourceforge.net> that
  inform the user that only 8 first characters of the password will
  actually be used when typing more than 8 characters, closes:
  #355619.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * PSres.c
 
3
 *
 
4
 * (c) Copyright 1991-1994 Adobe Systems Incorporated.
 
5
 * All rights reserved.
 
6
 * 
 
7
 * Permission to use, copy, modify, distribute, and sublicense this software
 
8
 * and its documentation for any purpose and without fee is hereby granted,
 
9
 * provided that the above copyright notices appear in all copies and that
 
10
 * both those copyright notices and this permission notice appear in
 
11
 * supporting documentation and that the name of Adobe Systems Incorporated
 
12
 * not be used in advertising or publicity pertaining to distribution of the
 
13
 * software without specific, written prior permission.  No trademark license
 
14
 * to use the Adobe trademarks is hereby granted.  If the Adobe trademark
 
15
 * "Display PostScript"(tm) is used to describe this software, its
 
16
 * functionality or for any other purpose, such use shall be limited to a
 
17
 * statement that this software works in conjunction with the Display
 
18
 * PostScript system.  Proper trademark attribution to reflect Adobe's
 
19
 * ownership of the trademark shall be given whenever any such reference to
 
20
 * the Display PostScript system is made.
 
21
 * 
 
22
 * ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR
 
23
 * ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
 
24
 * ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
26
 * NON- INFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO EVENT SHALL ADOBE BE LIABLE
 
27
 * TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL
 
28
 * DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,
 
29
 * NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN
 
30
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  ADOBE WILL NOT
 
31
 * PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE.
 
32
 * 
 
33
 * Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems
 
34
 * Incorporated which may be registered in certain jurisdictions
 
35
 * 
 
36
 * Author:  Adobe Systems Incorporated
 
37
 */
 
38
/* $XFree86: xc/lib/psres/PSres.c,v 1.4 2001/10/28 03:32:46 tsi Exp $ */
 
39
 
 
40
#include <stdio.h>
 
41
#include <stdlib.h>
 
42
 
 
43
#ifdef XENVIRONMENT
 
44
#include <X11/Xos.h>
 
45
#else
 
46
#include <string.h>
 
47
#include <sys/types.h>
 
48
#endif
 
49
 
 
50
#define USE_POSIX
 
51
 
 
52
#ifdef NeXT
 
53
#undef USE_POSIX
 
54
#endif /* NeXT */
 
55
 
 
56
#ifdef USE_POSIX
 
57
#include <dirent.h>
 
58
#else
 
59
#include <sys/dir.h>
 
60
#endif
 
61
 
 
62
#include <sys/stat.h>
 
63
#include <DPS/PSres.h>
 
64
 
 
65
#ifndef PSRES_NAME
 
66
#define PSRES_NAME "PSres.upr"
 
67
#endif /* PSRES_NAME */
 
68
 
 
69
#ifndef PSRES_EXT
 
70
#define PSRES_EXT ".upr"
 
71
#endif /* PSRES_EXT */
 
72
 
 
73
#ifndef SEEK_SET
 
74
#define SEEK_SET 0
 
75
#endif /* SEEK_SET */
 
76
 
 
77
/* MT is the right pointer type to pass to memcpy, MST the size type */
 
78
#define MT void *
 
79
#define MST size_t
 
80
 
 
81
#define MAXLEN 256
 
82
typedef int (*ReadContentsFunction)();
 
83
 
 
84
char *PSResFontOutline = "FontOutline",
 
85
     *PSResFontPrebuilt = "FontPrebuilt",
 
86
     *PSResFontAFM = "FontAFM",
 
87
     *PSResFontBDF = "FontBDF",
 
88
     *PSResFontFamily = "FontFamily",
 
89
     *PSResFontBDFSizes = "FontBDFSizes",
 
90
     *PSResForm = "Form",
 
91
     *PSResPattern = "Pattern",
 
92
     *PSResEncoding = "Encoding",
 
93
     *PSResProcSet = "ProcSet";
 
94
 
 
95
typedef struct _ResourceNameStruct {
 
96
    char *name;
 
97
    char *file;
 
98
} ResourceNameStruct, *ResourceName;
 
99
 
 
100
typedef struct _ResourceTypeStruct {
 
101
    char *type;
 
102
    long fileOffset;    /* -1 means not really in the file */
 
103
    ResourceName names;
 
104
    int nameCount;
 
105
    int filled;         /* Whether has all names or just already found names */
 
106
    char *nameBuffer;
 
107
    char **oldNameBuffers;
 
108
    int oldNameCount;
 
109
} ResourceTypeStruct, *ResourceType;
 
110
 
 
111
typedef struct _ResourceDirectoryStruct {
 
112
    char *directory;
 
113
    ResourceType types;
 
114
    int typeCount;
 
115
    char *typeNameBuffer;
 
116
    char *filePrefix;
 
117
    long endOfHeader;
 
118
    int exclusive;
 
119
    struct _ResourceDirectoryStruct *next;
 
120
} ResourceDirectoryStruct, *ResourceDirectory;
 
121
 
 
122
typedef struct {
 
123
    char *type;
 
124
    char *name;
 
125
} TypeName;
 
126
 
 
127
typedef struct {
 
128
    PSResourceEnumerator func;
 
129
    char *type;
 
130
    char *name;
 
131
    char *private;
 
132
    int done;
 
133
} EnumeratorStruct;
 
134
 
 
135
static ResourceDirectory resDir = NULL, lastResDir;
 
136
static char *savedPathOverride = NULL, *savedDefaultPath = NULL;
 
137
static PSResourceSavePolicy currentPolicy = PSSaveByType;
 
138
static int currentWillList;
 
139
static char **currentResourceTypes = NULL;
 
140
static char *resourceTypeBuffer = NULL;
 
141
static time_t lastModifiedTime;
 
142
static char nullStr = '\0';
 
143
 
 
144
/* Wrappers */
 
145
 
 
146
static char *mymalloc(size)
 
147
    int size;
 
148
{
 
149
    char *ret;
 
150
 
 
151
#ifdef XENVIRONMENT
 
152
#ifdef MALLOC_0_RETURNS_NULL
 
153
    if (size < 1) size = 1;
 
154
#endif
 
155
#else
 
156
    if (size < 1) size = 1;                     /* Better safe than sorry */
 
157
#endif
 
158
    
 
159
    ret = (char *) malloc((unsigned) size);
 
160
    if (ret != NULL) return ret;
 
161
    (void) fprintf(stderr, "malloc failed\n");
 
162
    exit(1);
 
163
    return NULL;
 
164
}
 
165
 
 
166
PSResMallocProc PSResMalloc = mymalloc;
 
167
#define MALLOC (*PSResMalloc)
 
168
 
 
169
static char *myrealloc(ptr, size)
 
170
    char *ptr;
 
171
    int size;
 
172
{
 
173
    char *ret;
 
174
 
 
175
#ifdef XENVIRONMENT
 
176
#ifdef MALLOC_0_RETURNS_NULL
 
177
    if (size < 1) size = 1;
 
178
#endif
 
179
#else
 
180
    if (size < 1) size = 1;                     /* Better safe than sorry */
 
181
#endif
 
182
 
 
183
    if (ptr == NULL) return MALLOC(size);
 
184
#ifdef NO_VOID_STAR
 
185
    ret = (char *) realloc(ptr, (unsigned) size);
 
186
#else
 
187
    ret = (char *) realloc((void *) ptr, (unsigned) size);
 
188
#endif
 
189
    if (ret != NULL) return ret;
 
190
    (void) fprintf(stderr, "realloc failed\n");
 
191
    exit(1);
 
192
    return NULL;
 
193
}
 
194
 
 
195
PSResReallocProc PSResRealloc = myrealloc;
 
196
#define REALLOC (*PSResRealloc)
 
197
 
 
198
static void myfree(ptr)
 
199
    char *ptr;
 
200
{
 
201
#ifdef NO_VOID_STAR
 
202
    if (ptr != NULL) free(ptr);
 
203
#else
 
204
    if (ptr != NULL) free((void *) ptr);
 
205
#endif
 
206
}
 
207
 
 
208
PSResFreeProc PSResFree = myfree;
 
209
#define FREE (*PSResFree)
 
210
 
 
211
#define NewString(str) ((char *) strcpy(MALLOC((int) (strlen(str)+1)),(str)))
 
212
 
 
213
static void FileWarningHandler(file, extraInfo)
 
214
    char *file;
 
215
    char *extraInfo;
 
216
{
 
217
    fprintf(stderr,
 
218
            "Syntax error found in PostScript resource file %s:\n  %s\n",
 
219
            file, extraInfo);
 
220
}
 
221
 
 
222
PSResFileWarningHandlerProc PSResFileWarningHandler = FileWarningHandler;
 
223
 
 
224
/* Just like fgets, but strips trailing newline, eliminates trailing comments,
 
225
   skips trailing white space, skips blank lines, and chops lines longer
 
226
   than size */
 
227
 
 
228
static char *myfgets(buf, size, f)
 
229
    char *buf;
 
230
    register int size;
 
231
    FILE *f;
 
232
{
 
233
    register int ch;
 
234
    register int count = 0;
 
235
 
 
236
#define STRIP_BLANKS \
 
237
        while (--count >= 0 && (buf[count] == ' ' || buf[count] == '\t')) \
 
238
               buf[count] = '\0';
 
239
#define RETURN_BUF \
 
240
        if (buf[0] != '\0') return buf; \
 
241
        else return myfgets(buf, size, f);
 
242
 
 
243
    if (size == 0) return buf;
 
244
    size--;
 
245
 
 
246
    while (count < size) {
 
247
        ch = getc(f);
 
248
        if (ch == EOF) {
 
249
            buf[count] = '\0';
 
250
            STRIP_BLANKS;
 
251
            return NULL;
 
252
        }
 
253
        if (ch == '\n') {
 
254
            buf[count] = '\0';
 
255
            STRIP_BLANKS;
 
256
            RETURN_BUF;
 
257
        }
 
258
        if (ch == '%') {        /* Comment */
 
259
            if (count == 0 || buf[count-1] != '\\') {
 
260
                buf[count] = '\0';
 
261
                do {
 
262
                    ch = getc(f);
 
263
                } while (ch != EOF && ch != '\n');
 
264
                STRIP_BLANKS;
 
265
                if (ch == EOF) return NULL;
 
266
                else RETURN_BUF;
 
267
            }
 
268
        }
 
269
                
 
270
        buf[count] = ch;
 
271
        count++;
 
272
    }
 
273
 
 
274
    /* Overflow, flush */
 
275
    buf[count] = '\0';
 
276
    do {
 
277
        ch = getc(f);
 
278
    } while (ch != EOF && ch != '\n');
 
279
    STRIP_BLANKS;
 
280
    if (ch == EOF) return NULL;
 
281
    else RETURN_BUF;
 
282
#undef RETURN_BUF
 
283
#undef STRIP_BLANKS
 
284
}
 
285
 
 
286
static int Dequote(buf, dontDequote)
 
287
    char *buf;
 
288
    char dontDequote;
 
289
{
 
290
    char *dst = buf, *src = buf;
 
291
 
 
292
    while (*src != '\0') {
 
293
        if (*src == '\\') {
 
294
            src++;
 
295
            if (*src == '\0') {
 
296
                *dst = '\0';
 
297
                return 1;
 
298
            } else if (*src == dontDequote) *dst++ = '\\';
 
299
        }
 
300
        *dst++ = *src++;
 
301
    }
 
302
    *dst = '\0';
 
303
    return 0;
 
304
}
 
305
 
 
306
/* Sep returns the first unquoted position of the break character.  The
 
307
   dontDequote character only applies after the break character.  If the
 
308
   separator character is doubled, doubleSep is set to 1 and only one
 
309
   of the separators is installed */
 
310
 
 
311
static int DequoteAndBreak(buf, sep, bchar, dontDequote, doubleSep)
 
312
    char *buf;
 
313
    char **sep;
 
314
    char bchar;
 
315
    char dontDequote;
 
316
    int *doubleSep;
 
317
{
 
318
    char *dst = buf, *src = buf;
 
319
 
 
320
    *doubleSep = 0;
 
321
    *sep = NULL;
 
322
 
 
323
    while (*src != '\0') {
 
324
        if (*src == '\\') {
 
325
            src++;
 
326
            if (*src == '\0') {
 
327
                *dst = '\0';
 
328
                return 1;
 
329
            } else if (*src == dontDequote && *sep != NULL) *dst++ = '\\';
 
330
        } else if (*sep == NULL && *src == bchar) {
 
331
            *sep = dst;
 
332
            if (*(src+1) == bchar) {
 
333
                src++;
 
334
                *doubleSep = 1;
 
335
            }
 
336
        }
 
337
        *dst++ = *src++;
 
338
    }
 
339
    *dst = '\0';
 
340
    return 0;
 
341
}
 
342
 
 
343
static float ParseVersion(f, excl)
 
344
    FILE *f;
 
345
    int *excl;
 
346
{
 
347
    char inBuf[MAXLEN];
 
348
    float version = 0.0;
 
349
    int count;
 
350
 
 
351
    if (myfgets(inBuf, MAXLEN, f) == NULL) return 0.0;
 
352
    
 
353
    /* Compare against magic value */
 
354
 
 
355
    count = sscanf(inBuf, "PS-Resources-Exclusive-%f", &version);
 
356
    if (count == 1) {
 
357
        *excl = 1;
 
358
        return version;
 
359
    }
 
360
    count = sscanf(inBuf, "PS-Resources-%f", &version);
 
361
    if (count == 1) {
 
362
        *excl = 0;
 
363
        return version;
 
364
    }
 
365
    return 0.0;
 
366
}
 
367
 
 
368
static int ParseResourceTypes(f, dir)
 
369
    FILE *f;
 
370
    ResourceDirectory dir;
 
371
{
 
372
    char inBuf[MAXLEN];
 
373
    char typebuf[MAXLEN];
 
374
    char *types = typebuf;
 
375
    int buflen = MAXLEN, typelen = 0, len;
 
376
    int count, i;
 
377
    int continued = 0, precontinued = 0;
 
378
 
 
379
    typebuf[0] = '\0';
 
380
    count = 0;
 
381
 
 
382
    while (1) {
 
383
        if (myfgets(inBuf, MAXLEN, f) == NULL) {
 
384
            if (types != typebuf) FREE((char *) types);
 
385
            return 1;
 
386
        }
 
387
        if (strcmp(inBuf, ".") == 0) break;
 
388
        precontinued = continued;
 
389
        continued = Dequote(inBuf, '\0');
 
390
 
 
391
        len = strlen(inBuf);
 
392
        if (typelen + len + 1 > buflen) {
 
393
            if (types == typebuf) {
 
394
                types = (char *) MALLOC(2*MAXLEN);
 
395
                (void) memcpy((MT) types, (MT) typebuf, (MST) typelen);
 
396
            } else types = REALLOC(types, buflen+MAXLEN);
 
397
            buflen += MAXLEN;
 
398
        }
 
399
 
 
400
        if (precontinued) typelen--;    /* Write over previous \0 */
 
401
        else count++;
 
402
        (void) strncpy(&types[typelen], inBuf, len+1);
 
403
        typelen += len+1;
 
404
    }
 
405
 
 
406
    dir->typeCount = count;
 
407
    if (count == 0) dir->types = NULL;
 
408
    else {
 
409
        dir->types = (ResourceType)
 
410
                MALLOC((int) (count * sizeof(ResourceTypeStruct)));
 
411
        dir->typeNameBuffer = (char *) MALLOC(typelen);
 
412
        (void) memcpy((MT) dir->typeNameBuffer, (MT) types, (MST) typelen);
 
413
    }
 
414
 
 
415
    len = 0;
 
416
    for (i = 0; i < count; i++) {
 
417
        dir->types[i].type = &(dir->typeNameBuffer[len]);
 
418
        dir->types[i].fileOffset = 0;
 
419
        dir->types[i].names = NULL;
 
420
        dir->types[i].nameBuffer = NULL;
 
421
        dir->types[i].filled = 0;
 
422
        dir->types[i].oldNameBuffers = NULL;
 
423
        dir->types[i].oldNameCount = 0;
 
424
        dir->types[i].nameCount = 0;
 
425
        len += strlen(dir->types[i].type) + 1;
 
426
    }
 
427
 
 
428
    if (types != typebuf) FREE((char *) types);
 
429
    return 0;
 
430
}
 
431
 
 
432
static int ParseFilePrefix(f, dir, dirName)
 
433
    FILE *f;
 
434
    ResourceDirectory dir;
 
435
    char *dirName;
 
436
{
 
437
    char inBuf[MAXLEN];
 
438
    int continued;
 
439
    int len;
 
440
    long savePos;
 
441
    char *prefix;
 
442
 
 
443
    dir->filePrefix = NULL;
 
444
 
 
445
    savePos = ftell(f);
 
446
    if (myfgets(inBuf, MAXLEN, f) == NULL) return 1;
 
447
 
 
448
    if (inBuf[0] != '/') {
 
449
        if (fseek(f, savePos, SEEK_SET) == -1) return 1;
 
450
        len = strlen(dirName);
 
451
        dir->filePrefix = strcpy((char *) MALLOC(len+2), dirName);
 
452
        dir->filePrefix[len] = '/';
 
453
        dir->filePrefix[len+1] = '\0';
 
454
        return 0;
 
455
    }
 
456
 
 
457
    continued = Dequote(inBuf, '\0');
 
458
    prefix = inBuf+1;
 
459
    len = strlen(prefix);
 
460
    dir->filePrefix = (char *) strcpy((char *) MALLOC(len+2), prefix);
 
461
    if (!continued) {
 
462
        dir->filePrefix[len] = '/';
 
463
        dir->filePrefix[len+1] = '\0';
 
464
        return 0;
 
465
    }
 
466
 
 
467
    while (1) {
 
468
        if (myfgets(inBuf, MAXLEN, f) == NULL) return 1;
 
469
        continued = Dequote(inBuf, '\0');
 
470
        len += strlen(inBuf);
 
471
        dir->filePrefix = (char *) REALLOC(dir->filePrefix, len+2);
 
472
        (void) strcat(dir->filePrefix, inBuf);
 
473
        if (!continued) {
 
474
            dir->filePrefix[len] = '/';
 
475
            dir->filePrefix[len+1] = '\0';
 
476
            return 0;
 
477
        }
 
478
    }
 
479
}
 
480
 
 
481
static ResourceDirectory ParseHeader(f, dirName, fileName)
 
482
    FILE *f;
 
483
    char *dirName, *fileName;
 
484
{
 
485
    ResourceDirectory dir;
 
486
    float version;
 
487
    int exclusive;
 
488
 
 
489
    rewind(f);
 
490
 
 
491
    version = ParseVersion(f, &exclusive);
 
492
    if (version < 1.0) return NULL;
 
493
 
 
494
    dir = (ResourceDirectory) MALLOC(sizeof(ResourceDirectoryStruct));
 
495
    dir->directory = (char *) NewString(fileName);
 
496
    dir->exclusive = exclusive;
 
497
    dir->next = NULL;
 
498
 
 
499
    if (ParseResourceTypes(f, dir)) {
 
500
        FREE((char *) dir->directory);
 
501
        FREE((char *) dir);
 
502
        return NULL;
 
503
    }
 
504
 
 
505
    if (ParseFilePrefix(f, dir, dirName)) dir->endOfHeader = 0;
 
506
    else dir->endOfHeader = ftell(f);
 
507
 
 
508
    return dir;
 
509
}
 
510
 
 
511
/* Store away old name buffer so pointers to it do not become invalid */
 
512
 
 
513
static void CacheOldNames(type)
 
514
    ResourceType type;
 
515
{
 
516
    type->oldNameCount++;
 
517
    type->oldNameBuffers = (char **) REALLOC((char *) type->oldNameBuffers,
 
518
                                               type->oldNameCount);
 
519
    type->oldNameBuffers[type->oldNameCount-1] = type->nameBuffer;
 
520
    type->nameBuffer = NULL;
 
521
}
 
522
 
 
523
/* Verify that the name matches the name in the file */
 
524
 
 
525
static int VerifyName(f, name)
 
526
    FILE *f;
 
527
    char *name;
 
528
{
 
529
    char inBuf[MAXLEN];
 
530
    int continued = 0;
 
531
    int len;
 
532
    int start = 0;
 
533
 
 
534
    while (1) {
 
535
        if (myfgets(inBuf, MAXLEN, f) == NULL) return 1;
 
536
        continued = Dequote(inBuf, '\0');
 
537
        if (continued) {
 
538
            len = strlen(inBuf);
 
539
            if (strncmp(inBuf, &name[start], len) != 0) return 1;
 
540
            start += len;
 
541
        } else {
 
542
            if (strcmp(inBuf, &name[start]) != 0) return 1;
 
543
            else break;
 
544
        }
 
545
    }
 
546
    return 0;
 
547
}
 
548
 
 
549
static int LookupResourceInList(type, name)
 
550
    ResourceType type;
 
551
    char *name;
 
552
{
 
553
    int i;
 
554
 
 
555
    for (i = 0; i < type->nameCount; i++) {
 
556
        if (strcmp(name, type->names[i].name) == 0) return 1;
 
557
    }
 
558
    return 0;
 
559
}
 
560
 
 
561
static int CheckInsertPrefix(type)
 
562
    char *type;
 
563
{
 
564
   /* Insert the prefix unless one of these special values */
 
565
 
 
566
   if (strcmp(type, PSResFontFamily) == 0 ||
 
567
       strcmp(type, PSResFontBDFSizes) == 0 ||
 
568
       strcmp(type, "FontAxes") == 0 ||
 
569
       strcmp(type, "FontBlendMap") == 0 ||
 
570
       strcmp(type, "FontBlendPositions") == 0 ||
 
571
       strcmp(type, "mkpsresPrivate") == 0) return 0;
 
572
   return 1;
 
573
}
 
574
 
 
575
/* Returns a line, including continuations.  Memory must be copied before
 
576
   calling this again. */
 
577
 
 
578
static int linebuflen = 0;
 
579
static char *inputline = NULL;
 
580
 
 
581
static char *ReadFullLine(f)
 
582
    FILE *f;
 
583
{
 
584
    char readbuf[MAXLEN];
 
585
    int start = 0;
 
586
    int len;
 
587
 
 
588
    while (1) {
 
589
        if (myfgets(readbuf, MAXLEN, f) == NULL) return NULL;
 
590
        len = strlen(readbuf);
 
591
        if (start + len + 1 > linebuflen) {
 
592
            linebuflen += MAXLEN + 1;
 
593
            inputline = REALLOC(inputline, linebuflen);
 
594
        }
 
595
        strncpy(inputline+start, readbuf, len+1);
 
596
 
 
597
        if (inputline[start+len-1] != '\\') break;
 
598
        
 
599
        start = start+len-1;
 
600
    }
 
601
    return inputline;
 
602
}
 
603
 
 
604
static void FreeLineBuf()
 
605
{
 
606
    if (inputline != NULL) FREE(inputline);
 
607
    inputline = NULL;
 
608
    linebuflen = 0;
 
609
}
 
610
 
 
611
/* Assumes being correctly positioned in the file */
 
612
 
 
613
static int ReadResourceSection(f, dir, type, name)
 
614
    FILE *f;
 
615
    ResourceDirectory dir;
 
616
    ResourceType type;
 
617
    char *name;         /* If NULL, enumerate */
 
618
{
 
619
#define GROW 1000
 
620
    char *linein;
 
621
    int start;
 
622
    int len;
 
623
    char namebuf[GROW];
 
624
    char *names = namebuf;
 
625
    int buflen = GROW, namelen = 0;
 
626
    int i, count = 0;
 
627
    char *sep;
 
628
    int prefixLen;
 
629
    int insertPrefix;
 
630
    char dontDequote;
 
631
    int doubleEquals;
 
632
    int addingPrefix;
 
633
    int newsize;
 
634
 
 
635
    if (type->nameBuffer != NULL) CacheOldNames(type);
 
636
 
 
637
    insertPrefix = CheckInsertPrefix(type->type);
 
638
    if (insertPrefix) {
 
639
        prefixLen = strlen(dir->filePrefix);
 
640
        dontDequote = '\0';
 
641
    } else {
 
642
        prefixLen = 0;
 
643
        dontDequote = ',';
 
644
    }
 
645
 
 
646
    while (1) {
 
647
        start = namelen;
 
648
 
 
649
        linein = ReadFullLine(f);
 
650
        if (linein == NULL) {
 
651
            if (names != namebuf) FREE((char *) names);
 
652
            FreeLineBuf();
 
653
            return 1;
 
654
        }
 
655
        if (strcmp(linein, ".") == 0) break;
 
656
 
 
657
        sep = NULL;
 
658
        (void) DequoteAndBreak(linein, &sep, '=', dontDequote, &doubleEquals);
 
659
 
 
660
        /* If no separator, a bogus line */
 
661
        if (sep == NULL) continue;
 
662
            
 
663
        /* Next line is UNIX specific! */
 
664
        addingPrefix = *(sep+1) != '/' && insertPrefix && !doubleEquals;
 
665
 
 
666
        len = strlen(linein) + 1 + (addingPrefix ? prefixLen : 0);
 
667
 
 
668
        if (namelen + len >= buflen) {
 
669
            newsize = buflen + GROW;
 
670
            if (namelen + len > newsize) newsize = namelen + len;
 
671
 
 
672
            if (names == namebuf) {
 
673
                names = (char *) MALLOC(newsize);
 
674
                (void) memcpy((MT) names, (MT) namebuf, (MST) namelen);
 
675
            } else names = REALLOC(names, newsize);
 
676
            buflen = newsize;
 
677
        }
 
678
 
 
679
        *sep = '\0';
 
680
        len = strlen(linein);
 
681
        (void) strncpy(&names[namelen], linein, len+1);
 
682
        namelen += len+1;
 
683
 
 
684
        if (addingPrefix) {
 
685
            (void) strncpy(&names[namelen], dir->filePrefix, prefixLen);
 
686
            namelen += prefixLen;
 
687
        }
 
688
        
 
689
        len = strlen(sep+1);
 
690
        (void) strncpy(&names[namelen], sep+1, len+1);
 
691
        namelen += len+1;
 
692
 
 
693
        if (name != NULL && strcmp(names, name) != 0) namelen = start;
 
694
        else count++;
 
695
    }
 
696
 
 
697
    type->nameCount = count;
 
698
    if (count == 0) type->names = NULL;
 
699
    else {
 
700
        type->names = (ResourceName)
 
701
                MALLOC((int) (count * sizeof(ResourceNameStruct)));
 
702
        type->nameBuffer = (char *) MALLOC(namelen);
 
703
        (void) memcpy((MT) type->nameBuffer, (MT) names, (MST) namelen);
 
704
    }
 
705
 
 
706
    len = 0;
 
707
    for (i = 0; i < count; i++) {
 
708
        type->names[i].name = &(type->nameBuffer[len]);
 
709
        len += strlen(type->names[i].name) + 1;
 
710
        type->names[i].file = &(type->nameBuffer[len]);
 
711
        len += strlen(type->names[i].file) + 1;
 
712
    }
 
713
 
 
714
    if (names != namebuf) FREE((char *) names);
 
715
    if (name == NULL) type->filled = 1;
 
716
    FreeLineBuf();
 
717
    return 0;
 
718
 
 
719
#undef GROW
 
720
}
 
721
 
 
722
/* Assumes being correctly positioned in the file */
 
723
 
 
724
static int SkipResourceSection(f, dir, type, checkName)
 
725
    FILE *f;
 
726
    ResourceDirectory dir;
 
727
    ResourceType type;
 
728
    int checkName;
 
729
{
 
730
    char inBuf[MAXLEN];
 
731
    int i;
 
732
 
 
733
    /* If next type has offset, just go there */
 
734
 
 
735
    for (i = 0; i < dir->typeCount && dir->types + i != type; i++) {}
 
736
 
 
737
    if (dir->types + i == type) {
 
738
        for (i++; i < dir->typeCount; i++) {
 
739
            if (dir->types[i].fileOffset == -1) continue;
 
740
            if (dir->types[i].fileOffset > 0) {
 
741
                if (fseek(f, dir->types[i].fileOffset, SEEK_SET) != -1) {
 
742
                    return 0;
 
743
                } else break;
 
744
            }
 
745
        }
 
746
    }
 
747
 
 
748
    if (checkName && VerifyName(f, type->type) != 0) return 1;
 
749
 
 
750
    while (1) {
 
751
        if (myfgets(inBuf, MAXLEN, f) == NULL) return 1;
 
752
        if (strcmp(inBuf, ".") == 0) return 0;
 
753
    }
 
754
}
 
755
 
 
756
/* Assumes being correctly positioned in the file */
 
757
 
 
758
static int ParseResourceSection(f, dir, type, name, checkName)
 
759
    FILE *f;
 
760
    ResourceDirectory dir;
 
761
    ResourceType type;
 
762
    char *name;         /* If NULL, enumerate */
 
763
    int checkName;
 
764
{
 
765
    if (checkName && VerifyName(f, type->type) != 0) return 1;
 
766
 
 
767
    if (type->filled || (name != NULL && LookupResourceInList(type, name))) { 
 
768
        return SkipResourceSection(f, dir, type, 0);
 
769
    }
 
770
 
 
771
    return ReadResourceSection(f, dir, type, name);
 
772
}
 
773
 
 
774
void FreePSResourceStorage(everything)
 
775
    int everything;
 
776
{
 
777
    ResourceDirectory d;
 
778
    ResourceType t;
 
779
    int i, j;
 
780
 
 
781
    if (resDir == NULL) return;
 
782
 
 
783
    for (d = resDir; d != NULL; d = d->next) {
 
784
        for (i = 0; i < d->typeCount; i++) {
 
785
            t = d->types + i;
 
786
            FREE(t->nameBuffer);
 
787
            FREE((char *) t->names);
 
788
            t->nameCount = 0;
 
789
            for (j = 0; j < t->oldNameCount; j++) FREE(t->oldNameBuffers[j]);
 
790
            if (t->oldNameBuffers != NULL) FREE((char *) t->oldNameBuffers);
 
791
            t->oldNameCount = 0;
 
792
            t->nameCount = 0;
 
793
            t->filled = 0;
 
794
        }
 
795
    }
 
796
 
 
797
    if (!everything) return;
 
798
 
 
799
    while (resDir != NULL) {
 
800
        d = resDir->next;
 
801
        FREE(resDir->directory);
 
802
        FREE((char *) resDir->types);
 
803
        FREE(resDir->typeNameBuffer);
 
804
        FREE(resDir->filePrefix);
 
805
        FREE((char *) resDir);
 
806
        resDir = d;
 
807
    }
 
808
    lastResDir = NULL;
 
809
    FREE(savedPathOverride);
 
810
    savedPathOverride = NULL;
 
811
    FREE(savedDefaultPath);
 
812
    savedDefaultPath = NULL;
 
813
}
 
814
 
 
815
static ResourceDirectory ReadAndStoreFile(dir, name, len, readFunc, data)
 
816
    char *dir, *name;
 
817
    int len;
 
818
    ReadContentsFunction readFunc;
 
819
    char *data;
 
820
{
 
821
    ResourceDirectory rd = NULL;
 
822
    FILE *f;
 
823
    char nameBuf[MAXLEN];
 
824
    char *fullName = nameBuf;
 
825
    int fullLen;
 
826
 
 
827
    fullLen = len + strlen(name) + 1;
 
828
    if (fullLen >= MAXLEN) fullName = MALLOC(fullLen+1);
 
829
    (void) strcpy(fullName, dir);
 
830
    fullName[len] = '/';
 
831
    (void) strcpy(fullName+len+1, name);
 
832
 
 
833
    f = fopen(fullName, "r");
 
834
    if (f != NULL) {
 
835
        rd = ParseHeader(f, dir, fullName);
 
836
 
 
837
        if (rd != NULL) {
 
838
            if (resDir == NULL) resDir = rd;
 
839
            else lastResDir->next = rd;
 
840
            lastResDir = rd;
 
841
            if (readFunc != NULL) (*readFunc) (f, rd, data);
 
842
        } else (*PSResFileWarningHandler)(fullName, "Malformed header");
 
843
        (void) fclose(f);
 
844
    }
 
845
    if (fullName != nameBuf) FREE(fullName);
 
846
    return rd;
 
847
}
 
848
 
 
849
static time_t ReadFilesInDirectory(dirName, readFunc, data)
 
850
    char *dirName;
 
851
    ReadContentsFunction readFunc;
 
852
    char *data;
 
853
{
 
854
    DIR *dir;
 
855
#ifdef USE_POSIX
 
856
    struct dirent *d;
 
857
#else
 
858
    struct direct *d;
 
859
#endif
 
860
    ResourceDirectory rd;
 
861
    int len = strlen(dirName);
 
862
    static int extensionLen = 0;
 
863
    struct stat buf;
 
864
    int namelen;
 
865
 
 
866
    if (extensionLen == 0) extensionLen = strlen(PSRES_EXT);
 
867
    if (stat(dirName, &buf) != 0) buf.st_mtime = 0;
 
868
 
 
869
    rd = ReadAndStoreFile(dirName, PSRES_NAME, len, readFunc, data);
 
870
 
 
871
    if (rd != 0 && rd->exclusive) return buf.st_mtime;
 
872
 
 
873
    dir = opendir(dirName);
 
874
    if (dir == NULL) return buf.st_mtime;
 
875
 
 
876
    while ((d = readdir(dir)) != NULL) {
 
877
        namelen = strlen(d->d_name);
 
878
        if (namelen < extensionLen) continue;
 
879
 
 
880
        if (strcmp(d->d_name + (namelen - extensionLen), PSRES_EXT) == 0
 
881
                && strcmp(d->d_name, PSRES_NAME) != 0) {
 
882
            (void) ReadAndStoreFile(dirName, d->d_name, len, readFunc, data);
 
883
        }
 
884
    }
 
885
    (void) closedir(dir);
 
886
    return buf.st_mtime;
 
887
}
 
888
 
 
889
/* Returns nonzero if current paths different from saved ones */
 
890
 
 
891
static int SetUpSavedPaths(pathOverride, defaultPath)
 
892
    char *pathOverride;
 
893
    char *defaultPath;
 
894
{
 
895
    if (pathOverride == NULL) pathOverride = &nullStr;
 
896
    if (defaultPath == NULL) defaultPath = &nullStr;
 
897
 
 
898
    if (savedPathOverride == NULL ||
 
899
            strcmp(pathOverride, savedPathOverride) != 0 ||
 
900
            strcmp(defaultPath, savedDefaultPath) != 0) {
 
901
 
 
902
        FreePSResourceStorage(1);
 
903
 
 
904
        savedPathOverride = NewString(pathOverride);
 
905
        savedDefaultPath = NewString(defaultPath);
 
906
 
 
907
        return 1;
 
908
    }
 
909
    return 0;
 
910
}
 
911
 
 
912
/* Like SetUpSavedPaths, but never affects saved state */
 
913
 
 
914
static int CheckSavedPaths(pathOverride, defaultPath)
 
915
    char *pathOverride;
 
916
    char *defaultPath;
 
917
{
 
918
    if (pathOverride == NULL) pathOverride = &nullStr;
 
919
    if (defaultPath == NULL) defaultPath = &nullStr;
 
920
 
 
921
    if (savedPathOverride == NULL ||
 
922
            strcmp(pathOverride, savedPathOverride) != 0 ||
 
923
            strcmp(defaultPath, savedDefaultPath) != 0) return 1;
 
924
    else return 0;
 
925
}
 
926
 
 
927
static time_t ReadFilesInPath(string, readFunc, data)
 
928
    char *string;
 
929
    ReadContentsFunction readFunc;
 
930
    char *data;
 
931
{
 
932
    char *pathChar;
 
933
    char pathBuf[MAXLEN];
 
934
    char *path;
 
935
    register char *dir;
 
936
    int len;
 
937
    register char ch;
 
938
    time_t newTime, latestTime = 0;
 
939
 
 
940
    pathChar = string;
 
941
 
 
942
    if (*pathChar == ':') pathChar++;
 
943
 
 
944
    len = strlen(pathChar);
 
945
    if (len < MAXLEN) path = pathBuf;
 
946
    else path = MALLOC(len+1);
 
947
 
 
948
    do {
 
949
        dir = path;
 
950
        do {
 
951
            while (*pathChar == '\\') {
 
952
                pathChar++;
 
953
                if (*pathChar != '\0') *dir++ = *pathChar++;
 
954
            }             
 
955
 
 
956
            *dir++ = ch = *pathChar++;
 
957
        } while (ch != '\0' && ch != ':');
 
958
        if (ch == ':') *(dir-1) = '\0';
 
959
 
 
960
        if (*path == '\0') {
 
961
            if (ch == ':' && string != savedDefaultPath) {
 
962
                newTime = ReadFilesInPath(savedDefaultPath, readFunc, data);
 
963
                if (newTime > latestTime) latestTime = newTime;
 
964
            }
 
965
        } else {
 
966
            newTime = ReadFilesInDirectory(path, readFunc, data);
 
967
            if (newTime > latestTime) latestTime = newTime;
 
968
        }
 
969
    } while (ch == ':');
 
970
    if (path != pathBuf) FREE(path);
 
971
    return latestTime;
 
972
}       
 
973
 
 
974
static time_t MaxTimeInPath(string)
 
975
    char *string;
 
976
{
 
977
    char *pathChar;
 
978
    char pathBuf[MAXLEN];
 
979
    char *path;
 
980
    register char *dir;
 
981
    int len;
 
982
    register char ch;
 
983
    time_t latestTime = 0;
 
984
    struct stat buf;
 
985
 
 
986
    pathChar = string;
 
987
 
 
988
    if (*pathChar == ':') pathChar++;
 
989
 
 
990
    len = strlen(pathChar);
 
991
    if (len < MAXLEN) path = pathBuf;
 
992
    else path = MALLOC(len+1);
 
993
 
 
994
    do {
 
995
        dir = path;
 
996
        do {
 
997
            while (*pathChar == '\\') {
 
998
                pathChar++;
 
999
                if (*pathChar != '\0') *dir++ = *pathChar++;
 
1000
            }             
 
1001
 
 
1002
            *dir++ = ch = *pathChar++;
 
1003
        } while (ch != '\0' && ch != ':');
 
1004
        if (ch == ':') *(dir-1) = '\0';
 
1005
 
 
1006
        if (*path == '\0') {
 
1007
            if (ch == ':' && string != savedDefaultPath) {
 
1008
                buf.st_mtime = MaxTimeInPath(savedDefaultPath);
 
1009
                if (buf.st_mtime > latestTime) latestTime = buf.st_mtime;
 
1010
            }
 
1011
        } else {
 
1012
            if (stat(path, &buf) != 0) buf.st_mtime = 0;
 
1013
            if (buf.st_mtime > latestTime) latestTime = buf.st_mtime;
 
1014
        }
 
1015
    } while (ch == ':');
 
1016
    if (path != pathBuf) FREE(path);
 
1017
    return latestTime;
 
1018
}       
 
1019
 
 
1020
static char *GetPath()
 
1021
{
 
1022
    static char defaultEnvironmentPath[] = "::";
 
1023
    static char *environmentPath = NULL;
 
1024
 
 
1025
    if (savedPathOverride != NULL && *savedPathOverride != '\0') {
 
1026
        return savedPathOverride;
 
1027
    }
 
1028
 
 
1029
    if (environmentPath == NULL) {
 
1030
        environmentPath = getenv("PSRESOURCEPATH");
 
1031
        if (environmentPath == NULL) environmentPath = defaultEnvironmentPath;
 
1032
    }
 
1033
 
 
1034
    return environmentPath;
 
1035
}
 
1036
 
 
1037
void SetPSResourcePolicy(policy, willList, resourceTypes)
 
1038
    PSResourceSavePolicy policy;
 
1039
    int willList;
 
1040
    char **resourceTypes;
 
1041
{
 
1042
    currentPolicy = policy;
 
1043
    currentWillList = willList;
 
1044
 
 
1045
    if (currentResourceTypes != NULL) FREE((char *) currentResourceTypes);
 
1046
    if (resourceTypeBuffer != NULL) FREE((char *) resourceTypeBuffer);
 
1047
 
 
1048
    if (resourceTypes == NULL) {
 
1049
        currentResourceTypes = NULL;
 
1050
        resourceTypeBuffer = NULL;
 
1051
    } else {
 
1052
        int i = 0, len = 0;
 
1053
        char **cp = resourceTypes;
 
1054
 
 
1055
        while (*cp != NULL) {
 
1056
            i++;
 
1057
            len += strlen(*cp) + 1;
 
1058
            cp++;
 
1059
        }
 
1060
        
 
1061
        currentResourceTypes =
 
1062
                (char **) MALLOC((int) ((i+1) * sizeof(char *)));
 
1063
        resourceTypeBuffer = MALLOC(len);
 
1064
        
 
1065
        len = 0;
 
1066
        i = 0;
 
1067
        cp = resourceTypes;
 
1068
 
 
1069
        while (*cp != NULL) {
 
1070
            (void) strcpy(resourceTypeBuffer+len, *cp);
 
1071
            currentResourceTypes[i++] = resourceTypeBuffer + len;
 
1072
            len += strlen(*cp) + 1;
 
1073
            cp++;
 
1074
        }
 
1075
        currentResourceTypes[i] = NULL;
 
1076
    }
 
1077
}
 
1078
 
 
1079
int InSavedList(type)
 
1080
    char *type;
 
1081
{
 
1082
    char **cp = currentResourceTypes;;
 
1083
 
 
1084
    if (cp == NULL) return 0;
 
1085
 
 
1086
    while (*cp != NULL) {
 
1087
        if (strcmp(*cp++, type) == 0) return 1;
 
1088
    }
 
1089
    return 0;
 
1090
}
 
1091
 
 
1092
/* ARGSUSED */
 
1093
static int ReadEverything(f, rd, data)
 
1094
    FILE *f;
 
1095
    ResourceDirectory rd;
 
1096
    char *data;
 
1097
{
 
1098
    int i;
 
1099
    ResourceType t;
 
1100
    long pos;
 
1101
 
 
1102
    /* We're at the start of the resource section; read all of them */
 
1103
 
 
1104
    for (i = 0; i < rd->typeCount; i++) {
 
1105
        t = &rd->types[i];
 
1106
 
 
1107
        if (t->fileOffset == -1) continue;      /* Not really there */
 
1108
 
 
1109
        if (t->fileOffset != 0 && fseek(f, t->fileOffset, SEEK_SET) != -1) {
 
1110
            if (!t->filled) {
 
1111
                if (ParseResourceSection(f, rd, t, (char *) NULL, 1)) {
 
1112
                    char buf[256];
 
1113
                    sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1114
                    PSResFileWarningHandler(rd->directory, buf);
 
1115
                    return 1;
 
1116
                }
 
1117
            } else {
 
1118
                if (SkipResourceSection(f, rd, t, 1)) {
 
1119
                    char buf[256];
 
1120
                    sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1121
                    PSResFileWarningHandler(rd->directory, buf);
 
1122
                    return 1;
 
1123
                }
 
1124
            }
 
1125
            continue;
 
1126
        }
 
1127
 
 
1128
        pos = ftell(f);
 
1129
        if (VerifyName(f, t->type) == 0) {
 
1130
            t->fileOffset = pos;
 
1131
            if (ParseResourceSection(f, rd, t, (char *) NULL, 0)) {
 
1132
                char buf[256];
 
1133
                sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1134
                PSResFileWarningHandler(rd->directory, buf);
 
1135
                return 1;
 
1136
            }
 
1137
        } else {
 
1138
            /* No resources of this type; try the next type */
 
1139
            t->fileOffset = -1;
 
1140
            if (fseek(f, pos, SEEK_SET)) {
 
1141
                PSResFileWarningHandler(rd->directory,
 
1142
                                        "File changed during execution");
 
1143
                return 1;
 
1144
            }
 
1145
        }
 
1146
    }
 
1147
    return 0;
 
1148
}
 
1149
 
 
1150
static int ReadType(f, rd, type)
 
1151
    FILE *f;
 
1152
    ResourceDirectory rd;
 
1153
    char *type;
 
1154
{
 
1155
    int i;
 
1156
    ResourceType t;
 
1157
    long pos;
 
1158
 
 
1159
    /* We're at the start of the resource section; read the sections that
 
1160
       are in the cached type list or are the passed in type */
 
1161
 
 
1162
    for (i = 0; i < rd->typeCount; i++) {
 
1163
        t = &rd->types[i];
 
1164
 
 
1165
        if (t->fileOffset == -1) continue;      /* Not really there */
 
1166
        if (t->fileOffset != 0 && fseek(f, t->fileOffset, SEEK_SET) != -1) {
 
1167
            if (!t->filled &&
 
1168
                    (strcmp(t->type, type) == 0 || InSavedList(t->type))) {
 
1169
                if (ParseResourceSection(f, rd, t, (char *) NULL, 1)) {
 
1170
                    char buf[256];
 
1171
                    sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1172
                    PSResFileWarningHandler(rd->directory, buf);
 
1173
                    return 1;
 
1174
                }
 
1175
            } else if (SkipResourceSection(f, rd, t, 1)) {
 
1176
                char buf[256];
 
1177
                sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1178
                PSResFileWarningHandler(rd->directory, buf);
 
1179
                return 1;
 
1180
            }
 
1181
            continue;
 
1182
        }
 
1183
 
 
1184
        pos = ftell(f);
 
1185
        if (VerifyName(f, t->type) == 0) {
 
1186
            t->fileOffset = pos;
 
1187
            if (strcmp(t->type, type) == 0 || InSavedList(t->type)) {
 
1188
                if (ParseResourceSection(f, rd, t, (char *) NULL, 0)){
 
1189
                    char buf[256];
 
1190
                    sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1191
                    PSResFileWarningHandler(rd->directory, buf);
 
1192
                    return 1;
 
1193
                }
 
1194
            } else if (SkipResourceSection(f, rd, t, 0)) {
 
1195
                char buf[256];
 
1196
                sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1197
                PSResFileWarningHandler(rd->directory, buf);
 
1198
                return 1;
 
1199
            }
 
1200
        } else {
 
1201
            /* No resources of this type; try the next type */
 
1202
            t->fileOffset = -1;
 
1203
            if (fseek(f, pos, SEEK_SET) == -1) {
 
1204
                PSResFileWarningHandler(rd->directory,
 
1205
                                        "File changed during execution");
 
1206
                return 1;
 
1207
            }
 
1208
        }
 
1209
    }
 
1210
    return 0;
 
1211
}
 
1212
 
 
1213
static int ReadName(f, rd, data)
 
1214
    FILE *f;
 
1215
    ResourceDirectory rd;
 
1216
    char *data;
 
1217
{
 
1218
    TypeName *tn = (TypeName *) data;
 
1219
    int i;
 
1220
    ResourceType t;
 
1221
    long pos;
 
1222
 
 
1223
    /* We're at the start of the resource section; read the name in the
 
1224
       section for the passed in type */
 
1225
 
 
1226
    for (i = 0; i < rd->typeCount; i++) {
 
1227
        t = &rd->types[i];
 
1228
 
 
1229
        if (t->fileOffset == -1) continue;      /* Not really there */
 
1230
        if (t->fileOffset != 0 && fseek(f, t->fileOffset, SEEK_SET)) {
 
1231
            if (strcmp(t->type, tn->type) == 0) {
 
1232
                if (ParseResourceSection(f, rd, t, tn->name, 1)) {
 
1233
                    char buf[256];
 
1234
                    sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1235
                    PSResFileWarningHandler(rd->directory, buf);
 
1236
                    return 1;
 
1237
                }
 
1238
            } else if (SkipResourceSection(f, rd, t, 1)) {
 
1239
                char buf[256];
 
1240
                sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1241
                PSResFileWarningHandler(rd->directory, buf);
 
1242
                return 1;
 
1243
            }
 
1244
            continue;
 
1245
        }
 
1246
 
 
1247
        pos = ftell(f);
 
1248
        if (VerifyName(f, t->type) == 0) {
 
1249
            t->fileOffset = pos;
 
1250
            if (fseek(f, pos, SEEK_SET) == -1) {
 
1251
                PSResFileWarningHandler(rd->directory,
 
1252
                                        "File changed during execution");
 
1253
                return 1;
 
1254
            }
 
1255
            if (strcmp(t->type, tn->type) == 0) {
 
1256
                if (ParseResourceSection(f, rd, t, tn->name, 0)) {
 
1257
                    char buf[256];
 
1258
                    sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1259
                    PSResFileWarningHandler(rd->directory, buf);
 
1260
                    return 1;
 
1261
                }
 
1262
            } else if (SkipResourceSection(f, rd, t, 0)) {
 
1263
                char buf[256];
 
1264
                sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1265
                PSResFileWarningHandler(rd->directory, buf);
 
1266
                return 1;
 
1267
            }
 
1268
        } else {
 
1269
            /* No resources of this type; try the next type */
 
1270
            t->fileOffset = -1;
 
1271
            if (fseek(f, pos, SEEK_SET) == -1) {
 
1272
                PSResFileWarningHandler(rd->directory,
 
1273
                                        "File changed during execution");
 
1274
                return 1;
 
1275
            }
 
1276
        }
 
1277
    }
 
1278
    return 0;
 
1279
}
 
1280
 
 
1281
static void ReadHeadersAndData(resourceType, resourceName)
 
1282
    char *resourceType;
 
1283
    char *resourceName;
 
1284
{
 
1285
    TypeName t;
 
1286
 
 
1287
    switch (currentPolicy) {
 
1288
        case PSSaveEverything:
 
1289
            lastModifiedTime =
 
1290
                    ReadFilesInPath(GetPath(), ReadEverything, (char *) NULL);
 
1291
            break;
 
1292
        case PSSaveByType:
 
1293
            lastModifiedTime =
 
1294
                    ReadFilesInPath(GetPath(), ReadType, resourceType);
 
1295
            break;
 
1296
        case PSSaveReturnValues:
 
1297
            t.type = resourceType;
 
1298
            t.name = resourceName;
 
1299
            lastModifiedTime =
 
1300
                    ReadFilesInPath(GetPath(), ReadName, (char *) &t);
 
1301
            break;
 
1302
    }
 
1303
}
 
1304
 
 
1305
static void UpdateData(resourceType, resourceName)
 
1306
    char *resourceType;
 
1307
    char *resourceName;
 
1308
{
 
1309
    ResourceDirectory rd;
 
1310
    ResourceType rt;
 
1311
    int i;
 
1312
    FILE *f;
 
1313
    TypeName tn;
 
1314
 
 
1315
    /* Make two passes; the first figures out if we're going to have to read
 
1316
       the file to service this request.  If we are, open the file and read
 
1317
       in sections in the saved list (from SetPSResourcePolicy).  If not
 
1318
       just saving return values, make sure we read in everything
 
1319
       in the section. */
 
1320
 
 
1321
    for (rd = resDir; rd != NULL; rd = rd->next) {
 
1322
        f = NULL;
 
1323
        for (i = 0; i < rd->typeCount; i++) {
 
1324
            rt = rd->types + i;
 
1325
            if (rt->filled) continue;
 
1326
            if (strcmp(rt->type, resourceType) != 0) continue;
 
1327
 
 
1328
            if (resourceName != NULL &&
 
1329
                    LookupResourceInList(rt, resourceName)) continue;
 
1330
 
 
1331
            f = fopen(rd->directory, "r");
 
1332
            break;
 
1333
        }
 
1334
        if (f == NULL) continue;
 
1335
 
 
1336
        /* Nuts, have to read the file */
 
1337
 
 
1338
        if (fseek(f, rd->endOfHeader, SEEK_SET) != -1) {
 
1339
            switch (currentPolicy) {
 
1340
                case PSSaveEverything:
 
1341
                    (void) ReadEverything(f, rd, (char *) NULL);
 
1342
                    break;
 
1343
                case PSSaveByType:
 
1344
                    (void) ReadType(f, rd, resourceType);
 
1345
                    break;
 
1346
                case PSSaveReturnValues:
 
1347
                    tn.type = resourceType;
 
1348
                    tn.name = resourceName;
 
1349
                    (void) ReadName(f, rd, (char *) &tn);
 
1350
                    break;
 
1351
            }
 
1352
        } else (*PSResFileWarningHandler)(rd->directory,
 
1353
                                          "File changed during execution");
 
1354
        (void) fclose(f);
 
1355
    }
 
1356
}
 
1357
 
 
1358
static int FindData(resourceType, resourceName,
 
1359
                    resourceNamesReturn, resourceFilesReturn)
 
1360
    char *resourceType;
 
1361
    char *resourceName;
 
1362
    char ***resourceNamesReturn;
 
1363
    char ***resourceFilesReturn;
 
1364
{
 
1365
    ResourceDirectory rd;
 
1366
    ResourceType rt;
 
1367
    int i, j, k;
 
1368
    int nameCount = 0;
 
1369
    char **names, **files;
 
1370
 
 
1371
    /* Make two passes; first count, then set and return */
 
1372
 
 
1373
    for (rd = resDir; rd != NULL; rd = rd->next) {
 
1374
        for (i = 0; i < rd->typeCount; i++) {
 
1375
            rt = rd->types + i;
 
1376
            if (strcmp(rt->type, resourceType) != 0) continue;
 
1377
            if (resourceName == NULL) nameCount += rt->nameCount;
 
1378
            else {
 
1379
                for (j = 0; j < rt->nameCount; j++) {
 
1380
                    if (strcmp(rt->names[j].name, resourceName) == 0) {
 
1381
                        nameCount++;
 
1382
                    }
 
1383
                }
 
1384
            }
 
1385
        }
 
1386
    }
 
1387
 
 
1388
    if (nameCount == 0) return 0;
 
1389
 
 
1390
    names = (char **) MALLOC((int) (nameCount * sizeof(char *)));
 
1391
    files = (char **) MALLOC((int) (nameCount * sizeof(char *)));
 
1392
    k = 0;
 
1393
 
 
1394
    for (rd = resDir; rd != NULL; rd = rd->next) {
 
1395
        for (i = 0; i < rd->typeCount; i++) {
 
1396
            rt = rd->types + i;
 
1397
            if (strcmp(rt->type, resourceType) != 0) continue;
 
1398
            for (j = 0; j < rt->nameCount; j++) {
 
1399
                if (resourceName == NULL ||
 
1400
                        strcmp(rt->names[j].name, resourceName) == 0) {
 
1401
                    names[k] = rt->names[j].name;
 
1402
                    files[k++] = rt->names[j].file;
 
1403
                }
 
1404
            }
 
1405
        }
 
1406
    }
 
1407
 
 
1408
    *resourceNamesReturn = names;
 
1409
    *resourceFilesReturn = files;
 
1410
    return nameCount;
 
1411
}
 
1412
 
 
1413
extern int ListPSResourceFiles(psResourcePathOverride, defaultPath,
 
1414
                               resourceType, resourceName,
 
1415
                               resourceNamesReturn, resourceFilesReturn)
 
1416
    char *psResourcePathOverride;
 
1417
    char *defaultPath;
 
1418
    char *resourceType;
 
1419
    char *resourceName;
 
1420
    char ***resourceNamesReturn;
 
1421
    char ***resourceFilesReturn;
 
1422
{
 
1423
    if (SetUpSavedPaths(psResourcePathOverride, defaultPath)) {
 
1424
        ReadHeadersAndData(resourceType, resourceName);
 
1425
    } else UpdateData(resourceType, resourceName);
 
1426
    return FindData(resourceType, resourceName,
 
1427
                    resourceNamesReturn, resourceFilesReturn);
 
1428
}
 
1429
 
 
1430
int ListPSResourceTypes(pathOverride, defaultPath, typesReturn)
 
1431
    char *pathOverride;
 
1432
    char *defaultPath;
 
1433
    char ***typesReturn;
 
1434
{
 
1435
#define GROW 5
 
1436
#define START 15
 
1437
    int typeCount = 0, i, j, typeBufSize = 0;
 
1438
    ResourceDirectory d;
 
1439
    register char **types = NULL;
 
1440
    int sig;
 
1441
    int *sigs = NULL;
 
1442
    char *ch;
 
1443
 
 
1444
    if (SetUpSavedPaths(pathOverride, defaultPath)) {
 
1445
        if (currentPolicy != PSSaveEverything) {
 
1446
            lastModifiedTime =
 
1447
                    ReadFilesInPath(GetPath(), (ReadContentsFunction) NULL,
 
1448
                            (char *) NULL);
 
1449
        } else lastModifiedTime =
 
1450
                    ReadFilesInPath(GetPath(), ReadEverything, (char *) NULL);
 
1451
    }
 
1452
 
 
1453
    for (d = resDir; d != NULL; d = d->next) {
 
1454
        for (i = 0; i < d->typeCount; i++) {
 
1455
            for (sig = 0, ch = d->types[i].type; *ch != '\0'; sig += *ch++) {}
 
1456
            for (j = 0; j < typeCount; j++) {
 
1457
                if (sig == sigs[j] &&
 
1458
                    strcmp(types[j], d->types[i].type) == 0) break;
 
1459
            }
 
1460
            if (j >= typeCount) {       /* Have to add */
 
1461
                if (typeCount >= typeBufSize) {
 
1462
                    if (typeCount == 0) typeBufSize = START;
 
1463
                    else typeBufSize += GROW;
 
1464
                    types = (char **) REALLOC((char *) types,
 
1465
                                              typeBufSize * sizeof(char *));
 
1466
                    sigs = (int *) REALLOC((char *) sigs,
 
1467
                                           typeBufSize * sizeof(int));
 
1468
                }
 
1469
                types[typeCount] = d->types[i].type;
 
1470
                sigs[typeCount++] = sig;
 
1471
            }
 
1472
        }
 
1473
    }
 
1474
 
 
1475
    FREE((char *) sigs);
 
1476
    *typesReturn = types;
 
1477
    return typeCount;
 
1478
#undef START
 
1479
#undef GROW
 
1480
}
 
1481
 
 
1482
/* Assumes being correctly positioned in the file */
 
1483
 
 
1484
static int EnumerateResourceSection(f, dir, type, s, checkName)
 
1485
    FILE *f;
 
1486
    ResourceDirectory dir;
 
1487
    ResourceType type;
 
1488
    EnumeratorStruct *s;
 
1489
    int checkName;
 
1490
{
 
1491
#define GROW 1000
 
1492
    char *linein;
 
1493
    int len;
 
1494
    char namebuf[GROW];
 
1495
    char *names = namebuf;
 
1496
    int buflen = GROW, namelen = 0;
 
1497
    char *sep;
 
1498
    int prefixLen;
 
1499
    int insertPrefix;
 
1500
    char *file;
 
1501
    char dontDequote;
 
1502
    int doubleEquals;
 
1503
    int addingPrefix;
 
1504
 
 
1505
    if (checkName && VerifyName(f, type->type) != 0) return 1;
 
1506
 
 
1507
    insertPrefix = CheckInsertPrefix(type->type);
 
1508
    if (insertPrefix) {
 
1509
        prefixLen = strlen(dir->filePrefix);
 
1510
        dontDequote = '\0';
 
1511
    } else {
 
1512
        prefixLen = 0;
 
1513
        dontDequote = ',';
 
1514
    }
 
1515
 
 
1516
    while (1) {
 
1517
        linein = ReadFullLine(f);
 
1518
        if (linein == NULL) {
 
1519
            if (names != namebuf) FREE((char *) names);
 
1520
            FreeLineBuf();
 
1521
            return 1;
 
1522
        }
 
1523
 
 
1524
        if (strcmp(linein, ".") == 0) {
 
1525
            if (names != namebuf) FREE((char *) names);
 
1526
            FreeLineBuf();
 
1527
            return 0;
 
1528
        }
 
1529
 
 
1530
        sep = NULL;
 
1531
        (void) DequoteAndBreak(linein, &sep, '=', dontDequote, &doubleEquals);
 
1532
 
 
1533
        /* If no separator, a bogus line */
 
1534
        if (sep == NULL) continue;
 
1535
 
 
1536
        /* Next line is UNIX specific! */
 
1537
        addingPrefix = *(sep+1) != '/' && insertPrefix && !doubleEquals;
 
1538
 
 
1539
        len = strlen(linein) + (addingPrefix ? 0 : prefixLen) + 1;
 
1540
        if (len > buflen) {
 
1541
            if (names != namebuf) FREE((char *) names);
 
1542
            names = (char *) MALLOC(len);
 
1543
        }
 
1544
 
 
1545
        *sep = '\0';
 
1546
        len = strlen(linein);
 
1547
        (void) strncpy(names, linein, len+1);
 
1548
 
 
1549
        namelen = len+1;
 
1550
        file = &names[namelen];
 
1551
        
 
1552
        if (addingPrefix) {
 
1553
            (void) strncpy(&names[namelen], dir->filePrefix, prefixLen);
 
1554
            namelen += prefixLen;
 
1555
        }
 
1556
        
 
1557
        len = strlen(sep+1);
 
1558
        (void) strncpy(&names[namelen], sep+1, len+1);
 
1559
 
 
1560
        if (s->name == NULL || strcmp(names, s->name) == 0) {
 
1561
            s->done = (*s->func) (s->type, names, file, s->private);
 
1562
            if (s->done) {
 
1563
                if (names != namebuf) FREE((char *) names);
 
1564
                FreeLineBuf();
 
1565
                return 0;
 
1566
            }
 
1567
        }
 
1568
    }
 
1569
#undef GROW
 
1570
}
 
1571
 
 
1572
static int Enumerate(f, rd, data)
 
1573
    FILE *f;
 
1574
    ResourceDirectory rd;
 
1575
    char *data;
 
1576
{
 
1577
    EnumeratorStruct *s = (EnumeratorStruct *) data;
 
1578
    int i;
 
1579
    ResourceType t;
 
1580
    long pos;
 
1581
 
 
1582
    if (s->done) return 0;
 
1583
 
 
1584
    for (i = 0; i < rd->typeCount; i++) {
 
1585
        t = &rd->types[i];
 
1586
 
 
1587
        if (t->fileOffset == -1) continue;      /* Not really there */
 
1588
        if (t->fileOffset != 0 && fseek(f, t->fileOffset, SEEK_SET) != -1) {
 
1589
            if (strcmp(t->type, s->type) == 0) {
 
1590
                if (EnumerateResourceSection(f, rd, t, s, 1)) {
 
1591
                    char buf[256];
 
1592
                    sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1593
                    PSResFileWarningHandler(rd->directory, buf);
 
1594
                    return 1;
 
1595
                }
 
1596
                if (s->done) return 0;;
 
1597
            } else if (SkipResourceSection(f, rd, t, 1)) {
 
1598
                char buf[256];
 
1599
                sprintf(buf, "Trouble parsing resource type %s", t->type);
 
1600
                PSResFileWarningHandler(rd->directory, buf);
 
1601
                return 1;
 
1602
            }
 
1603
            continue;
 
1604
        }
 
1605
 
 
1606
        pos = ftell(f);
 
1607
        if (VerifyName(f, t->type) == 0) {
 
1608
            t->fileOffset = pos;
 
1609
            if (strcmp(t->type, s->type) == 0) {
 
1610
                if (EnumerateResourceSection(f, rd, t, s, 0)) return 1;
 
1611
                if (s->done) return 0;
 
1612
            } else if (SkipResourceSection(f, rd, t, 0)) return 1;
 
1613
        } else {
 
1614
            /* No resources of this type; try the next type */
 
1615
            t->fileOffset = -1;
 
1616
            if (fseek(f, pos, SEEK_SET) == -1) return 1;
 
1617
        }
 
1618
    }
 
1619
    return 0;
 
1620
}
 
1621
 
 
1622
void EnumeratePSResourceFiles(pathOverride, defaultPath, resourceType,
 
1623
                              resourceName, enumerator, private)
 
1624
    char *pathOverride;
 
1625
    char *defaultPath;
 
1626
    char *resourceType;
 
1627
    char *resourceName;
 
1628
    PSResourceEnumerator enumerator;
 
1629
    char *private;
 
1630
{
 
1631
    ResourceDirectory d;
 
1632
    FILE *f;
 
1633
    EnumeratorStruct s;
 
1634
 
 
1635
    s.func = enumerator;
 
1636
    s.type = resourceType;
 
1637
    s.name = resourceName;
 
1638
    s.private = private;
 
1639
    s.done = 0;
 
1640
 
 
1641
    if (SetUpSavedPaths(pathOverride, defaultPath)) {
 
1642
        lastModifiedTime =
 
1643
                    ReadFilesInPath(GetPath(), Enumerate, (char *) &s);
 
1644
        return;
 
1645
    }
 
1646
 
 
1647
    for (d = resDir; d != NULL && !s.done; d = d->next) {
 
1648
        f = fopen(d->directory, "r");
 
1649
        if (f == NULL) continue;
 
1650
        if (fseek(f, d->endOfHeader, SEEK_SET) != -1) {
 
1651
            (void) Enumerate(f, d, (char *) &s);
 
1652
        }
 
1653
        (void) fclose(f);
 
1654
    }
 
1655
}
 
1656
 
 
1657
int CheckPSResourceTime(pathOverride, defaultPath)
 
1658
    char *pathOverride;
 
1659
    char *defaultPath;
 
1660
{
 
1661
    if (CheckSavedPaths(pathOverride, defaultPath)) return 1;
 
1662
    return MaxTimeInPath(GetPath()) > lastModifiedTime;
 
1663
}