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