fonts.c revision 40c5823b
1/*
2 * font control
3 */
4/*
5
6Copyright 1990, 1991, 1998  The Open Group
7
8Permission to use, copy, modify, distribute, and sell this software and its
9documentation for any purpose is hereby granted without fee, provided that
10the above copyright notice appear in all copies and that both that
11copyright notice and this permission notice appear in supporting
12documentation.
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of The Open Group shall not be
25used in advertising or otherwise to promote the sale, use or other dealings
26in this Software without prior written authorization from The Open Group.
27
28 * Copyright 1990, 1991 Network Computing Devices;
29 * Portions Copyright 1987 by Digital Equipment Corporation
30 *
31 * Permission to use, copy, modify, distribute, and sell this software and
32 * its documentation for any purpose is hereby granted without fee, provided
33 * that the above copyright notice appear in all copies and that both that
34 * copyright notice and this permission notice appear in supporting
35 * documentation, and that the names of Network Computing Devices or Digital
36 * not be used in advertising or publicity pertaining to distribution
37 * of the software without specific, written prior permission.
38 *
39 * NETWORK COMPUTING DEVICES AND DIGITAL DISCLAIM ALL WARRANTIES WITH
40 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
41 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES
42 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
43 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
44 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
45 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
46 * THIS SOFTWARE.
47 */
48/*#define DEBUG*/
49
50#include	"config.h"
51
52#include        <X11/fonts/FS.h>
53#include        <X11/fonts/FSproto.h>
54#include	<stdio.h>
55#include	<stdlib.h>
56#include	<X11/Xos.h>
57#include	"clientstr.h"
58#include	"fsresource.h"
59#include	"difsfnst.h"
60#include	<X11/fonts/fontstruct.h>
61#include	"closestr.h"
62#include	"globals.h"
63#include	"difs.h"
64#include	"dispatch.h"
65#include	"swaprep.h"
66#include        <X11/fonts/libxfont2.h>
67
68static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
69static int  num_fpes = 0;
70static xfont2_fpe_funcs_rec *fpe_functions;
71static int  num_fpe_types = 0;
72
73static int  num_slept_fpes = 0;
74static int  size_slept_fpes = 0;
75static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
76
77#define	NUM_IDS_PER_CLIENT	5
78
79int
80FontToFSError(int err)
81{
82    switch (err) {
83    case Successful:
84	return FSSuccess;
85    case AllocError:
86	return FSBadAlloc;
87    case BadFontName:
88    case BadFontPath:
89	return FSBadName;
90    case BadFontFormat:
91	return FSBadFormat;
92    case BadCharRange:
93	return FSBadRange;
94    default:
95	return err;
96    }
97}
98
99static inline void
100UseFPE(FontPathElementPtr fpe)
101{
102    fpe->refcount++;
103}
104
105static inline void
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 */
125static void
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
154static void
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 */
172static void
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);
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    Font        orig;
281    FontIDListPtr *idlist,
282                ids;
283    int		aliascount = 20;
284
285    if (client->clientGone == CLIENT_GONE) {
286	if (cPtr->current_fpe < cPtr->num_fpes) {
287	    fpe = cPtr->fpe_list[cPtr->current_fpe];
288	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
289	}
290	err = Successful;
291	goto dropout;
292    }
293    while (cPtr->current_fpe < cPtr->num_fpes) {
294	fpe = cPtr->fpe_list[cPtr->current_fpe];
295	err = (*fpe_functions[fpe->type].open_font)
296	    ((pointer) cPtr->client, fpe, cPtr->flags,
297	     cPtr->fontname, cPtr->fnamelen, cPtr->format, cPtr->format_mask,
298	     cPtr->fontid, &pfont, &alias,
299	     cPtr->non_cachable_font && cPtr->non_cachable_font->fpe == fpe ?
300		 cPtr->non_cachable_font :
301		 (FontPtr)0);
302
303	if (err == FontNameAlias && alias) {
304	    newlen = strlen(alias);
305	    newname = (char *) fsrealloc(cPtr->fontname, newlen);
306	    if (!newname) {
307		err = AllocError;
308		break;
309	    }
310	    memmove( newname, alias, newlen);
311	    cPtr->fontname = newname;
312	    cPtr->fnamelen = newlen;
313	    cPtr->current_fpe = 0;
314	    if (--aliascount <= 0) break;
315	    continue;
316	}
317	if (err == BadFontName) {
318	    cPtr->current_fpe++;
319	    continue;
320	}
321	if (err == Suspended) {
322	    if (!cPtr->slept) {
323		cPtr->slept = TRUE;
324		ClientSleep(client, do_open_font, (pointer) cPtr);
325	    }
326	    return TRUE;
327	}
328	break;
329    }
330    if (err != Successful) {
331	goto dropout;
332    }
333    if (!pfont) {
334	err = BadFontName;
335	goto dropout;
336    }
337    cfp = (ClientFontPtr) fsalloc(sizeof(ClientFontRec));
338    if (!cfp) {
339	err = AllocError;
340	goto dropout;
341    }
342    cfp->font = pfont;
343    cfp->clientindex = cPtr->client->index;
344
345    if (fontPatternCache && pfont != cPtr->non_cachable_font)
346	xfont2_cache_font_pattern(fontPatternCache, cPtr->orig_name,
347                                  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    else {
390        /* send the reply */
391	fsOpenBitmapFontReply rep = {
392	    .type = FS_Reply,
393	    .otherid_valid = orig ? TRUE : FALSE,
394	    .sequenceNumber = client->sequence,
395	    .length = SIZEOF(fsOpenBitmapFontReply) >> 2,
396	    .otherid = orig,
397	    .cachable = pfont->info.cachable
398	};
399	WriteReplyToClient(client,
400			   SIZEOF(fsOpenBitmapFontReply), &rep);
401	add_id_to_list(ids, cPtr->fontid);
402	if (pfont->refcnt == 0) {
403	    if (!pfont->fpe)
404		pfont->fpe = fpe;
405	    UseFPE(pfont->fpe);
406	}
407	pfont->refcnt++;
408    }
409dropout:
410    if (err != Successful) {
411	SendErrToClient(cPtr->client, FontToFSError(err), (pointer) &(cPtr->fontid));
412    }
413    if (cPtr->slept)
414	ClientWakeup(cPtr->client);
415    for (i = 0; i < cPtr->num_fpes; i++) {
416	FreeFPE(cPtr->fpe_list[i]);
417    }
418    fsfree(cPtr->fpe_list);
419    fsfree(cPtr->fontname);
420    fsfree(cPtr);
421    return TRUE;
422}
423
424int
425OpenFont(
426    ClientPtr   client,
427    Font        fid,
428    fsBitmapFormat format,
429    fsBitmapFormatMask format_mask,
430    int         namelen,
431    char       *name)
432{
433    FontPtr     pfont = (FontPtr)0;
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 = xfont2_find_cached_font_pattern(fontPatternCache, name,
465                                                   namelen)) &&
466	   pfont->info.cachable) {
467	ClientFontPtr cfp;
468
469	idlist = (FontIDListPtr *) pfont->svrPrivate;
470	ids = idlist[client->index];
471	if (!ids) {
472	    ids = make_clients_id_list();
473	    if (!ids) {
474		goto lowmem;
475	    }
476	    idlist[client->index] = ids;
477	}
478	cfp = (ClientFontPtr) fsalloc(sizeof(ClientFontRec));
479	if (!cfp) {
480    lowmem:
481	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
482	    return FSBadAlloc;
483	}
484	cfp->font = pfont;
485	cfp->clientindex = client->index;
486	if (!AddResource(client->index, fid, RT_FONT, (pointer) cfp)) {
487	    goto lowmem;
488	}
489	if (!add_id_to_list(ids, fid)) {
490	    goto lowmem;
491	}
492	else {
493	    fsOpenBitmapFontReply rep = {
494		.type = FS_Reply,
495		.otherid_valid = (ids->num > 1) ? TRUE : FALSE,
496		.sequenceNumber = client->sequence,
497		.length = SIZEOF(fsOpenBitmapFontReply) >> 2,
498		.otherid = (ids->num > 1) ? ids->client_list[0] : 0,
499		.cachable = TRUE	/* XXX */
500	    };
501	    WriteReplyToClient(client,
502			       SIZEOF(fsOpenBitmapFontReply), &rep);
503	    pfont->refcnt++;
504	    return FSSuccess;
505	}
506    }
507    c = (OFclosurePtr) fsalloc(sizeof(OFclosureRec));
508    if (!c)
509	goto lowmem;
510    c->fontname = (char *) fsalloc(namelen);
511    if (!c->fontname) {
512	fsfree(c);
513	goto lowmem;
514    }
515    /*
516     * copy the current FPE list, so that if it gets changed by another client
517     * while we're blocking, the request still appears atomic
518     */
519    c->fpe_list = (FontPathElementPtr *)
520	fsalloc(sizeof(FontPathElementPtr) * num_fpes);
521    if (!c->fpe_list) {
522	fsfree(c->fontname);
523	fsfree(c);
524	goto lowmem;
525    }
526    memmove( c->fontname, name, namelen);
527    for (i = 0; i < num_fpes; i++) {
528	c->fpe_list[i] = font_path_elements[i];
529	UseFPE(c->fpe_list[i]);
530    }
531    c->client = client;
532    c->fontid = fid;
533    c->current_fpe = 0;
534    c->num_fpes = num_fpes;
535    c->fnamelen = namelen;
536    c->orig_name = name;
537    c->orig_len = namelen;
538    c->slept = FALSE;
539    c->flags = (FontLoadInfo | FontLoadProps);
540    c->format = format;
541    c->format_mask = format_mask;
542    c->non_cachable_font = pfont;
543
544    (void) do_open_font(client, (pointer) c);
545    return FSSuccess;
546}
547
548static int
549close_font(FontPtr pfont)
550{
551    FontPathElementPtr fpe;
552
553    assert(pfont);
554    if (--pfont->refcnt == 0) {
555	if (fontPatternCache)
556	    xfont2_remove_cached_font_pattern(fontPatternCache, pfont);
557	fpe = pfont->fpe;
558	free_svrPrivate(pfont->svrPrivate);
559	(*fpe_functions[fpe->type].close_font) (fpe, pfont);
560	FreeFPE(fpe);
561    }
562    return FSSuccess;
563}
564
565int
566CloseClientFont(
567    ClientFontPtr cfp,
568    FSID        fid)
569{
570    FontIDListPtr *idlist;
571    FontIDListPtr ids;
572    int ret;
573
574    assert(cfp);
575    /* clear otherid id */
576    idlist = (FontIDListPtr *) cfp->font->svrPrivate;
577    ids = idlist[cfp->clientindex];
578    remove_id_from_list(ids, fid);
579    ret = close_font(cfp->font);
580    fsfree((char *) cfp);
581    return ret;
582}
583
584/*
585 * search all the known FPE prefixes looking for one to match the given
586 * FPE name
587 */
588static int
589determine_fpe_type(char *name)
590{
591    int	i;
592    for (i = 0; i < num_fpe_types; i++) {
593	if ((*fpe_functions[i].name_check) (name))
594	    return i;
595    }
596    return -1;
597}
598
599static void
600free_font_path(FontPathElementPtr *list, int n)
601{
602    int         i;
603
604    for (i = 0; i < n; i++) {
605	FreeFPE(list[i]);
606    }
607    fsfree((char *) list);
608}
609
610static FontPathElementPtr
611find_existing_fpe(
612    FontPathElementPtr *list,
613    int         num,
614    char       *name,
615    int         len)
616{
617    FontPathElementPtr fpe;
618    int         i;
619
620    for (i = 0; i < num; i++) {
621	fpe = list[i];
622	if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
623	    return fpe;
624    }
625    return (FontPathElementPtr) 0;
626}
627
628/*
629 * does the work of setting up the fpe list
630 *
631 * paths should be a counted string
632 */
633static int
634set_font_path_elements(
635    int         npaths,
636    char       *paths,
637    int        *bad)
638{
639    int		i, validpaths, err = 0;
640    int		len;
641    int		type;
642    char       *cp = paths;
643    char       *name;
644    FontPathElementPtr fpe, *fplist;
645
646    fplist = (FontPathElementPtr *)
647	fsalloc(sizeof(FontPathElementPtr) * npaths);
648    if (!fplist) {
649	*bad = 0;
650	return FSBadAlloc;
651    }
652    for (i = 0; i < num_fpe_types; i++) {
653	if (fpe_functions[i].set_path_hook)
654	    (*fpe_functions[i].set_path_hook) ();
655    }
656    for (i = 0, validpaths = 0; i < npaths; i++) {
657	len = *cp++;
658	if (len) {
659	    /* if it's already in our active list, just reset it */
660	    /*
661	     * note that this can miss FPE's in limbo -- may be worth catching
662	     * them, though it'd muck up refcounting
663	     */
664	    fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
665	    if (fpe) {
666		err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
667		if (err == Successful) {
668		    UseFPE(fpe);/* since it'll be decref'd later when freed
669				 * from the old list */
670		    fplist[validpaths++] = fpe;
671		    cp += len;
672		    continue;
673		}
674		/* can't do it, so act like it's a new one */
675	    }
676	    name = (char *) fsalloc(len + 1);
677	    if (!name) {
678		err = FSBadAlloc;
679		goto bail;
680	    }
681	    strncpy(name, (char *) cp, len);
682	    name[len] = '\0';
683	    type = determine_fpe_type(name);
684	    if (type == -1)
685	    {
686		NoticeF("ignoring font path element %s (bad font path descriptor)\n", name);
687		fsfree(name);
688		cp += len;
689		continue;
690	    }
691	    /* must be new -- make it */
692	    fpe = (FontPathElementPtr) fsalloc(sizeof(FontPathElementRec));
693	    if (!fpe) {
694		fsfree(name);
695		err = FSBadAlloc;
696		goto bail;
697	    }
698	    fpe->type = type;
699	    fpe->name = name;
700	    fpe->refcount = 1;
701
702	    cp += len;
703	    fpe->name_length = len;
704	    err = (*fpe_functions[fpe->type].init_fpe) (fpe);
705	    if (err != Successful) {
706		NoticeF("ignoring font path element %s (unreadable)\n", fpe->name);
707		fsfree(fpe->name);
708		fsfree(fpe);
709		continue;
710	    }
711	    fplist[validpaths++] = fpe;
712	}
713    }
714    if (validpaths < npaths) {
715	FontPathElementPtr *ftmp = (FontPathElementPtr *)
716	    fsrealloc(fplist, sizeof(FontPathElementPtr) * validpaths);
717
718	if (!ftmp && validpaths)
719	    goto bail;
720
721	fplist = ftmp;
722	npaths = validpaths;
723    }
724    if (validpaths == 0) {
725	err = FontToFSError(err);
726	goto bail;
727    }
728    free_font_path(font_path_elements, num_fpes);
729    font_path_elements = fplist;
730    num_fpes = npaths;
731    if (fontPatternCache)
732	xfont2_empty_font_pattern_cache(fontPatternCache);
733    return FSSuccess;
734bail:
735    *bad = validpaths;
736    while (--validpaths >= 0)
737	FreeFPE(fplist[i]);
738    fsfree(fplist);
739    return err;
740}
741
742/*
743 * expects comma seperated string
744 */
745int
746SetFontCatalogue(
747    char       *str,
748    int        *badpath)
749{
750    int         len,
751                npaths;
752    char       *paths,
753               *end,
754               *p;
755    int         err;
756
757    len = strlen(str) + 1;
758    paths = p = (char *) ALLOCATE_LOCAL(len);
759    npaths = 0;
760
761    while (*str) {
762	end = index(str, ',');
763	if (!end) {
764	    end = str + strlen(str);
765	}
766	*p++ = len = end - str;
767	memmove( p, str, len);
768	npaths++;
769	str += len;		/* skip entry */
770	if (*str == ',')
771           str++;		/* skip any comma */
772	p += len;
773    }
774
775    err = set_font_path_elements(npaths, paths, badpath);
776
777    DEALLOCATE_LOCAL(paths);
778
779    return err;
780}
781
782#undef  cPtr
783#define cPtr ((LFclosurePtr)data)
784
785static Bool
786do_list_fonts_and_aliases(ClientPtr client, pointer data)
787{
788    FontPathElementPtr fpe;
789    int         err = Successful;
790    FontNamesPtr names = NULL;
791    char       *name, *resolved;
792    int         namelen, resolvedlen;
793    int		nnames;
794    int         stringLens;
795    int         i;
796    fsListFontsReply reply;
797    char	*bufptr;
798    char	*bufferStart;
799    int		aliascount = 0;
800
801    if (client->clientGone == CLIENT_GONE) {
802	if (cPtr->current.current_fpe < cPtr->num_fpes) {
803	    fpe = cPtr->fpe_list[cPtr->current.current_fpe];
804	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
805	}
806	err = Successful;
807	goto bail;
808    }
809
810    if (!cPtr->current.patlen)
811	goto finish;
812
813    while (cPtr->current.current_fpe < cPtr->num_fpes) {
814	fpe = cPtr->fpe_list[cPtr->current.current_fpe];
815	err = Successful;
816
817	if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
818	{
819	    /* This FPE doesn't support/require list_fonts_and_aliases */
820
821	    err = (*fpe_functions[fpe->type].list_fonts)
822		((pointer) cPtr->client, fpe, cPtr->current.pattern,
823		 cPtr->current.patlen, cPtr->current.max_names - cPtr->names->nnames,
824		 cPtr->names);
825
826	    if (err == Suspended) {
827		if (!cPtr->slept) {
828		    cPtr->slept = TRUE;
829		    ClientSleep(client, do_list_fonts_and_aliases, (pointer) cPtr);
830		}
831		return TRUE;
832	    }
833
834	    err = BadFontName;
835	}
836	else
837	{
838	    /* Start of list_fonts_and_aliases functionality.  Modeled
839	       after list_fonts_with_info in that it resolves aliases,
840	       except that the information collected from FPEs is just
841	       names, not font info.  Each list_next_font_or_alias()
842	       returns either a name into name/namelen or an alias into
843	       name/namelen and its target name into resolved/resolvedlen.
844	       The code at this level then resolves the alias by polling
845	       the FPEs.  */
846
847	    if (!cPtr->current.list_started) {
848		err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
849		    ((pointer) cPtr->client, fpe, cPtr->current.pattern,
850		     cPtr->current.patlen, cPtr->current.max_names - cPtr->names->nnames,
851		     &cPtr->current.private);
852		if (err == Suspended) {
853		    if (!cPtr->slept) {
854			ClientSleep(client, do_list_fonts_and_aliases,
855				    (pointer) cPtr);
856			cPtr->slept = TRUE;
857		    }
858		    return TRUE;
859		}
860		if (err == Successful)
861		    cPtr->current.list_started = TRUE;
862	    }
863	    if (err == Successful) {
864		name = NULL;
865		err = (*fpe_functions[fpe->type].list_next_font_or_alias)
866		    ((pointer) cPtr->client, fpe, &name, &namelen, &resolved,
867		     &resolvedlen, cPtr->current.private);
868		if (err == Suspended) {
869		    if (!cPtr->slept) {
870			ClientSleep(client, do_list_fonts_and_aliases,
871				    (pointer) cPtr);
872			cPtr->slept = TRUE;
873		    }
874		    return TRUE;
875		}
876	    }
877
878	    if (err == Successful)
879	    {
880		if (cPtr->haveSaved)
881		{
882		    if (cPtr->savedName)
883			xfont2_add_font_names_name(cPtr->names, cPtr->savedName,
884                                                   cPtr->savedNameLen);
885		}
886		else
887		    xfont2_add_font_names_name(cPtr->names, name, namelen);
888	    }
889
890	    /*
891	     * When we get an alias back, save our state and reset back to
892	     * the start of the FPE looking for the specified name.  As
893	     * soon as a real font is found for the alias, pop back to the
894	     * old state
895	     */
896	    else if (err == FontNameAlias) {
897		char	tmp_pattern[XLFDMAXFONTNAMELEN];
898		/*
899		 * when an alias recurses, we need to give
900		 * the last FPE a chance to clean up; so we call
901		 * it again, and assume that the error returned
902		 * is BadFontName, indicating the alias resolution
903		 * is complete.
904		 */
905		memmove(tmp_pattern, resolved, resolvedlen);
906		if (cPtr->haveSaved)
907		{
908		    char    *tmpname;
909		    int     tmpnamelen;
910
911		    tmpname = NULL;
912		    (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
913			((pointer) cPtr->client, fpe, &tmpname, &tmpnamelen,
914			 &tmpname, &tmpnamelen, cPtr->current.private);
915		    if (--aliascount <= 0)
916		    {
917			err = BadFontName;
918			goto ContBadFontName;
919		    }
920		}
921		else
922		{
923		    cPtr->saved = cPtr->current;
924		    cPtr->haveSaved = TRUE;
925		    if (cPtr->savedName)
926			fsfree(cPtr->savedName);
927		    cPtr->savedName = (char *)fsalloc(namelen + 1);
928		    if (cPtr->savedName)
929			memmove(cPtr->savedName, name, namelen + 1);
930		    cPtr->savedNameLen = namelen;
931		    aliascount = 20;
932		}
933		memmove(cPtr->current.pattern, tmp_pattern, resolvedlen);
934		cPtr->current.patlen = resolvedlen;
935		cPtr->current.max_names = cPtr->names->nnames + 1;
936		cPtr->current.current_fpe = -1;
937		cPtr->current.private = NULL;
938		err = BadFontName;
939	    }
940	}
941	/*
942	 * At the end of this FPE, step to the next.  If we've finished
943	 * processing an alias, pop state back. If we've collected enough
944	 * font names, quit.
945	 */
946	if (err == BadFontName) {
947	  ContBadFontName: ;
948	    cPtr->current.list_started = FALSE;
949	    cPtr->current.current_fpe++;
950	    err = Successful;
951	    if (cPtr->haveSaved)
952	    {
953		/* If we're searching for an alias, limit the search to
954		   FPE's of the same type as the one the alias came
955		   from.  This is unnecessarily restrictive, but if we
956		   have both fontfile and fs FPE's, this restriction can
957		   drastically reduce network traffic to the fs -- else
958		   we could poll the fs for *every* local alias found;
959		   on a typical system enabling FILE_NAMES_ALIASES, this
960		   is significant.  */
961
962		while (cPtr->current.current_fpe < cPtr->num_fpes &&
963		       cPtr->fpe_list[cPtr->current.current_fpe]->type !=
964		       cPtr->fpe_list[cPtr->saved.current_fpe]->type)
965		cPtr->current.current_fpe++;
966
967		if (cPtr->names->nnames == cPtr->current.max_names ||
968			cPtr->current.current_fpe == cPtr->num_fpes) {
969		    cPtr->haveSaved = FALSE;
970		    cPtr->current = cPtr->saved;
971		    /* Give the saved namelist a chance to clean itself up */
972		    continue;
973		}
974	    }
975	    if (cPtr->names->nnames == cPtr->current.max_names)
976		break;
977	}
978    }
979
980    /*
981     * send the reply
982     */
983    if (err != Successful) {
984	SendErrToClient(client, FontToFSError(err), (pointer) 0);
985	goto bail;
986    }
987
988finish:
989
990    names = cPtr->names;
991    nnames = names->nnames;
992    client = cPtr->client;
993    stringLens = 0;
994    for (i = 0; i < nnames; i++)
995	stringLens += (names->length[i] <= 255) ? names->length[i] : 0;
996
997    reply = (fsListFontsReply) {
998	.type = FS_Reply,
999	.sequenceNumber = client->sequence,
1000	.length = (SIZEOF(fsListFontsReply) + stringLens + nnames + 3) >> 2,
1001	.following = 0,
1002	.nFonts = nnames
1003    };
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    xfont2_free_font_names(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 = xfont2_make_font_names_record(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 = NULL;
1091    c->haveSaved = FALSE;
1092    c->slept = FALSE;
1093    c->savedName = NULL;
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 = NULL;
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 = NULL;
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 = NULL;
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		break;
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 = NULL;
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 = NULL;
1378    c->savedNumFonts = 0;
1379    c->haveSaved = FALSE;
1380    c->slept = FALSE;
1381    c->savedName = NULL;
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
1409register_fpe_funcs(const xfont2_fpe_funcs_rec *funcs)
1410{
1411    xfont2_fpe_funcs_rec *new;
1412
1413    /* grow the list */
1414    new = fsrealloc(fpe_functions, (num_fpe_types + 1) * sizeof(*new));
1415    if (!new)
1416	return -1;
1417    fpe_functions = new;
1418
1419    memcpy(&fpe_functions[num_fpe_types], funcs, sizeof(*funcs));
1420
1421    return num_fpe_types++;
1422}
1423
1424
1425/* convenience functions for FS interface */
1426
1427FontPtr
1428find_old_font(FSID id)
1429{
1430    return (FontPtr) LookupIDByType(SERVER_CLIENT, id, RT_NONE);
1431}
1432
1433Font
1434GetNewFontClientID(void)
1435{
1436    return (Font) FakeClientID(SERVER_CLIENT);
1437}
1438
1439int
1440StoreFontClientFont(
1441    FontPtr     pfont,
1442    Font        id)
1443{
1444    return AddResource(SERVER_CLIENT, id, RT_NONE, (pointer) pfont);
1445}
1446
1447void
1448DeleteFontClientID(Font id)
1449{
1450    FreeResource(SERVER_CLIENT, id, RT_NONE);
1451}
1452
1453static int  fs_handlers_installed = 0;
1454static unsigned int last_server_gen;
1455
1456int
1457xfs_init_fs_handlers(
1458    FontPathElementPtr fpe,
1459    FontBlockHandlerProcPtr block_handler)
1460{
1461    /* if server has reset, make sure the b&w handlers are reinstalled */
1462    if (last_server_gen < serverGeneration) {
1463	last_server_gen = serverGeneration;
1464	fs_handlers_installed = 0;
1465    }
1466    if (fs_handlers_installed == 0) {
1467
1468#ifdef DEBUG
1469	fprintf(stderr, "adding FS b & w handlers\n");
1470#endif
1471
1472	if (!RegisterBlockAndWakeupHandlers(block_handler,
1473					    FontWakeup, (pointer) 0))
1474	    return AllocError;
1475	fs_handlers_installed++;
1476    }
1477    QueueFontWakeup(fpe);
1478    return Successful;
1479}
1480
1481void
1482xfs_remove_fs_handlers(
1483    FontPathElementPtr fpe,
1484    FontBlockHandlerProcPtr block_handler,
1485    Bool        all)
1486{
1487    if (all) {
1488	/* remove the handlers if no one else is using them */
1489	if (--fs_handlers_installed == 0) {
1490
1491#ifdef DEBUG
1492	    fprintf(stderr, "removing FS b & w handlers\n");
1493#endif
1494
1495	    RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
1496					 (pointer) 0);
1497	}
1498    }
1499    RemoveFontWakeup(fpe);
1500}
1501
1502void
1503DeleteClientFontStuff(ClientPtr client)
1504{
1505    int i;
1506    FontPathElementPtr fpe;
1507
1508    for (i = 0; i < num_fpes; i++)
1509    {
1510	fpe = font_path_elements[i];
1511
1512	if (fpe_functions[fpe->type].client_died)
1513	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1514    }
1515}
1516