dirfile.c revision 7f7f5e4e
1/* $Xorg: dirfile.c,v 1.4 2001/02/09 02:04:03 xorgcvs Exp $ */
2
3/*
4
5Copyright 1991, 1998  The Open Group
6
7Permission to use, copy, modify, distribute, and sell this software and its
8documentation for any purpose is hereby granted without fee, provided that
9the above copyright notice appear in all copies and that both that
10copyright notice and this permission notice appear in supporting
11documentation.
12
13The above copyright notice and this permission notice shall be included in
14all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall not be
24used in advertising or otherwise to promote the sale, use or other dealings
25in this Software without prior written authorization from The Open Group.
26
27*/
28/* $XFree86: xc/lib/font/fontfile/dirfile.c,v 3.17 2004/02/08 01:52:27 dawes Exp $ */
29
30/*
31 * Author:  Keith Packard, MIT X Consortium
32 */
33
34/*
35 * dirfile.c
36 *
37 * Read fonts.dir and fonts.alias files
38 */
39
40#ifdef HAVE_CONFIG_H
41#include <config.h>
42#endif
43#include <X11/fonts/fntfilst.h>
44#include <stdio.h>
45#include <sys/types.h>
46#include <sys/stat.h>
47#include <errno.h>
48
49static Bool AddFileNameAliases ( FontDirectoryPtr dir );
50static int ReadFontAlias ( char *directory, Bool isFile,
51			   FontDirectoryPtr *pdir );
52static int lexAlias ( FILE *file, char **lexToken );
53static int lexc ( FILE *file );
54
55int
56FontFileReadDirectory (char *directory, FontDirectoryPtr *pdir)
57{
58    char        file_name[MAXFONTFILENAMELEN];
59    char        font_name[MAXFONTNAMELEN];
60    char        dir_file[MAXFONTFILENAMELEN];
61    char	dir_path[MAXFONTFILENAMELEN];
62    char	*ptr;
63    FILE       *file;
64    int         count,
65                num_fonts,
66                status;
67    struct stat	statb;
68    static char format[24] = "";
69#if defined(WIN32)
70    int i;
71#endif
72
73    FontDirectoryPtr	dir = NullFontDirectory;
74
75    if (strlen(directory) + 1 + sizeof(FontDirFile) > sizeof(dir_file))
76	return BadFontPath;
77
78    /* Check for font directory attributes */
79#if !defined(WIN32)
80    if ((ptr = strchr(directory, ':'))) {
81#else
82    /* OS/2 and WIN32 path might start with a drive letter, don't clip this */
83    if ((ptr = strchr(directory+2, ':'))) {
84#endif
85	strncpy(dir_path, directory, ptr - directory);
86	dir_path[ptr - directory] = '\0';
87    } else {
88	strcpy(dir_path, directory);
89    }
90    strcpy(dir_file, dir_path);
91    if (dir_file[strlen(dir_file) - 1] != '/')
92	strcat(dir_file, "/");
93    strcat(dir_file, FontDirFile);
94    file = fopen(dir_file, "rt");
95    if (file) {
96#ifndef WIN32
97	if (fstat (fileno(file), &statb) == -1)
98#else
99	if (stat (dir_file, &statb) == -1)
100#endif
101        {
102            fclose(file);
103	    return BadFontPath;
104        }
105	count = fscanf(file, "%d\n", &num_fonts);
106	if ((count == EOF) || (count != 1)) {
107	    fclose(file);
108	    return BadFontPath;
109	}
110	dir = FontFileMakeDir(directory, num_fonts);
111	if (dir == NULL) {
112	    fclose(file);
113	    return BadFontPath;
114	}
115	dir->dir_mtime = statb.st_mtime;
116	if (format[0] == '\0')
117	    sprintf(format, "%%%ds %%%d[^\n]\n",
118		MAXFONTFILENAMELEN-1, MAXFONTNAMELEN-1);
119
120	while ((count = fscanf(file, format, file_name, font_name)) != EOF) {
121#if defined(WIN32)
122	    /* strip any existing trailing CR */
123	    for (i=0; i<strlen(font_name); i++) {
124		if (font_name[i]=='\r') font_name[i] = '\0';
125	    }
126#endif
127	    if (count != 2) {
128		FontFileFreeDir (dir);
129		fclose(file);
130		return BadFontPath;
131	    }
132
133	    /*
134	     * We blindly try to load all the font files specified.
135	     * In theory, we might want to warn that some of the fonts
136	     * couldn't be loaded.
137	     */
138	    FontFileAddFontFile (dir, font_name, file_name);
139	}
140	fclose(file);
141
142    } else if (errno != ENOENT) {
143	return BadFontPath;
144    }
145    status = ReadFontAlias(dir_path, FALSE, &dir);
146    if (status != Successful) {
147	if (dir)
148	    FontFileFreeDir (dir);
149	return status;
150    }
151    if (!dir)
152	return BadFontPath;
153
154    FontFileSortDir(dir);
155
156    *pdir = dir;
157    return Successful;
158}
159
160Bool
161FontFileDirectoryChanged(FontDirectoryPtr dir)
162{
163    char	dir_file[MAXFONTFILENAMELEN];
164    struct stat	statb;
165
166    if (strlen(dir->directory) + sizeof(FontDirFile) > sizeof(dir_file))
167	return FALSE;
168
169    strcpy (dir_file, dir->directory);
170    strcat (dir_file, FontDirFile);
171    if (stat (dir_file, &statb) == -1)
172    {
173	if (errno != ENOENT || dir->dir_mtime != 0)
174	    return TRUE;
175	return FALSE;		/* doesn't exist and never did: no change */
176    }
177    if (dir->dir_mtime != statb.st_mtime)
178	return TRUE;
179
180    if ((strlen(dir->directory) + sizeof(FontAliasFile)) > sizeof(dir_file))
181	return FALSE;
182    strcpy (dir_file, dir->directory);
183    strcat (dir_file, FontAliasFile);
184    if (stat (dir_file, &statb) == -1)
185    {
186	if (errno != ENOENT || dir->alias_mtime != 0)
187	    return TRUE;
188	return FALSE;		/* doesn't exist and never did: no change */
189    }
190    if (dir->alias_mtime != statb.st_mtime)
191	return TRUE;
192    return FALSE;
193}
194
195/*
196 * Make each of the file names an automatic alias for each of the files.
197 */
198
199static Bool
200AddFileNameAliases(FontDirectoryPtr dir)
201{
202    int		    i;
203    char	    copy[MAXFONTFILENAMELEN];
204    char	    *fileName;
205    FontTablePtr    table;
206    FontRendererPtr renderer;
207    int		    len;
208    FontNameRec	    name;
209
210    table = &dir->nonScalable;
211    for (i = 0; i < table->used; i++) {
212	if (table->entries[i].type != FONT_ENTRY_BITMAP)
213	    continue;
214	fileName = table->entries[i].u.bitmap.fileName;
215	renderer = FontFileMatchRenderer (fileName);
216	if (!renderer)
217	    continue;
218
219	len = strlen (fileName) - renderer->fileSuffixLen;
220	if (len >= sizeof(copy))
221	    continue;
222	CopyISOLatin1Lowered (copy, fileName, len);
223	copy[len] = '\0';
224	name.name = copy;
225	name.length = len;
226	name.ndashes = FontFileCountDashes (copy, len);
227
228	if (!FontFileFindNameInDir(table, &name)) {
229	    if (!FontFileAddFontAlias (dir, copy, table->entries[i].name.name))
230		return FALSE;
231	}
232    }
233    return TRUE;
234}
235
236/*
237 * parse the font.alias file.  Format is:
238 *
239 * alias font-name
240 *
241 * To imbed white-space in an alias name, enclose it like "font name"
242 * in double quotes.  \ escapes and character, so
243 * "font name \"With Double Quotes\" \\ and \\ back-slashes"
244 * works just fine.
245 *
246 * A line beginning with a ! denotes a newline-terminated comment.
247 */
248
249/*
250 * token types
251 */
252
253#define NAME		0
254#define NEWLINE		1
255#define DONE		2
256#define EALLOC		3
257
258static int
259ReadFontAlias(char *directory, Bool isFile, FontDirectoryPtr *pdir)
260{
261    char		alias[MAXFONTNAMELEN];
262    char		font_name[MAXFONTNAMELEN];
263    char		alias_file[MAXFONTFILENAMELEN];
264    FILE		*file;
265    FontDirectoryPtr	dir;
266    int			token;
267    char		*lexToken;
268    int			status = Successful;
269    struct stat		statb;
270
271    if (strlen(directory) >= sizeof(alias_file))
272	return BadFontPath;
273    dir = *pdir;
274    strcpy(alias_file, directory);
275    if (!isFile) {
276	if (strlen(directory) + 1 + sizeof(FontAliasFile) > sizeof(alias_file))
277	    return BadFontPath;
278	if (directory[strlen(directory) - 1] != '/')
279	    strcat(alias_file, "/");
280	strcat(alias_file, FontAliasFile);
281    }
282    file = fopen(alias_file, "rt");
283    if (!file)
284	return ((errno == ENOENT) ? Successful : BadFontPath);
285    if (!dir)
286	*pdir = dir = FontFileMakeDir(directory, 10);
287    if (!dir)
288    {
289	fclose (file);
290	return AllocError;
291    }
292#ifndef WIN32
293    if (fstat (fileno (file), &statb) == -1)
294#else
295    if (stat (alias_file, &statb) == -1)
296#endif
297    {
298	fclose (file);
299	return BadFontPath;
300    }
301    dir->alias_mtime = statb.st_mtime;
302    while (status == Successful) {
303	token = lexAlias(file, &lexToken);
304	switch (token) {
305	case NEWLINE:
306	    break;
307	case DONE:
308	    fclose(file);
309	    return Successful;
310	case EALLOC:
311	    status = AllocError;
312	    break;
313	case NAME:
314	    if (strlen(lexToken) >= sizeof(alias)) {
315		status = BadFontPath;
316		break;
317	    }
318	    strcpy(alias, lexToken);
319	    token = lexAlias(file, &lexToken);
320	    switch (token) {
321	    case NEWLINE:
322		if (strcmp(alias, "FILE_NAMES_ALIASES"))
323		    status = BadFontPath;
324		else if (!AddFileNameAliases(dir))
325		    status = AllocError;
326		break;
327	    case DONE:
328		status = BadFontPath;
329		break;
330	    case EALLOC:
331		status = AllocError;
332		break;
333	    case NAME:
334		if (strlen(lexToken) >= sizeof(font_name)) {
335		    status = BadFontPath;
336		    break;
337		}
338		CopyISOLatin1Lowered(alias, alias, strlen(alias));
339		CopyISOLatin1Lowered(font_name, lexToken, strlen(lexToken));
340		if (!FontFileAddFontAlias (dir, alias, font_name))
341		    status = AllocError;
342		break;
343	    }
344	}
345    }
346    fclose(file);
347    return status;
348}
349
350#define QUOTE		0
351#define WHITE		1
352#define NORMAL		2
353#define END		3
354#define NL		4
355#define BANG		5
356
357static int  charClass;
358
359static int
360lexAlias(FILE *file, char **lexToken)
361{
362    int         c;
363    char       *t;
364    enum state {
365	Begin, Normal, Quoted, Comment
366    }           state;
367    int         count;
368
369    static char *tokenBuf = (char *) NULL;
370    static int  tokenSize = 0;
371
372    t = tokenBuf;
373    count = 0;
374    state = Begin;
375    for (;;) {
376	if (count == tokenSize) {
377	    int         nsize;
378	    char       *nbuf;
379
380	    nsize = tokenSize ? (tokenSize << 1) : 64;
381	    nbuf = realloc(tokenBuf, nsize);
382	    if (!nbuf)
383		return EALLOC;
384	    tokenBuf = nbuf;
385	    tokenSize = nsize;
386	    t = tokenBuf + count;
387	}
388	c = lexc(file);
389	switch (charClass) {
390	case QUOTE:
391	    switch (state) {
392	    case Begin:
393	    case Normal:
394		state = Quoted;
395		break;
396	    case Quoted:
397		state = Normal;
398		break;
399	    case Comment:
400		break;
401	    }
402	    break;
403	case WHITE:
404	    switch (state) {
405	    case Begin:
406	    case Comment:
407		continue;
408	    case Normal:
409		*t = '\0';
410		*lexToken = tokenBuf;
411		return NAME;
412	    case Quoted:
413		break;
414	    }
415	    /* fall through */
416	case NORMAL:
417	    switch (state) {
418	    case Begin:
419		state = Normal;
420		break;
421	    case Comment:
422		continue;
423	    default:
424		break;
425	    }
426	    *t++ = c;
427	    ++count;
428	    break;
429	case END:
430	case NL:
431	    switch (state) {
432	    case Begin:
433	    case Comment:
434		*lexToken = (char *) NULL;
435		return charClass == END ? DONE : NEWLINE;
436	    default:
437		*t = '\0';
438		*lexToken = tokenBuf;
439		ungetc(c, file);
440		return NAME;
441	    }
442	    break;
443	case BANG:
444	    switch (state) {
445	    case Begin:
446		state = Comment;
447		break;
448            case Comment:
449		break;
450            default:
451		*t++ = c;
452		++count;
453	    }
454	    break;
455	}
456    }
457}
458
459static int
460lexc(FILE *file)
461{
462    int         c;
463
464    c = getc(file);
465    switch (c) {
466    case EOF:
467	charClass = END;
468	break;
469    case '\\':
470	c = getc(file);
471	if (c == EOF)
472	    charClass = END;
473	else
474	    charClass = NORMAL;
475	break;
476    case '"':
477	charClass = QUOTE;
478	break;
479    case ' ':
480    case '\t':
481	charClass = WHITE;
482	break;
483    case '\r':
484    case '\n':
485	charClass = NL;
486	break;
487    case '!':
488	charClass = BANG;
489	break;
490    default:
491	charClass = NORMAL;
492	break;
493    }
494    return c;
495}
496