diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:48:57 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:48:57 +0000 |
commit | 75039f613b11cc79e999d545e75ced399f39b277 (patch) | |
tree | 2913bd8336b40852655dadc91f17e0de0bb14c2e |
Initial revisionXORG-STABLE
-rw-r--r-- | makepsres.c | 2338 | ||||
-rw-r--r-- | makepsres.man | 227 |
2 files changed, 2565 insertions, 0 deletions
diff --git a/makepsres.c b/makepsres.c new file mode 100644 index 0000000..a28e874 --- /dev/null +++ b/makepsres.c @@ -0,0 +1,2338 @@ +/* + * makepsres.c + * + * (c) Copyright 1991, 1994 Adobe Systems Incorporated. + * All rights reserved. + * + * Permission to use, copy, modify, distribute, and sublicense this software + * and its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notices appear in all copies and that + * both those copyright notices and this permission notice appear in + * supporting documentation and that the name of Adobe Systems Incorporated + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. No trademark license + * to use the Adobe trademarks is hereby granted. If the Adobe trademark + * "Display PostScript"(tm) is used to describe this software, its + * functionality or for any other purpose, such use shall be limited to a + * statement that this software works in conjunction with the Display + * PostScript system. Proper trademark attribution to reflect Adobe's + * ownership of the trademark shall be given whenever any such reference to + * the Display PostScript system is made. + * + * ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR + * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. + * ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON- INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE + * TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT + * PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE. + * + * Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems + * Incorporated which may be registered in certain jurisdictions + * + * Author: Adobe Systems Incorporated + */ +/* $XFree86: xc/programs/makepsres/makepsres.c,v 1.7 2002/09/18 17:11:51 tsi Exp $ */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> + +#ifdef XENVIRONMENT +#include <X11/Xos.h> +#else +#include <string.h> +#include <sys/types.h> +#endif + +#include <sys/stat.h> + +#include <dirent.h> + +#ifndef S_ISDIR +#ifdef S_IFDIR +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#else +#define S_ISDIR(mode) (((mode) & _S_IFMT) == _S_IFDIR) +#endif /* S_IFDIR */ +#endif /* S_ISDIR */ + +#define true 1 +#define false 0 + +/* The max line length is really 256, but why make things that are hard + to read??? */ +#define MAXLINELEN 79 + +#ifndef DEBUG +#define DEBUG false +#endif + +#define QUOTE 042 + +#define HASHSIZE 2048 + +/* Command line information */ + +char **directories; +int *directoryLen; +int directoryCount; +int recursive; +int discard; +int keep; +char *outputFilename; +char **inputFiles; +int inputCount; +int makeExclusive; +int interactive; +int strict; +int noPrefix; +int issueWarnings; +int noBackup; +int noSuffix; + +typedef struct _t_Resource { + char *name; + char *file; + int noPrefix; + struct _t_Resource *next; +} Resource; + +typedef struct _t_Duplicate { + char *name; + char *file1; + char *file2; + struct _t_Duplicate *next; +} Duplicate; + +typedef struct _t_Category { + char *name; + Resource *list; + Resource **hash; /* Currently used only for mkpsresPrivate */ + Duplicate *duplicates; + struct _t_Category *next; +} Category; + +char *program; + +#if 0 +extern char *malloc(), *realloc(); +extern char *sys_errlist[]; +extern int errno; +#endif + +#define BUFFER_SIZE 1024 +static char lineBuffer[BUFFER_SIZE]; + +Category *categories; + +static char *ckmalloc(size, whynot) + int size; + char *whynot; +{ + char *result; + + if (size == 0) size = 1; + result = malloc(size); + if (result == NULL) { + fprintf(stderr, "%s: %s\n", program, whynot); + exit(1); + } + return result; +} + +static char *ckrealloc(ptr, size, whynot) + char *ptr; + int size; + char *whynot; +{ + char *result; + + if (size == 0) size = 1; + result = realloc(ptr, size); + if (result == NULL) { + fprintf(stderr, "%sf : %s\n", program, whynot); + exit(1); + } + return result; +} + +static char *ckcalloc(count, size, whynot) + int count; + int size; + char *whynot; +{ + char *result; + + if (size == 0) size = 1; + if (count == 0) count = 1; + result = (char *) calloc(count, size); + if (result == NULL) { + fprintf(stderr, "%s: %s\n", program, whynot); + exit(1); + } + return result; +} + + +static Category *AddCategory (name) + char *name; +{ + Category *newCategory = (Category *) ckcalloc (1, sizeof (Category), + "Failed to allocate Category record."); + + newCategory->name = (char *) ckmalloc (strlen (name) + 1, + "Failed to allocate Category name."); + + strcpy (newCategory->name, name); + + if (categories == NULL) { + categories = newCategory; + } else { + /* Insert into alphabetical position */ + Category *current, + *previous; + + current = previous = categories; + + while (current != NULL) { + if (strcmp (current->name, name) > 0) { + break; + } else { + previous = current; + current = current->next; + } + } + + if (current == NULL) { + newCategory->next = NULL; + previous->next = newCategory; + } else { + newCategory->next = current; + + if (current == categories) { + categories = newCategory; + } else { + previous->next = newCategory; + } + } + } + + return (newCategory); +} + + +static Category *FindCategory (name) + char *name; +{ + Category *category = categories; + + while (category != NULL) { + if (strcmp (category->name, name) == 0) + break; + else + category = category->next; + } + + if (category == NULL) + category = AddCategory (name); + + return (category); +} + + +int Hash(string) + char *string; +{ + int hash = 0; + unsigned char *ch = (unsigned char *) string; + + while (1) { + if (*ch == '\0') return hash % HASHSIZE; + if (*(ch+1) == '\0') { + hash += *ch; + return hash % HASHSIZE; + } + hash += *ch++; + hash += (*ch++ << 8); + } +} + +static void AddHashedResource(resource, category) + Resource *resource; + Category *category; +{ + Resource *current, *previous; + int comparison, hash; + + if (category->hash == NULL) { + category->hash = (Resource **) ckcalloc(HASHSIZE, sizeof(Resource *), + "Failed to allocate hash table."); + } + + hash = Hash(resource->file); + current = previous = category->hash[hash]; + + while (current != NULL) { + comparison = strcmp (current->file, resource->file); + if (comparison > 0) break; + + if (comparison == 0 && + strcmp(current->name, resource->name) != 0) break; + + previous = current; + current = current->next; + } + + if (category->hash[hash] == NULL) { + category->hash[hash] = resource; + resource->next = NULL; + + } else if (current == NULL) { + resource->next = NULL; + previous->next = resource; + + } else { + resource->next = current; + + if (current == category->hash[hash]) { + category->hash[hash] = resource; + } else { + previous->next = resource; + } + } +} + +void EnterDuplicateWarning(category, res1, res2) + Category *category; + Resource *res1, *res2; +{ + Duplicate *dup, *previous, *current; + + if (!issueWarnings) return; + + dup = (Duplicate *) ckcalloc(1, sizeof(Duplicate), + "Failed to allocate Duplicate record."); + + dup->name = res1->name; + dup->file1 = res1->file; + dup->file2 = res2->file; + + current = previous = category->duplicates; + + while (current != NULL) { + if (strcmp (current->name, res1->name) >= 0) break; + previous = current; + current = current->next; + } + + if (category->duplicates == NULL) category->duplicates = dup; + else if (current == NULL) { + dup->next = NULL; + previous->next = dup; + } else { + dup->next = current; + + if (current == category->duplicates) category->duplicates = dup; + else previous->next = dup; + } +} + +static void AddResource (categoryName, resourceName, fileName, noPrefix) + char *resourceName; + char *categoryName; + char *fileName; + int noPrefix; +{ + Category *category = FindCategory (categoryName); + Resource *resource, + *current, + *previous; + int comparison; + + resource = (Resource *) ckcalloc (1, sizeof (Resource), + "Failed to allocate Resource record."); + + resource->name = ckmalloc (strlen (resourceName) + 1, + "Failed to allocate Resource name."); + + strcpy (resource->name, resourceName); + + if (fileName[0] == '.' && fileName[1] == '/') fileName+=2; + + resource->file = ckmalloc (strlen (fileName) + 1, + "Failed to allocate Resource filename."); + + strcpy (resource->file, fileName); + + resource->noPrefix = noPrefix; + + if (strcmp(categoryName, "mkpsresPrivate") == 0) { + AddHashedResource(resource, category); + return; + } + + current = previous = category->list; + + while (current != NULL) { + comparison = strcmp (current->name, resourceName); + if (comparison > 0) break; + else if (comparison == 0) { + comparison = strcmp (current->file, fileName); + if (comparison > 0) { + if (strcmp(categoryName, "FontBDFSizes") != 0 && + strcmp(categoryName, "FontFamily") != 0 && + strcmp(categoryName, "mkpsresPrivate") != 0) { + EnterDuplicateWarning(category, current, resource); + } + break; + } else if (comparison == 0) { /* Same file */ + free (resource->name); + free (resource->file); + free (resource); + return; + } + } + previous = current; + current = current->next; + } + + if (category->list == NULL) { + category->list = resource; + } else if (current == NULL) { + resource->next = NULL; + previous->next = resource; + } else { + resource->next = current; + + if (current == category->list) { + category->list = resource; + } else { + previous->next = resource; + } + } +} + +int FindResource(categoryName, resourceName) + char *categoryName; + char *resourceName; +{ + Category *category = FindCategory (categoryName); + Resource *resource; + int i; + + for (resource = category->list; + resource != NULL && strcmp(resource->name, resourceName) != 0; + resource = resource->next) {} + + if (resource != NULL) return true; + + if (category->hash == NULL) return false; + + for (i = 0; i < HASHSIZE; i++) { + for (resource = category->hash[i]; + resource != NULL && strcmp(resource->name, resourceName) != 0; + resource = resource->next) {} + if (resource != NULL) return true; + } + + return false; +} + + +typedef struct _t_UPRResource { + char *name; + char *file; + char *category; + int found; + int noPrefix; + struct _t_UPRResource *next; +} UPRResource; + +UPRResource *UPRresources[HASHSIZE]; + +#if DEBUG +int bucketCount[HASHSIZE]; +int totalHashed = 0; +#endif + +static void AddUPRResource (categoryName, resourceName, fileName, prefix, + noPrefix) + char *resourceName; + char *categoryName; + char *fileName; + char *prefix; + int noPrefix; +{ + UPRResource *resource, *current, *previous; + int comparison, hash; + + if (noPrefix || prefix == NULL) { + prefix = ""; + if (fileName[0] == '.' && fileName[1] == '/') fileName+=2; + } else { + prefix++; /* Skip over leading / */ + if (prefix[0] == '.' && prefix[1] == '/') prefix += 2; + } + + resource = (UPRResource *) ckcalloc (1, sizeof (UPRResource), + "Failed to allocate Resource record."); + + resource->name = ckmalloc (strlen (resourceName) + 1, + "Failed to allocate Resource name."); + + strcpy (resource->name, resourceName); + + resource->file = ckmalloc (strlen (fileName) + strlen(prefix) + 2, + "Failed to allocate Resource filename."); + + if (prefix != NULL && prefix[0] != '\0') { + strcpy (resource->file, prefix); + strcat (resource->file, "/"); + strcat (resource->file, fileName); + } else strcpy (resource->file, fileName); + + resource->category = ckmalloc (strlen (categoryName) + 1, + "Failed to allocate Resource name."); + + strcpy(resource->category, categoryName); + + resource->noPrefix = noPrefix; + resource->found = false; + + hash = Hash(resource->file); + current = previous = UPRresources[hash]; + + while (current != NULL) { + comparison = strcmp (current->file, resource->file); + if (comparison > 0) break; + + if (comparison == 0) { + if (noPrefix) break; + + if (strcmp(current->name, resource->name) != 0 || + strcmp(current->category, resource->category) != 0) { /* Same */ + if (strcmp(current->category, "mkpsresPrivate") == 0 && + strcmp(current->name, "NONRESOURCE") == 0) { + + /* Replace "NONRESOURCE" entry with resource one */ + free(current->name); + current->name = resource->name; + free(current->category); + current->category = resource->category; + free(resource->file); + free (resource); + return; + } + fprintf(stderr, + "%s: Warning: file %s identified as different resources\n", + program, resource->file); + fprintf(stderr, " Using %s\n", current->category); + } + free (resource->name); + free (resource->file); + free (resource->category); + free (resource); + return; + } + previous = current; + current = current->next; + } + + if (UPRresources[hash] == NULL) { + UPRresources[hash] = resource; + resource->next = NULL; + + } else if (current == NULL) { + resource->next = NULL; + previous->next = resource; + } else { + resource->next = current; + + if (current == UPRresources[hash]) { + UPRresources[hash] = resource; + } else { + previous->next = resource; + } + } +#if DEBUG + totalHashed++; + bucketCount[hash]++; +#endif +} + + +void AddUPRResourceBDF(font, sizes) + char *font; + char *sizes; +{ + char *ch = sizes; + char *buf; + + while (*ch != '\0') { + while (*ch != '\0' && *ch != ',') ch++; + if (*ch == ',') { + *ch = '\0'; + if (*sizes != '\0') { + /* Stick in the font size to spread out the hash table */ + + buf = ckmalloc(strlen(font) + strlen(sizes) + 2, + "Failed to allocate BDF string"); + sprintf(buf, "%s,%s", font, sizes); + AddUPRResource("FontBDFSizes", font, buf, NULL, true); + free(buf); + } + sizes = ++ch; + } + } +} + +void AddUPRResourceFontFamily(family, faces) + char *family; + char *faces; +{ + char *ch = faces, *chunk = faces; + char old; + + while (true) { + while (true) { + while (*ch != '\0' && *ch != ',') ch++; + if (*ch == '\0') return; + if (ch > faces && *(ch-1) == '\\') ch++; + else break; + } + /* Found the first , look for the second */ + ch++; + while (true) { + while (*ch != '\0' && *ch != ',') ch++; + if (*ch == '\0') break; + if (*(ch-1) == '\\') ch++; + else break; + } + + old = *ch; + *ch = '\0'; + AddUPRResource("FontFamily", family, chunk, NULL, true); + if (old == '\0') return; + chunk = ++ch; + } +} + +static int SkipWhiteSpace(file) + FILE *file; +{ + int c; + + while (1) { + c = fgetc(file); + if (c == ' ' || c == '\t') continue; + if (c == EOF) return false; + ungetc(c, file); + return true; + } +} + + +static int ReadItem(file, buf, size) + FILE *file; + char *buf; + int size; +{ + int c; + char closechar, openchar; + int count = 0, nesting = 0;; + + openchar = '\0'; + + c = fgetc(file); + if (c == EOF) return false; + if (c == '(') {closechar = ')'; openchar = c;} + else if (c == '[') {closechar = ']'; openchar = c;} + else if (c == QUOTE) closechar = QUOTE; + else if (c == '/') closechar = '\0'; + else { + closechar = '\0'; + ungetc(c, file); + } + + while (count < size) { + c = fgetc(file); + if (openchar != '\0' && c == openchar) nesting++; + if (c == EOF) break; + if (c == closechar) { + if (nesting == 0) break; + else nesting--; + } + if (closechar == '\0' && strchr(" \t\n\r", c) != NULL) break; + buf[count++] = c; + } + + buf[count] = '\0'; + return true; +} + +static char *FindKeyValue (file, key) + FILE *file; + char *key; +{ + char lineKey[64]; + char *result = NULL; + + while (true) { + if (fgets (lineBuffer, BUFFER_SIZE, file) == NULL) + break; + + sscanf (lineBuffer, "%64[%a-zA-Z]", lineKey); + if (strcmp (key, lineKey) == 0) { + result = strchr (lineBuffer, ' '); + if (result != NULL) { + result++; + break; + } + } + } + + return (result); +} + +static void StripName (name) + char *name; +{ + char closeCharacter = '\0'; + char *pointer; + + if (name[0] == '/') strcpy(name, name+1); + + while (true) { + if (name[0] == '(') closeCharacter = ')'; + else if (name[0] == QUOTE) closeCharacter = QUOTE; + else break; + + pointer = strrchr (name, closeCharacter); + + if (pointer != NULL) { + *pointer = '\0'; + strcpy (name, name + 1); + } else break; /* No close character */ + } + + pointer = strrchr (name, '\r'); + + if (pointer != NULL) *pointer = '\0'; + else { + pointer = strrchr (name, '\n'); + if (pointer != NULL) *pointer = '\0'; + } +} + + +static char *bugFamilies[] = { + "Berkeley", "CaslonFiveForty", "CaslonThree", "GaramondThree", + "Music", "TimesTen", NULL + }; + +static char *fixedFamilies[] = { + "ITC Berkeley Oldstyle", "Caslon 540", "Caslon 3", "Garamond 3", + "Sonata", "Times 10", NULL +}; + +static char *missingFoundries[] = { + "Berthold ", "ITC ", "Linotype ", NULL +}; + +static int missingFoundryLen[] = { + 9, 4, 9, 0 +}; + +static void MungeFontNames(name, family, fullname, weight, + familyReturn, fullnameReturn, faceReturn) + char *name, *family, *fullname, *weight; + char *familyReturn, *fullnameReturn, *faceReturn; +{ + register char *src, *dst, prev; + char buf[256]; + int digits = 0; + int i, diff; + + /* Copy the fullname into buf, enforcing one space between words. + Eliminate leading digits and spaces, ignore asterisks, if the + full name ends with 5 digits strip them, and replace periods that + aren't followed by a space with a space. If leading digits are + followed by " pt " skip that too. */ + + dst = buf; + prev = ' '; + src = fullname; + while (isdigit(*src)) src++; + while (*src == ' ' || *src == '\t') src++; + if (strncmp(src, "pt ", 3) == 0) src += 3; + else if (strncmp(src, "pt. ", 4) == 0) src += 4; + + while (*src != '\0') { + if (*src == '*') { + src++; + continue; + } + + if (*src == '.') { + if (*(src+1) != ' ') { + prev = *dst++ = ' '; + } else prev = *dst++ = '.'; + src++; + continue; + } + + if (isdigit(*src)) digits++; + else digits = 0; + + if (isupper(*src)) { + if (prev != ' ' && (islower(*(src+1)) || islower(prev))) { + *dst++ = ' '; + prev = *dst++ = *src++; + } else prev = *dst++ = *src++; + + } else if (*src == ' ' || *src == '\t') { + if (prev == ' ') { + src++; + continue; + } + prev = *dst++ = ' '; + src++; + + } else prev = *dst++ = *src++; + } + + if (digits == 5) { + dst -= 5; + } + if (dst > buf && *(dst-1) == ' ') dst--; + + *dst = '\0'; + + if (strcmp(name, "FetteFraktur-Dfr") == 0) strcat(buf, " Black Dfr"); + else if (strcmp(name, "Linotext-Dfr") == 0) strcat(buf, " Dfr"); + + if (strncmp(fullname, "pt ", 3) == 0) { + src = buf + 2; + while (*++src != '\0') *(src-3) = *src; + *(src-3) = '\0'; + } + + strcpy(fullnameReturn, buf); + + /* From here on fullname should not be used */ + + /* Done with the full name; now onto the family */ + + for (i = 0; bugFamilies[i] != NULL; i++) { + diff = strcmp(family, bugFamilies[i]); + if (diff < 0) break; + if (diff == 0) { + strcpy(familyReturn, fixedFamilies[i]); + goto FAMILY_DONE; + } + } + + /* Copy the family into buf, enforcing one space between words */ + + dst = buf; + prev = ' '; + src = family; + + while (*src != '\0') { + if (isupper(*src)) { + if (prev != ' ' && (islower(*(src+1)) || islower(prev))) { + *dst++ = ' '; + prev = *dst++ = *src++; + } else prev = *dst++ = *src++; + + } else if (*src == ' ' || *src == '\t') { + if (prev == ' ') { + src++; + continue; + } + prev = *dst++ = ' '; + src++; + + } else prev = *dst++ = *src++; + } + + if (dst > buf && *(dst-1) == ' ') dst--; + *dst = '\0'; + + /* Compensate for fonts with foundries in the full name but not the + family name by adding to the family name */ + + for (i = 0; missingFoundries[i] != NULL; i++) { + diff = strncmp(fullnameReturn, missingFoundries[i], + missingFoundryLen[i]); + if (diff > 0) continue; + if (diff == 0 && strncmp(buf, missingFoundries[i], + missingFoundryLen[i] != 0)) { + while (dst >= buf) { + *(dst+missingFoundryLen[i]) = *dst; + dst--; + } + strncpy(buf, missingFoundries[i], missingFoundryLen[i]); + } + break; + } + + /* From here on dst no longer points to the end of the buffer */ + + if (strncmp(fullnameReturn, "Helvetica Rounded ", 18) == 0) { + strcat(buf, " Rounded"); + } + + strcpy(familyReturn, buf); + +FAMILY_DONE: + + /* From here on family should not be used */ + + /* Now to find the face in all this */ + + src = fullnameReturn; + dst = familyReturn; + while (*dst == *src && *dst != '\0') { + src++; + dst++; + } + if (*src == ' ') src++; + + if (*src == '\0') { + if (*weight != '\0') { + /* Handle Multiple Master fonts */ + if (strcmp(weight, "All") == 0) src = "Roman"; + else { + if (islower(weight[0])) weight[0] = toupper(weight[0]); + src = weight; + } + } else src = "Medium"; + } + + strcpy(faceReturn, src); +} + + +void StripComments(buf) + char *buf; +{ + register char *ch = buf; + + while (true) { + while (*ch != '%' && *ch != '\0') ch++; + if (*ch == '\0') break; + if (ch == buf || *(ch-1) != '\\') { + *ch = '\0'; + break; + } + ch++; + } + + /* ch points to '\0' right now */ + + if (ch == buf) return; + ch--; + + while (ch > buf && (*ch == ' ' || *ch == '\t' || *ch == '\n')) { + *ch = '\0'; + ch--; + } + + if (ch == buf && (*ch == ' ' || *ch == '\t' || *ch == '\n')) *ch = '\0'; +} + +/* Caller must free returned line */ + +char *GetWholeLine(file) + FILE *file; +{ + char *line; + int len, oldlen; + + if (fgets (lineBuffer, BUFFER_SIZE, file) == NULL) return NULL; + + StripComments(lineBuffer); + + len = strlen(lineBuffer); + line = ckmalloc(len+1, "Failed to allocate input line."); + strcpy(line, lineBuffer); + + if (line[len-1] == '\\') { /* Continued... */ + line[len-1] = '\0'; + oldlen = len-1; + while (true) { + if (fgets(lineBuffer, BUFFER_SIZE, file) == NULL) { + return line; + } + + StripComments(lineBuffer); + if (lineBuffer[0] == '\0') return line; + + len = strlen(lineBuffer); + line = ckrealloc(line, oldlen+len+1, + "Failed to reallocate input line."); + strcat(line, lineBuffer); + + oldlen += len; + if (line[oldlen-1] != '\\') break; + line[oldlen-1] = '\0'; + oldlen--; + } + } + return line; +} + +static void HandleUnopenableUPRFile(filename, err) + char *filename; + int err; +{ + if (issueWarnings) { + fprintf (stderr, "%s: Could not open file %s (%s).\n", + program, filename, strerror(err)); + } + + if (strict) exit(1); +} + + +void PreprocessResourceDirectory(fullname) + char *fullname; +{ + char *category; + FILE *file; + char *line; + char *directoryPrefix = NULL; + int noPrefix; + + file = fopen (fullname, "r"); + + if (file == NULL) { + HandleUnopenableUPRFile(fullname, errno); + return; + } + + /* Skip over list of categories */ + + while (true) { + if (fgets (lineBuffer, BUFFER_SIZE, file) == NULL) return; + + if (lineBuffer[0] == '.') break; + } + + while (true) { + /* Process category */ + + line = GetWholeLine(file); + if (line == NULL) { + if (directoryPrefix != NULL) free(directoryPrefix); + return; + } + + if (line[0] == '/') { /* Handle optional directory prefix */ + directoryPrefix = line; + continue; + } + + category = line; + + while (true) { + char *resourceFile; + + line = GetWholeLine(file); + if (line == NULL) { + if (directoryPrefix != NULL) free(directoryPrefix); + free(category); + } + + if (line[0] == '.') { + free(category); + free(line); + break; + } + + resourceFile = line; + while (true) { + if ((resourceFile = strchr(resourceFile, '=')) != NULL) { + if (resourceFile != line && *(resourceFile-1) != '\\') { + *resourceFile++ = '\0'; + noPrefix = (*resourceFile == '='); + if (noPrefix) resourceFile++; + if (strcmp(category, "FontBDFSizes") == 0) { + AddUPRResourceBDF(line, resourceFile); + } else if (strcmp(category, "FontFamily") == 0) { + AddUPRResourceFontFamily(line, resourceFile); + } else AddUPRResource (category, line, + resourceFile, + (noPrefix ? NULL : + directoryPrefix), + noPrefix); + break; + } + resourceFile++; + } else break; /* Bogus line */ + } + free(line); + } + } +} + +static int SkipToCharacter (file, character) + FILE *file; + char character; +{ + int c; + + while ((c = fgetc (file)) != EOF) { + if (c == character) + return (true); + } + + return (false); +} + +static int SkipToEitherCharacter (file, character1, character2, outchar) + FILE *file; + char character1, character2; + char *outchar; +{ + register int c; + + while ((c = fgetc (file)) != EOF) { + if (c == character1 || c == character2) { + *outchar = c; + return (true); + } + } + + return (false); +} + + +static void ProcessFont (file, fileName) + FILE *file; + char *fileName; +{ + char fontName[256], fontFamily[256], fontFullName[256], fontWeight[256]; + char key[256], buf[513]; + char familyReturn[256], fullnameReturn[256], faceReturn[256]; + char blendDesignPositions[256], blendDesignMap[256], blendAxisTypes[256]; + char out; + int found = 0; + + fontName[0] = fontFamily[0] = fontFullName[0] = fontWeight[0] = '\0'; + blendDesignPositions[0] = blendDesignMap[0] = blendAxisTypes[0] = '\0'; + + while (found != 0x7F && SkipToEitherCharacter (file, '/', 'e', &out)) { + /* If we encounter an eexec, skip the rest of the file */ + if (out == 'e') { + if (fscanf (file, "%256s", key) != 1) continue; + if (strcmp(key, "exec") == 0) break; + continue; + } + + if (fscanf (file, "%256s", key) != 1) continue; + if (!SkipWhiteSpace(file)) break; + if (!ReadItem(file, buf, 256)) break; + + if ((found & 0x1) == 0 && strcmp(key, "FullName") == 0) { + strcpy(fontFullName, buf); + found |= 0x1; + continue; + } + if ((found & 0x2) == 0 && strcmp(key, "FamilyName") == 0) { + strcpy(fontFamily, buf); + found |= 0x2; + continue; + } + if ((found & 0x4) == 0 && strcmp(key, "Weight") == 0) { + strcpy(fontWeight, buf); + found |= 0x4; + continue; + } + if ((found & 0x8) == 0 && strcmp(key, "FontName") == 0) { + strcpy(fontName, buf); + found |= 0x8; + continue; + } + if ((found & 0x10) == 0 && strcmp(key, "BlendDesignPositions") == 0) { + strcpy(blendDesignPositions, buf); + found |= 0x10; + continue; + } + if ((found & 0x20) == 0 && strcmp(key, "BlendDesignMap") == 0) { + strcpy(blendDesignMap, buf); + found |= 0x20; + continue; + } + if ((found & 0x40) == 0 && strcmp(key, "BlendAxisTypes") == 0) { + strcpy(blendAxisTypes, buf); + found |= 0x40; + continue; + } + } + + if (fontName[0] != '\0') { + if (fontFullName[0] == '\0') { + if (fontFamily[0] != '\0') strcpy(fontFullName, fontFamily); + else strcpy(fontFullName, fontName); + } + if (fontFamily[0] == '\0') strcpy(fontFamily, fontFullName); + + MungeFontNames(fontName, fontFamily, fontFullName, fontWeight, + familyReturn, fullnameReturn, faceReturn); +#if DEBUG + printf("Found font %s\n", fontName); + printf("Munged to (%s) (%s)\n", familyReturn, faceReturn); +#endif + sprintf(buf, "%s,%s", faceReturn, fontName); + AddResource ("FontOutline", fontName, fileName, false); + AddResource("FontFamily", familyReturn, buf, true); + if (blendDesignPositions[0] != '\0' && blendDesignMap[0] != '\0' && + blendAxisTypes[0] != '\0') { +#if DEBUG + printf("Font %s is multiple master\n", fontName); +#endif + AddResource("FontBlendPositions", fontName, blendDesignPositions, true); + AddResource("FontBlendMap", fontName, blendDesignMap, true); + AddResource("FontAxes", fontName, blendAxisTypes, true); + } + } +} + + +static void ProcessResource (file, fileName) + FILE *file; + char *fileName; +{ + char resourceType[256]; + char resourceName[256]; + char *pointer; + + sscanf (lineBuffer, "%%!PS-Adobe-%*[0123456789.] Resource-%128s", + resourceType); + + StripName (resourceType); + + if (strcmp(resourceType, "Font") == 0) { + ProcessFont(file, fileName); + return; + } + + pointer = FindKeyValue (file, "%%BeginResource"); + + if (pointer == NULL) return; + + sscanf (pointer, "%*256s%256s", resourceName); + StripName (resourceName); + + AddResource (resourceType, resourceName, fileName, false); +} + + +static void ProcessBDF (file, fileName) + FILE *file; + char *fileName; +{ + char fontName[256]; + char psFontName[256]; + char key[256]; + unsigned int found = 0; + char nameSize[300]; + int resx, resy, size; + char sizebuf[50]; + + fontName[0] = psFontName[0] = '\0'; + resx = resy = size = 0; + + while (SkipToCharacter(file, '\n')) { + if (!SkipWhiteSpace(file)) break; + if (fscanf (file, "%256s", key) != 1) continue; + if (!SkipWhiteSpace(file)) break; + + if ((found & 1) == 0 && strcmp(key, "FONT") == 0) { + if (!ReadItem(file, fontName, 256)) break; + found |= 1; + continue; + } + if ((found & 2) == 0 && strcmp(key, "RESOLUTION_X") == 0) { + if (fscanf (file, "%d", &resx) != 1) break; + found |= 2; + continue; + } + if ((found & 4) == 0 && strcmp(key, "RESOLUTION_Y") == 0) { + if (fscanf (file, "%d", &resy) != 1) break; + found |= 4; + continue; + } + if ((found & 8) == 0 && strcmp(key, "_ADOBE_PSFONT") == 0) { + if (!ReadItem(file, psFontName, 256)) break; + found |= 8; + continue; + } + if ((found & 16) == 0 && strcmp(key, "SIZE") == 0) { + if (fscanf(file, "%d %d %d", &size, &resx, &resy) != 3) break; + found |= 16; + continue; + } + if ((found & 32) == 0 && strcmp(key, "POINT_SIZE") == 0) { + if (fscanf(file, "%d", &size) != 1) break; + size /= 10; + found |= 32; + } + if (strcmp(key, "ENDPROPERTIES") == 0) break; + if (strcmp(key, "STARTCHAR") == 0) break; + } + + if (psFontName[0] != '\0') strcpy(fontName, psFontName); + + if (size == 0 || fontName[0] == '\0') return; + if (resx == 0 || resy == 0) sprintf(sizebuf, "%d", size); + else sprintf(sizebuf, "%d-%d-%d", size, resx, resy); + + sprintf(nameSize, "%s%s", fontName, sizebuf); + + AddResource ("FontBDF", nameSize, fileName, false); + AddResource ("FontBDFSizes", fontName, sizebuf, true); +} + +static void ProcessAFM (file, fileName) + FILE *file; + char *fileName; +{ + char fontName[256]; + char *pointer; + char *extraCr; + + pointer = FindKeyValue (file, "FontName"); + + if (pointer == NULL) + return; + + sscanf (pointer, "%256s", fontName); + + extraCr = strchr (fontName, '\r'); /* Handle DOS newlines */ + + if (extraCr != NULL) *extraCr = '\0'; + + AddResource ("FontAFM", fontName, fileName, false); +} + +/* ARGSUSED */ +static void ProcessResourceDirectory (file, fileName) + FILE *file; + char *fileName; +{ +} + +void MarkAsNonResource(filename) + char *filename; +{ + AddResource("mkpsresPrivate", "NONRESOURCE", filename, false); +} + +char *userCategories[] = { + "Encoding", + "File", + "FontAFM", + "FontBDF", + "FontOutline", + "FontPrebuilt", + "Form", + "Pattern", + "ProcSet", + NULL +}; + +static void IdentifyFromUser(filename, file) + char *filename; + FILE *file; +{ + int i, numCats, choice, size; + char buf[256], name[256]; + static int stdinEOF = false; + + if (stdinEOF) return; + + if (file != NULL) rewind(file); + + while (1) { + printf("Please indentify the file\n"); + printf(" 0 - Not a resource file\n"); + i = 0; + while (userCategories[i] != NULL) { + printf(" %d - %s\n", i+1, userCategories[i]); + i++; + } + numCats = i; + printf(" %d - Other\n", numCats+1); + if (file != NULL) printf(" %d - Show some of file\n", numCats+2); + printf("> "); + fflush(stdout); + if (scanf("%d", &choice) != 1) { + stdinEOF = true; + return; + } + /* Skip the last of the number input line */ + if (fgets(buf, 256, stdin) == NULL) { + stdinEOF = true; + return; + } + if (choice < 0 || (file != NULL && choice > numCats+2) || + (file == NULL && choice > numCats+1)) { + printf("Invalid choice\n\n"); + continue; + } + if (choice == numCats+2) { + printf("\n"); + for (i = 0; i < 10; i++) { + if (fgets(buf, 256, file) != NULL) fputs(buf, stdout); + } + printf("\n"); + continue; + } + if (choice == 0) { + MarkAsNonResource(filename); + return; + } + if (choice == numCats+1) { + printf("Please enter resource category: "); + fflush(stdout); + if (fgets(buf, 256, stdin) == NULL) { + stdinEOF = true; + return; + } + if (buf[0] == '\0') continue; + printf("Please enter resource name: "); + fflush(stdout); + if (fgets(name, 256, stdin) == NULL) { + stdinEOF = true; + return; + } + if (name[0] == '\0') continue; + StripName(buf); + StripName(name); + AddResource(buf, name, filename, false); + return; + } + if (strcmp(userCategories[choice-1], "FontBDF") == 0) { + printf("Please enter font name: "); + fflush(stdout); + if (fgets(name, 256, stdin) == NULL) { + stdinEOF = true; + return; + } + if (name[0] == '\0') continue; + StripName(name); + printf("Please enter font size: "); + fflush(stdout); + if (scanf("%d", &size) != 1) { + stdinEOF = true; + return; + } + /* Skip the last of the number input line */ + if (fgets(buf, 256, stdin) == NULL) { + stdinEOF = true; + return; + } + if (size <= 0) continue; + sprintf(buf, "%d", size); + AddResource("FontBDFSizes", name, buf, false); + sprintf(buf, "%s%d", name, size); + AddResource("FontBDF", buf, filename, true); + return; + } + if (strcmp(userCategories[choice-1], "FontOutline") == 0) { + char family[256], face[256]; + printf("Please enter font name: "); + fflush(stdout); + if (fgets(name, 256, stdin) == NULL) { + stdinEOF = true; + return; + } + if (name[0] == '\0') continue; + StripName(name); + printf("Please enter font family: "); + fflush(stdout); + if (fgets(family, 256, stdin) == NULL) { + stdinEOF = true; + return; + } + if (name[0] == '\0') continue; + StripName(family); + printf("Please enter font face: "); + fflush(stdout); + if (fgets(face, 256, stdin) == NULL) { + stdinEOF = true; + return; + } + if (name[0] == '\0') continue; + StripName(face); + AddResource("FontOutline", name, filename, true); + sprintf(buf, "%s,%s", face, name); + AddResource("FontFamily", family, buf, false); + return; + } + + printf("Please enter %s name: ", userCategories[choice-1]); + fflush(stdout); + if (fgets(name, 256, stdin) == NULL) { + stdinEOF = true; + return; + } + if (name[0] == '\0') continue; + StripName(name); + AddResource(userCategories[choice-1], name, filename, true); + return; + } +} + +int IdentifyFromUPRList(filename) + char *filename; +{ + UPRResource *resource = UPRresources[Hash(filename)]; + + while (resource != NULL && strcmp(filename, resource->file) != 0) { + resource = resource->next; + } + if (resource == NULL) return false; + AddResource(resource->category, resource->name, resource->file, + resource->noPrefix); + return true; +} + +int IdentifyFromFileSuffix(fileName) + char *fileName; +{ + int len, len1; + char fontName[256]; + register char *ch; + + /* The only files we can get anything useful from without looking inside + are AFM files and prebuilt files */ + + len = strlen(fileName); + if (len < 5) return false; + if (strcmp(".afm", fileName + len - 4) == 0) { + len1 = 0; + for (ch = fileName+len-5; ch > fileName && *ch != '/'; ch--) len1++; + if (*ch == '/') ch++; + else len1++; + strcpy(fontName, ch); + fontName[len1] = '\0'; + AddResource("FontAFM", fontName, fileName, false); + return true; + } + if (len < 6) return false; + if ((strcmp(".bepf", fileName + len - 5) == 0) || + (strcmp(".lepf", fileName + len - 5) == 0)) { + len1 = 0; + for (ch = fileName+len-6; ch > fileName && *ch != '/'; ch--) len1++; + if (*ch == '/') ch++; + else len1++; + strcpy(fontName, ch); + fontName[len1] = '\0'; + AddResource("FontPrebuilt", fontName, fileName, false); + return true; + } + return false; +} + +static void HandleUnopenableFile(filename, err) + char *filename; + int err; +{ + if (IdentifyFromUPRList(filename)) return; + + if (!noSuffix && IdentifyFromFileSuffix(filename)) return; + + if (issueWarnings) { + fprintf (stderr, "%s: Could not open file %s (%s).\n", + program, filename, strerror(err)); + } + + if (strict) exit(1); + + if (interactive) IdentifyFromUser(filename, (FILE *) NULL); + else MarkAsNonResource(filename); +} + + +static void HandleUnidentifiableFile(filename, file) + char *filename; + FILE *file; +{ + if (IdentifyFromUPRList(filename)) return; + + if (!noSuffix && IdentifyFromFileSuffix(filename)) return; + + if (issueWarnings) { + fprintf (stderr, "%s: Could not identify file %s.\n", + program, filename); + } + + if (strict) exit(1); + + if (interactive) IdentifyFromUser(filename, file); + else MarkAsNonResource(filename); +} + + +typedef struct { + char *key; + int keyLength; + char *key2; + int key2Length; + void (*proc)(/* FILE *file, char *fileName */); +} ResourceKey; + +static ResourceKey resourceTypes[] = { + {"%!PS-AdobeFont-", 15, NULL, 0, ProcessFont}, + {"%!PS-Adobe-", 11, " Resource-", 10, ProcessResource}, + {"STARTFONT", 9, NULL, 0, ProcessBDF}, + {"StartFontMetrics", 16, NULL, 0, ProcessAFM}, + {"PS-Resources-", 13, NULL, 0, ProcessResourceDirectory}, + {NULL, 0, NULL} +}; + +static void ProcessFile (fileName, filePath) + char *fileName; + char *filePath; +{ + FILE *file; + ResourceKey *resourceType; + char version[10]; + + if (fileName[0] == '.') + return; + + file = fopen (filePath, "r"); + + if (file == NULL) { + HandleUnopenableFile(filePath, errno); + return; + } + + fgets (lineBuffer, BUFFER_SIZE, file); + + for (resourceType = resourceTypes; resourceType->key != NULL; + resourceType++) { + if (strncmp (resourceType->key, lineBuffer, + resourceType->keyLength) == 0) { + if (resourceType->key2 == NULL) { + (*resourceType->proc) (file, filePath); + break; + + } else { + if (sscanf(lineBuffer+resourceType->keyLength, + "%10[0123456789.]", version) != 1) continue; + + if (strncmp(resourceType->key2, + lineBuffer + resourceType->keyLength + + strlen(version), + resourceType->key2Length) == 0) { + (*resourceType->proc) (file, filePath); + break; + } + } + } + } + + if (resourceType->key == NULL) HandleUnidentifiableFile(filePath, file); + + fclose (file); +} + +static void ProcessUPRFile (fileName, filePath) + char *fileName; + char *filePath; +{ + int len; + + if (fileName[0] == '.') + return; + + len = strlen(fileName); + if (len < 4) return; + if (strcmp(".upr", fileName + len - 4) != 0) return; + + PreprocessResourceDirectory(filePath); +} + + +static void ProcessDirectory (directoryName, top, fileFunction) + char *directoryName; + int top; + void (*fileFunction)(); +{ + DIR *directory; + struct dirent *directoryEntry; + struct stat status; + char *filePath, *fileName; + +#if DEBUG + fprintf (stderr, "Directory: %s\n", directoryName); +#endif + + directory = opendir (directoryName); + + if (directory == NULL) { + /* Treat top level failures to open differently from subdirectories */ + if (top || issueWarnings) { + fprintf (stderr, "%s: Could not open directory %s (%s).\n", + program, directoryName, strerror(errno)); + } + if (strict) exit(1); + return; + } + while ((directoryEntry = readdir (directory)) != NULL) { + fileName = directoryEntry->d_name; + if (fileName[0] == '.') continue; + filePath = ckmalloc (strlen (directoryName) + strlen (fileName) + 2, + "Failed to allocate file name string."); + sprintf (filePath, "%s/%s", directoryName, fileName); + if (stat(filePath, &status) == -1) { + if (issueWarnings) { + fprintf(stderr, "Couldn't get status of file %s (%s)\n", + filePath, strerror(errno)); + } + if (strict) exit(1); + continue; + } + if (S_ISDIR(status.st_mode)) { + if (recursive) ProcessDirectory(filePath, false, fileFunction); + } else (*fileFunction) (fileName, filePath); + free (filePath); + } + + closedir (directory); +} + + +void GenerateEntriesFromUPRList() +{ + Category *category; + Resource *resource; + UPRResource *upr; + int i, bucket; + + for (category = categories; category != NULL; category = category->next) { + if (strcmp(category->name, "FontBDFSizes") == 0 || + strcmp(category->name, "FontFamily") == 0) { + continue; + } + + for (resource = category->list; resource != NULL; + resource = resource->next) { + for (upr = UPRresources[Hash(resource->file)]; + upr != NULL && strcmp(upr->file, resource->file) < 0; + upr = upr->next) {} + if (upr != NULL) upr->found = true; + } + + if (category->hash != NULL) { + for (bucket = 0; bucket < HASHSIZE; bucket++) { + for (resource = category->hash[bucket]; resource != NULL; + resource = resource->next) { + for (upr = UPRresources[Hash(resource->file)]; + upr != NULL && strcmp(upr->file, resource->file) < 0; + upr = upr->next) {} + if (upr != NULL) upr->found = true; + } + } + } + } + + for (bucket = 0; bucket < HASHSIZE; bucket++) { + for (upr = UPRresources[bucket]; upr != NULL; upr = upr->next) { + if (upr->found) continue; + + if (strcmp(upr->category, "FontBDFSizes") != 0 && + strcmp(upr->category, "FontFamily") != 0) { + + if (!keep) { + /* If this file is in one of the input dirs, but wasn't + found, it must have been deleted since the previous run */ + + for (i = 0; i < directoryCount; i++) { + if (strncmp(upr->file, directories[i], + directoryLen[i]) == 0 && + upr->file[directoryLen[i]+1] == '/') goto NEXT_UPR; + } + } + AddResource(upr->category, upr->name, upr->file, upr->noPrefix); + } +NEXT_UPR: ; + } + } + + /* Now do BDFSizes and Families */ + + for (bucket = 0; bucket < HASHSIZE; bucket++) { + for (upr = UPRresources[bucket]; upr != NULL; upr = upr->next) { + if (upr->found) continue; + + if (strcmp(upr->category, "FontBDFSizes") == 0) { + char *buf, *ch = upr->file; + + /* We know there's a comma since we put one in. Anything + before the comma is just there to make hashing work better */ + + while (*ch != '\0') ch++; + while (ch >= upr->file && *ch != ',') ch--; + if (*ch == ',') ch++; + + buf = ckmalloc(strlen(upr->name) + strlen(ch) + 1, + "Failed to allocate BDF name\n"); + strcpy(buf, upr->name); + strcat(buf, ch); + + if (FindResource("FontBDF", buf)) { + AddResource(upr->category, upr->name, ch, false); + } + free(buf); + + } else if (strcmp(upr->category, "FontFamily") == 0) { + char *ch = upr->file; + + while (true) { + while (*ch != '\0' && *ch != ',') ch++; + if (*ch == '\0') break; + if (ch > upr->file && *(ch-1) == '\\') ch++; + else break; + } + if (*ch == ',') { + ch++; + if (FindResource("FontOutline", ch)) { + AddResource(upr->category, upr->name, upr->file, false); + } + } + } + } + } +} + + +static char *ExtractDirectoryPrefix() +{ + Category *category; + Resource *resource; + char *prefix = NULL; + char *ch1, *ch2; + int bucket; + + if (noPrefix) return NULL; + + category = categories; + + while (category != NULL) { + if (strcmp(category->name, "FontBDFSizes") == 0 || + strcmp(category->name, "FontFamily") == 0 || + strcmp(category->name, "FontBlendPositions") == 0 || + strcmp(category->name, "FontBlendMap") == 0 || + strcmp(category->name, "FontAxes") == 0) { + category = category->next; + continue; + } + resource = category->list; + + while (resource != NULL) { + if (resource->noPrefix) { + resource = resource->next; + continue; + } + if (prefix == NULL) { + prefix = ckmalloc(strlen(resource->file) + 1, + "Failed to allocate directory prefix"); + strcpy(prefix, resource->file); +#if DEBUG + printf("New directory prefix: %s\n", prefix); +#endif + } else { + ch1 = prefix; + ch2 = resource->file; + while (*ch1 != '\0' && *ch2 != '\0' && *ch1 == *ch2) { + ch1++; ch2++; + } +#if DEBUG + if (*ch1 != '\0') { + *ch1 = '\0'; + printf("New directory prefix: %s\n", prefix); + } +#endif + *ch1 = '\0'; + } + resource = resource->next; + } + + if (category->hash != NULL) { + for (bucket = 0; bucket < HASHSIZE; bucket++) { + for (resource = category->hash[bucket]; resource != NULL; + resource = resource->next) { + + if (resource->noPrefix) continue; + + if (prefix == NULL) { + prefix = ckmalloc(strlen(resource->file) + 1, + "Failed to allocate directory prefix"); + strcpy(prefix, resource->file); +#if DEBUG + printf("New directory prefix: %s\n", prefix); +#endif + } else { + ch1 = prefix; + ch2 = resource->file; + while (*ch1 != '\0' && *ch2 != '\0' && *ch1 == *ch2) { + ch1++; ch2++; + } +#if DEBUG + if (*ch1 != '\0') { + *ch1 = '\0'; + printf("New directory prefix: %s\n", prefix); + } +#endif + *ch1 = '\0'; + } + } + } + } + category = category->next; + } + if (prefix != NULL) { + ch1 = ch2 = prefix; + while (*ch1 != '\0') { + if (*ch1 == '/') ch2 = ch1; + ch1++; + } + *ch2 = '\0'; + } + + /* Prefixes must be absolute path names */ + if (prefix != NULL && prefix[0] != '/') prefix[0] = '\0'; + return prefix; +} + + +static void OutputChar(file, c) + FILE *file; + char c; +{ + static int len; /* Rely upon being 0 initially */ + + if (c == '\n') len = 0; + else { + len++; + if (len == MAXLINELEN) { + fputs("\\\n", file); + len = 1;; + } + } + + putc(c, file); +} + +static void OutputString(file, s) + FILE *file; + char *s; +{ + while (*s != '\0') OutputChar(file, *s++); +} + + +static void PrintResourceDirectory (directoryName, file) + char *directoryName; + FILE *file; +{ + Category *category; + Resource *resource; + char *pname; + int prefixlen; + int bucket; +#define outs(s) OutputString(file, s) +#define outc(c) OutputChar(file, c) + + if (directoryName == NULL || *directoryName == '\0') prefixlen = 0; + else prefixlen = strlen(directoryName) + 1; + + if (makeExclusive) outs("PS-Resources-Exclusive-1.0\n"); + else outs("PS-Resources-1.0\n"); + + category = categories; + + while (category != NULL) { + outs(category->name); + outc('\n'); + category = category->next; + } + + outs(".\n"); + if (prefixlen > 1) { + outc('/'); + outs(directoryName); + outc('\n'); + } + + category = categories; + + while (category != NULL) { + resource = category->list; + outs(category->name); + outc('\n'); + if (strcmp(category->name, "FontBDFSizes") != 0 && + strcmp(category->name, "FontFamily") != 0) { + while (resource != NULL) { + outs(resource->name); + outc('='); + if (resource->noPrefix) { + outc('='); + outs(resource->file); + } else outs(resource->file+prefixlen); + outc('\n'); + resource = resource->next; + } + } else { + while (resource != NULL) { + outs(resource->name); + outc('='); + outs(resource->file); + pname = resource->name; + resource = resource->next; + while (resource != NULL && strcmp(resource->name, pname) == 0) { + outc(','); + outs(resource->file); + resource = resource->next; + } + outc('\n'); + } + } + if (category->hash != NULL) { + for (bucket = 0; bucket < HASHSIZE; bucket++) { + for (resource = category->hash[bucket]; resource != NULL; + resource = resource->next) { + outs(resource->name); + outc('='); + if (resource->noPrefix) { + outc('='); + outs(resource->file); + } else outs(resource->file+prefixlen); + outc('\n'); + } + } + } + outs(".\n"); + category = category->next; + } +#undef outs +#undef outc +} + + +void Usage() +{ + fprintf(stderr, + "Usage: %s [-o outputfile] [-f inputfile]... [-dir directory]...\n", + program); + fprintf(stderr, + " [-e] [-i] [-nr] [-s] [-p] [-d] [-k] [-q] directory...\n"); + exit(1); +} + +int stdinDirectories = false; + +void ReadStdinDirectories() +{ + char buf[256]; + + if (stdinDirectories) { + fprintf(stderr, "%s: Can only read stdin as directory list once.\n", + program); + Usage(); + } + + stdinDirectories = true; + + while (scanf("%256s", buf) == 1) { + directoryCount++; + directories = (char **) ckrealloc((char *) directories, + directoryCount * sizeof(char *), + "Failed to reallocate directory list."); + directories[directoryCount-1] = ckmalloc(strlen(buf)+1, + "Failed to allocate directory name."); + strcpy(directories[directoryCount-1], buf); + } +} + +void ProcessArglist(argc, argv) + int argc; + char *argv[]; +{ + int i = 1, j; + + if (argc > 0) { + program = strrchr(argv[0], '/'); + if (program != NULL) program++; + else program = argv[0]; + } else program = "makepsres"; + + directories = (char **) ckmalloc(argc * sizeof(char *), + "Failed to allocate directory list."); + while (i < argc) { + if (strcmp(argv[i], "-help") == 0) Usage(); + + else if (strcmp(argv[i], "-q") == 0) issueWarnings = false; + + else if (strcmp(argv[i], "-k") == 0) keep = true; + + else if (strcmp(argv[i], "-d") == 0) discard = true; + + else if (strcmp(argv[i], "-p") == 0) noPrefix = true; + + else if (strcmp(argv[i], "-s") == 0) strict = true; + + else if (strcmp(argv[i], "-nr") == 0) recursive = false; + + else if (strcmp(argv[i], "-nb") == 0) noBackup = true; + + else if (strcmp(argv[i], "-ns") == 0) noSuffix = true; + + else if (strcmp(argv[i], "-i") == 0) interactive = true; + + else if (strcmp(argv[i], "-e") == 0) makeExclusive = true; + + else if (strcmp(argv[i], "-f") == 0) { + i++; + if (i >= argc) Usage(); + if (inputFiles == NULL) { + inputFiles = (char **) ckmalloc(argc * sizeof(char *), + "Failed to allocat input file list."); + } + inputFiles[inputCount++] = argv[i]; + } + + else if (strcmp(argv[i], "-o") == 0) { + i++; + if (i >= argc) Usage(); + outputFilename = argv[i]; + } + + else if (strcmp(argv[i], "-dir") == 0) { + i++; + if (i >= argc) Usage(); + directories[directoryCount++] = argv[i]; + } + + else directories[directoryCount++] = argv[i]; + + i++; + } + + if (directoryCount == 0) { + directoryCount = 1; + directories[0] = "."; + } else { + for (i = 0; i < directoryCount; i++) { + if (strcmp(directories[i], "-") == 0) ReadStdinDirectories(); + } + } + + if (stdinDirectories) { + j = 0; + for (i = 0; i < directoryCount; i++) { + if (strcmp(directories[i], "-") != 0) { + directories[j] = directories[i]; + j++; + } + } + directoryCount--; + } + + for (i = 0; i < inputCount; i++) { + if (strcmp(inputFiles[i], "-") == 0 && stdinDirectories) { + fprintf(stderr, + "%s: Cannot read stdin as both directory list and input file\n", + program); + Usage(); + } + } + +#if DEBUG + printf("Input directory list:\n"); + for (i = 0; i < directoryCount; i++) printf(" %s\n", directories[i]); +#endif + + directoryLen = (int *) ckmalloc(directoryCount * sizeof(int), + "Failed to allocate directory length list."); + + for (i = 0; i < directoryCount; i++) { + directoryLen[i] = strlen(directories[i]); + } +} + + +void CheckBackup(filename) + char *filename; +{ + char *backupname; + + if (noBackup || strcmp(filename, "/dev/null") == 0) return; + + backupname = ckmalloc(strlen(filename)+2, + "Failed to allocate backup file name.'"); + strcpy(backupname, filename); + strcat(backupname, "~"); + + /* Effect "rename (filename, backupname)" in BSD/Sys-V independent way */ + + (void) unlink (backupname); /* Ignore error */ + +#ifndef __UNIXOS2__ + if (link (filename, backupname) != 0) { + if (errno != ENOENT) { + fprintf(stderr, "%s: Could not back up output file %s\n", + program, filename); + fprintf(stderr, " and will not write over it (%s)\n", + strerror(errno)); + exit(1); + } + } else (void) unlink(filename); +#else + if (rename(filename,backupname) != 0) { + fprintf(stderr, "%s: Could not back up output file %s\n", + program, filename); + fprintf(stderr, " and will not write over it (%s)\n", + strerror(errno)); + exit(1); + } +#endif + free(backupname); +} + + +void IssueDuplicateWarnings() +{ + int headerIssued = false; + Category *category; + Duplicate *dup; + + for (category = categories; category != NULL; category = category->next) { + if (category->duplicates == NULL) continue; + if (!headerIssued) { + headerIssued = true; + fprintf(stderr, + "%s: Warning: The output resource file contains the following\n", + program); + fprintf(stderr, + " duplicates. Edit them out if you wish.\n"); + } + fprintf(stderr, "Category %s:\n", category->name); + for (dup = category->duplicates; dup != NULL; dup = dup->next) { + fprintf(stderr, " Resource: %s\n", dup->name); + fprintf(stderr, " First file: %s\n", dup->file1); + fprintf(stderr, " Second file: %s\n", dup->file2); + } + } +} + +int +main (argc, argv) + int argc; + char *argv[]; +{ + FILE *outputFile; + int i, len; + char *prefix; + + directories = NULL; + directoryCount = 0; + recursive = true; + discard = false; + keep = false; + outputFilename = NULL; + inputFiles = NULL; + inputCount = 0; + makeExclusive = false; + interactive = false; + strict = false; + noPrefix = false; + issueWarnings = true; + noBackup = false; + noSuffix = false; + + ProcessArglist(argc, argv); + + for (i = 0; i < inputCount; i++) { + PreprocessResourceDirectory(inputFiles[i]); + } + + /* Make two passes; the first time we just look for .upr files, and the + second time we look for everything. This gives us a better chance at + identifying files. */ + + for (i = 0; i < directoryCount; i++) { + len = strlen (directories[i]); + if (directories[i][len - 1] == '/') directories[i][len - 1] = '\0'; + + ProcessDirectory (directories[i], true, ProcessUPRFile); + } + +#if DEBUG + { + int i, biggestBucket, emptyCount; + static int count[11]; + emptyCount = biggestBucket = 0; + for (i = 0; i < HASHSIZE; i++) { + if (bucketCount[i] == 0) emptyCount++; + if (bucketCount[i] > biggestBucket) biggestBucket = bucketCount[i]; + } + if (biggestBucket != 0) { + for (i = 0; i < HASHSIZE; i++) { + count[bucketCount[i] * 10 / biggestBucket]++; + } + } + printf("Total UPR entries: %d\n", totalHashed); + printf("Buckets: %d\n", HASHSIZE); + printf("Longest bucket: %d\n", biggestBucket); + printf("Number of empty buckets: %d\n", emptyCount); + if (biggestBucket != 0) { + for (i = 0; i < 10; i++) { + printf("Number of buckets <= %d entries: %d\n", + biggestBucket*(i+1) / 10, count[i]); + } + } + } +#endif + + for (i = 0; i < directoryCount; i++) { + len = strlen (directories[i]); + if (directories[i][len - 1] == '/') directories[i][len - 1] = '\0'; + + ProcessDirectory (directories[i], true, ProcessFile); + } + + if (outputFilename == NULL) outputFilename = "PSres.upr"; + + if (strcmp(outputFilename, "-") == 0) outputFile = stdout; + else { + CheckBackup(outputFilename); + outputFile = fopen (outputFilename, "w"); + } + + if (outputFile == NULL) { + fprintf (stderr, + "%s: Failed to open %s for writing: %s\n", + program, outputFilename, strerror(errno)); + exit (1); + } + + if (!discard) GenerateEntriesFromUPRList(); + + prefix = ExtractDirectoryPrefix(); + PrintResourceDirectory (prefix, outputFile); + IssueDuplicateWarnings(); + exit (0); +} diff --git a/makepsres.man b/makepsres.man new file mode 100644 index 0000000..5ad9a4d --- /dev/null +++ b/makepsres.man @@ -0,0 +1,227 @@ +.\" Id: makepsres.man,v 6.1 1994/05/18 23:21:05 asente Exp $ +.TH MAKEPSRES 1 "13 May 1993" "Adobe Systems" +.SH NAME +makepsres \- Build PostScript resource database file. + +.SH SYNOPSIS +.B makepsres +[ +.I options +] +.I directory ... + +.SH DESCRIPTION +.B makepsres +creates PostScript language resource database files. +Resource database files can be used to +specify the location of resources that are used by the font selection +panel and other Adobe software. +For a complete description of the +resource location facilities in the Display PostScript system, +see Appendix A and Appendix B of "Display PostScript Toolkit +for X" in \fIProgramming the Display PostScript System with X.\fR +.LP +.B makepsres +creates a resource database file named +.I PSres.upr +that contains all the resources in all the +.I directory +path names specified on the command line. +.RS .25in +.LP +If the list of directories contains +.B \- , +.B makepsres +reads from +.I stdin +and expects a list of directories separated by space, tab, or newline. +.LP +If the list of directories is empty, it is taken to be the current directory. +.LP +If all specified directories have a common initial prefix, +.B makepsres +extracts it as a directory prefix in the new resource database file. +.RE +.LP +.B makepsres +normally acts recursively; it looks for resource files in subdirectories of +any specified directory. This behavior can be overridden with the command +line option +.B \-nr. +.LP +.B makepsres +uses existing resource database files to assist in identifying files. By +default, +.B makepsres +creates a new resource database file containing all of the +following that apply: +.RS .25in +.LP +Resource files found in the directories on the command line. +.LP +Resource files pointed to by the resource database files in the directories on +the command line. +.LP +Resource entries found in the input resource database files. These entries are +copied if the files they specify still exist and are located in directories not +specified on the command line. +.RE +.LP +If you run +.B makepsres +in discard mode (with the +.B \-d +option), it +does not copy resource entries from the input resource database files. In that case, +the output file consists only of entries from the directories on the command line. +The input resource database files are only used to assist in identifying files. +.LP +If you run +.B makepsres +in keep mode (with the +.B \-k +option), it +includes in the output file all resource entries in the input resource database files, +even entries for files that no longer exist or are located in directories specified on +the command line. +.LP +.B makepsres +uses various heuristics to identify files. A file that is of a private +resource type or that does not conform to the standard format for a resource file +must be specified in one of the following ways: +.RS .25in +.LP +By running +.B makepsres +in interactive mode +.LP +By preloading the file into a resource database +file used for input +.LP +By beginning the file with the following line: +.LP +.RS .25in +%!PS-Adobe-3.0 Resource-<resource-type> +.RE +.RE + +.SH OPTIONS +.TP +.BI \-o " filename" +Writes the output to the specified filename. +The construction "\fB\-o \-\fR" +writes to stdout. If the +.B \-o +option is not specified, +.B makepsres +creates a +.I PSres.upr +file in the current directory +and writes the output to that file. +.TP +.BI \-f " filename" +Uses information from the specified file to assist in resource typing. +The file must be in resource database file format. +Multiple +.B \-f +options may be specified. The construction "\fB\-f \-\fR" +uses +.I stdin +as an input file and may not be used if "\fB\-\fR" +is specified as a directory on the command line. +.TP +.BI \-dir " dirname" +Specifies that +.I dirname +is a directory. Needed only in rare cases when +.I dirname +is the same as a command-line option such as +.B \-nb. +.TP +.B \-d +Specifies discard mode. The resulting output file consists solely +of entries from the directories on the command line. +.TP +.B \-e +Marks the resulting +.I PSres.upr +file as exclusive. This option +makes the resource location library run more quickly since it does not have to +look for other resource database files. It becomes necessary, however, to run +.B makepsres +whenever new resources are added to the directory, even if the +resources come with their own resource database file. +.TP +.B \-i +Specifies interactive mode. In interactive mode, you +will be queried for the resource type of any encountered +file that +.B makepsres +cannot identify. If +.B \-i +is not specified, +.B makepsres +assumes an unidentifiable file is not a resource file. +.TP +.B \-k +Specifies keep mode. +.TP +.B \-nb +If the output file already exists, do not back it up. +.TP +.B \-nr +Specifies nonrecursive mode. +.B makepsres +normally acts recursively: it looks for +resource files in subdirectories of any specified directory. If +.B \-nr +is used, +.B makepsres +does not look in subdirectories for resource files. +.TP +.B \-p +Specifies no directory prefix. If +.B \-p +is used, +.B makepsres +does not try to find a common directory prefix among the specified directories. +.TP +.B \-q +Quiet mode: ignores unidentifiable files instead of warning about them. +.TP +.B \-s +Specifies strict mode. If +.B \-s +is used, +.B makepsres +terminates with an error if it encounters a file it cannot identify. + +.SH EXAMPLES +.TP +.B "makepsres ." +Creates a resource database file that contains all the +resources in the current directory. +.TP +.B "makepsres \-i \-o local.upr /usr/local/lib/ps/fonts" +Runs +.B makepsres +in interactive mode and creates a resource database file named +.I local.upr, +which contains all the resources in the directory +.I /usr/local/lib/ps/fonts. + +.SH SEE ALSO +.LP +\fIProgramming the Display PostScript System with X\fR +(Addison-Wesley Publishing Company, Inc., 1993). + +.SH AUTHOR +Adobe Systems Incorporated + +.SH NOTES +PostScript and Display PostScript are trademarks +of Adobe Systems Incorporated which may be registered +in certain jurisdictions. +.LP +Copyright (c) 1989-1994 Adobe Systems Incorporated. All rights reserved. + |