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