fontdir.c revision 60da515c
1a96d7823Smrg/*
2a96d7823Smrg
3a96d7823SmrgCopyright 1991, 1998  The Open Group
4a96d7823Smrg
5a96d7823SmrgPermission to use, copy, modify, distribute, and sell this software and its
6a96d7823Smrgdocumentation for any purpose is hereby granted without fee, provided that
7a96d7823Smrgthe above copyright notice appear in all copies and that both that
8a96d7823Smrgcopyright notice and this permission notice appear in supporting
9a96d7823Smrgdocumentation.
10a96d7823Smrg
11a96d7823SmrgThe above copyright notice and this permission notice shall be included in
12a96d7823Smrgall copies or substantial portions of the Software.
13a96d7823Smrg
14a96d7823SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15a96d7823SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16a96d7823SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17a96d7823SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18a96d7823SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19a96d7823SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20a96d7823Smrg
21a96d7823SmrgExcept as contained in this notice, the name of The Open Group shall not be
22a96d7823Smrgused in advertising or otherwise to promote the sale, use or other dealings
23a96d7823Smrgin this Software without prior written authorization from The Open Group.
24a96d7823Smrg
25a96d7823Smrg*/
26a96d7823Smrg
27a96d7823Smrg/*
28a96d7823Smrg * Author:  Keith Packard, MIT X Consortium
29a96d7823Smrg */
30a96d7823Smrg
31a96d7823Smrg#ifdef HAVE_CONFIG_H
32a96d7823Smrg#include <config.h>
33a96d7823Smrg#endif
34a96d7823Smrg#include "libxfontint.h"
35a96d7823Smrg#include    <X11/fonts/fntfilst.h>
36a96d7823Smrg#include    <X11/keysym.h>
37c7b4381aSmrg#include "src/util/replace.h"
38a96d7823Smrg
39a96d7823Smrg#if HAVE_STDINT_H
40a96d7823Smrg#include <stdint.h>
41a96d7823Smrg#elif !defined(INT32_MAX)
42a96d7823Smrg#define INT32_MAX 0x7fffffff
43a96d7823Smrg#endif
44a96d7823Smrg
45a96d7823SmrgBool
46a96d7823SmrgFontFileInitTable (FontTablePtr table, int size)
47a96d7823Smrg{
48a96d7823Smrg    if (size < 0 || (size > INT32_MAX/sizeof(FontEntryRec)))
49a96d7823Smrg	return FALSE;
50a96d7823Smrg    if (size)
51a96d7823Smrg    {
52c7b4381aSmrg	table->entries = mallocarray(size, sizeof(FontEntryRec));
53a96d7823Smrg	if (!table->entries)
54a96d7823Smrg	    return FALSE;
55a96d7823Smrg    }
56a96d7823Smrg    else
57a96d7823Smrg	table->entries = 0;
58a96d7823Smrg    table->used = 0;
59a96d7823Smrg    table->size = size;
60a96d7823Smrg    table->sorted = FALSE;
61a96d7823Smrg    return TRUE;
62a96d7823Smrg}
63a96d7823Smrg
64a96d7823Smrgvoid
65a96d7823SmrgFontFileFreeEntry (FontEntryPtr entry)
66a96d7823Smrg{
67a96d7823Smrg    FontScalableExtraPtr   extra;
68a96d7823Smrg    int i;
69a96d7823Smrg
70a96d7823Smrg    if (entry->name.name)
71a96d7823Smrg	free(entry->name.name);
72a96d7823Smrg    entry->name.name = NULL;
73a96d7823Smrg
74a96d7823Smrg    switch (entry->type)
75a96d7823Smrg    {
76a96d7823Smrg    case FONT_ENTRY_SCALABLE:
77a96d7823Smrg	free (entry->u.scalable.fileName);
78a96d7823Smrg	extra = entry->u.scalable.extra;
79a96d7823Smrg	for (i = 0; i < extra->numScaled; i++)
80a96d7823Smrg	    if (extra->scaled[i].vals.ranges)
81a96d7823Smrg		free (extra->scaled[i].vals.ranges);
82a96d7823Smrg	free (extra->scaled);
83a96d7823Smrg	free (extra);
84a96d7823Smrg	break;
85a96d7823Smrg    case FONT_ENTRY_BITMAP:
86a96d7823Smrg	free (entry->u.bitmap.fileName);
87a96d7823Smrg	entry->u.bitmap.fileName = NULL;
88a96d7823Smrg	break;
89a96d7823Smrg    case FONT_ENTRY_ALIAS:
90a96d7823Smrg	free (entry->u.alias.resolved);
91a96d7823Smrg	entry->u.alias.resolved = NULL;
92a96d7823Smrg	break;
93a96d7823Smrg    }
94a96d7823Smrg}
95a96d7823Smrg
96a96d7823Smrgvoid
97a96d7823SmrgFontFileFreeTable (FontTablePtr table)
98a96d7823Smrg{
99a96d7823Smrg    int	i;
100a96d7823Smrg
101a96d7823Smrg    for (i = 0; i < table->used; i++)
102a96d7823Smrg	FontFileFreeEntry (&table->entries[i]);
103a96d7823Smrg    free (table->entries);
104a96d7823Smrg}
105a96d7823Smrg
106a96d7823SmrgFontDirectoryPtr
107a96d7823SmrgFontFileMakeDir(const char *dirName, int size)
108a96d7823Smrg{
109a96d7823Smrg    FontDirectoryPtr	dir;
110a96d7823Smrg    int			dirlen;
111a96d7823Smrg    int			needslash = 0;
112a96d7823Smrg    const char		*attrib;
113a96d7823Smrg    int			attriblen;
114a96d7823Smrg
115a96d7823Smrg#if !defined(WIN32)
116a96d7823Smrg    attrib = strchr(dirName, ':');
117a96d7823Smrg#else
118a96d7823Smrg    /* OS/2 uses the colon in the drive letter descriptor, skip this */
119a96d7823Smrg    attrib = strchr(dirName+2, ':');
120a96d7823Smrg#endif
121a96d7823Smrg    if (attrib) {
122a96d7823Smrg	dirlen = attrib - dirName;
123a96d7823Smrg	attriblen = strlen(attrib);
124a96d7823Smrg    } else {
125a96d7823Smrg	dirlen = strlen(dirName);
126a96d7823Smrg	attriblen = 0;
127a96d7823Smrg    }
12860da515cSmrg    if (dirlen && dirName[dirlen - 1] != '/')
129a96d7823Smrg	needslash = 1;
130a96d7823Smrg    dir = malloc(sizeof *dir + dirlen + needslash + 1 +
131a96d7823Smrg		 (attriblen ? attriblen + 1 : 0));
132a96d7823Smrg    if (!dir)
133a96d7823Smrg	return (FontDirectoryPtr)0;
134a96d7823Smrg    if (!FontFileInitTable (&dir->scalable, 0))
135a96d7823Smrg    {
136a96d7823Smrg	free (dir);
137a96d7823Smrg	return (FontDirectoryPtr)0;
138a96d7823Smrg    }
139a96d7823Smrg    if (!FontFileInitTable (&dir->nonScalable, size))
140a96d7823Smrg    {
141a96d7823Smrg	FontFileFreeTable (&dir->scalable);
142a96d7823Smrg	free (dir);
143a96d7823Smrg	return (FontDirectoryPtr)0;
144a96d7823Smrg    }
145a96d7823Smrg    dir->directory = (char *) (dir + 1);
146a96d7823Smrg    dir->dir_mtime = 0;
147a96d7823Smrg    dir->alias_mtime = 0;
148a96d7823Smrg    if (attriblen)
149a96d7823Smrg	dir->attributes = dir->directory + dirlen + needslash + 1;
150a96d7823Smrg    else
151a96d7823Smrg	dir->attributes = NULL;
152a96d7823Smrg    strncpy(dir->directory, dirName, dirlen);
153a96d7823Smrg    if (needslash)
154c7b4381aSmrg	dir->directory[dirlen] = '/';
155c7b4381aSmrg    dir->directory[dirlen + needslash] = '\0';
156c7b4381aSmrg    if (dir->attributes)
157c7b4381aSmrg	strlcpy(dir->attributes, attrib, attriblen + 1);
158a96d7823Smrg    return dir;
159a96d7823Smrg}
160a96d7823Smrg
161a96d7823Smrgvoid
162a96d7823SmrgFontFileFreeDir (FontDirectoryPtr dir)
163a96d7823Smrg{
164a96d7823Smrg    FontFileFreeTable (&dir->scalable);
165a96d7823Smrg    FontFileFreeTable (&dir->nonScalable);
166a96d7823Smrg    free(dir);
167a96d7823Smrg}
168a96d7823Smrg
169a96d7823SmrgFontEntryPtr
170a96d7823SmrgFontFileAddEntry(FontTablePtr table, FontEntryPtr prototype)
171a96d7823Smrg{
172a96d7823Smrg    FontEntryPtr    entry;
173a96d7823Smrg    int		    newsize;
174a96d7823Smrg
175a96d7823Smrg    /* can't add entries to a sorted table, pointers get broken! */
176a96d7823Smrg    if (table->sorted)
177a96d7823Smrg	return (FontEntryPtr) 0;    /* "cannot" happen */
178a96d7823Smrg    if (table->used == table->size) {
179a96d7823Smrg	if (table->size >= ((INT32_MAX / sizeof(FontEntryRec)) - 100))
180a96d7823Smrg	    /* If we've read so many entries we're going to ask for 2gb
181a96d7823Smrg	       or more of memory, something is so wrong with this font
182a96d7823Smrg	       directory that we should just give up before we overflow. */
183a96d7823Smrg	    return NULL;
184a96d7823Smrg	newsize = table->size + 100;
185c7b4381aSmrg	entry = reallocarray(table->entries, newsize, sizeof(FontEntryRec));
186a96d7823Smrg	if (!entry)
187a96d7823Smrg	    return (FontEntryPtr)0;
188a96d7823Smrg	table->size = newsize;
189a96d7823Smrg	table->entries = entry;
190a96d7823Smrg    }
191a96d7823Smrg    entry = &table->entries[table->used];
192a96d7823Smrg    *entry = *prototype;
193a96d7823Smrg    entry->name.name = malloc(prototype->name.length + 1);
194a96d7823Smrg    if (!entry->name.name)
195a96d7823Smrg	return (FontEntryPtr)0;
196a96d7823Smrg    memcpy (entry->name.name, prototype->name.name, prototype->name.length);
197a96d7823Smrg    entry->name.name[entry->name.length] = '\0';
198a96d7823Smrg    table->used++;
199a96d7823Smrg    return entry;
200a96d7823Smrg}
201a96d7823Smrg
202a96d7823Smrg/*
203a96d7823Smrg * Compare two strings just like strcmp, but preserve decimal integer
204a96d7823Smrg * sorting order, i.e. "2" < "10" or "iso8859-2" < "iso8859-10" <
205a96d7823Smrg * "iso10646-1". Strings are sorted as if sequences of digits were
206a96d7823Smrg * prefixed by a length indicator (i.e., does not ignore leading zeroes).
207a96d7823Smrg *
208a96d7823Smrg * Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk>
209a96d7823Smrg */
210a96d7823Smrg#define Xisdigit(c) ('\060' <= (c) && (c) <= '\071')
211a96d7823Smrg
212a96d7823Smrgstatic int strcmpn(const char *s1, const char *s2)
213a96d7823Smrg{
214a96d7823Smrg    int digits, predigits = 0;
215a96d7823Smrg    const char *ss1, *ss2;
216a96d7823Smrg
217a96d7823Smrg    while (1) {
218a96d7823Smrg	if (*s1 == 0 && *s2 == 0)
219a96d7823Smrg	    return 0;
220a96d7823Smrg	digits = Xisdigit(*s1) && Xisdigit(*s2);
221a96d7823Smrg	if (digits && !predigits) {
222a96d7823Smrg	    ss1 = s1;
223a96d7823Smrg	    ss2 = s2;
224a96d7823Smrg	    while (Xisdigit(*ss1) && Xisdigit(*ss2))
225a96d7823Smrg		ss1++, ss2++;
226a96d7823Smrg	    if (!Xisdigit(*ss1) && Xisdigit(*ss2))
227a96d7823Smrg		return -1;
228a96d7823Smrg	    if (Xisdigit(*ss1) && !Xisdigit(*ss2))
229a96d7823Smrg		return 1;
230a96d7823Smrg	}
231a96d7823Smrg	if ((unsigned char)*s1 < (unsigned char)*s2)
232a96d7823Smrg	    return -1;
233a96d7823Smrg	if ((unsigned char)*s1 > (unsigned char)*s2)
234a96d7823Smrg	    return 1;
235a96d7823Smrg	predigits = digits;
236a96d7823Smrg	s1++, s2++;
237a96d7823Smrg    }
238a96d7823Smrg}
239a96d7823Smrg
240a96d7823Smrg
241a96d7823Smrgstatic int
242a96d7823SmrgFontFileNameCompare(const void* a, const void* b)
243a96d7823Smrg{
244a96d7823Smrg    FontEntryPtr    a_name = (FontEntryPtr) a,
245a96d7823Smrg		    b_name = (FontEntryPtr) b;
246a96d7823Smrg
247a96d7823Smrg    return strcmpn(a_name->name.name, b_name->name.name);
248a96d7823Smrg}
249a96d7823Smrg
250a96d7823Smrgvoid
251a96d7823SmrgFontFileSortTable (FontTablePtr table)
252a96d7823Smrg{
253a96d7823Smrg    if (!table->sorted) {
254a96d7823Smrg	qsort((char *) table->entries, table->used, sizeof(FontEntryRec),
255a96d7823Smrg	      FontFileNameCompare);
256a96d7823Smrg	table->sorted = TRUE;
257a96d7823Smrg    }
258a96d7823Smrg}
259a96d7823Smrg
260a96d7823Smrgvoid
261a96d7823SmrgFontFileSortDir(FontDirectoryPtr dir)
262a96d7823Smrg{
263a96d7823Smrg    FontFileSortTable (&dir->scalable);
264a96d7823Smrg    FontFileSortTable (&dir->nonScalable);
265a96d7823Smrg    /* now that the table is fixed in size, swizzle the pointers */
266a96d7823Smrg    FontFileSwitchStringsToBitmapPointers (dir);
267a96d7823Smrg}
268a96d7823Smrg
269a96d7823Smrg/*
270a96d7823Smrg  Given a Font Table, SetupWildMatch() sets up various pointers and state
271a96d7823Smrg  information so the table can be searched for name(s) that match a given
272a96d7823Smrg  fontname pattern -- which may contain wildcards.  Under certain
273a96d7823Smrg  circumstances, SetupWildMatch() will find the one table entry that
274a96d7823Smrg  matches the pattern.  If those circumstances do not pertain,
275a96d7823Smrg  SetupWildMatch() returns a range within the the table that should be
276a96d7823Smrg  searched for matching name(s).  With the information established by
277a96d7823Smrg  SetupWildMatch(), including state information in "private", the
278a96d7823Smrg  PatternMatch() procedure is then used to test names in the range for a
279a96d7823Smrg  match.
280a96d7823Smrg*/
281a96d7823Smrg
282a96d7823Smrg#define isWild(c)   ((c) == XK_asterisk || (c) == XK_question)
283a96d7823Smrg#define isDigit(c)  (XK_0 <= (c) && (c) <= XK_9)
284a96d7823Smrg
285a96d7823Smrgstatic int
286a96d7823SmrgSetupWildMatch(FontTablePtr table, FontNamePtr pat,
287a96d7823Smrg	       int *leftp, int *rightp, int *privatep)
288a96d7823Smrg{
289a96d7823Smrg    int         nDashes;
290a96d7823Smrg    char        c;
291a96d7823Smrg    char       *t;
292a96d7823Smrg    char       *firstWild;
293a96d7823Smrg    char       *firstDigit;
294a96d7823Smrg    int         first;
295a96d7823Smrg    int         center,
296a96d7823Smrg                left,
297a96d7823Smrg                right;
298a96d7823Smrg    int         result;
299a96d7823Smrg    char	*name;
300a96d7823Smrg
301a96d7823Smrg    name = pat->name;
302a96d7823Smrg    nDashes = pat->ndashes;
303a96d7823Smrg    firstWild = 0;
304a96d7823Smrg    firstDigit = 0;
305a96d7823Smrg    t = name;
306a96d7823Smrg    while ((c = *t++)) {
307a96d7823Smrg	if (isWild(c)) {
308a96d7823Smrg	    if (!firstWild)
309a96d7823Smrg		firstWild = t - 1;
310a96d7823Smrg	}
311a96d7823Smrg	if (isDigit(c)) {
312a96d7823Smrg	    if (!firstDigit)
313a96d7823Smrg		firstDigit = t - 1;
314a96d7823Smrg	}
315a96d7823Smrg    }
316a96d7823Smrg    left = 0;
317a96d7823Smrg    right = table->used;
318a96d7823Smrg    if (firstWild)
319a96d7823Smrg	*privatep = nDashes;
320a96d7823Smrg    else
321a96d7823Smrg	*privatep = -1;
322a96d7823Smrg    if (!table->sorted) {
323a96d7823Smrg	*leftp = left;
324a96d7823Smrg	*rightp = right;
325a96d7823Smrg	return -1;
326a96d7823Smrg    } else if (firstWild) {
327a96d7823Smrg	if (firstDigit && firstDigit < firstWild)
328a96d7823Smrg	    first = firstDigit - name;
329a96d7823Smrg	else
330a96d7823Smrg	    first = firstWild - name;
331a96d7823Smrg	while (left < right) {
332a96d7823Smrg	    center = (left + right) / 2;
333a96d7823Smrg	    result = strncmp(name, table->entries[center].name.name, first);
334a96d7823Smrg	    if (result == 0)
335a96d7823Smrg		break;
336a96d7823Smrg	    if (result < 0)
337a96d7823Smrg		right = center;
338a96d7823Smrg	    else
339a96d7823Smrg		left = center + 1;
340a96d7823Smrg	}
341a96d7823Smrg	*leftp = left;
342a96d7823Smrg	*rightp = right;
343a96d7823Smrg	return -1;
344a96d7823Smrg    } else {
345a96d7823Smrg	while (left < right) {
346a96d7823Smrg	    center = (left + right) / 2;
347a96d7823Smrg	    result = strcmpn(name, table->entries[center].name.name);
348a96d7823Smrg	    if (result == 0)
349a96d7823Smrg		return center;
350a96d7823Smrg	    if (result < 0)
351a96d7823Smrg		right = center;
352a96d7823Smrg	    else
353a96d7823Smrg		left = center + 1;
354a96d7823Smrg	}
355a96d7823Smrg	*leftp = 1;
356a96d7823Smrg	*rightp = 0;
357a96d7823Smrg	return -1;
358a96d7823Smrg    }
359a96d7823Smrg}
360a96d7823Smrg
361a96d7823Smrgstatic int
362a96d7823SmrgPatternMatch(char *pat, int patdashes, char *string, int stringdashes)
363a96d7823Smrg{
364a96d7823Smrg    char        c,
365a96d7823Smrg                t;
366a96d7823Smrg
367a96d7823Smrg    if (stringdashes < patdashes)
368a96d7823Smrg	return 0;
369a96d7823Smrg    for (;;) {
370a96d7823Smrg	switch (c = *pat++) {
371a96d7823Smrg	case '*':
372a96d7823Smrg	    if (!(c = *pat++))
373a96d7823Smrg		return 1;
374a96d7823Smrg	    if (c == XK_minus) {
375a96d7823Smrg		patdashes--;
376a96d7823Smrg		for (;;) {
377a96d7823Smrg		    while ((t = *string++) != XK_minus)
378a96d7823Smrg			if (!t)
379a96d7823Smrg			    return 0;
380a96d7823Smrg		    stringdashes--;
381a96d7823Smrg		    if (PatternMatch(pat, patdashes, string, stringdashes))
382a96d7823Smrg			return 1;
383a96d7823Smrg		    if (stringdashes == patdashes)
384a96d7823Smrg			return 0;
385a96d7823Smrg		}
386a96d7823Smrg	    } else {
387a96d7823Smrg		for (;;) {
388a96d7823Smrg		    while ((t = *string++) != c) {
389a96d7823Smrg			if (!t)
390a96d7823Smrg			    return 0;
391a96d7823Smrg			if (t == XK_minus) {
392a96d7823Smrg			    if (stringdashes-- < patdashes)
393a96d7823Smrg				return 0;
394a96d7823Smrg			}
395a96d7823Smrg		    }
396a96d7823Smrg		    if (PatternMatch(pat, patdashes, string, stringdashes))
397a96d7823Smrg			return 1;
398a96d7823Smrg		}
399a96d7823Smrg	    }
400a96d7823Smrg	case '?':
401fd60135fSmrg	    if ((t = *string++) == XK_minus)
402a96d7823Smrg		stringdashes--;
403fd60135fSmrg	    if (!t)
404fd60135fSmrg		return 0;
405a96d7823Smrg	    break;
406a96d7823Smrg	case '\0':
407a96d7823Smrg	    return (*string == '\0');
408a96d7823Smrg	case XK_minus:
409a96d7823Smrg	    if (*string++ == XK_minus) {
410a96d7823Smrg		patdashes--;
411a96d7823Smrg		stringdashes--;
412a96d7823Smrg		break;
413a96d7823Smrg	    }
414a96d7823Smrg	    return 0;
415a96d7823Smrg	default:
416a96d7823Smrg	    if (c == *string++)
417a96d7823Smrg		break;
418a96d7823Smrg	    return 0;
419a96d7823Smrg	}
420a96d7823Smrg    }
421a96d7823Smrg}
422a96d7823Smrg
423a96d7823Smrgint
424a96d7823SmrgFontFileCountDashes (char *name, int namelen)
425a96d7823Smrg{
426a96d7823Smrg    int	ndashes = 0;
427a96d7823Smrg
428a96d7823Smrg    while (namelen--)
429a96d7823Smrg	if (*name++ == '\055')	/* avoid non ascii systems */
430a96d7823Smrg	    ++ndashes;
431a96d7823Smrg    return ndashes;
432a96d7823Smrg}
433a96d7823Smrg
434a96d7823Smrg/* exported in public API in <X11/fonts/fntfil.h> */
435a96d7823Smrgchar *
436a96d7823SmrgFontFileSaveString (char *s)
437a96d7823Smrg{
438a96d7823Smrg    return strdup(s);
439a96d7823Smrg}
440a96d7823Smrg#define FontFileSaveString(s) strdup(s)
441a96d7823Smrg
442a96d7823SmrgFontEntryPtr
443a96d7823SmrgFontFileFindNameInScalableDir(FontTablePtr table, FontNamePtr pat,
444a96d7823Smrg			      FontScalablePtr vals)
445a96d7823Smrg{
446a96d7823Smrg    int         i,
447a96d7823Smrg                start,
448a96d7823Smrg                stop,
449a96d7823Smrg                res,
450a96d7823Smrg                private;
451a96d7823Smrg    FontNamePtr	name;
452a96d7823Smrg
453a96d7823Smrg    if (!table->entries)
454a96d7823Smrg	return NULL;
455a96d7823Smrg    if ((i = SetupWildMatch(table, pat, &start, &stop, &private)) >= 0)
456a96d7823Smrg	return &table->entries[i];
457a96d7823Smrg    for (i = start; i < stop; i++) {
458a96d7823Smrg	name = &table->entries[i].name;
459a96d7823Smrg	res = PatternMatch(pat->name, private, name->name, name->ndashes);
460a96d7823Smrg	if (res > 0)
461a96d7823Smrg	{
462a96d7823Smrg	    /* Check to see if enhancements requested are available */
463a96d7823Smrg	    if (vals)
464a96d7823Smrg	    {
465a96d7823Smrg		int vs = vals->values_supplied;
466a96d7823Smrg		int cap;
467a96d7823Smrg
468a96d7823Smrg		if (table->entries[i].type == FONT_ENTRY_SCALABLE)
469a96d7823Smrg		    cap = table->entries[i].u.scalable.renderer->capabilities;
470a96d7823Smrg		else if (table->entries[i].type == FONT_ENTRY_ALIAS)
471a96d7823Smrg		    cap = ~0;	/* Calling code will have to see if true */
472a96d7823Smrg		else
473a96d7823Smrg		    cap = 0;
474a96d7823Smrg		if ((((vs & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
475a96d7823Smrg		      (vs & POINTSIZE_MASK) == POINTSIZE_ARRAY) &&
476a96d7823Smrg		     !(cap & CAP_MATRIX)) ||
477a96d7823Smrg		    ((vs & CHARSUBSET_SPECIFIED) &&
478a96d7823Smrg		     !(cap & CAP_CHARSUBSETTING)))
479a96d7823Smrg		    continue;
480a96d7823Smrg	    }
481a96d7823Smrg	    return &table->entries[i];
482a96d7823Smrg	}
483a96d7823Smrg	if (res < 0)
484a96d7823Smrg	    break;
485a96d7823Smrg    }
486a96d7823Smrg    return (FontEntryPtr)0;
487a96d7823Smrg}
488a96d7823Smrg
489a96d7823SmrgFontEntryPtr
490a96d7823SmrgFontFileFindNameInDir(FontTablePtr table, FontNamePtr pat)
491a96d7823Smrg{
492a96d7823Smrg    return FontFileFindNameInScalableDir(table, pat, (FontScalablePtr)0);
493a96d7823Smrg}
494a96d7823Smrg
495a96d7823Smrgint
496a96d7823SmrgFontFileFindNamesInScalableDir(FontTablePtr table, FontNamePtr pat, int max,
497a96d7823Smrg			       FontNamesPtr names, FontScalablePtr vals,
498a96d7823Smrg			       int alias_behavior, int *newmax)
499a96d7823Smrg{
500a96d7823Smrg    int		    i,
501a96d7823Smrg		    start,
502a96d7823Smrg		    stop,
503a96d7823Smrg		    res,
504a96d7823Smrg		    private;
505a96d7823Smrg    int		    ret = Successful;
506a96d7823Smrg    FontEntryPtr    fname;
507a96d7823Smrg    FontNamePtr	    name;
508a96d7823Smrg
509a96d7823Smrg    if (max <= 0)
510a96d7823Smrg	return Successful;
511a96d7823Smrg    if ((i = SetupWildMatch(table, pat, &start, &stop, &private)) >= 0) {
512a96d7823Smrg	if (alias_behavior == NORMAL_ALIAS_BEHAVIOR ||
513a96d7823Smrg	    table->entries[i].type != FONT_ENTRY_ALIAS)
514a96d7823Smrg	{
515a96d7823Smrg	    name = &table->entries[i].name;
516a96d7823Smrg	    if (newmax) *newmax = max - 1;
517a96d7823Smrg	    return xfont2_add_font_names_name(names, name->name, name->length);
518a96d7823Smrg	}
519a96d7823Smrg	start = i;
520a96d7823Smrg	stop = i + 1;
521a96d7823Smrg    }
522a96d7823Smrg    for (i = start, fname = &table->entries[start]; i < stop; i++, fname++) {
523a96d7823Smrg	res = PatternMatch(pat->name, private, fname->name.name, fname->name.ndashes);
524a96d7823Smrg	if (res > 0) {
525a96d7823Smrg	    if (vals)
526a96d7823Smrg	    {
527a96d7823Smrg		int vs = vals->values_supplied;
528a96d7823Smrg		int cap;
529a96d7823Smrg
530a96d7823Smrg		if (fname->type == FONT_ENTRY_SCALABLE)
531a96d7823Smrg		    cap = fname->u.scalable.renderer->capabilities;
532a96d7823Smrg		else if (fname->type == FONT_ENTRY_ALIAS)
533a96d7823Smrg		    cap = ~0;	/* Calling code will have to see if true */
534a96d7823Smrg		else
535a96d7823Smrg		    cap = 0;
536a96d7823Smrg		if ((((vs & PIXELSIZE_MASK) == PIXELSIZE_ARRAY ||
537a96d7823Smrg		     (vs & POINTSIZE_MASK) == POINTSIZE_ARRAY) &&
538a96d7823Smrg		    !(cap & CAP_MATRIX)) ||
539a96d7823Smrg		    ((vs & CHARSUBSET_SPECIFIED) &&
540a96d7823Smrg		    !(cap & CAP_CHARSUBSETTING)))
541a96d7823Smrg		    continue;
542a96d7823Smrg	    }
543a96d7823Smrg
544a96d7823Smrg	    if ((alias_behavior & IGNORE_SCALABLE_ALIASES) &&
545a96d7823Smrg		fname->type == FONT_ENTRY_ALIAS)
546a96d7823Smrg	    {
547a96d7823Smrg		FontScalableRec	tmpvals;
548a96d7823Smrg		if (FontParseXLFDName (fname->name.name, &tmpvals,
549a96d7823Smrg				       FONT_XLFD_REPLACE_NONE) &&
550a96d7823Smrg		    !(tmpvals.values_supplied & SIZE_SPECIFY_MASK))
551a96d7823Smrg		    continue;
552a96d7823Smrg	    }
553a96d7823Smrg
554a96d7823Smrg	    ret = xfont2_add_font_names_name(names, fname->name.name, fname->name.length);
555a96d7823Smrg	    if (ret != Successful)
556a96d7823Smrg		goto bail;
557a96d7823Smrg
558a96d7823Smrg	    /* If alias_behavior is LIST_ALIASES_AND_TARGET_NAMES, mark
559a96d7823Smrg	       this entry as an alias by negating its length and follow
560a96d7823Smrg	       it by the resolved name */
561a96d7823Smrg	    if ((alias_behavior & LIST_ALIASES_AND_TARGET_NAMES) &&
562a96d7823Smrg		fname->type == FONT_ENTRY_ALIAS)
563a96d7823Smrg	    {
564a96d7823Smrg		names->length[names->nnames - 1] =
565a96d7823Smrg		    -names->length[names->nnames - 1];
566a96d7823Smrg		ret = xfont2_add_font_names_name(names, fname->u.alias.resolved,
567a96d7823Smrg				       strlen(fname->u.alias.resolved));
568a96d7823Smrg		if (ret != Successful)
569a96d7823Smrg		    goto bail;
570a96d7823Smrg	    }
571a96d7823Smrg
572a96d7823Smrg	    if (--max <= 0)
573a96d7823Smrg		break;
574a96d7823Smrg	} else if (res < 0)
575a96d7823Smrg	    break;
576a96d7823Smrg    }
577a96d7823Smrg  bail: ;
578a96d7823Smrg    if (newmax) *newmax = max;
579a96d7823Smrg    return ret;
580a96d7823Smrg}
581a96d7823Smrg
582a96d7823Smrgint
583a96d7823SmrgFontFileFindNamesInDir(FontTablePtr table, FontNamePtr pat,
584a96d7823Smrg		       int max, FontNamesPtr names)
585a96d7823Smrg{
586a96d7823Smrg    return FontFileFindNamesInScalableDir(table, pat, max, names,
587a96d7823Smrg					  (FontScalablePtr)0,
588a96d7823Smrg					  NORMAL_ALIAS_BEHAVIOR, (int *)0);
589a96d7823Smrg}
590a96d7823Smrg
591a96d7823SmrgBool
592a96d7823SmrgFontFileMatchName(char *name, int length, FontNamePtr pat)
593a96d7823Smrg{
594a96d7823Smrg    /* Perform a fontfile-type name match on a single name */
595a96d7823Smrg    FontTableRec table;
596a96d7823Smrg    FontEntryRec entries[1];
597a96d7823Smrg
598a96d7823Smrg    /* Dummy up a table */
599a96d7823Smrg    table.used = 1;
600a96d7823Smrg    table.size = 1;
601a96d7823Smrg    table.sorted = TRUE;
602a96d7823Smrg    table.entries = entries;
603a96d7823Smrg    entries[0].name.name = name;
604a96d7823Smrg    entries[0].name.length = length;
605a96d7823Smrg    entries[0].name.ndashes = FontFileCountDashes(name, length);
606a96d7823Smrg
607a96d7823Smrg    return FontFileFindNameInDir(&table, pat) != (FontEntryPtr)0;
608a96d7823Smrg}
609a96d7823Smrg
610a96d7823Smrg/*
611a96d7823Smrg * Add a font file to a directory.  This handles bitmap and
612a96d7823Smrg * scalable names both
613a96d7823Smrg */
614a96d7823Smrg
615a96d7823SmrgBool
616a96d7823SmrgFontFileAddFontFile (FontDirectoryPtr dir, char *fontName, char *fileName)
617a96d7823Smrg{
618a96d7823Smrg    FontEntryRec	    entry;
619a96d7823Smrg    FontScalableRec	    vals, zeroVals;
620a96d7823Smrg    FontRendererPtr	    renderer;
621a96d7823Smrg    FontEntryPtr	    existing;
622a96d7823Smrg    FontScalableExtraPtr    extra;
623a96d7823Smrg    FontEntryPtr	    bitmap = 0, scalable;
624a96d7823Smrg    Bool		    isscale;
625a96d7823Smrg    Bool		    scalable_xlfd;
626a96d7823Smrg
627a96d7823Smrg    renderer = FontFileMatchRenderer (fileName);
628a96d7823Smrg    if (!renderer)
629a96d7823Smrg	return FALSE;
630a96d7823Smrg    entry.name.length = strlen (fontName);
631a96d7823Smrg    if (entry.name.length > MAXFONTNAMELEN)
632a96d7823Smrg	entry.name.length = MAXFONTNAMELEN;
633a96d7823Smrg    entry.name.name = fontName;
634a96d7823Smrg    CopyISOLatin1Lowered (entry.name.name, fontName, entry.name.length);
635a96d7823Smrg    entry.name.ndashes = FontFileCountDashes (entry.name.name, entry.name.length);
636a96d7823Smrg    entry.name.name[entry.name.length] = '\0';
637a96d7823Smrg    /*
638a96d7823Smrg     * Add a bitmap name if the incoming name isn't an XLFD name, or
639a96d7823Smrg     * if it isn't a scalable name (i.e. non-zero scalable fields)
640a96d7823Smrg     *
641a96d7823Smrg     * If name of bitmapped font contains XLFD enhancements, do not add
642a96d7823Smrg     * a scalable version of the name... this can lead to confusion and
643a96d7823Smrg     * ambiguity between the font name and the field enhancements.
644a96d7823Smrg     */
645a96d7823Smrg    isscale = entry.name.ndashes == 14 &&
646a96d7823Smrg	      FontParseXLFDName(entry.name.name,
647a96d7823Smrg				&vals, FONT_XLFD_REPLACE_NONE) &&
648a96d7823Smrg	      (vals.values_supplied & PIXELSIZE_MASK) != PIXELSIZE_ARRAY &&
649a96d7823Smrg	      (vals.values_supplied & POINTSIZE_MASK) != POINTSIZE_ARRAY &&
650a96d7823Smrg	      !(vals.values_supplied & ENHANCEMENT_SPECIFY_MASK);
651a96d7823Smrg#define UNSCALED_ATTRIB "unscaled"
652a96d7823Smrg    scalable_xlfd = (isscale &&
653a96d7823Smrg		(((vals.values_supplied & PIXELSIZE_MASK) == 0) ||
654a96d7823Smrg		 ((vals.values_supplied & POINTSIZE_MASK) == 0)));
655a96d7823Smrg    /*
656a96d7823Smrg     * For scalable fonts without a scalable XFLD, check if the "unscaled"
657a96d7823Smrg     * attribute is present.
658a96d7823Smrg     */
659a96d7823Smrg    if (isscale && !scalable_xlfd &&
660a96d7823Smrg	    dir->attributes && dir->attributes[0] == ':') {
661a96d7823Smrg	char *ptr1 = dir->attributes + 1;
662a96d7823Smrg	char *ptr2;
663a96d7823Smrg	int length;
664a96d7823Smrg	int uslength = strlen(UNSCALED_ATTRIB);
665a96d7823Smrg
666a96d7823Smrg	do {
667a96d7823Smrg	    ptr2 = strchr(ptr1, ':');
668a96d7823Smrg	    if (ptr2)
669a96d7823Smrg		length = ptr2 - ptr1;
670a96d7823Smrg	    else
671a96d7823Smrg		length = dir->attributes + strlen(dir->attributes) - ptr1;
672a96d7823Smrg	    if (length == uslength && !strncmp(ptr1, UNSCALED_ATTRIB, uslength))
673a96d7823Smrg		isscale = FALSE;
674a96d7823Smrg	    if (ptr2)
675a96d7823Smrg		ptr1 = ptr2 + 1;
676a96d7823Smrg	} while (ptr2);
677a96d7823Smrg    }
678a96d7823Smrg    if (!isscale || (vals.values_supplied & SIZE_SPECIFY_MASK))
679a96d7823Smrg    {
680a96d7823Smrg      /*
681a96d7823Smrg       * If the renderer doesn't support OpenBitmap, FontFileOpenFont
682a96d7823Smrg       * will still do the right thing.
683a96d7823Smrg       */
684a96d7823Smrg	entry.type = FONT_ENTRY_BITMAP;
685a96d7823Smrg	entry.u.bitmap.renderer = renderer;
686a96d7823Smrg	entry.u.bitmap.pFont = NullFont;
687a96d7823Smrg	if (!(entry.u.bitmap.fileName = FontFileSaveString (fileName)))
688a96d7823Smrg	    return FALSE;
689a96d7823Smrg	if (!(bitmap = FontFileAddEntry (&dir->nonScalable, &entry)))
690a96d7823Smrg	{
691a96d7823Smrg	    free (entry.u.bitmap.fileName);
692a96d7823Smrg	    return FALSE;
693a96d7823Smrg	}
694a96d7823Smrg    }
695a96d7823Smrg    /*
696a96d7823Smrg     * Parse out scalable fields from XLFD names - a scalable name
697a96d7823Smrg     * just gets inserted, a scaled name has more things to do.
698a96d7823Smrg     */
699a96d7823Smrg    if (isscale)
700a96d7823Smrg    {
701a96d7823Smrg	if (vals.values_supplied & SIZE_SPECIFY_MASK)
702a96d7823Smrg	{
703a96d7823Smrg	    bzero((char *)&zeroVals, sizeof(zeroVals));
704a96d7823Smrg	    zeroVals.x = vals.x;
705a96d7823Smrg	    zeroVals.y = vals.y;
706a96d7823Smrg	    zeroVals.values_supplied = PIXELSIZE_SCALAR | POINTSIZE_SCALAR;
707a96d7823Smrg	    FontParseXLFDName (entry.name.name, &zeroVals,
708a96d7823Smrg			       FONT_XLFD_REPLACE_VALUE);
709a96d7823Smrg	    entry.name.length = strlen (entry.name.name);
710a96d7823Smrg	    existing = FontFileFindNameInDir (&dir->scalable, &entry.name);
711a96d7823Smrg	    if (existing)
712a96d7823Smrg	    {
713a96d7823Smrg		if ((vals.values_supplied & POINTSIZE_MASK) ==
714a96d7823Smrg			POINTSIZE_SCALAR &&
715a96d7823Smrg		    (int)(vals.point_matrix[3] * 10) == GetDefaultPointSize())
716a96d7823Smrg		{
717a96d7823Smrg		    existing->u.scalable.extra->defaults = vals;
718a96d7823Smrg
719a96d7823Smrg		    free (existing->u.scalable.fileName);
720a96d7823Smrg		    if (!(existing->u.scalable.fileName = FontFileSaveString (fileName)))
721a96d7823Smrg			return FALSE;
722a96d7823Smrg		}
723a96d7823Smrg                if(bitmap)
724a96d7823Smrg                {
725a96d7823Smrg                    FontFileCompleteXLFD(&vals, &vals);
726a96d7823Smrg                    FontFileAddScaledInstance (existing, &vals, NullFont,
727a96d7823Smrg                                               bitmap->name.name);
728a96d7823Smrg                    return TRUE;
729a96d7823Smrg                }
730a96d7823Smrg	    }
731a96d7823Smrg	}
732a96d7823Smrg	if (!(entry.u.scalable.fileName = FontFileSaveString (fileName)))
733a96d7823Smrg	    return FALSE;
734a96d7823Smrg	extra = malloc (sizeof (FontScalableExtraRec));
735a96d7823Smrg	if (!extra)
736a96d7823Smrg	{
737a96d7823Smrg	    free (entry.u.scalable.fileName);
738a96d7823Smrg	    return FALSE;
739a96d7823Smrg	}
740a96d7823Smrg	bzero((char *)&extra->defaults, sizeof(extra->defaults));
741a96d7823Smrg	if ((vals.values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR &&
742a96d7823Smrg	    (int)(vals.point_matrix[3] * 10) == GetDefaultPointSize())
743a96d7823Smrg	    extra->defaults = vals;
744a96d7823Smrg	else
745a96d7823Smrg	{
746a96d7823Smrg	    FontResolutionPtr resolution;
747a96d7823Smrg	    int num;
748a96d7823Smrg	    int default_point_size = GetDefaultPointSize();
749a96d7823Smrg
750a96d7823Smrg	    extra->defaults.point_matrix[0] =
751a96d7823Smrg		extra->defaults.point_matrix[3] =
752a96d7823Smrg	            (double)default_point_size / 10.0;
753a96d7823Smrg	    extra->defaults.point_matrix[1] =
754a96d7823Smrg		extra->defaults.point_matrix[2] = 0.0;
755a96d7823Smrg	    extra->defaults.values_supplied =
756a96d7823Smrg		POINTSIZE_SCALAR | PIXELSIZE_UNDEFINED;
757a96d7823Smrg	    extra->defaults.width = -1;
758a96d7823Smrg	    if (vals.x <= 0 || vals.y <= 0)
759a96d7823Smrg	    {
760a96d7823Smrg	        resolution = GetClientResolutions (&num);
761a96d7823Smrg	        if (resolution && num > 0)
762a96d7823Smrg	        {
763a96d7823Smrg	    	    extra->defaults.x = resolution->x_resolution;
764a96d7823Smrg	    	    extra->defaults.y = resolution->y_resolution;
765a96d7823Smrg	        }
766a96d7823Smrg	        else
767a96d7823Smrg	        {
768a96d7823Smrg		    extra->defaults.x = 75;
769a96d7823Smrg		    extra->defaults.y = 75;
770a96d7823Smrg	        }
771a96d7823Smrg	     }
772a96d7823Smrg	     else
773a96d7823Smrg	     {
774a96d7823Smrg		extra->defaults.x = vals.x;
775a96d7823Smrg		extra->defaults.y = vals.y;
776a96d7823Smrg	     }
777a96d7823Smrg	     FontFileCompleteXLFD (&extra->defaults, &extra->defaults);
778a96d7823Smrg	}
779a96d7823Smrg	extra->numScaled = 0;
780a96d7823Smrg	extra->sizeScaled = 0;
781a96d7823Smrg	extra->scaled = 0;
782a96d7823Smrg	extra->private = 0;
783a96d7823Smrg	entry.type = FONT_ENTRY_SCALABLE;
784a96d7823Smrg	entry.u.scalable.renderer = renderer;
785a96d7823Smrg	entry.u.scalable.extra = extra;
786a96d7823Smrg	if (!(scalable = FontFileAddEntry (&dir->scalable, &entry)))
787a96d7823Smrg	{
788a96d7823Smrg	    free (extra);
789a96d7823Smrg	    free (entry.u.scalable.fileName);
790a96d7823Smrg	    return FALSE;
791a96d7823Smrg	}
792a96d7823Smrg	if (vals.values_supplied & SIZE_SPECIFY_MASK)
793a96d7823Smrg	{
794a96d7823Smrg            if(bitmap)
795a96d7823Smrg            {
796a96d7823Smrg                FontFileCompleteXLFD(&vals, &vals);
797a96d7823Smrg                FontFileAddScaledInstance (scalable, &vals, NullFont,
798a96d7823Smrg                                           bitmap->name.name);
799a96d7823Smrg            }
800a96d7823Smrg	}
801a96d7823Smrg    }
802a96d7823Smrg    return TRUE;
803a96d7823Smrg}
804a96d7823Smrg
805a96d7823SmrgBool
806a96d7823SmrgFontFileAddFontAlias (FontDirectoryPtr dir, char *aliasName, char *fontName)
807a96d7823Smrg{
808a96d7823Smrg    FontEntryRec	entry;
809a96d7823Smrg
810a96d7823Smrg    if (strcmp(aliasName,fontName) == 0) {
811a96d7823Smrg        /* Don't allow an alias to point to itself and create a loop */
812a96d7823Smrg        return FALSE;
813a96d7823Smrg    }
814a96d7823Smrg    entry.name.length = strlen (aliasName);
815a96d7823Smrg    CopyISOLatin1Lowered (aliasName, aliasName, entry.name.length);
816a96d7823Smrg    entry.name.name = aliasName;
817a96d7823Smrg    entry.name.ndashes = FontFileCountDashes (entry.name.name, entry.name.length);
818a96d7823Smrg    entry.type = FONT_ENTRY_ALIAS;
819a96d7823Smrg    if (!(entry.u.alias.resolved = FontFileSaveString (fontName)))
820a96d7823Smrg	return FALSE;
821a96d7823Smrg    if (!FontFileAddEntry (&dir->nonScalable, &entry))
822a96d7823Smrg    {
823a96d7823Smrg	free (entry.u.alias.resolved);
824a96d7823Smrg	return FALSE;
825a96d7823Smrg    }
826a96d7823Smrg    return TRUE;
827a96d7823Smrg}
828