fslsfonts.c revision d1333322
1/* $Xorg: fslsfonts.c,v 1.4 2001/02/09 02:05:30 xorgcvs Exp $ */
2/*
3
4Copyright 1990, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25
26 * Copyright 1990 Network Computing Devices;
27 * Portions Copyright 1987 by Digital Equipment Corporation
28 *
29 * Permission to use, copy, modify, distribute, and sell this software and
30 * its documentation for any purpose is hereby granted without fee, provided
31 * that the above copyright notice appear in all copies and that both that
32 * copyright notice and this permission notice appear in supporting
33 * documentation, and that the names of Network Computing Devices, or Digital
34 * not be used in advertising or publicity pertaining to distribution
35 * of the software without specific, written prior permission.
36 *
37 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
38 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
39 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
40 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
41 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
42 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
43 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
44 * THIS SOFTWARE.
45 */
46/* $XFree86: xc/programs/fslsfonts/fslsfonts.c,v 3.7 2001/08/27 17:41:01 dawes Exp $ */
47
48#include <X11/fonts/FSlib.h>
49#include <stdio.h>
50#include <X11/Xos.h>
51#include <stdlib.h>
52
53#ifndef N_START
54#define N_START 1000		/* Maximum # of fonts to start with */
55#endif
56
57int         max_output_line_width = 79;
58int         output_line_padding = 3;
59int         columns = 0;
60
61#define L_SHORT 0
62#define L_MEDIUM 1
63#define L_LONG 2
64#define L_VERYLONG 3
65
66Bool        sort_output = True;
67int         long_list = L_SHORT;
68int         nnames = N_START;
69int         font_cnt;
70int         min_max;
71typedef struct {
72    char       *name;
73    FSXFontInfoHeader *info;
74    FSPropInfo *pi;
75    FSPropOffset *po;
76    unsigned char *pd;
77}           FontList;
78FontList   *font_list;
79
80FSServer   *svr;
81
82char       *program_name;
83
84static void usage ( void );
85static void get_list ( char *pattern );
86static int compare ( const void *f1, const void *f2 );
87static void show_fonts ( void );
88static void print_font_header ( void );
89static void show_font_header ( FontList *list );
90static void copy_number ( char **pp1, char **pp2, int n1, int n2 );
91static void show_font_props ( FontList *list );
92
93static void
94usage(void)
95{
96    fprintf(stderr, "usage:  %s [-options] [-fn pattern]\n", program_name);
97    fprintf(stderr, "where options include:\n");
98
99    fprintf(stderr,
100	    "    -l[l[l]]                 give long info about each font\n");
101    fprintf(stderr,
102	 "    -m                       give character min and max bounds\n");
103
104    fprintf(stderr,
105	    "    -C                       force columns\n");
106    fprintf(stderr,
107	    "    -1                       force single column\n");
108    fprintf(stderr,
109	    "    -u                       keep output unsorted\n");
110    fprintf(stderr,
111	"    -w width                 maximum width for multiple columns\n");
112    fprintf(stderr,
113	 "    -n columns               number of columns if multi column\n");
114    fprintf(stderr,
115	    "    -server servername       font server to contact\n");
116    fprintf(stderr,
117	    "\n");
118    exit(1);
119}
120
121int
122main(int argc, char *argv[])
123{
124    int         argcnt = 0,
125                i;
126    char       *servername = NULL;
127
128    program_name = argv[0];
129
130    for (i = 1; i < argc; i++) {
131	if (strncmp(argv[i], "-s", 2) == 0) {
132	    if (++i >= argc)
133		usage();
134	    servername = argv[i];
135	}
136    }
137
138    if ((svr = FSOpenServer(servername)) == NULL) {
139	if (FSServerName(servername) == NULL) {
140	    fprintf(stderr, "%s: no font server defined\n", program_name);
141	    exit(0);
142	}
143	fprintf(stderr, "%s:  unable to open server \"%s\"\n",
144		program_name, FSServerName(servername));
145	exit(0);
146    }
147    /* Handle command line arguments, open display */
148    for (argv++, argc--; argc; argv++, argc--) {
149	if (argv[0][0] == '-') {
150	    if (argcnt > 0)
151		usage();
152	    for (i = 1; argv[0][i]; i++)
153		switch (argv[0][i]) {
154		case 'l':
155		    long_list++;
156		    break;
157		case 'm':
158		    min_max++;
159		    break;
160		case 'C':
161		    columns = 0;
162		    break;
163		case '1':
164		    columns = 1;
165		    break;
166		case 'f':
167		    if (--argc <= 0)
168			usage();
169		    argcnt++;
170		    argv++;
171		    get_list(argv[0]);
172		    goto next;
173		case 'w':
174		    if (--argc <= 0)
175			usage();
176		    argv++;
177		    max_output_line_width = atoi(argv[0]);
178		    goto next;
179		case 'n':
180		    if (--argc <= 0)
181			usage();
182		    argv++;
183		    columns = atoi(argv[0]);
184		    goto next;
185		case 'u':
186		    sort_output = False;
187		    break;
188		case 's':	/* eat -s */
189		    if (--argc <= 0)
190			usage();
191		    argv++;
192		    goto next;
193		default:
194		    usage();
195		    break;
196		}
197	    if (i == 1)
198		usage();
199	} else {
200	    argcnt++;
201	    get_list(argv[0]);
202	}
203next:	;
204    }
205    if (argcnt == 0)
206	get_list("*");
207    FSCloseServer(svr);
208    show_fonts();
209    exit(0);
210}
211
212static void
213get_list(char *pattern)
214{
215    int         available = nnames + 1,
216                i;
217    char      **fonts;
218    FSXFontInfoHeader **info;
219    FSPropInfo **props;
220    FSPropOffset **offsets;
221    unsigned char **pdata;
222
223    /* Get list of fonts matching pattern */
224    for (;;) {
225
226	if (long_list >= L_MEDIUM)
227	    fonts = FSListFontsWithXInfo(svr,
228	       pattern, nnames, &available, &info, &props, &offsets, &pdata);
229	else
230	    fonts = FSListFonts(svr, pattern, nnames, &available);
231	if (fonts == NULL || available < nnames)
232	    break;
233
234	if (long_list >= L_MEDIUM) {
235	    for (i = 0; i < available; i++) {
236		FSFree((char *) fonts[i]);
237		FSFree((char *) info[i]);
238		FSFree((char *) props[i]);
239		FSFree((char *) offsets[i]);
240		FSFree((char *) pdata[i]);
241	    }
242	    FSFree((char *) fonts);
243	    FSFree((char *) info);
244	    FSFree((char *) props);
245	    FSFree((char *) offsets);
246	    FSFree((char *) pdata);
247	} else {
248	    FSFreeFontNames(fonts);
249	}
250	nnames = available * 2;
251    }
252
253    if (fonts == NULL) {
254	fprintf(stderr, "%s: pattern \"%s\" unmatched\n",
255		program_name, pattern);
256	return;
257    }
258    if (font_list)
259	font_list = (FontList *) realloc(font_list,
260				  (font_cnt + available) * sizeof(FontList));
261    else
262	font_list = (FontList *) malloc((unsigned)
263				  (font_cnt + available) * sizeof(FontList));
264    for (i = 0; i < available; i++) {
265	font_list[font_cnt].name = fonts[i];
266
267	if (long_list >= L_MEDIUM) {
268	    font_list[font_cnt].info = info[i];
269	    font_list[font_cnt].pi = props[i];
270	    font_list[font_cnt].po = offsets[i];
271	    font_list[font_cnt].pd = pdata[i];
272	} else
273	    font_list[font_cnt].info = NULL;
274	font_cnt++;
275    }
276}
277
278static int
279compare(const void *f1, const void *f2)
280{
281    char       *p1 = ((FontList *)f1)->name,
282               *p2 = ((FontList *)f2)->name;
283
284    while (*p1 && *p2 && *p1 == *p2)
285	p1++, p2++;
286    return (*p1 - *p2);
287}
288
289static void
290show_fonts(void)
291{
292    int         i;
293
294    if (font_cnt == 0)
295	return;
296
297    /* first sort the output */
298    if (sort_output)
299	qsort(font_list, font_cnt, sizeof(FontList), compare);
300
301    if (long_list > L_MEDIUM) {
302	print_font_header();
303	for (i = 0; i < font_cnt; i++) {
304	    show_font_header(&font_list[i]);
305	    show_font_props(&font_list[i]);
306	}
307	return;
308    }
309    if (long_list == L_MEDIUM) {
310	print_font_header();
311
312	for (i = 0; i < font_cnt; i++) {
313	    show_font_header(&font_list[i]);
314	}
315
316	return;
317    }
318    if ((columns == 0 && isatty(1)) || columns > 1) {
319	int         width,
320	            max_width = 0,
321	            lines_per_column,
322	            j,
323	            index;
324
325	for (i = 0; i < font_cnt; i++) {
326	    width = strlen(font_list[i].name);
327	    if (width > max_width)
328		max_width = width;
329	}
330	if (max_width == 0) {
331	    fprintf(stderr, "all %d fontnames listed are zero length",
332		    font_cnt);
333	    exit(-1);
334	}
335	if (columns == 0) {
336	    if ((max_width * 2) + output_line_padding >
337		    max_output_line_width) {
338		columns = 1;
339	    } else {
340		max_width += output_line_padding;
341		columns = ((max_output_line_width +
342			    output_line_padding) / max_width);
343	    }
344	} else {
345	    max_width += output_line_padding;
346	}
347	if (columns <= 1)
348	    goto single_column;
349
350	if (font_cnt < columns)
351	    columns = font_cnt;
352	lines_per_column = (font_cnt + columns - 1) / columns;
353
354	for (i = 0; i < lines_per_column; i++) {
355	    for (j = 0; j < columns; j++) {
356		index = j * lines_per_column + i;
357		if (index >= font_cnt)
358		    break;
359		if (j + 1 == columns)
360		    printf("%s", font_list[index].name);
361		else
362		    printf("%-*s",
363			   max_width,
364			   font_list[index].name);
365	    }
366	    printf("\n");
367	}
368	return;
369    }
370single_column:
371    for (i = 0; i < font_cnt; i++)
372	printf("%s\n", font_list[i].name);
373}
374
375static void
376print_font_header(void)
377{
378    printf("DIR  ");
379    printf("MIN  ");
380    printf("MAX ");
381    printf("EXIST ");
382    printf("DFLT ");
383    printf("ASC ");
384    printf("DESC ");
385    printf("NAME");
386    printf("\n");
387}
388
389static void
390show_font_header(FontList *list)
391{
392    char       *string;
393    FSXFontInfoHeader *pfh;
394
395    pfh = list->info;
396    if (!pfh) {
397	fprintf(stderr,
398		"%s:  no font information for font \"%s\".\n",
399		program_name, list->name ? list->name : "");
400	return;
401    }
402    if (pfh->draw_direction == LeftToRightDrawDirection)
403	string = "-->";
404    else
405	string = "<--";
406    printf("%-4s", string);
407    if (pfh->char_range.min_char.high == 0
408	    && pfh->char_range.max_char.high == 0) {
409	printf(" %3d ", pfh->char_range.min_char.low);
410	printf(" %3d ", pfh->char_range.max_char.low);
411    } else {
412	printf("*%3d ", pfh->char_range.min_char.high);
413	printf("*%3d ", pfh->char_range.max_char.high);
414    }
415    printf("%5s ", (pfh->flags & FontInfoAllCharsExist) ? "all" : "some");
416    printf("%4d ", (pfh->default_char.high << 8) + pfh->default_char.low);
417    printf("%3d ", pfh->font_ascent);
418    printf("%4d ", pfh->font_descent);
419    printf("%s\n", list->name);
420    if (min_max) {
421	char        min[BUFSIZ],
422	            max[BUFSIZ];
423	char       *pmax = max,
424	           *pmin = min;
425
426	strcpy(pmin, "     min(l,r,w,a,d) = (");
427	strcpy(pmax, "     max(l,r,w,a,d) = (");
428	pmin += strlen(pmin);
429	pmax += strlen(pmax);
430
431	copy_number(&pmin, &pmax,
432		    pfh->min_bounds.left,
433		    pfh->max_bounds.left);
434	*pmin++ = *pmax++ = ',';
435	copy_number(&pmin, &pmax,
436		    pfh->min_bounds.right,
437		    pfh->max_bounds.right);
438	*pmin++ = *pmax++ = ',';
439	copy_number(&pmin, &pmax,
440		    pfh->min_bounds.width,
441		    pfh->max_bounds.width);
442	*pmin++ = *pmax++ = ',';
443	copy_number(&pmin, &pmax,
444		    pfh->min_bounds.ascent,
445		    pfh->max_bounds.ascent);
446	*pmin++ = *pmax++ = ',';
447	copy_number(&pmin, &pmax,
448		    pfh->min_bounds.descent,
449		    pfh->max_bounds.descent);
450	*pmin++ = *pmax++ = ')';
451	*pmin = *pmax = '\0';
452	printf("%s\n", min);
453	printf("%s\n", max);
454    }
455}
456
457#ifndef max
458#define	max(a, b)	((a) > (b) ? (a) : (b))
459#endif
460
461static void
462copy_number(char **pp1, char **pp2, int n1, int n2)
463{
464    char       *p1 = *pp1;
465    char       *p2 = *pp2;
466    int         w;
467
468    sprintf(p1, "%d", n1);
469    sprintf(p2, "%d", n2);
470    w = max(strlen(p1), strlen(p2));
471    sprintf(p1, "%*d", w, n1);
472    sprintf(p2, "%*d", w, n2);
473    p1 += strlen(p1);
474    p2 += strlen(p2);
475    *pp1 = p1;
476    *pp2 = p2;
477}
478
479static void
480show_font_props(FontList *list)
481{
482    int         i;
483    char        buf[1000];
484    FSPropInfo *pi = list->pi;
485    FSPropOffset *po = list->po;
486    unsigned char *pd = list->pd;
487    int         num_props;
488
489    num_props = pi->num_offsets;
490    for (i = 0; i < num_props; i++, po++) {
491	strncpy(buf, (char *) (pd + po->name.position), po->name.length);
492	buf[po->name.length] = '\0';
493	printf("%s\t", buf);
494	switch (po->type) {
495	case PropTypeString:
496	    strncpy(buf, (char *)pd + po->value.position, po->value.length);
497	    buf[po->value.length] = '\0';
498	    printf("%s\n", buf);
499	    break;
500	case PropTypeUnsigned:
501	    printf("%lu\n", (unsigned long) po->value.position);
502	    break;
503	case PropTypeSigned:
504	    printf("%lu\n", (long) po->value.position);
505	    break;
506	default:
507	    fprintf(stderr, "bogus property\n");
508	    break;
509	}
510
511    }
512}
513