installalias.c revision 919
1088N/A/*
235N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
1088N/A * Use is subject to license terms.
235N/A *
235N/A * Permission is hereby granted, free of charge, to any person obtaining a
919N/A * copy of this software and associated documentation files (the "Software"),
919N/A * to deal in the Software without restriction, including without limitation
919N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
919N/A * and/or sell copies of the Software, and to permit persons to whom the
919N/A * Software is furnished to do so, subject to the following conditions:
919N/A *
919N/A * The above copyright notice and this permission notice (including the next
919N/A * paragraph) shall be included in all copies or substantial portions of the
919N/A * Software.
919N/A *
919N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
919N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
919N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
919N/A * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
919N/A * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
919N/A * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
919N/A * DEALINGS IN THE SOFTWARE.
235N/A */
235N/A/* Code copied from libXfont is:
235N/A
235N/ACopyright 1991, 1998 The Open Group
967N/A
235N/APermission to use, copy, modify, distribute, and sell this software and its
493N/Adocumentation for any purpose is hereby granted without fee, provided that
493N/Athe above copyright notice appear in all copies and that both that
970N/Acopyright notice and this permission notice appear in supporting
970N/Adocumentation.
970N/A
970N/AThe above copyright notice and this permission notice shall be included in
970N/Aall copies or substantial portions of the Software.
970N/A
970N/ATHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
493N/AIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
967N/AFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
493N/AOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1088N/AAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1088N/ACONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
235N/A
1097N/AExcept as contained in this notice, the name of The Open Group shall not be
1262N/Aused in advertising or otherwise to promote the sale, use or other dealings
235N/Ain this Software without prior written authorization from The Open Group.
947N/A
1124N/A*/
947N/A
235N/A/*
235N/A * Ensure that a fonts.alias file only contains aliases for fonts that exist
1201N/A * We do this by first reading in the fonts.dir file and then for
750N/A * each entry in the fonts.alias file we verify that the alias can
235N/A * be resolved. Most this of this code is borrowed from
851N/A * libXfont with minor modifications.
705N/A */
235N/A#include <X11/fonts/fntfilst.h>
1003N/A#include <stdio.h>
1003N/A#include <sys/types.h>
851N/A#include <errno.h>
742N/A#include <sys/stat.h>
235N/A#include <ctype.h>
493N/A#include <limits.h>
235N/A#include <stdarg.h>
963N/A#include <stdlib.h>
851N/A#include <X11/keysym.h>
606N/A
606N/A#define EBadFontPath 0
235N/A#define EBadFontName 0
851N/A#define EAllocError 0
851N/A#define Success 1
235N/A
235N/Apointer serverClient;
493N/Astatic char *programName;
705N/A
493N/Astatic int lexc(FILE *file);
493N/A
606N/Avoid
606N/AErrorF (const char * f, ...)
235N/A{
606N/A va_list args;
606N/A
493N/A va_start(args, f);
493N/A fprintf(stderr, "%s: ", programName);
493N/A vfprintf(stderr, f, args);
235N/A va_end(args);
235N/A}
235N/A
705N/A/* Provide pseudo renderers for font file formats we may find in fonts.dir
493N/A files during installation, but which libXfont does not support */
235N/A/* ARGSUSED */
235N/Astatic int
235N/APseudoOpenScalable (FontPathElementPtr fpe, FontPtr *ppFont, int flags,
606N/A FontEntryPtr entry, char *fileName, FontScalablePtr vals,
606N/A fsBitmapFormat format, fsBitmapFormatMask fmask,
606N/A FontPtr non_cachable_font)
851N/A{
606N/A return 1;
493N/A}
1095N/A
493N/A/* ARGSUSED */
965N/Astatic int
965N/APseudoGetInfoScalable (FontPathElementPtr fpe, FontInfoPtr info,
1196N/A FontEntryPtr entry, FontNamePtr fontName,
1196N/A char *fileName, FontScalablePtr vals)
1196N/A{
235N/A return 1;
235N/A}
705N/A
493N/Astatic FontRendererRec PseudoRenderers[] = {
851N/A { ".spd", 4, NULL, PseudoOpenScalable, NULL, PseudoGetInfoScalable, 0 }
493N/A};
1190N/A
1190N/Astatic void
1190N/APseudoFontFileRegisterFpeFunctions (void)
1190N/A{
1190N/A int i;
1190N/A
493N/A for (i = 0; i < (sizeof(PseudoRenderers) / sizeof(FontRendererRec)); i++) {
967N/A FontFileRegisterRenderer(&PseudoRenderers[i]);
493N/A }
1030N/A}
1097N/A
1097N/Aint
1097N/AProcessFontsDirectory (
963N/A char *directory,
1097N/A FontDirectoryPtr *pdir)
1097N/A{
1097N/A char file_name[MAXFONTNAMELEN];
916N/A char font_name[MAXFONTNAMELEN];
1097N/A char dir_file[MAXFONTNAMELEN];
1097N/A FILE *file;
1097N/A int count, i;
1097N/A struct stat statb;
963N/A
1097N/A FontDirectoryPtr dir = NullFontDirectory;
1097N/A
963N/A i = strlcpy(dir_file, directory, sizeof(dir_file));
1097N/A if (directory[i - 1] != '/')
963N/A strlcat(dir_file, "/", sizeof(dir_file));
1097N/A strlcat(dir_file, FontDirFile, sizeof(dir_file));
file = fopen(dir_file, "r");
if (file) {
if (fstat (fileno(file), &statb) == -1)
return EBadFontPath;
count = fscanf(file, "%d\n", &i);
if ((count == EOF) || (count != 1)) {
fclose(file);
return EBadFontPath;
}
dir = FontFileMakeDir(directory, i);
if (dir == NULL) {
fclose(file);
return EBadFontPath;
}
dir->dir_mtime = statb.st_mtime;
while ((count = fscanf(file, "%1024s %[^\n]\n", file_name, font_name))
!= EOF) {
if (count != 2) {
FontFileFreeDir (dir);
fclose(file);
return EBadFontPath;
}
if (!FontFileAddFontFile (dir, font_name, file_name))
{
FontFileFreeDir (dir);
fclose(file);
return EBadFontPath;
}
}
fclose(file);
} else if (errno != ENOENT) {
return EBadFontPath;
}
if (!dir)
return EBadFontPath;
*pdir = dir;
return Success;
}
#define NAME 0
#define NEWLINE 1
#define DONE 2
#define EALLOC 3
#define FileClosed 4
#define QUOTE 0
#define WHITE 1
#define NORMAL 2
#define END 3
#define NL 4
static int charClass;
static int
lexAlias(
FILE *file,
char **lexToken)
{
int c;
char *t;
enum state {
Begin, Normal, Quoted
} state;
int count;
static char *tokenBuf = (char *) NULL;
static unsigned int tokenSize = 0;
t = tokenBuf;
count = 0;
state = Begin;
for (;;) {
if (count == tokenSize) {
unsigned int nsize;
char *nbuf;
nsize = tokenSize ? (tokenSize << 1) : 64;
nbuf = realloc(tokenBuf, nsize);
if (!nbuf)
return EALLOC;
tokenBuf = nbuf;
tokenSize = nsize;
t = tokenBuf + count;
}
c = lexc(file);
switch (charClass) {
case QUOTE:
switch (state) {
case Begin:
case Normal:
state = Quoted;
break;
case Quoted:
state = Normal;
break;
}
break;
case WHITE:
switch (state) {
case Begin:
continue;
case Normal:
*t = '\0';
*lexToken = tokenBuf;
return NAME;
case Quoted:
break;
}
/* fall through */
case NORMAL:
switch (state) {
case Begin:
state = Normal;
}
*t++ = c;
++count;
break;
case END:
case NL:
switch (state) {
case Begin:
*lexToken = (char *) NULL;
return charClass == END ? DONE : NEWLINE;
default:
*t = '\0';
*lexToken = tokenBuf;
ungetc(c, file);
return NAME;
}
}
}
}
static int
lexc(FILE *file)
{
int c;
c = getc(file);
switch (c) {
case EOF:
charClass = END;
break;
case '\\':
c = getc(file);
if (c == EOF)
charClass = END;
else
charClass = NORMAL;
break;
case '"':
charClass = QUOTE;
break;
case ' ':
case '\t':
charClass = WHITE;
break;
case '\n':
charClass = NL;
break;
default:
charClass = NORMAL;
break;
}
return c;
}
static inline unsigned char
ISOLatin1ToLower(unsigned char source)
{
if (source >= XK_A && source <= XK_Z)
return source + (XK_a - XK_A);
if (source >= XK_Agrave && source <= XK_Odiaeresis)
return source + (XK_agrave - XK_Agrave);
if (source >= XK_Ooblique && source <= XK_Thorn)
return source + (XK_oslash - XK_Ooblique);
return source;
}
static void
copyISOLatin1Lowered(char *dest, char *source, int length)
{
int i;
for (i = 0; i < length; i++, source++, dest++)
*dest = ISOLatin1ToLower(*source);
*dest = '\0';
}
static int
ReadAliases(
FILE *file,
char *alias,
char *font_name)
{
int token;
char *lexToken;
int status = Success;
while (status == Success) {
token = lexAlias(file, &lexToken);
switch (token) {
case NEWLINE:
break;
case DONE:
fclose(file);
return FileClosed;
case EALLOC:
status = EAllocError;
break;
case NAME:
strlcpy(alias, lexToken, MAXFONTNAMELEN);
token = lexAlias(file, &lexToken);
switch (token) {
case NEWLINE:
break;
case DONE:
status = EBadFontPath;
break;
case EALLOC:
status = EAllocError;
break;
case NAME:
copyISOLatin1Lowered(alias, alias, strlen(alias));
copyISOLatin1Lowered(font_name, lexToken, strlen(lexToken));
return status;
}
}
}
fclose(file);
return FileClosed;
}
#define FontAliasEntry 8
static int
OpenAndVerifyFont (
char *name,
int namelen,
FontDirectoryPtr dir)
{
char lowerName[MAXFONTNAMELEN];
char *p;
FontNameRec tmpName;
FontEntryPtr entry;
FontScalableRec vals;
FontBitmapEntryPtr bitmap;
FontBCEntryPtr bc;
int ret = 0;
Bool isxlfd;
Bool scaleAlias;
if (namelen >= MAXFONTNAMELEN)
return EAllocError;
copyISOLatin1Lowered (lowerName, name, namelen);
lowerName[namelen] = '\0';
tmpName.name = lowerName;
tmpName.length = namelen;
tmpName.ndashes = FontFileCountDashes (lowerName, namelen);
/* Match XLFD patterns */
if (tmpName.ndashes == 14 &&
FontParseXLFDName (lowerName, &vals, FONT_XLFD_REPLACE_ZERO))
{
isxlfd = TRUE;
tmpName.length = strlen (lowerName);
entry = FontFileFindNameInDir (&dir->scalable, &tmpName);
if (entry) {
return Success;
}
}
else
{
isxlfd = FALSE;
}
/* Match non XLFD pattern */
if (entry = FontFileFindNameInDir (&dir->nonScalable, &tmpName))
{
switch (entry->type) {
case FONT_ENTRY_BITMAP:
bitmap = &entry->u.bitmap;
ret = Success;
break;
case FONT_ENTRY_ALIAS:
if (entry->u.alias.resolved) {
strlcpy(name, entry->u.alias.resolved, MAXFONTNAMELEN);
ret = FontAliasEntry;
} else {
ret = EBadFontName;
}
break;
case FONT_ENTRY_BC:
bc = &entry->u.bc;
entry = bc->entry;
break;
default:
ret = EBadFontName;
}
}
else
{
scaleAlias = FALSE;
if (isxlfd)
{
FontParseXLFDName(lowerName, &vals, FONT_XLFD_REPLACE_ZERO);
tmpName.length = strlen (lowerName);
scaleAlias = TRUE;
}
else
{
p = lowerName + tmpName.length;
while (p > lowerName && isdigit(p[-1]))
p--;
if (*p)
{
vals.point = atoi(p) * 10;
if (p[-1] == '-')
p--;
if (p > lowerName)
{
*p = '\0';
vals.pixel = 0;
vals.x = 0;
vals.y = 0;
vals.width = 0;
tmpName.length = p - lowerName;
scaleAlias = TRUE;
}
}
}
if (scaleAlias &&
(entry = FontFileFindNameInDir (&dir->nonScalable, &tmpName)) &&
entry->type == FONT_ENTRY_ALIAS)
{
if (entry->u.alias.resolved) {
strlcpy(name, entry->u.alias.resolved, MAXFONTNAMELEN);
return FontAliasEntry;
} else {
return EBadFontName;
}
}
else
{
ret = EBadFontName;
}
}
return ret;
}
#define TempFileSuffix "_TMPFILE"
static void
ProcessAliasFile(
FontDirectoryPtr dir,
const char *aliasfilename)
{
char alias[MAXFONTNAMELEN];
char font_name[MAXFONTNAMELEN];
char save_font_name[MAXFONTNAMELEN];
char aliasfile[MAXFONTNAMELEN];
char tmpfile[MAXFONTNAMELEN];
char outfile[MAXFONTNAMELEN];
FILE *file, *newfile;
int ret;
struct stat statb;
int retvalue;
int containsSpace = 0;
strlcpy(aliasfile, dir->directory, sizeof(aliasfile));
strlcat(aliasfile, aliasfilename, sizeof(aliasfile));
file = fopen(aliasfile, "r");
if (!file)
return; /* fail silently -- if no alias file, we're done */
else
if (fstat (fileno(file), &statb) == -1)
return;
strlcpy(tmpfile, aliasfile, sizeof(tmpfile));
strlcat(tmpfile, TempFileSuffix, sizeof(tmpfile));
newfile = fopen(tmpfile, "w");
if (!newfile) {
ErrorF("Can't create new alias file %s\n", tmpfile);
return;
}
while ((ret = ReadAliases(file, alias, font_name)) != FileClosed) {
strlcpy(save_font_name, font_name, sizeof(save_font_name));
while ((retvalue = OpenAndVerifyFont(font_name,strlen(font_name), dir))
== FontAliasEntry) {
continue;
}
if (strcmp(alias,save_font_name) == 0) {
/* 4258475: don't add if the names are the same */
#ifdef DEBUG
fprintf(stderr,"%s\t%s aliased to itself!\n", alias, save_font_name);
#endif
} else if (retvalue == Success) {
/* add this alias to list of known aliases */
if (strchr(alias, ' '))
containsSpace = 1;
if (!FontFileAddFontAlias (dir, alias, save_font_name))
#ifdef DEBUG
fprintf(stderr, "installalias: unable to add alias to list\n");
#else
; /* do nothing -- fail silently */
#endif /* DEBUG */
if (containsSpace) {
containsSpace = 0;
fprintf(newfile, "\"%s\"\t\"%s\"\n",alias, save_font_name);
} else {
fprintf(newfile, "%s\t\"%s\"\n",alias, save_font_name);
}
}
#ifdef DEBUG
else
fprintf(stderr,"%s\t%s not found\n", alias, save_font_name);
#endif /* DEBUG */
}
fclose(newfile);
fclose(file);
strlcpy(outfile, dir->directory, sizeof(outfile));
strlcat(outfile, "fonts.alias", sizeof(outfile));
ret = rename(tmpfile, outfile);
if (ret < 0) {
ErrorF("Unable to rename %s to %s.\n", tmpfile, outfile);
}
return;
}
int
GetDefaultPointSize (void)
{
return 120;
}
/* ARGSUSED */
FontResolutionPtr GetClientResolutions (int *num)
{
return 0;
}
/* ARGSUSED */
int RegisterFPEFunctions ( NameCheckFunc name_func,
InitFpeFunc init_func,
FreeFpeFunc free_func,
ResetFpeFunc reset_func,
OpenFontFunc open_func,
CloseFontFunc close_func,
ListFontsFunc list_func,
StartLfwiFunc start_lfwi_func,
NextLfwiFunc next_lfwi_func,
WakeupFpeFunc wakeup_func,
ClientDiedFunc client_died,
LoadGlyphsFunc load_glyphs,
StartLaFunc start_list_alias_func,
NextLaFunc next_list_alias_func,
SetPathFunc set_path_func )
{
return 0;
}
void
InitFontFileFunctions(void)
{
FontFileRegisterFpeFunctions();
PseudoFontFileRegisterFpeFunctions();
return;
}
int
main(int argc, char **argv)
{
FontDirectoryPtr dir;
const char *aliasFileName = "fonts.alias";
char *defaultDirectoryList[] = { ".", NULL };
char **directoryList = defaultDirectoryList;
int directoryCount = 1;
int i = 0, ret;
programName = argv[0];
InitFontFileFunctions();
if (argc > 1) {
aliasFileName = argv[1];
}
if (argc > 2) {
directoryCount = argc;
directoryList = argv;
i = 2;
}
for (/* i initialized above */ ; i < directoryCount; i++) {
ret = ProcessFontsDirectory(directoryList[i], &dir);
if (ret == Success) {
ProcessAliasFile(dir, aliasFileName);
} else {
char curdir[PATH_MAX];
const char *directory = directoryList[i];
if (strcmp(directory, ".") == 0) {
getcwd(curdir, sizeof(curdir));
directory = curdir;
}
ErrorF("failed to process fonts.dir file in %s\n", directory);
exit (1);
}
}
exit (0);
}