fonts.c revision e1db7cd1
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	    FSreallocarray(slept_fpes, (size_slept_fpes + 4),
144			   sizeof(FontPathElementPtr));
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 *) FSreallocarray(ids->client_list,
198					  (ids->size + NUM_IDS_PER_CLIENT),
199					  sizeof(Font));
200	if (!newlist)
201	    return FALSE;
202	ids->client_list = newlist;
203	ids->size += NUM_IDS_PER_CLIENT;
204    }
205    ids->client_list[ids->num++] = fid;
206    return TRUE;
207}
208
209static void
210remove_id_from_list(FontIDListPtr ids, Font fid)
211{
212    int         i;
213
214    for (i = 0; i < ids->num; i++) {
215	if (ids->client_list[i] == fid) {
216	    /* a memmove() might be better here */
217	    while (i < ids->num) {
218		ids->client_list[i] = ids->client_list[i + 1];
219		i++;
220	    }
221	    ids->num--;
222	    return;
223	}
224    }
225    assert(0);
226}
227
228static FontIDListPtr
229make_clients_id_list(void)
230{
231    FontIDListPtr ids;
232    Font       *fids;
233
234    ids = (FontIDListPtr) FSalloc(sizeof(FontIDListRec));
235    fids = (Font *) FScalloc(NUM_IDS_PER_CLIENT, sizeof(Font));
236    if (!ids || !fids) {
237	FSfree(ids);
238	FSfree(fids);
239	return (FontIDListPtr) 0;
240    }
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 *)
365            FScalloc(MAXCLIENTS, sizeof(FontIDListPtr));
366	if (!idlist) {
367	    err = AllocError;
368	    FSfree(cfp);
369	    goto dropout;
370	}
371	ids = make_clients_id_list();
372	if (!ids) {
373	    err = AllocError;
374	    FSfree(idlist);
375	    FSfree(cfp);
376	    goto dropout;
377	}
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	FSallocarray(num_fpes, sizeof(FontPathElementPtr));
521    if (!c->fpe_list) {
522	FSfree(c->fontname);
523	FSfree(c);
524	goto lowmem;
525    }
526    memcpy(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	FSallocarray(npaths, sizeof(FontPathElementPtr));
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	    FSreallocarray(fplist, validpaths, sizeof(FontPathElementPtr));
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 separated 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    if (p == NULL)
761        return FSBadAlloc;
762
763    while (*str) {
764	end = index(str, ',');
765	if (!end) {
766	    end = str + strlen(str);
767	}
768	*p++ = len = end - str;
769	memcpy(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 = NULL;
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			xfont2_add_font_names_name(cPtr->names, cPtr->savedName,
886                                                   cPtr->savedNameLen);
887		}
888		else
889		    xfont2_add_font_names_name(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		memcpy(tmp_pattern, resolved, resolvedlen);
908		if (cPtr->haveSaved)
909		{
910		    char    *tmpname;
911		    int     tmpnamelen;
912
913		    tmpname = NULL;
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			memcpy(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 = NULL;
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 = (fsListFontsReply) {
1000	.type = FS_Reply,
1001	.sequenceNumber = client->sequence,
1002	.length = (SIZEOF(fsListFontsReply) + stringLens + nnames + 3) >> 2,
1003	.following = 0,
1004	.nFonts = nnames
1005    };
1006
1007    bufptr = bufferStart = (char *) ALLOCATE_LOCAL(reply.length << 2);
1008
1009    if (!bufptr && reply.length) {
1010	SendErrToClient(client, FSBadAlloc, (pointer) 0);
1011	goto bail;
1012    }
1013    /*
1014     * since WriteToClient long word aligns things, copy to temp buffer and
1015     * write all at once
1016     */
1017    for (i = 0; i < nnames; i++) {
1018	if (names->length[i] > 255)
1019	    reply.nFonts--;
1020	else
1021	{
1022	    *bufptr++ = names->length[i];
1023	    memmove( bufptr, names->names[i], names->length[i]);
1024	    bufptr += names->length[i];
1025	}
1026    }
1027    nnames = reply.nFonts;
1028    reply.length = (SIZEOF(fsListFontsReply) + stringLens + nnames + 3) >> 2;
1029    WriteReplyToClient(client, SIZEOF(fsListFontsReply), &reply);
1030    (void) WriteToClient(client, stringLens + nnames, bufferStart);
1031    DEALLOCATE_LOCAL(bufferStart);
1032
1033bail:
1034    if (cPtr->slept)
1035	ClientWakeup(client);
1036    for (i = 0; i < cPtr->num_fpes; i++)
1037	FreeFPE(cPtr->fpe_list[i]);
1038    FSfree(cPtr->fpe_list);
1039    if (cPtr->savedName) FSfree(cPtr->savedName);
1040    xfont2_free_font_names(names);
1041    FSfree(cPtr);
1042    return TRUE;
1043}
1044
1045int
1046ListFonts(
1047    ClientPtr   client,
1048    int         length,
1049    unsigned char *pattern,
1050    int         maxNames)
1051{
1052    int         i;
1053    LFclosurePtr c;
1054
1055    /*
1056     * The right error to return here would be BadName, however the
1057     * specification does not allow for a Name error on this request.
1058     * Perhaps a better solution would be to return a nil list, i.e.
1059     * a list containing zero fontnames.
1060     */
1061    if (length > XLFDMAXFONTNAMELEN) {
1062	SendErrToClient(client, FSBadAlloc, (pointer) 0);
1063	return TRUE;
1064    }
1065
1066    if (!(c = (LFclosurePtr) FSalloc(sizeof *c)))
1067	goto badAlloc;
1068    c->fpe_list = (FontPathElementPtr *)
1069	FSallocarray(num_fpes, sizeof(FontPathElementPtr));
1070    if (!c->fpe_list) {
1071	FSfree(c);
1072	goto badAlloc;
1073    }
1074    c->names = xfont2_make_font_names_record(maxNames < 100 ? maxNames : 100);
1075    if (!c->names)
1076    {
1077	FSfree(c->fpe_list);
1078	FSfree(c);
1079	goto badAlloc;
1080    }
1081    memmove( c->current.pattern, pattern, length);
1082    for (i = 0; i < num_fpes; i++) {
1083	c->fpe_list[i] = font_path_elements[i];
1084	UseFPE(c->fpe_list[i]);
1085    }
1086    c->client = client;
1087    c->num_fpes = num_fpes;
1088    c->current.patlen = length;
1089    c->current.current_fpe = 0;
1090    c->current.max_names = maxNames;
1091    c->current.list_started = FALSE;
1092    c->current.private = NULL;
1093    c->haveSaved = FALSE;
1094    c->slept = FALSE;
1095    c->savedName = NULL;
1096    do_list_fonts_and_aliases(client, (pointer) c);
1097    return TRUE;
1098badAlloc:
1099    SendErrToClient(client, FSBadAlloc, (pointer) 0);
1100    return TRUE;
1101}
1102
1103static int padlength[4] = {0, 3, 2, 1};
1104static char padding[3];
1105
1106#undef  cPtr
1107#define cPtr ((LFWXIclosurePtr)data)
1108
1109static Bool
1110do_list_fonts_with_info(ClientPtr client, pointer data)
1111{
1112    FontPathElementPtr fpe;
1113    int         err = Successful;
1114    char       *name;
1115    int         namelen;
1116    int         numFonts;
1117    FontInfoRec fontInfo,
1118               *pFontInfo;
1119    fsListFontsWithXInfoReply *reply;
1120    int         length;
1121    fsPropInfo *prop_info;
1122    int         lenpropdata;
1123    int         i;
1124    int		aliascount = 0;
1125
1126    if (client->clientGone == CLIENT_GONE) {
1127	if (cPtr->current.current_fpe < cPtr->num_fpes) {
1128	    fpe = cPtr->fpe_list[cPtr->current.current_fpe];
1129	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1130	}
1131	err = Successful;
1132	goto bail;
1133    }
1134    while (cPtr->current.current_fpe < cPtr->num_fpes) {
1135	fpe = cPtr->fpe_list[cPtr->current.current_fpe];
1136	err = Successful;
1137	if (!cPtr->current.list_started) {
1138	    err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
1139		((pointer) cPtr->client, fpe, cPtr->current.pattern,
1140		 cPtr->current.patlen, cPtr->current.max_names,
1141		 &cPtr->current.private);
1142	    if (err == Suspended) {
1143		if (!cPtr->slept) {
1144		    ClientSleep(client, do_list_fonts_with_info,
1145				(pointer) cPtr);
1146		    cPtr->slept = TRUE;
1147		}
1148		return TRUE;
1149	    }
1150	    if (err == Successful)
1151		cPtr->current.list_started = TRUE;
1152	}
1153	if (err == Successful) {
1154	    name = NULL;
1155	    pFontInfo = &fontInfo;
1156	    err = (*fpe_functions[fpe->type].list_next_font_with_info)
1157		((pointer) cPtr->client, fpe, &name, &namelen,
1158		 &pFontInfo, &numFonts, cPtr->current.private);
1159	    if (err == Suspended) {
1160		if (!cPtr->slept) {
1161		    ClientSleep(client, do_list_fonts_with_info,
1162				(pointer) cPtr);
1163		    cPtr->slept = TRUE;
1164		}
1165		return TRUE;
1166	    }
1167	}
1168	/*
1169	 * When we get an alias back, save our state and reset back to the
1170	 * start of the FPE looking for the specified name.  As soon as a real
1171	 * font is found for the alias, pop back to the old state
1172	 */
1173	if (err == FontNameAlias) {
1174	    /*
1175	     * when an alias recurses, we need to give
1176	     * the last FPE a chance to clean up; so we call
1177	     * it again, and assume that the error returned
1178	     * is BadFontName, indicating the alias resolution
1179	     * is complete.
1180	     */
1181	    if (cPtr->haveSaved)
1182	    {
1183		char	*tmpname;
1184		int	tmpnamelen;
1185		FontInfoPtr tmpFontInfo;
1186
1187		tmpname = NULL;
1188	    	tmpFontInfo = &fontInfo;
1189	    	(void) (*fpe_functions[fpe->type].list_next_font_with_info)
1190		    ((pointer) client, fpe, &tmpname, &tmpnamelen,
1191		     &tmpFontInfo, &numFonts, cPtr->current.private);
1192		if (--aliascount <= 0)
1193		{
1194		    err = BadFontName;
1195		    goto ContBadFontName;
1196		}
1197	    }
1198	    else
1199	    {
1200		cPtr->saved = cPtr->current;
1201		cPtr->haveSaved = TRUE;
1202		cPtr->savedNumFonts = numFonts;
1203		if (cPtr->savedName)
1204		  FSfree(cPtr->savedName);
1205		cPtr->savedName = (char *)FSalloc(namelen + 1);
1206		if (cPtr->savedName)
1207		  memcpy(cPtr->savedName, name, namelen + 1);
1208		aliascount = 20;
1209	    }
1210	    memmove(cPtr->current.pattern, name, namelen);
1211	    cPtr->current.patlen = namelen;
1212	    cPtr->current.max_names = 1;
1213	    cPtr->current.current_fpe = 0;
1214	    cPtr->current.private = NULL;
1215	    cPtr->current.list_started = FALSE;
1216	}
1217	/*
1218	 * At the end of this FPE, step to the next.  If we've finished
1219	 * processing an alias, pop state back. If we've sent enough font
1220	 * names, quit.
1221	 */
1222	else if (err == BadFontName) {
1223	  ContBadFontName: ;
1224	    cPtr->current.list_started = FALSE;
1225	    cPtr->current.current_fpe++;
1226	    err = Successful;
1227	    if (cPtr->haveSaved) {
1228		if (cPtr->current.max_names == 0 ||
1229			cPtr->current.current_fpe == cPtr->num_fpes) {
1230		    cPtr->haveSaved = FALSE;
1231		    cPtr->saved.max_names -= (1 - cPtr->current.max_names);
1232		    cPtr->current = cPtr->saved;
1233		}
1234	    }
1235	    else if (cPtr->current.max_names == 0)
1236		break;
1237	} else if (err == Successful) {
1238/* XXX why is it xFontProp ? */
1239	    length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
1240	    reply = cPtr->reply;
1241	    if (cPtr->length < length) {
1242		reply = (fsListFontsWithXInfoReply *) FSrealloc(cPtr->reply, length);
1243		if (!reply) {
1244		    err = AllocError;
1245		    break;
1246		}
1247		cPtr->reply = reply;
1248		cPtr->length = length;
1249	    }
1250	    if (cPtr->haveSaved) {
1251		numFonts = cPtr->savedNumFonts;
1252		name = cPtr->savedName;
1253		namelen = strlen(name);
1254	    }
1255	    fsPack_XFontInfoHeader(pFontInfo, reply, client->major_version);
1256	    err = convert_props(pFontInfo, &prop_info);
1257	    if (err != Successful)
1258		break;
1259	    lenpropdata = SIZEOF(fsPropInfo) +
1260		prop_info->num_offsets * SIZEOF(fsPropOffset) +
1261		prop_info->data_len;
1262
1263	    reply->type = FS_Reply;
1264	    reply->length =
1265		(SIZEOF(fsListFontsWithXInfoReply) +
1266		 lenpropdata + namelen + 3) >> 2;
1267	    reply->sequenceNumber = client->sequence;
1268	    reply->nameLength = namelen;
1269	    reply->nReplies = numFonts;
1270	    WriteReplyToClient(client, SIZEOF(fsListFontsWithXInfoReply), reply);
1271	    if (client->swapped)
1272		SwapPropInfo(prop_info);
1273	    if (client->major_version > 1)
1274	    {
1275		(void)WriteToClientUnpadded(client, lenpropdata, (char *) prop_info);
1276		(void)WriteToClientUnpadded(client, namelen, name);
1277		(void)WriteToClientUnpadded(client,
1278					    padlength[(lenpropdata+namelen)&3],
1279					    padding);
1280	    } else {
1281		(void) WriteToClient(client, namelen, name);
1282		(void) WriteToClient(client, lenpropdata, (char *) prop_info);
1283	    }
1284	    if (pFontInfo == &fontInfo) {
1285		FSfree(fontInfo.props);
1286		FSfree(fontInfo.isStringProp);
1287	    }
1288	    FSfree(prop_info);
1289
1290	    --cPtr->current.max_names;
1291	    if (cPtr->current.max_names < 0)
1292		break;
1293	}
1294    }
1295
1296    /*
1297     * send the final reply
1298     */
1299    if (err == Successful) {
1300	fsGenericReply *final_reply;
1301
1302	final_reply = (fsGenericReply *)cPtr->reply;
1303	if (client->major_version > 1)
1304	    length = SIZEOF(fsGenericReply);
1305	else
1306	    length = SIZEOF(fsListFontsWithXInfoReply);
1307	if (cPtr->length < length) {
1308	    final_reply = (fsGenericReply *) FSrealloc(cPtr->reply, length);
1309	    if (final_reply) {
1310		cPtr->reply = (fsListFontsWithXInfoReply *)final_reply;
1311		cPtr->length = length;
1312	    } else
1313		err = AllocError;
1314	}
1315	if (err == Successful) {
1316	    final_reply->type = FS_Reply;
1317	    final_reply->data1 = 0; /* notes that this is final */
1318	    final_reply->sequenceNumber = client->sequence;
1319	    final_reply->length = length >> 2;
1320	    WriteReplyToClient(client, length, final_reply);
1321	}
1322    }
1323    if (err != Successful)
1324	SendErrToClient(client, FontToFSError(err), (pointer) 0);
1325bail:
1326    if (cPtr->slept)
1327	ClientWakeup(client);
1328    for (i = 0; i < cPtr->num_fpes; i++)
1329	FreeFPE(cPtr->fpe_list[i]);
1330    FSfree(cPtr->fpe_list);
1331    if (cPtr->savedName) FSfree(cPtr->savedName);
1332    FSfree(cPtr->reply);
1333    FSfree(cPtr);
1334    return TRUE;
1335}
1336
1337int
1338StartListFontsWithInfo(
1339    ClientPtr   client,
1340    int         length,
1341    unsigned char *pattern,
1342    int         maxNames)
1343{
1344    int         i;
1345    LFWXIclosurePtr c;
1346
1347    /*
1348     * The right error to return here would be BadName, however the
1349     * specification does not allow for a Name error on this request.
1350     * Perhaps a better solution would be to return a nil list, i.e.
1351     * a list containing zero fontnames.
1352     */
1353    if (length > XLFDMAXFONTNAMELEN) {
1354	SendErrToClient(client, FSBadAlloc, (pointer) 0);
1355	return TRUE;
1356    }
1357
1358    if (!(c = (LFWXIclosurePtr) FSalloc(sizeof *c)))
1359	goto badAlloc;
1360    c->fpe_list = (FontPathElementPtr *)
1361	FSallocarray(num_fpes, sizeof(FontPathElementPtr));
1362    if (!c->fpe_list) {
1363	FSfree(c);
1364	goto badAlloc;
1365    }
1366    memmove( c->current.pattern, pattern, length);
1367    for (i = 0; i < num_fpes; i++) {
1368	c->fpe_list[i] = font_path_elements[i];
1369	UseFPE(c->fpe_list[i]);
1370    }
1371    c->client = client;
1372    c->num_fpes = num_fpes;
1373    c->reply = NULL;
1374    c->length = 0;
1375    c->current.patlen = length;
1376    c->current.current_fpe = 0;
1377    c->current.max_names = maxNames;
1378    c->current.list_started = FALSE;
1379    c->current.private = NULL;
1380    c->savedNumFonts = 0;
1381    c->haveSaved = FALSE;
1382    c->slept = FALSE;
1383    c->savedName = NULL;
1384    do_list_fonts_with_info(client, (pointer) c);
1385    return TRUE;
1386badAlloc:
1387    SendErrToClient(client, FSBadAlloc, (pointer) 0);
1388    return TRUE;
1389}
1390
1391int
1392LoadGlyphRanges(
1393    ClientPtr   client,
1394    FontPtr	pfont,
1395    Bool	range_flag,
1396    int		num_ranges,
1397    int		item_size,
1398    fsChar2b	*data)
1399{
1400    /* either returns Successful, Suspended, or some nasty error */
1401    if (fpe_functions[pfont->fpe->type].load_glyphs)
1402	return (*fpe_functions[pfont->fpe->type].load_glyphs)(
1403		(pointer)client, pfont, range_flag, num_ranges, item_size,
1404		(unsigned char *)data);
1405    else
1406	return Successful;
1407}
1408
1409
1410int
1411register_fpe_funcs(const xfont2_fpe_funcs_rec *funcs)
1412{
1413    xfont2_fpe_funcs_rec *new;
1414
1415    /* grow the list */
1416    new = FSreallocarray(fpe_functions, (num_fpe_types + 1), sizeof(*new));
1417    if (!new)
1418	return -1;
1419    fpe_functions = new;
1420
1421    memcpy(&fpe_functions[num_fpe_types], funcs, sizeof(*funcs));
1422
1423    return num_fpe_types++;
1424}
1425
1426
1427/* convenience functions for FS interface */
1428
1429FontPtr
1430find_old_font(FSID id)
1431{
1432    return (FontPtr) LookupIDByType(SERVER_CLIENT, id, RT_NONE);
1433}
1434
1435Font
1436GetNewFontClientID(void)
1437{
1438    return (Font) FakeClientID(SERVER_CLIENT);
1439}
1440
1441int
1442StoreFontClientFont(
1443    FontPtr     pfont,
1444    Font        id)
1445{
1446    return AddResource(SERVER_CLIENT, id, RT_NONE, (pointer) pfont);
1447}
1448
1449void
1450DeleteFontClientID(Font id)
1451{
1452    FreeResource(SERVER_CLIENT, id, RT_NONE);
1453}
1454
1455static int  fs_handlers_installed = 0;
1456static unsigned int last_server_gen;
1457
1458int
1459xfs_init_fs_handlers(
1460    FontPathElementPtr fpe,
1461    FontBlockHandlerProcPtr block_handler)
1462{
1463    /* if server has reset, make sure the b&w handlers are reinstalled */
1464    if (last_server_gen < serverGeneration) {
1465	last_server_gen = serverGeneration;
1466	fs_handlers_installed = 0;
1467    }
1468    if (fs_handlers_installed == 0) {
1469
1470#ifdef DEBUG
1471	fprintf(stderr, "adding FS b & w handlers\n");
1472#endif
1473
1474	if (!RegisterBlockAndWakeupHandlers(block_handler,
1475					    FontWakeup, (pointer) 0))
1476	    return AllocError;
1477	fs_handlers_installed++;
1478    }
1479    QueueFontWakeup(fpe);
1480    return Successful;
1481}
1482
1483void
1484xfs_remove_fs_handlers(
1485    FontPathElementPtr fpe,
1486    FontBlockHandlerProcPtr block_handler,
1487    Bool        all)
1488{
1489    if (all) {
1490	/* remove the handlers if no one else is using them */
1491	if (--fs_handlers_installed == 0) {
1492
1493#ifdef DEBUG
1494	    fprintf(stderr, "removing FS b & w handlers\n");
1495#endif
1496
1497	    RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
1498					 (pointer) 0);
1499	}
1500    }
1501    RemoveFontWakeup(fpe);
1502}
1503
1504void
1505DeleteClientFontStuff(ClientPtr client)
1506{
1507    int i;
1508    FontPathElementPtr fpe;
1509
1510    for (i = 0; i < num_fpes; i++)
1511    {
1512	fpe = font_path_elements[i];
1513
1514	if (fpe_functions[fpe->type].client_died)
1515	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1516    }
1517}
1518