/*
* 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.8tsi 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(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(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(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, "%63[%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, "%255s", key) != 1) continue;
if (strcmp(key, "exec") == 0) break;
continue;
}
if (fscanf (file, "%255s", 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%255s", 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, "%255s", 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, "%255s", 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("%255s", 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);
}