fonts.c revision bbe1b32b
1/* $Xorg: fonts.c,v 1.5 2001/02/09 02:05:42 xorgcvs Exp $ */
2/*
3 * font control
4 */
5/*
6
7Copyright 1990, 1991, 1998  The Open Group
8
9Permission to use, copy, modify, distribute, and sell this software and its
10documentation for any purpose is hereby granted without fee, provided that
11the above copyright notice appear in all copies and that both that
12copyright notice and this permission notice appear in supporting
13documentation.
14
15The above copyright notice and this permission notice shall be included in
16all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
21OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of The Open Group shall not be
26used in advertising or otherwise to promote the sale, use or other dealings
27in this Software without prior written authorization from The Open Group.
28
29 * Copyright 1990, 1991 Network Computing Devices;
30 * Portions Copyright 1987 by Digital Equipment Corporation
31 *
32 * Permission to use, copy, modify, distribute, and sell this software and
33 * its documentation for any purpose is hereby granted without fee, provided
34 * that the above copyright notice appear in all copies and that both that
35 * copyright notice and this permission notice appear in supporting
36 * documentation, and that the names of Network Computing Devices or Digital
37 * not be used in advertising or publicity pertaining to distribution
38 * of the software without specific, written prior permission.
39 *
40 * NETWORK COMPUTING DEVICES AND DIGITAL DISCLAIM ALL WARRANTIES WITH
41 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
42 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES
43 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
44 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
47 * THIS SOFTWARE.
48 */
49/*#define DEBUG*/
50#include        <X11/fonts/FS.h>
51#include        <X11/fonts/FSproto.h>
52#include	<stdio.h>
53#include	<stdlib.h>
54#include	<X11/Xos.h>
55#include	"clientstr.h"
56#include	"fsresource.h"
57#include	"difsfnst.h"
58#include	<X11/fonts/fontstruct.h>
59#include	"closestr.h"
60#include	"globals.h"
61#include	"difs.h"
62#include	"dispatch.h"
63#include	"swaprep.h"
64
65static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
66static int  num_fpes = 0;
67static FPEFunctions *fpe_functions = (FPEFunctions *) 0;
68static int  num_fpe_types = 0;
69
70static int  num_slept_fpes = 0;
71static int  size_slept_fpes = 0;
72static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
73
74extern FontPatternCachePtr fontPatternCache;
75
76#define	NUM_IDS_PER_CLIENT	5
77
78int
79FontToFSError(int err)
80{
81    switch (err) {
82    case Successful:
83	return FSSuccess;
84    case AllocError:
85	return FSBadAlloc;
86    case BadFontName:
87    case BadFontPath:
88	return FSBadName;
89    case BadFontFormat:
90	return FSBadFormat;
91    case BadCharRange:
92	return FSBadRange;
93    default:
94	return err;
95    }
96}
97
98/* XXX -- these two funcs may want to be broken into macros */
99void
100UseFPE(FontPathElementPtr fpe)
101{
102    fpe->refcount++;
103}
104
105void
106FreeFPE(FontPathElementPtr fpe)
107{
108    fpe->refcount--;
109    if (fpe->refcount == 0) {
110	(*fpe_functions[fpe->type].free_fpe) (fpe);
111	fsfree(fpe->name);
112	fsfree(fpe);
113    }
114}
115
116/*
117 * note that the font wakeup queue is not refcounted.  this is because
118 * an fpe needs to be added when it's inited, and removed when it's finally
119 * freed, in order to handle any data that isn't requested, like FS events.
120 *
121 * since the only thing that should call these routines is the renderer's
122 * init_fpe() and free_fpe(), there shouldn't be any problem in using
123 * freed data.
124 */
125void
126QueueFontWakeup(FontPathElementPtr fpe)
127{
128    int         i;
129    FontPathElementPtr *new;
130
131    for (i = 0; i < num_slept_fpes; i++) {
132	if (slept_fpes[i] == fpe) {
133
134#ifdef DEBUG
135	    fprintf(stderr, "re-queueing fpe wakeup\n");
136#endif
137
138	    return;
139	}
140    }
141    if (num_slept_fpes == size_slept_fpes) {
142	new = (FontPathElementPtr *)
143	    fsrealloc(slept_fpes,
144		      sizeof(FontPathElementPtr) * (size_slept_fpes + 4));
145	if (!new)
146	    return;
147	slept_fpes = new;
148	size_slept_fpes += 4;
149    }
150    slept_fpes[num_slept_fpes] = fpe;
151    num_slept_fpes++;
152}
153
154void
155RemoveFontWakeup(FontPathElementPtr fpe)
156{
157    int         i,
158                j;
159
160    for (i = 0; i < num_slept_fpes; i++) {
161	if (slept_fpes[i] == fpe) {
162	    for (j = i; j < num_slept_fpes; j++) {
163		slept_fpes[j] = slept_fpes[j + 1];
164	    }
165	    num_slept_fpes--;
166	    return;
167	}
168    }
169}
170
171/* ARGSUSED */
172void
173FontWakeup(pointer data, int count, unsigned long *LastSelectMask)
174{
175    int         i;
176    FontPathElementPtr fpe;
177
178    if (count < 0)
179	return;			/* ignore -1 return from select XXX */
180    /* wake up any fpe's that may be waiting for information */
181    for (i = 0; i < num_slept_fpes; i++) {
182	fpe = slept_fpes[i];
183	(void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask);
184    }
185}
186
187static Bool
188add_id_to_list(FontIDListPtr ids, Font fid)
189{
190    Font       *newlist;
191
192    /*
193     * assumes the list is packed tightly
194     */
195    if (ids->num == ids->size) {
196	/* increase size of array */
197	newlist = (Font *) fsrealloc(ids->client_list,
198			      sizeof(Font) * (ids->size + NUM_IDS_PER_CLIENT));
199	if (!newlist)
200	    return FALSE;
201	ids->client_list = newlist;
202	ids->size += NUM_IDS_PER_CLIENT;
203    }
204    ids->client_list[ids->num++] = fid;
205    return TRUE;
206}
207
208static void
209remove_id_from_list(FontIDListPtr ids, Font fid)
210{
211    int         i;
212
213    for (i = 0; i < ids->num; i++) {
214	if (ids->client_list[i] == fid) {
215	    /* a memmove() might be better here */
216	    while (i < ids->num) {
217		ids->client_list[i] = ids->client_list[i + 1];
218		i++;
219	    }
220	    ids->num--;
221	    return;
222	}
223    }
224    assert(0);
225}
226
227static FontIDListPtr
228make_clients_id_list(void)
229{
230    FontIDListPtr ids;
231    Font       *fids;
232
233    ids = (FontIDListPtr) fsalloc(sizeof(FontIDListRec));
234    fids = (Font *) fsalloc(sizeof(Font) * NUM_IDS_PER_CLIENT);
235    if (!ids || !fids) {
236	fsfree(ids);
237	fsfree(fids);
238	return (FontIDListPtr) 0;
239    }
240    bzero((char *) fids, sizeof(Font) * NUM_IDS_PER_CLIENT);
241    ids->client_list = fids;
242    ids->size = NUM_IDS_PER_CLIENT;
243    ids->num = 0;
244    return ids;
245}
246
247static void
248free_svrPrivate(pointer svrPrivate)
249{
250    int i;
251    FontIDListPtr *idlist, ids;
252
253    idlist = (FontIDListPtr *) svrPrivate;
254    if (idlist) {
255	for (i = 0; i < MAXCLIENTS; i++) {
256	    ids = idlist[i];
257	    if (ids) {
258		fsfree((char *) ids->client_list);
259		fsfree((char *) ids);
260	    }
261	}
262	fsfree((char *) idlist);
263    }
264}
265
266#undef  cPtr
267#define cPtr ((OFclosurePtr )data)
268
269static Bool
270do_open_font(ClientPtr client, pointer data)
271{
272    FontPtr     pfont = NullFont;
273    FontPathElementPtr fpe = NULL;
274    int         err = 0;
275    int         i;
276    char       *alias,
277               *newname;
278    int         newlen;
279    ClientFontPtr cfp;
280    fsOpenBitmapFontReply rep;
281    Font        orig;
282    FontIDListPtr *idlist,
283                ids;
284    int		aliascount = 20;
285
286    if (client->clientGone == CLIENT_GONE) {
287	if (cPtr->current_fpe < cPtr->num_fpes) {
288	    fpe = cPtr->fpe_list[cPtr->current_fpe];
289	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
290	}
291	err = Successful;
292	goto dropout;
293    }
294    while (cPtr->current_fpe < cPtr->num_fpes) {
295	fpe = cPtr->fpe_list[cPtr->current_fpe];
296	err = (*fpe_functions[fpe->type].open_font)
297	    ((pointer) cPtr->client, fpe, cPtr->flags,
298	     cPtr->fontname, cPtr->fnamelen, cPtr->format, cPtr->format_mask,
299	     cPtr->fontid, &pfont, &alias,
300	     cPtr->non_cachable_font && cPtr->non_cachable_font->fpe == fpe ?
301		 cPtr->non_cachable_font :
302		 (FontPtr)0);
303
304	if (err == FontNameAlias && alias) {
305	    newlen = strlen(alias);
306	    newname = (char *) fsrealloc(cPtr->fontname, newlen);
307	    if (!newname) {
308		err = AllocError;
309		break;
310	    }
311	    memmove( newname, alias, newlen);
312	    cPtr->fontname = newname;
313	    cPtr->fnamelen = newlen;
314	    cPtr->current_fpe = 0;
315	    if (--aliascount <= 0) break;
316	    continue;
317	}
318	if (err == BadFontName) {
319	    cPtr->current_fpe++;
320	    continue;
321	}
322	if (err == Suspended) {
323	    if (!cPtr->slept) {
324		cPtr->slept = TRUE;
325		ClientSleep(client, do_open_font, (pointer) cPtr);
326	    }
327	    return TRUE;
328	}
329	break;
330    }
331    if (err != Successful) {
332	goto dropout;
333    }
334    if (!pfont) {
335	err = BadFontName;
336	goto dropout;
337    }
338    cfp = (ClientFontPtr) fsalloc(sizeof(ClientFontRec));
339    if (!cfp) {
340	err = AllocError;
341	goto dropout;
342    }
343    cfp->font = pfont;
344    cfp->clientindex = cPtr->client->index;
345
346    if (fontPatternCache && pfont != cPtr->non_cachable_font)
347	CacheFontPattern(fontPatternCache, cPtr->orig_name, cPtr->orig_len, pfont);
348
349    /* either pull out the other id or make the array */
350    if (pfont->refcnt != 0) {
351	idlist = (FontIDListPtr *) pfont->svrPrivate;
352	ids = idlist[cPtr->client->index];
353	if (!ids) {
354	    ids = make_clients_id_list();
355	    if (!ids) {
356		err = AllocError;
357		fsfree(cfp);
358		goto dropout;
359	    }
360	    idlist[cPtr->client->index] = ids;
361	}
362	orig = (ids->num > 0) ? ids->client_list[0] : (Font)0;
363    } else {
364	idlist = (FontIDListPtr *) fsalloc(sizeof(FontIDListPtr) * MAXCLIENTS);
365	if (!idlist) {
366	    err = AllocError;
367	    fsfree(cfp);
368	    goto dropout;
369	}
370	ids = make_clients_id_list();
371	if (!ids) {
372	    err = AllocError;
373	    fsfree(idlist);
374	    fsfree(cfp);
375	    goto dropout;
376	}
377	bzero((char *) idlist, (sizeof(FontIDListPtr) * MAXCLIENTS));
378	idlist[cPtr->client->index] = ids;
379	orig = (Font) 0;
380	pfont->svrPrivate = (pointer) idlist;
381    }
382    if (!AddResource(cPtr->client->index, cPtr->fontid, RT_FONT, (pointer) cfp)) {
383	fsfree(cfp);
384	free_svrPrivate(pfont->svrPrivate);
385	pfont->svrPrivate = (pointer) 0;
386	err = AllocError;
387	goto dropout;
388    }
389    add_id_to_list(ids, cPtr->fontid);
390    /* send the reply */
391    rep.type = FS_Reply;
392    rep.otherid = orig;
393    if (orig)
394	rep.otherid_valid = TRUE;
395    else
396	rep.otherid_valid = FALSE;
397    rep.cachable = pfont->info.cachable;
398    rep.sequenceNumber = client->sequence;
399    rep.length = SIZEOF(fsOpenBitmapFontReply) >> 2;
400    WriteReplyToClient(client,
401		       SIZEOF(fsOpenBitmapFontReply), &rep);
402    if (pfont->refcnt == 0) {
403	if (!pfont->fpe)
404	    pfont->fpe = fpe;
405	UseFPE(pfont->fpe);
406    }
407    pfont->refcnt++;
408dropout:
409    if (err != Successful) {
410	SendErrToClient(cPtr->client, FontToFSError(err), (pointer) &(cPtr->fontid));
411    }
412    if (cPtr->slept)
413	ClientWakeup(cPtr->client);
414    for (i = 0; i < cPtr->num_fpes; i++) {
415	FreeFPE(cPtr->fpe_list[i]);
416    }
417    fsfree(cPtr->fpe_list);
418    fsfree(cPtr->fontname);
419    fsfree(cPtr);
420    return TRUE;
421}
422
423int
424OpenFont(
425    ClientPtr   client,
426    Font        fid,
427    fsBitmapFormat format,
428    fsBitmapFormatMask format_mask,
429    int         namelen,
430    char       *name)
431{
432    FontPtr     pfont = (FontPtr)0;
433    fsOpenBitmapFontReply rep;
434    OFclosurePtr c;
435    FontIDListPtr *idlist,
436                ids;
437    int         i;
438
439    if (namelen == 0 || namelen > XLFDMAXFONTNAMELEN) {
440	SendErrToClient(client, FSBadName, (pointer) 0);
441	return FSBadName;
442    }
443#ifdef DEBUG
444    fprintf(stderr,"OpenFont: %sn",name);
445#endif
446    /*
447    ** Check name cache.  If we find a cached version of this font that
448    ** is cachable, immediately satisfy the request with it.  If we find
449    ** a cached version of this font that is non-cachable, we do not
450    ** satisfy the request with it.  Instead, we pass the FontPtr to the
451    ** FPE's open_font code (the fontfile FPE in turn passes the
452    ** information to the rasterizer; the fserve FPE ignores it).
453    **
454    ** Presumably, the font is marked non-cachable because the FPE has
455    ** put some licensing restrictions on it.  If the FPE, using
456    ** whatever logic it relies on, determines that it is willing to
457    ** share this existing font with the client, then it has the option
458    ** to return the FontPtr we passed it as the newly-opened font.
459    ** This allows the FPE to exercise its licensing logic without
460    ** having to create another instance of a font that already exists.
461    */
462
463    if (fontPatternCache &&
464	  (pfont = FindCachedFontPattern(fontPatternCache, name, namelen)) &&
465	   pfont->info.cachable) {
466	ClientFontPtr cfp;
467
468	idlist = (FontIDListPtr *) pfont->svrPrivate;
469	ids = idlist[client->index];
470	if (!ids) {
471	    ids = make_clients_id_list();
472	    if (!ids) {
473		goto lowmem;
474	    }
475	    idlist[client->index] = ids;
476	}
477	cfp = (ClientFontPtr) fsalloc(sizeof(ClientFontRec));
478	if (!cfp) {
479    lowmem:
480	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
481	    return FSBadAlloc;
482	}
483	cfp->font = pfont;
484	cfp->clientindex = client->index;
485	if (!AddResource(client->index, fid, RT_FONT, (pointer) cfp)) {
486	    goto lowmem;
487	}
488	if (!add_id_to_list(ids, fid)) {
489	    goto lowmem;
490	}
491	pfont->refcnt++;
492	rep.type = FS_Reply;
493	if (ids->num > 1)
494	{
495	    rep.otherid = ids->client_list[0];
496	    rep.otherid_valid = TRUE;
497	}
498	else
499	{
500	    rep.otherid = 0;
501	    rep.otherid_valid = FALSE;
502	}
503	rep.cachable = TRUE;	/* XXX */
504	rep.sequenceNumber = client->sequence;
505	rep.length = SIZEOF(fsOpenBitmapFontReply) >> 2;
506	WriteReplyToClient(client,
507			   SIZEOF(fsOpenBitmapFontReply), &rep);
508	return FSSuccess;
509    }
510    c = (OFclosurePtr) fsalloc(sizeof(OFclosureRec));
511    if (!c)
512	goto lowmem;
513    c->fontname = (char *) fsalloc(namelen);
514    if (!c->fontname) {
515	fsfree(c);
516	goto lowmem;
517    }
518    /*
519     * copy the current FPE list, so that if it gets changed by another client
520     * while we're blocking, the request still appears atomic
521     */
522    c->fpe_list = (FontPathElementPtr *)
523	fsalloc(sizeof(FontPathElementPtr) * num_fpes);
524    if (!c->fpe_list) {
525	fsfree(c->fontname);
526	fsfree(c);
527	goto lowmem;
528    }
529    memmove( c->fontname, name, namelen);
530    for (i = 0; i < num_fpes; i++) {
531	c->fpe_list[i] = font_path_elements[i];
532	UseFPE(c->fpe_list[i]);
533    }
534    c->client = client;
535    c->fontid = fid;
536    c->current_fpe = 0;
537    c->num_fpes = num_fpes;
538    c->fnamelen = namelen;
539    c->orig_name = name;
540    c->orig_len = namelen;
541    c->slept = FALSE;
542    c->flags = (FontLoadInfo | FontLoadProps);
543    c->format = format;
544    c->format_mask = format_mask;
545    c->non_cachable_font = pfont;
546
547    (void) do_open_font(client, (pointer) c);
548    return FSSuccess;
549}
550
551static int
552close_font(FontPtr pfont)
553{
554    FontPathElementPtr fpe;
555
556    assert(pfont);
557    if (--pfont->refcnt == 0) {
558	if (fontPatternCache)
559	    RemoveCachedFontPattern(fontPatternCache, pfont);
560	fpe = pfont->fpe;
561	free_svrPrivate(pfont->svrPrivate);
562	(*fpe_functions[fpe->type].close_font) (fpe, pfont);
563	FreeFPE(fpe);
564    }
565    return FSSuccess;
566}
567
568int
569CloseClientFont(
570    ClientFontPtr cfp,
571    FSID        fid)
572{
573    FontIDListPtr *idlist;
574    FontIDListPtr ids;
575    int ret;
576
577    assert(cfp);
578    /* clear otherid id */
579    idlist = (FontIDListPtr *) cfp->font->svrPrivate;
580    ids = idlist[cfp->clientindex];
581    remove_id_from_list(ids, fid);
582    ret = close_font(cfp->font);
583    fsfree((char *) cfp);
584    return ret;
585}
586
587/*
588 * search all the known FPE prefixes looking for one to match the given
589 * FPE name
590 */
591static int
592determine_fpe_type(char *name)
593{
594    int	i;
595    for (i = 0; i < num_fpe_types; i++) {
596	if ((*fpe_functions[i].name_check) (name))
597	    return i;
598    }
599    return -1;
600}
601
602static void
603free_font_path(FontPathElementPtr *list, int n)
604{
605    int         i;
606
607    for (i = 0; i < n; i++) {
608	FreeFPE(list[i]);
609    }
610    fsfree((char *) list);
611}
612
613static FontPathElementPtr
614find_existing_fpe(
615    FontPathElementPtr *list,
616    int         num,
617    char       *name,
618    int         len)
619{
620    FontPathElementPtr fpe;
621    int         i;
622
623    for (i = 0; i < num; i++) {
624	fpe = list[i];
625	if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
626	    return fpe;
627    }
628    return (FontPathElementPtr) 0;
629}
630
631/*
632 * does the work of setting up the fpe list
633 *
634 * paths should be a counted string
635 */
636static int
637set_font_path_elements(
638    int         npaths,
639    char       *paths,
640    int        *bad)
641{
642    int		i, validpaths, err = 0;
643    int		len;
644    int		type;
645    char       *cp = paths;
646    char       *name;
647    FontPathElementPtr fpe, *fplist;
648
649    fplist = (FontPathElementPtr *)
650	fsalloc(sizeof(FontPathElementPtr) * npaths);
651    if (!fplist) {
652	*bad = 0;
653	return FSBadAlloc;
654    }
655    for (i = 0; i < num_fpe_types; i++) {
656	if (fpe_functions[i].set_path_hook)
657	    (*fpe_functions[i].set_path_hook) ();
658    }
659    for (i = 0, validpaths = 0; i < npaths; i++) {
660	len = *cp++;
661	if (len) {
662	    /* if it's already in our active list, just reset it */
663	    /*
664	     * note that this can miss FPE's in limbo -- may be worth catching
665	     * them, though it'd muck up refcounting
666	     */
667	    fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
668	    if (fpe) {
669		err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
670		if (err == Successful) {
671		    UseFPE(fpe);/* since it'll be decref'd later when freed
672				 * from the old list */
673		    fplist[validpaths++] = fpe;
674		    cp += len;
675		    continue;
676		}
677		/* can't do it, so act like it's a new one */
678	    }
679	    name = (char *) fsalloc(len + 1);
680	    if (!name) {
681		err = FSBadAlloc;
682		goto bail;
683	    }
684	    strncpy(name, (char *) cp, len);
685	    name[len] = '\0';
686	    type = determine_fpe_type(name);
687	    if (type == -1)
688	    {
689		NoticeF("ignoring font path element %s (bad font path descriptor)\n", name);
690		fsfree(name);
691		continue;
692	    }
693	    /* must be new -- make it */
694	    fpe = (FontPathElementPtr) fsalloc(sizeof(FontPathElementRec));
695	    if (!fpe) {
696		fsfree(name);
697		err = FSBadAlloc;
698		goto bail;
699	    }
700	    fpe->type = type;
701	    fpe->name = name;
702	    fpe->refcount = 1;
703
704	    cp += len;
705	    fpe->name_length = len;
706	    err = (*fpe_functions[fpe->type].init_fpe) (fpe);
707	    if (err != Successful) {
708		NoticeF("ignoring font path element %s (unreadable)\n", fpe->name);
709		fsfree(fpe->name);
710		fsfree(fpe);
711		continue;
712	    }
713	    fplist[validpaths++] = fpe;
714	}
715    }
716    if (validpaths < npaths) {
717	FontPathElementPtr *ftmp = (FontPathElementPtr *)
718	    fsrealloc(fplist, sizeof(FontPathElementPtr) * validpaths);
719
720	if (!ftmp && validpaths)
721	    goto bail;
722
723	fplist = ftmp;
724	npaths = validpaths;
725    }
726    if (validpaths == 0) {
727	err = FontToFSError(err);
728	goto bail;
729    }
730    free_font_path(font_path_elements, num_fpes);
731    font_path_elements = fplist;
732    num_fpes = npaths;
733    if (fontPatternCache)
734	EmptyFontPatternCache(fontPatternCache);
735    return FSSuccess;
736bail:
737    *bad = validpaths;
738    while (--validpaths >= 0)
739	FreeFPE(fplist[i]);
740    fsfree(fplist);
741    return err;
742}
743
744/*
745 * expects comma seperated string
746 */
747int
748SetFontCatalogue(
749    char       *str,
750    int        *badpath)
751{
752    int         len,
753                npaths;
754    char       *paths,
755               *end,
756               *p;
757    int         err;
758
759    len = strlen(str) + 1;
760    paths = p = (char *) ALLOCATE_LOCAL(len);
761    npaths = 0;
762
763    while (*str) {
764	end = index(str, ',');
765	if (!end) {
766	    end = str + strlen(str);
767	}
768	*p++ = len = end - str;
769	memmove( p, str, len);
770	npaths++;
771	str += len;		/* skip entry */
772	if (*str == ',')
773           str++;		/* skip any comma */
774	p += len;
775    }
776
777    err = set_font_path_elements(npaths, paths, badpath);
778
779    DEALLOCATE_LOCAL(paths);
780
781    return err;
782}
783
784#undef  cPtr
785#define cPtr ((LFclosurePtr)data)
786
787static Bool
788do_list_fonts_and_aliases(ClientPtr client, pointer data)
789{
790    FontPathElementPtr fpe;
791    int         err = Successful;
792    FontNamesPtr names = NULL;
793    char       *name, *resolved;
794    int         namelen, resolvedlen;
795    int		nnames;
796    int         stringLens;
797    int         i;
798    fsListFontsReply reply;
799    char	*bufptr;
800    char	*bufferStart;
801    int		aliascount = 0;
802
803    if (client->clientGone == CLIENT_GONE) {
804	if (cPtr->current.current_fpe < cPtr->num_fpes) {
805	    fpe = cPtr->fpe_list[cPtr->current.current_fpe];
806	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
807	}
808	err = Successful;
809	goto bail;
810    }
811
812    if (!cPtr->current.patlen)
813	goto finish;
814
815    while (cPtr->current.current_fpe < cPtr->num_fpes) {
816	fpe = cPtr->fpe_list[cPtr->current.current_fpe];
817	err = Successful;
818
819	if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
820	{
821	    /* This FPE doesn't support/require list_fonts_and_aliases */
822
823	    err = (*fpe_functions[fpe->type].list_fonts)
824		((pointer) cPtr->client, fpe, cPtr->current.pattern,
825		 cPtr->current.patlen, cPtr->current.max_names - cPtr->names->nnames,
826		 cPtr->names);
827
828	    if (err == Suspended) {
829		if (!cPtr->slept) {
830		    cPtr->slept = TRUE;
831		    ClientSleep(client, do_list_fonts_and_aliases, (pointer) cPtr);
832		}
833		return TRUE;
834	    }
835
836	    err = BadFontName;
837	}
838	else
839	{
840	    /* Start of list_fonts_and_aliases functionality.  Modeled
841	       after list_fonts_with_info in that it resolves aliases,
842	       except that the information collected from FPEs is just
843	       names, not font info.  Each list_next_font_or_alias()
844	       returns either a name into name/namelen or an alias into
845	       name/namelen and its target name into resolved/resolvedlen.
846	       The code at this level then resolves the alias by polling
847	       the FPEs.  */
848
849	    if (!cPtr->current.list_started) {
850		err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
851		    ((pointer) cPtr->client, fpe, cPtr->current.pattern,
852		     cPtr->current.patlen, cPtr->current.max_names - cPtr->names->nnames,
853		     &cPtr->current.private);
854		if (err == Suspended) {
855		    if (!cPtr->slept) {
856			ClientSleep(client, do_list_fonts_and_aliases,
857				    (pointer) cPtr);
858			cPtr->slept = TRUE;
859		    }
860		    return TRUE;
861		}
862		if (err == Successful)
863		    cPtr->current.list_started = TRUE;
864	    }
865	    if (err == Successful) {
866		name = 0;
867		err = (*fpe_functions[fpe->type].list_next_font_or_alias)
868		    ((pointer) cPtr->client, fpe, &name, &namelen, &resolved,
869		     &resolvedlen, cPtr->current.private);
870		if (err == Suspended) {
871		    if (!cPtr->slept) {
872			ClientSleep(client, do_list_fonts_and_aliases,
873				    (pointer) cPtr);
874			cPtr->slept = TRUE;
875		    }
876		    return TRUE;
877		}
878	    }
879
880	    if (err == Successful)
881	    {
882		if (cPtr->haveSaved)
883		{
884		    if (cPtr->savedName)
885			(void)AddFontNamesName(cPtr->names, cPtr->savedName,
886					       cPtr->savedNameLen);
887		}
888		else
889		    (void)AddFontNamesName(cPtr->names, name, namelen);
890	    }
891
892	    /*
893	     * When we get an alias back, save our state and reset back to
894	     * the start of the FPE looking for the specified name.  As
895	     * soon as a real font is found for the alias, pop back to the
896	     * old state
897	     */
898	    else if (err == FontNameAlias) {
899		char	tmp_pattern[XLFDMAXFONTNAMELEN];
900		/*
901		 * when an alias recurses, we need to give
902		 * the last FPE a chance to clean up; so we call
903		 * it again, and assume that the error returned
904		 * is BadFontName, indicating the alias resolution
905		 * is complete.
906		 */
907		memmove(tmp_pattern, resolved, resolvedlen);
908		if (cPtr->haveSaved)
909		{
910		    char    *tmpname;
911		    int     tmpnamelen;
912
913		    tmpname = 0;
914		    (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
915			((pointer) cPtr->client, fpe, &tmpname, &tmpnamelen,
916			 &tmpname, &tmpnamelen, cPtr->current.private);
917		    if (--aliascount <= 0)
918		    {
919			err = BadFontName;
920			goto ContBadFontName;
921		    }
922		}
923		else
924		{
925		    cPtr->saved = cPtr->current;
926		    cPtr->haveSaved = TRUE;
927		    if (cPtr->savedName)
928			fsfree(cPtr->savedName);
929		    cPtr->savedName = (char *)fsalloc(namelen + 1);
930		    if (cPtr->savedName)
931			memmove(cPtr->savedName, name, namelen + 1);
932		    cPtr->savedNameLen = namelen;
933		    aliascount = 20;
934		}
935		memmove(cPtr->current.pattern, tmp_pattern, resolvedlen);
936		cPtr->current.patlen = resolvedlen;
937		cPtr->current.max_names = cPtr->names->nnames + 1;
938		cPtr->current.current_fpe = -1;
939		cPtr->current.private = 0;
940		err = BadFontName;
941	    }
942	}
943	/*
944	 * At the end of this FPE, step to the next.  If we've finished
945	 * processing an alias, pop state back. If we've collected enough
946	 * font names, quit.
947	 */
948	if (err == BadFontName) {
949	  ContBadFontName: ;
950	    cPtr->current.list_started = FALSE;
951	    cPtr->current.current_fpe++;
952	    err = Successful;
953	    if (cPtr->haveSaved)
954	    {
955		/* If we're searching for an alias, limit the search to
956		   FPE's of the same type as the one the alias came
957		   from.  This is unnecessarily restrictive, but if we
958		   have both fontfile and fs FPE's, this restriction can
959		   drastically reduce network traffic to the fs -- else
960		   we could poll the fs for *every* local alias found;
961		   on a typical system enabling FILE_NAMES_ALIASES, this
962		   is significant.  */
963
964		while (cPtr->current.current_fpe < cPtr->num_fpes &&
965		       cPtr->fpe_list[cPtr->current.current_fpe]->type !=
966		       cPtr->fpe_list[cPtr->saved.current_fpe]->type)
967		cPtr->current.current_fpe++;
968
969		if (cPtr->names->nnames == cPtr->current.max_names ||
970			cPtr->current.current_fpe == cPtr->num_fpes) {
971		    cPtr->haveSaved = FALSE;
972		    cPtr->current = cPtr->saved;
973		    /* Give the saved namelist a chance to clean itself up */
974		    continue;
975		}
976	    }
977	    if (cPtr->names->nnames == cPtr->current.max_names)
978		break;
979	}
980    }
981
982    /*
983     * send the reply
984     */
985    if (err != Successful) {
986	SendErrToClient(client, FontToFSError(err), (pointer) 0);
987	goto bail;
988    }
989
990finish:
991
992    names = cPtr->names;
993    nnames = names->nnames;
994    client = cPtr->client;
995    stringLens = 0;
996    for (i = 0; i < nnames; i++)
997	stringLens += (names->length[i] <= 255) ? names->length[i] : 0;
998
999    reply.type = FS_Reply;
1000    reply.length = (SIZEOF(fsListFontsReply) + stringLens + nnames + 3) >> 2;
1001    reply.following = 0;
1002    reply.nFonts = nnames;
1003    reply.sequenceNumber = client->sequence;
1004
1005    bufptr = bufferStart = (char *) ALLOCATE_LOCAL(reply.length << 2);
1006
1007    if (!bufptr && reply.length) {
1008	SendErrToClient(client, FSBadAlloc, (pointer) 0);
1009	goto bail;
1010    }
1011    /*
1012     * since WriteToClient long word aligns things, copy to temp buffer and
1013     * write all at once
1014     */
1015    for (i = 0; i < nnames; i++) {
1016	if (names->length[i] > 255)
1017	    reply.nFonts--;
1018	else
1019	{
1020	    *bufptr++ = names->length[i];
1021	    memmove( bufptr, names->names[i], names->length[i]);
1022	    bufptr += names->length[i];
1023	}
1024    }
1025    nnames = reply.nFonts;
1026    reply.length = (SIZEOF(fsListFontsReply) + stringLens + nnames + 3) >> 2;
1027    WriteReplyToClient(client, SIZEOF(fsListFontsReply), &reply);
1028    (void) WriteToClient(client, stringLens + nnames, bufferStart);
1029    DEALLOCATE_LOCAL(bufferStart);
1030
1031bail:
1032    if (cPtr->slept)
1033	ClientWakeup(client);
1034    for (i = 0; i < cPtr->num_fpes; i++)
1035	FreeFPE(cPtr->fpe_list[i]);
1036    fsfree(cPtr->fpe_list);
1037    if (cPtr->savedName) fsfree(cPtr->savedName);
1038    FreeFontNames(names);
1039    fsfree(cPtr);
1040    return TRUE;
1041}
1042
1043int
1044ListFonts(
1045    ClientPtr   client,
1046    int         length,
1047    unsigned char *pattern,
1048    int         maxNames)
1049{
1050    int         i;
1051    LFclosurePtr c;
1052
1053    /*
1054     * The right error to return here would be BadName, however the
1055     * specification does not allow for a Name error on this request.
1056     * Perhaps a better solution would be to return a nil list, i.e.
1057     * a list containing zero fontnames.
1058     */
1059    if (length > XLFDMAXFONTNAMELEN) {
1060	SendErrToClient(client, FSBadAlloc, (pointer) 0);
1061	return TRUE;
1062    }
1063
1064    if (!(c = (LFclosurePtr) fsalloc(sizeof *c)))
1065	goto badAlloc;
1066    c->fpe_list = (FontPathElementPtr *)
1067	fsalloc(sizeof(FontPathElementPtr) * num_fpes);
1068    if (!c->fpe_list) {
1069	fsfree(c);
1070	goto badAlloc;
1071    }
1072    c->names = MakeFontNamesRecord(maxNames < 100 ? maxNames : 100);
1073    if (!c->names)
1074    {
1075	fsfree(c->fpe_list);
1076	fsfree(c);
1077	goto badAlloc;
1078    }
1079    memmove( c->current.pattern, pattern, length);
1080    for (i = 0; i < num_fpes; i++) {
1081	c->fpe_list[i] = font_path_elements[i];
1082	UseFPE(c->fpe_list[i]);
1083    }
1084    c->client = client;
1085    c->num_fpes = num_fpes;
1086    c->current.patlen = length;
1087    c->current.current_fpe = 0;
1088    c->current.max_names = maxNames;
1089    c->current.list_started = FALSE;
1090    c->current.private = 0;
1091    c->haveSaved = FALSE;
1092    c->slept = FALSE;
1093    c->savedName = 0;
1094    do_list_fonts_and_aliases(client, (pointer) c);
1095    return TRUE;
1096badAlloc:
1097    SendErrToClient(client, FSBadAlloc, (pointer) 0);
1098    return TRUE;
1099}
1100
1101static int padlength[4] = {0, 3, 2, 1};
1102static char padding[3];
1103
1104#undef  cPtr
1105#define cPtr ((LFWXIclosurePtr)data)
1106
1107static Bool
1108do_list_fonts_with_info(ClientPtr client, pointer data)
1109{
1110    FontPathElementPtr fpe;
1111    int         err = Successful;
1112    char       *name;
1113    int         namelen;
1114    int         numFonts;
1115    FontInfoRec fontInfo,
1116               *pFontInfo;
1117    fsListFontsWithXInfoReply *reply;
1118    int         length;
1119    fsPropInfo *prop_info;
1120    int         lenpropdata;
1121    int         i;
1122    int		aliascount = 0;
1123
1124    if (client->clientGone == CLIENT_GONE) {
1125	if (cPtr->current.current_fpe < cPtr->num_fpes) {
1126	    fpe = cPtr->fpe_list[cPtr->current.current_fpe];
1127	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1128	}
1129	err = Successful;
1130	goto bail;
1131    }
1132    while (cPtr->current.current_fpe < cPtr->num_fpes) {
1133	fpe = cPtr->fpe_list[cPtr->current.current_fpe];
1134	err = Successful;
1135	if (!cPtr->current.list_started) {
1136	    err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
1137		((pointer) cPtr->client, fpe, cPtr->current.pattern,
1138		 cPtr->current.patlen, cPtr->current.max_names,
1139		 &cPtr->current.private);
1140	    if (err == Suspended) {
1141		if (!cPtr->slept) {
1142		    ClientSleep(client, do_list_fonts_with_info,
1143				(pointer) cPtr);
1144		    cPtr->slept = TRUE;
1145		}
1146		return TRUE;
1147	    }
1148	    if (err == Successful)
1149		cPtr->current.list_started = TRUE;
1150	}
1151	if (err == Successful) {
1152	    name = 0;
1153	    pFontInfo = &fontInfo;
1154	    err = (*fpe_functions[fpe->type].list_next_font_with_info)
1155		((pointer) cPtr->client, fpe, &name, &namelen,
1156		 &pFontInfo, &numFonts, cPtr->current.private);
1157	    if (err == Suspended) {
1158		if (!cPtr->slept) {
1159		    ClientSleep(client, do_list_fonts_with_info,
1160				(pointer) cPtr);
1161		    cPtr->slept = TRUE;
1162		}
1163		return TRUE;
1164	    }
1165	}
1166	/*
1167	 * When we get an alias back, save our state and reset back to the
1168	 * start of the FPE looking for the specified name.  As soon as a real
1169	 * font is found for the alias, pop back to the old state
1170	 */
1171	if (err == FontNameAlias) {
1172	    /*
1173	     * when an alias recurses, we need to give
1174	     * the last FPE a chance to clean up; so we call
1175	     * it again, and assume that the error returned
1176	     * is BadFontName, indicating the alias resolution
1177	     * is complete.
1178	     */
1179	    if (cPtr->haveSaved)
1180	    {
1181		char	*tmpname;
1182		int	tmpnamelen;
1183		FontInfoPtr tmpFontInfo;
1184
1185	    	tmpname = 0;
1186	    	tmpFontInfo = &fontInfo;
1187	    	(void) (*fpe_functions[fpe->type].list_next_font_with_info)
1188		    ((pointer) client, fpe, &tmpname, &tmpnamelen,
1189		     &tmpFontInfo, &numFonts, cPtr->current.private);
1190		if (--aliascount <= 0)
1191		{
1192		    err = BadFontName;
1193		    goto ContBadFontName;
1194		}
1195	    }
1196	    else
1197	    {
1198		cPtr->saved = cPtr->current;
1199		cPtr->haveSaved = TRUE;
1200		cPtr->savedNumFonts = numFonts;
1201		if (cPtr->savedName)
1202		  fsfree(cPtr->savedName);
1203		cPtr->savedName = (char *)fsalloc(namelen + 1);
1204		if (cPtr->savedName)
1205		  memmove(cPtr->savedName, name, namelen + 1);
1206		aliascount = 20;
1207	    }
1208	    memmove(cPtr->current.pattern, name, namelen);
1209	    cPtr->current.patlen = namelen;
1210	    cPtr->current.max_names = 1;
1211	    cPtr->current.current_fpe = 0;
1212	    cPtr->current.private = 0;
1213	    cPtr->current.list_started = FALSE;
1214	}
1215	/*
1216	 * At the end of this FPE, step to the next.  If we've finished
1217	 * processing an alias, pop state back. If we've sent enough font
1218	 * names, quit.
1219	 */
1220	else if (err == BadFontName) {
1221	  ContBadFontName: ;
1222	    cPtr->current.list_started = FALSE;
1223	    cPtr->current.current_fpe++;
1224	    err = Successful;
1225	    if (cPtr->haveSaved) {
1226		if (cPtr->current.max_names == 0 ||
1227			cPtr->current.current_fpe == cPtr->num_fpes) {
1228		    cPtr->haveSaved = FALSE;
1229		    cPtr->saved.max_names -= (1 - cPtr->current.max_names);
1230		    cPtr->current = cPtr->saved;
1231		}
1232	    }
1233	    else if (cPtr->current.max_names == 0)
1234		break;
1235	} else if (err == Successful) {
1236/* XXX why is it xFontProp ? */
1237	    length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
1238	    reply = cPtr->reply;
1239	    if (cPtr->length < length) {
1240		reply = (fsListFontsWithXInfoReply *) fsrealloc(cPtr->reply, length);
1241		if (!reply) {
1242		    err = AllocError;
1243		    break;
1244		}
1245		cPtr->reply = reply;
1246		cPtr->length = length;
1247	    }
1248	    if (cPtr->haveSaved) {
1249		numFonts = cPtr->savedNumFonts;
1250		name = cPtr->savedName;
1251		namelen = strlen(name);
1252	    }
1253	    fsPack_XFontInfoHeader(pFontInfo, reply, client->major_version);
1254	    err = convert_props(pFontInfo, &prop_info);
1255	    if (err != Successful)
1256		break;
1257	    lenpropdata = SIZEOF(fsPropInfo) +
1258		prop_info->num_offsets * SIZEOF(fsPropOffset) +
1259		prop_info->data_len;
1260
1261	    reply->type = FS_Reply;
1262	    reply->length =
1263		(SIZEOF(fsListFontsWithXInfoReply) +
1264		 lenpropdata + namelen + 3) >> 2;
1265	    reply->sequenceNumber = client->sequence;
1266	    reply->nameLength = namelen;
1267	    reply->nReplies = numFonts;
1268	    WriteReplyToClient(client, SIZEOF(fsListFontsWithXInfoReply), reply);
1269	    if (client->swapped)
1270		SwapPropInfo(prop_info);
1271	    if (client->major_version > 1)
1272	    {
1273		(void)WriteToClientUnpadded(client, lenpropdata, (char *) prop_info);
1274		(void)WriteToClientUnpadded(client, namelen, name);
1275		(void)WriteToClientUnpadded(client,
1276					    padlength[(lenpropdata+namelen)&3],
1277					    padding);
1278	    } else {
1279		(void) WriteToClient(client, namelen, name);
1280		(void) WriteToClient(client, lenpropdata, (char *) prop_info);
1281	    }
1282	    if (pFontInfo == &fontInfo) {
1283		fsfree(fontInfo.props);
1284		fsfree(fontInfo.isStringProp);
1285	    }
1286	    fsfree(prop_info);
1287
1288	    --cPtr->current.max_names;
1289	    if (cPtr->current.max_names < 0)
1290		abort();
1291	}
1292    }
1293
1294    /*
1295     * send the final reply
1296     */
1297    if (err == Successful) {
1298	fsGenericReply *final_reply;
1299
1300	final_reply = (fsGenericReply *)cPtr->reply;
1301	if (client->major_version > 1)
1302	    length = SIZEOF(fsGenericReply);
1303	else
1304	    length = SIZEOF(fsListFontsWithXInfoReply);
1305	if (cPtr->length < length) {
1306	    final_reply = (fsGenericReply *) fsrealloc(cPtr->reply, length);
1307	    if (final_reply) {
1308		cPtr->reply = (fsListFontsWithXInfoReply *)final_reply;
1309		cPtr->length = length;
1310	    } else
1311		err = AllocError;
1312	}
1313	if (err == Successful) {
1314	    final_reply->type = FS_Reply;
1315	    final_reply->data1 = 0; /* notes that this is final */
1316	    final_reply->sequenceNumber = client->sequence;
1317	    final_reply->length = length >> 2;
1318	    WriteReplyToClient(client, length, final_reply);
1319	}
1320    }
1321    if (err != Successful)
1322	SendErrToClient(client, FontToFSError(err), (pointer) 0);
1323bail:
1324    if (cPtr->slept)
1325	ClientWakeup(client);
1326    for (i = 0; i < cPtr->num_fpes; i++)
1327	FreeFPE(cPtr->fpe_list[i]);
1328    fsfree(cPtr->fpe_list);
1329    if (cPtr->savedName) fsfree(cPtr->savedName);
1330    fsfree(cPtr->reply);
1331    fsfree(cPtr);
1332    return TRUE;
1333}
1334
1335int
1336StartListFontsWithInfo(
1337    ClientPtr   client,
1338    int         length,
1339    unsigned char *pattern,
1340    int         maxNames)
1341{
1342    int         i;
1343    LFWXIclosurePtr c;
1344
1345    /*
1346     * The right error to return here would be BadName, however the
1347     * specification does not allow for a Name error on this request.
1348     * Perhaps a better solution would be to return a nil list, i.e.
1349     * a list containing zero fontnames.
1350     */
1351    if (length > XLFDMAXFONTNAMELEN) {
1352	SendErrToClient(client, FSBadAlloc, (pointer) 0);
1353	return TRUE;
1354    }
1355
1356    if (!(c = (LFWXIclosurePtr) fsalloc(sizeof *c)))
1357	goto badAlloc;
1358    c->fpe_list = (FontPathElementPtr *)
1359	fsalloc(sizeof(FontPathElementPtr) * num_fpes);
1360    if (!c->fpe_list) {
1361	fsfree(c);
1362	goto badAlloc;
1363    }
1364    memmove( c->current.pattern, pattern, length);
1365    for (i = 0; i < num_fpes; i++) {
1366	c->fpe_list[i] = font_path_elements[i];
1367	UseFPE(c->fpe_list[i]);
1368    }
1369    c->client = client;
1370    c->num_fpes = num_fpes;
1371    c->reply = 0;
1372    c->length = 0;
1373    c->current.patlen = length;
1374    c->current.current_fpe = 0;
1375    c->current.max_names = maxNames;
1376    c->current.list_started = FALSE;
1377    c->current.private = 0;
1378    c->savedNumFonts = 0;
1379    c->haveSaved = FALSE;
1380    c->slept = FALSE;
1381    c->savedName = 0;
1382    do_list_fonts_with_info(client, (pointer) c);
1383    return TRUE;
1384badAlloc:
1385    SendErrToClient(client, FSBadAlloc, (pointer) 0);
1386    return TRUE;
1387}
1388
1389int
1390LoadGlyphRanges(
1391    ClientPtr   client,
1392    FontPtr	pfont,
1393    Bool	range_flag,
1394    int		num_ranges,
1395    int		item_size,
1396    fsChar2b	*data)
1397{
1398    /* either returns Successful, Suspended, or some nasty error */
1399    if (fpe_functions[pfont->fpe->type].load_glyphs)
1400	return (*fpe_functions[pfont->fpe->type].load_glyphs)(
1401		(pointer)client, pfont, range_flag, num_ranges, item_size,
1402		(unsigned char *)data);
1403    else
1404	return Successful;
1405}
1406
1407
1408int
1409RegisterFPEFunctions(
1410    Bool          (*name_func) (char *name),
1411    InitFpeFunc   init_func,
1412    FreeFpeFunc   free_func,
1413    ResetFpeFunc  reset_func,
1414    OpenFontFunc  open_func,
1415    CloseFontFunc close_func,
1416    ListFontsFunc list_func,
1417    StartLfwiFunc start_lfwi_func,
1418    NextLfwiFunc  next_lfwi_func,
1419    WakeupFpeFunc wakeup_func,
1420    ClientDiedFunc client_died,
1421    LoadGlyphsFunc load_glyphs,
1422    StartLaFunc   start_list_alias_func,
1423    NextLaFunc    next_list_alias_func,
1424    void	  (*set_path_func) (void))
1425{
1426    FPEFunctions *new;
1427
1428    /* grow the list */
1429    new = (FPEFunctions *) fsrealloc(fpe_functions,
1430				 (num_fpe_types + 1) * sizeof(FPEFunctions));
1431    if (!new)
1432	return -1;
1433    fpe_functions = new;
1434
1435    fpe_functions[num_fpe_types].name_check = name_func;
1436    fpe_functions[num_fpe_types].open_font = open_func;
1437    fpe_functions[num_fpe_types].close_font = close_func;
1438    fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func;
1439    fpe_functions[num_fpe_types].list_fonts = list_func;
1440    fpe_functions[num_fpe_types].start_list_fonts_with_info =
1441	start_lfwi_func;
1442    fpe_functions[num_fpe_types].list_next_font_with_info =
1443	next_lfwi_func;
1444    fpe_functions[num_fpe_types].init_fpe = init_func;
1445    fpe_functions[num_fpe_types].free_fpe = free_func;
1446    fpe_functions[num_fpe_types].reset_fpe = reset_func;
1447
1448    fpe_functions[num_fpe_types].client_died = client_died;
1449    fpe_functions[num_fpe_types].load_glyphs = load_glyphs;
1450    fpe_functions[num_fpe_types].start_list_fonts_and_aliases =
1451	start_list_alias_func;
1452    fpe_functions[num_fpe_types].list_next_font_or_alias =
1453	next_list_alias_func;
1454    fpe_functions[num_fpe_types].set_path_hook = set_path_func;
1455
1456    return num_fpe_types++;
1457}
1458
1459void
1460FreeFonts(void)
1461{
1462}
1463
1464/* convenience functions for FS interface */
1465
1466FontPtr
1467find_old_font(FSID id)
1468{
1469    return (FontPtr) LookupIDByType(SERVER_CLIENT, id, RT_NONE);
1470}
1471
1472Font
1473GetNewFontClientID(void)
1474{
1475    return (Font) FakeClientID(SERVER_CLIENT);
1476}
1477
1478int
1479StoreFontClientFont(
1480    FontPtr     pfont,
1481    Font        id)
1482{
1483    return AddResource(SERVER_CLIENT, id, RT_NONE, (pointer) pfont);
1484}
1485
1486void
1487DeleteFontClientID(Font id)
1488{
1489    FreeResource(SERVER_CLIENT, id, RT_NONE);
1490}
1491
1492static int  fs_handlers_installed = 0;
1493static unsigned int last_server_gen;
1494
1495int
1496init_fs_handlers(
1497    FontPathElementPtr fpe,
1498    BlockHandlerProcPtr block_handler)
1499{
1500    /* if server has reset, make sure the b&w handlers are reinstalled */
1501    if (last_server_gen < serverGeneration) {
1502	last_server_gen = serverGeneration;
1503	fs_handlers_installed = 0;
1504    }
1505    if (fs_handlers_installed == 0) {
1506
1507#ifdef DEBUG
1508	fprintf(stderr, "adding FS b & w handlers\n");
1509#endif
1510
1511	if (!RegisterBlockAndWakeupHandlers(block_handler,
1512					    FontWakeup, (pointer) 0))
1513	    return AllocError;
1514	fs_handlers_installed++;
1515    }
1516    QueueFontWakeup(fpe);
1517    return Successful;
1518}
1519
1520void
1521remove_fs_handlers(
1522    FontPathElementPtr fpe,
1523    BlockHandlerProcPtr block_handler,
1524    Bool        all)
1525{
1526    if (all) {
1527	/* remove the handlers if no one else is using them */
1528	if (--fs_handlers_installed == 0) {
1529
1530#ifdef DEBUG
1531	    fprintf(stderr, "removing FS b & w handlers\n");
1532#endif
1533
1534	    RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
1535					 (pointer) 0);
1536	}
1537    }
1538    RemoveFontWakeup(fpe);
1539}
1540
1541void
1542DeleteClientFontStuff(ClientPtr client)
1543{
1544    int i;
1545    FontPathElementPtr fpe;
1546
1547    for (i = 0; i < num_fpes; i++)
1548    {
1549	fpe = font_path_elements[i];
1550
1551	if (fpe_functions[fpe->type].client_died)
1552	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1553    }
1554}
1555