fontdir.c revision a96d7823
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>
37a96d7823Smrg
38a96d7823Smrg#if HAVE_STDINT_H
39a96d7823Smrg#include <stdint.h>
40a96d7823Smrg#elif !defined(INT32_MAX)
41a96d7823Smrg#define INT32_MAX 0x7fffffff
42a96d7823Smrg#endif
43a96d7823Smrg
44a96d7823SmrgBool
45a96d7823SmrgFontFileInitTable (FontTablePtr table, int size)
46a96d7823Smrg{
47a96d7823Smrg    if (size < 0 || (size > INT32_MAX/sizeof(FontEntryRec)))
48a96d7823Smrg	return FALSE;
49a96d7823Smrg    if (size)
50a96d7823Smrg    {
51a96d7823Smrg	table->entries = malloc(sizeof(FontEntryRec) * size);
52a96d7823Smrg	if (!table->entries)
53a96d7823Smrg	    return FALSE;
54a96d7823Smrg    }
55a96d7823Smrg    else
56a96d7823Smrg	table->entries = 0;
57a96d7823Smrg    table->used = 0;
58a96d7823Smrg    table->size = size;
59a96d7823Smrg    table->sorted = FALSE;
60a96d7823Smrg    return TRUE;
61a96d7823Smrg}
62a96d7823Smrg
63a96d7823Smrgvoid
64a96d7823SmrgFontFileFreeEntry (FontEntryPtr entry)
65a96d7823Smrg{
66a96d7823Smrg    FontScalableExtraPtr   extra;
67a96d7823Smrg    int i;
68a96d7823Smrg
69a96d7823Smrg    if (entry->name.name)
70a96d7823Smrg	free(entry->name.name);
71a96d7823Smrg    entry->name.name = NULL;
72a96d7823Smrg
73a96d7823Smrg    switch (entry->type)
74a96d7823Smrg    {
75a96d7823Smrg    case FONT_ENTRY_SCALABLE:
76a96d7823Smrg	free (entry->u.scalable.fileName);
77a96d7823Smrg	extra = entry->u.scalable.extra;
78a96d7823Smrg	for (i = 0; i < extra->numScaled; i++)
79a96d7823Smrg	    if (extra->scaled[i].vals.ranges)
80a96d7823Smrg		free (extra->scaled[i].vals.ranges);
81a96d7823Smrg	free (extra->scaled);
82a96d7823Smrg	free (extra);
83a96d7823Smrg	break;
84a96d7823Smrg    case FONT_ENTRY_BITMAP:
85a96d7823Smrg	free (entry->u.bitmap.fileName);
86a96d7823Smrg	entry->u.bitmap.fileName = NULL;
87a96d7823Smrg	break;
88a96d7823Smrg    case FONT_ENTRY_ALIAS:
89a96d7823Smrg	free (entry->u.alias.resolved);
90a96d7823Smrg	entry->u.alias.resolved = NULL;
91a96d7823Smrg	break;
92a96d7823Smrg    }
93a96d7823Smrg}
94a96d7823Smrg
95a96d7823Smrgvoid
96a96d7823SmrgFontFileFreeTable (FontTablePtr table)
97a96d7823Smrg{
98a96d7823Smrg    int	i;
99a96d7823Smrg
100a96d7823Smrg    for (i = 0; i < table->used; i++)
101a96d7823Smrg	FontFileFreeEntry (&table->entries[i]);
102a96d7823Smrg    free (table->entries);
103a96d7823Smrg}
104a96d7823Smrg
105a96d7823SmrgFontDirectoryPtr
106a96d7823SmrgFontFileMakeDir(const char *dirName, int size)
107a96d7823Smrg{
108a96d7823Smrg    FontDirectoryPtr	dir;
109a96d7823Smrg    int			dirlen;
110a96d7823Smrg    int			needslash = 0;
111a96d7823Smrg    const char		*attrib;
112a96d7823Smrg    int			attriblen;
113a96d7823Smrg
114a96d7823Smrg#if !defined(WIN32)
115a96d7823Smrg    attrib = strchr(dirName, ':');
116a96d7823Smrg#else
117a96d7823Smrg    /* OS/2 uses the colon in the drive letter descriptor, skip this */
118a96d7823Smrg    attrib = strchr(dirName+2, ':');
119a96d7823Smrg#endif
120a96d7823Smrg    if (attrib) {
121a96d7823Smrg	dirlen = attrib - dirName;
122a96d7823Smrg	attriblen = strlen(attrib);
123a96d7823Smrg    } else {
124a96d7823Smrg	dirlen = strlen(dirName);
125a96d7823Smrg	attriblen = 0;
126a96d7823Smrg    }
127a96d7823Smrg    if (dirName[dirlen - 1] != '/')
128a96d7823Smrg#ifdef NCD
129a96d7823Smrg    if (dirlen)     /* leave out slash for builtins */
130a96d7823Smrg#endif
131a96d7823Smrg	needslash = 1;
132a96d7823Smrg    dir = malloc(sizeof *dir + dirlen + needslash + 1 +
133a96d7823Smrg		 (attriblen ? attriblen + 1 : 0));
134a96d7823Smrg    if (!dir)
135a96d7823Smrg	return (FontDirectoryPtr)0;
136a96d7823Smrg    if (!FontFileInitTable (&dir->scalable, 0))
137a96d7823Smrg    {
138a96d7823Smrg	free (dir);
139a96d7823Smrg	return (FontDirectoryPtr)0;
140a96d7823Smrg    }
141a96d7823Smrg    if (!FontFileInitTable (&dir->nonScalable, size))
142a96d7823Smrg    {
143a96d7823Smrg	FontFileFreeTable (&dir->scalable);
144a96d7823Smrg	free (dir);
145a96d7823Smrg	return (FontDirectoryPtr)0;
146a96d7823Smrg    }
147a96d7823Smrg    dir->directory = (char *) (dir + 1);
148a96d7823Smrg    dir->dir_mtime = 0;
149a96d7823Smrg    dir->alias_mtime = 0;
150a96d7823Smrg    if (attriblen)
151a96d7823Smrg	dir->attributes = dir->directory + dirlen + needslash + 1;
152a96d7823Smrg    else
153a96d7823Smrg	dir->attributes = NULL;
154a96d7823Smrg    strncpy(dir->directory, dirName, dirlen);
155a96d7823Smrg    dir->directory[dirlen] = '\0';
156a96d7823Smrg    if (dir->attributes)
157a96d7823Smrg	strcpy(dir->attributes, attrib);
158a96d7823Smrg    if (needslash)
159a96d7823Smrg	strcat(dir->directory, "/");
160a96d7823Smrg    return dir;
161a96d7823Smrg}
162a96d7823Smrg
163a96d7823Smrgvoid
164a96d7823SmrgFontFileFreeDir (FontDirectoryPtr dir)
165a96d7823Smrg{
166a96d7823Smrg    FontFileFreeTable (&dir->scalable);
167a96d7823Smrg    FontFileFreeTable (&dir->nonScalable);
168a96d7823Smrg    free(dir);
169a96d7823Smrg}
170a96d7823Smrg
171a96d7823SmrgFontEntryPtr
172a96d7823SmrgFontFileAddEntry(FontTablePtr table, FontEntryPtr prototype)
173a96d7823Smrg{
174a96d7823Smrg    FontEntryPtr    entry;
175a96d7823Smrg    int		    newsize;
176a96d7823Smrg
177a96d7823Smrg    /* can't add entries to a sorted table, pointers get broken! */
178a96d7823Smrg    if (table->sorted)
179a96d7823Smrg	return (FontEntryPtr) 0;    /* "cannot" happen */
180a96d7823Smrg    if (table->used == table->size) {
181a96d7823Smrg	if (table->size >= ((INT32_MAX / sizeof(FontEntryRec)) - 100))
182a96d7823Smrg	    /* If we've read so many entries we're going to ask for 2gb
183a96d7823Smrg	       or more of memory, something is so wrong with this font
184a96d7823Smrg	       directory that we should just give up before we overflow. */
185a96d7823Smrg	    return NULL;
186a96d7823Smrg	newsize = table->size + 100;
187a96d7823Smrg	entry = realloc(table->entries, newsize * sizeof(FontEntryRec));
188a96d7823Smrg	if (!entry)
189a96d7823Smrg	    return (FontEntryPtr)0;
190a96d7823Smrg	table->size = newsize;
191a96d7823Smrg	table->entries = entry;
192a96d7823Smrg    }
193a96d7823Smrg    entry = &table->entries[table->used];
194a96d7823Smrg    *entry = *prototype;
195a96d7823Smrg    entry->name.name = malloc(prototype->name.length + 1);
196a96d7823Smrg    if (!entry->name.name)
197a96d7823Smrg	return (FontEntryPtr)0;
198a96d7823Smrg    memcpy (entry->name.name, prototype->name.name, prototype->name.length);
199a96d7823Smrg    entry->name.name[entry->name.length] = '\0';
200a96d7823Smrg    table->used++;
201a96d7823Smrg    return entry;
202a96d7823Smrg}
203a96d7823Smrg
204a96d7823Smrg/*
205a96d7823Smrg * Compare two strings just like strcmp, but preserve decimal integer
206a96d7823Smrg * sorting order, i.e. "2" < "10" or "iso8859-2" < "iso8859-10" <
207a96d7823Smrg * "iso10646-1". Strings are sorted as if sequences of digits were
208a96d7823Smrg * prefixed by a length indicator (i.e., does not ignore leading zeroes).
209a96d7823Smrg *
210a96d7823Smrg * Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk>
211a96d7823Smrg */
212a96d7823Smrg#define Xisdigit(c) ('\060' <= (c) && (c) <= '\071')
213a96d7823Smrg
214a96d7823Smrgstatic int strcmpn(const char *s1, const char *s2)
215a96d7823Smrg{
216a96d7823Smrg    int digits, predigits = 0;
217a96d7823Smrg    const char *ss1, *ss2;
218a96d7823Smrg
219a96d7823Smrg    while (1) {
220a96d7823Smrg	if (*s1 == 0 && *s2 == 0)
221a96d7823Smrg	    return 0;
222a96d7823Smrg	digits = Xisdigit(*s1) && Xisdigit(*s2);
223a96d7823Smrg	if (digits && !predigits) {
224a96d7823Smrg	    ss1 = s1;
225a96d7823Smrg	    ss2 = s2;
226a96d7823Smrg	    while (Xisdigit(*ss1) && Xisdigit(*ss2))
227a96d7823Smrg		ss1++, ss2++;
228a96d7823Smrg	    if (!Xisdigit(*ss1) && Xisdigit(*ss2))
229a96d7823Smrg		return -1;
230a96d7823Smrg	    if (Xisdigit(*ss1) && !Xisdigit(*ss2))
231a96d7823Smrg		return 1;
232a96d7823Smrg	}
233a96d7823Smrg	if ((unsigned char)*s1 < (unsigned char)*s2)
234a96d7823Smrg	    return -1;
235a96d7823Smrg	if ((unsigned char)*s1 > (unsigned char)*s2)
236a96d7823Smrg	    return 1;
237a96d7823Smrg	predigits = digits;
238a96d7823Smrg	s1++, s2++;
239a96d7823Smrg    }
240a96d7823Smrg}
241a96d7823Smrg
242a96d7823Smrg
243a96d7823Smrgstatic int
244a96d7823SmrgFontFileNameCompare(const void* a, const void* b)
245a96d7823Smrg{
246a96d7823Smrg    FontEntryPtr    a_name = (FontEntryPtr) a,
247a96d7823Smrg		    b_name = (FontEntryPtr) b;
248a96d7823Smrg
249a96d7823Smrg    return strcmpn(a_name->name.name, b_name->name.name);
250a96d7823Smrg}
251a96d7823Smrg
252a96d7823Smrgvoid
253a96d7823SmrgFontFileSortTable (FontTablePtr table)
254a96d7823Smrg{
255a96d7823Smrg    if (!table->sorted) {
256a96d7823Smrg	qsort((char *) table->entries, table->used, sizeof(FontEntryRec),
257a96d7823Smrg	      FontFileNameCompare);
258a96d7823Smrg	table->sorted = TRUE;
259a96d7823Smrg    }
260a96d7823Smrg}
261a96d7823Smrg
262a96d7823Smrgvoid
263a96d7823SmrgFontFileSortDir(FontDirectoryPtr dir)
264a96d7823Smrg{
265a96d7823Smrg    FontFileSortTable (&dir->scalable);
266a96d7823Smrg    FontFileSortTable (&dir->nonScalable);
267a96d7823Smrg    /* now that the table is fixed in size, swizzle the pointers */
268a96d7823Smrg    FontFileSwitchStringsToBitmapPointers (dir);
269a96d7823Smrg}
270a96d7823Smrg
271a96d7823Smrg/*
272a96d7823Smrg  Given a Font Table, SetupWildMatch() sets up various pointers and state
273a96d7823Smrg  information so the table can be searched for name(s) that match a given
274a96d7823Smrg  fontname pattern -- which may contain wildcards.  Under certain
275a96d7823Smrg  circumstances, SetupWildMatch() will find the one table entry that
276a96d7823Smrg  matches the pattern.  If those circumstances do not pertain,
277a96d7823Smrg  SetupWildMatch() returns a range within the the table that should be
278a96d7823Smrg  searched for matching name(s).  With the information established by
279a96d7823Smrg  SetupWildMatch(), including state information in "private", the
280a96d7823Smrg  PatternMatch() procedure is then used to test names in the range for a
281a96d7823Smrg  match.
282a96d7823Smrg*/
283a96d7823Smrg
284a96d7823Smrg#define isWild(c)   ((c) == XK_asterisk || (c) == XK_question)
285a96d7823Smrg#define isDigit(c)  (XK_0 <= (c) && (c) <= XK_9)
286a96d7823Smrg
287a96d7823Smrgstatic int
288a96d7823SmrgSetupWildMatch(FontTablePtr table, FontNamePtr pat,
289a96d7823Smrg	       int *leftp, int *rightp, int *privatep)
290a96d7823Smrg{
291a96d7823Smrg    int         nDashes;
292a96d7823Smrg    char        c;
293a96d7823Smrg    char       *t;
294a96d7823Smrg    char       *firstWild;
295a96d7823Smrg    char       *firstDigit;
296a96d7823Smrg    int         first;
297a96d7823Smrg    int         center,
298a96d7823Smrg                left,
299a96d7823Smrg                right;
300a96d7823Smrg    int         result;
301a96d7823Smrg    char	*name;
302a96d7823Smrg
303a96d7823Smrg    name = pat->name;
304a96d7823Smrg    nDashes = pat->ndashes;
305a96d7823Smrg    firstWild = 0;
306a96d7823Smrg    firstDigit = 0;
307a96d7823Smrg    t = name;
308a96d7823Smrg    while ((c = *t++)) {
309a96d7823Smrg	if (isWild(c)) {
310a96d7823Smrg	    if (!firstWild)
311a96d7823Smrg		firstWild = t - 1;
312a96d7823Smrg	}
313a96d7823Smrg	if (isDigit(c)) {
314a96d7823Smrg	    if (!firstDigit)
315a96d7823Smrg		firstDigit = t - 1;
316a96d7823Smrg	}
317a96d7823Smrg    }
318a96d7823Smrg    left = 0;
319a96d7823Smrg    right = table->used;
320a96d7823Smrg    if (firstWild)
321a96d7823Smrg	*privatep = nDashes;
322a96d7823Smrg    else
323a96d7823Smrg	*privatep = -1;
324a96d7823Smrg    if (!table->sorted) {
325a96d7823Smrg	*leftp = left;
326a96d7823Smrg	*rightp = right;
327a96d7823Smrg	return -1;
328a96d7823Smrg    } else if (firstWild) {
329a96d7823Smrg	if (firstDigit && firstDigit < firstWild)
330a96d7823Smrg	    first = firstDigit - name;
331a96d7823Smrg	else
332a96d7823Smrg	    first = firstWild - name;
333a96d7823Smrg	while (left < right) {
334a96d7823Smrg	    center = (left + right) / 2;
335a96d7823Smrg	    result = strncmp(name, table->entries[center].name.name, first);
336a96d7823Smrg	    if (result == 0)
337a96d7823Smrg		break;
338a96d7823Smrg	    if (result < 0)
339a96d7823Smrg		right = center;
340a96d7823Smrg	    else
341a96d7823Smrg		left = center + 1;
342a96d7823Smrg	}
343a96d7823Smrg	*leftp = left;
344a96d7823Smrg	*rightp = right;
345a96d7823Smrg	return -1;
346a96d7823Smrg    } else {
347a96d7823Smrg	while (left < right) {
348a96d7823Smrg	    center = (left + right) / 2;
349a96d7823Smrg	    result = strcmpn(name, table->entries[center].name.name);
350a96d7823Smrg	    if (result == 0)
351a96d7823Smrg		return center;
352a96d7823Smrg	    if (result < 0)
353a96d7823Smrg		right = center;
354a96d7823Smrg	    else
355a96d7823Smrg		left = center + 1;
356a96d7823Smrg	}
357a96d7823Smrg	*leftp = 1;
358a96d7823Smrg	*rightp = 0;
359a96d7823Smrg	return -1;
360a96d7823Smrg    }
361a96d7823Smrg}
362a96d7823Smrg
363a96d7823Smrgstatic int
364a96d7823SmrgPatternMatch(char *pat, int patdashes, char *string, int stringdashes)
365a96d7823Smrg{
366a96d7823Smrg    char        c,
367a96d7823Smrg                t;
368a96d7823Smrg
369a96d7823Smrg    if (stringdashes < patdashes)
370a96d7823Smrg	return 0;
371a96d7823Smrg    for (;;) {
372a96d7823Smrg	switch (c = *pat++) {
373a96d7823Smrg	case '*':
374a96d7823Smrg	    if (!(c = *pat++))
375a96d7823Smrg		return 1;
376a96d7823Smrg	    if (c == XK_minus) {
377a96d7823Smrg		patdashes--;
378a96d7823Smrg		for (;;) {
379a96d7823Smrg		    while ((t = *string++) != XK_minus)
380a96d7823Smrg			if (!t)
381a96d7823Smrg			    return 0;
382a96d7823Smrg		    stringdashes--;
383a96d7823Smrg		    if (PatternMatch(pat, patdashes, string, stringdashes))
384a96d7823Smrg			return 1;
385a96d7823Smrg		    if (stringdashes == patdashes)
386a96d7823Smrg			return 0;
387a96d7823Smrg		}
388a96d7823Smrg	    } else {
389a96d7823Smrg		for (;;) {
390a96d7823Smrg		    while ((t = *string++) != c) {
391a96d7823Smrg			if (!t)
392a96d7823Smrg			    return 0;
393a96d7823Smrg			if (t == XK_minus) {
394a96d7823Smrg			    if (stringdashes-- < patdashes)
395a96d7823Smrg				return 0;
396a96d7823Smrg			}
397a96d7823Smrg		    }
398a96d7823Smrg		    if (PatternMatch(pat, patdashes, string, stringdashes))
399a96d7823Smrg			return 1;
400a96d7823Smrg		}
401a96d7823Smrg	    }
402a96d7823Smrg	case '?':
403a96d7823Smrg	    if (*string++ == XK_minus)
404a96d7823Smrg		stringdashes--;
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