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