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