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