fslsfonts.c revision d04472e1
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#include <assert.h>
55
56#ifdef HAVE_BSD_STDLIB_H
57#include <bsd/stdlib.h>
58#endif
59
60#ifndef HAVE_REALLOCARRAY
61#define reallocarray(old, num, size) realloc(old, (num) * (size))
62#endif
63
64#ifndef N_START
65#define N_START 1000		/* Maximum # of fonts to start with */
66#endif
67
68static unsigned int max_output_line_width = 79;
69static unsigned int output_line_padding = 3;
70static unsigned int columns = 0;
71
72#define L_SHORT 0
73#define L_MEDIUM 1
74#define L_LONG 2
75#define L_VERYLONG 3
76
77static Bool sort_output = True;
78static int  long_list = L_SHORT;
79static int  nnames = N_START;
80static unsigned int  font_cnt;
81static int  min_max;
82typedef struct {
83    char       *name;
84    FSXFontInfoHeader *info;
85    FSPropInfo *pi;
86    FSPropOffset *po;
87    unsigned char *pd;
88}           FontList;
89static FontList *font_list;
90
91static FSServer *svr;
92
93static char *program_name;
94
95static void usage (const char *msg) _X_NORETURN _X_COLD;
96static void get_list ( const char *pattern );
97static int compare ( const void *f1, const void *f2 );
98static void show_fonts ( void );
99static void print_font_header ( void );
100static void show_font_header ( FontList *list );
101static void copy_number ( char **pp1, char **pp2, char **ep1, char **ep2,
102                          int n1, int n2, char suffix );
103static void show_font_props ( FontList *list );
104
105static void _X_NORETURN _X_COLD
106missing_arg (const char *option)
107{
108    char msg[32];
109
110    snprintf(msg, sizeof(msg), "%s requires an argument", option);
111    usage(msg);
112}
113
114static void
115usage(const char *msg)
116{
117    if (msg)
118	fprintf(stderr, "%s: %s\n", program_name, msg);
119    fprintf(stderr, "usage:  %s [-options] [-fn pattern]\n", program_name);
120    fprintf(stderr, "%s", "where options include:\n"
121	    "    -l[l[l]]                 give long info about each font\n"
122	    "    -m                       give character min and max bounds\n"
123	    "    -C                       force columns\n"
124	    "    -1                       force single column\n"
125	    "    -u                       keep output unsorted\n"
126	    "    -w width                 maximum width for multiple columns\n"
127	    "    -n columns               number of columns if multi column\n"
128	    "    -server servername       font server to contact\n"
129	    "    -version                 print command version and exit\n"
130	    "\n");
131    exit(1);
132}
133
134int
135main(int argc, char *argv[])
136{
137    int         argcnt = 0,
138                i;
139    char       *servername = NULL;
140
141    program_name = argv[0];
142
143    for (i = 1; i < argc; i++) {
144	if (strncmp(argv[i], "-s", 2) == 0) {
145	    if (++i >= argc)
146		missing_arg("-server");
147	    servername = argv[i];
148	}
149	else if (strcmp(argv[i], "-version") == 0) {
150	    printf("%s\n", PACKAGE_STRING);
151	    exit(0);
152	}
153    }
154
155    if ((svr = FSOpenServer(servername)) == NULL) {
156	if (FSServerName(servername) == NULL) {
157	    usage("no font server defined");
158	}
159	fprintf(stderr, "%s:  unable to open server \"%s\"\n",
160		program_name, FSServerName(servername));
161	exit(0);
162    }
163    /* Handle command line arguments, open display */
164    for (argv++, argc--; argc; argv++, argc--) {
165	if (argv[0][0] == '-') {
166	    if (argcnt > 0)
167		usage(NULL);
168	    for (i = 1; argv[0][i]; i++)
169		switch (argv[0][i]) {
170		case 'l':
171		    long_list++;
172		    break;
173		case 'm':
174		    min_max++;
175		    break;
176		case 'C':
177		    columns = 0;
178		    break;
179		case '1':
180		    columns = 1;
181		    break;
182		case 'f':
183		    if (--argc <= 0)
184			missing_arg("-fn");
185		    argcnt++;
186		    argv++;
187		    get_list(argv[0]);
188		    goto next;
189		case 'w':
190		    if (--argc <= 0)
191			missing_arg("-w");
192		    argv++;
193		    max_output_line_width = (unsigned int) atoi(argv[0]);
194		    goto next;
195		case 'n':
196		    if (--argc <= 0)
197			missing_arg("-n");
198		    argv++;
199		    columns = (unsigned int) atoi(argv[0]);
200		    goto next;
201		case 'u':
202		    sort_output = False;
203		    break;
204		case 's':	/* eat -s */
205		    if (--argc <= 0)
206			missing_arg("-server");
207		    argv++;
208		    goto next;
209		default:
210		    fprintf(stderr, "%s: unrecognized option '%s'\n",
211			    program_name, argv[0]);
212		    usage(NULL);
213		}
214	    if (i == 1)
215		usage(NULL);
216	} else {
217	    argcnt++;
218	    get_list(argv[0]);
219	}
220next:	;
221    }
222    if (argcnt == 0)
223	get_list("*");
224    FSCloseServer(svr);
225    show_fonts();
226    exit(0);
227}
228
229static void
230get_list(const char *pattern)
231{
232    int         available = nnames + 1,
233                i;
234    char      **fonts;
235    FSXFontInfoHeader **info;
236    FSPropInfo **props;
237    FSPropOffset **offsets;
238    unsigned char **pdata;
239
240    /* Get list of fonts matching pattern */
241    for (;;) {
242
243	if (long_list >= L_MEDIUM)
244	    fonts = FSListFontsWithXInfo(svr,
245	       pattern, nnames, &available, &info, &props, &offsets, &pdata);
246	else
247	    fonts = FSListFonts(svr, pattern, nnames, &available);
248	if (fonts == NULL || available < nnames)
249	    break;
250
251	if (long_list >= L_MEDIUM) {
252	    for (i = 0; i < available; i++) {
253		FSFree((char *) fonts[i]);
254		FSFree((char *) info[i]);
255		FSFree((char *) props[i]);
256		FSFree((char *) offsets[i]);
257		FSFree((char *) pdata[i]);
258	    }
259	    FSFree((char *) fonts);
260	    FSFree((char *) info);
261	    FSFree((char *) props);
262	    FSFree((char *) offsets);
263	    FSFree((char *) pdata);
264	} else {
265	    FSFreeFontNames(fonts);
266	}
267	nnames = available * 2;
268    }
269
270    if (fonts == NULL) {
271	fprintf(stderr, "%s: pattern \"%s\" unmatched\n",
272		program_name, pattern);
273	return;
274    }
275    else {
276	FontList *old_list = font_list;
277
278	font_list = reallocarray(old_list, (font_cnt + (unsigned) available),
279                                 sizeof(FontList));
280
281	if (font_list == NULL) {
282	    free(old_list);
283	    fprintf(stderr, "%s: unable to allocate %zu bytes for font list\n",
284		    program_name,
285		    (font_cnt + (unsigned) available) * sizeof(FontList));
286	    exit(-1);
287	}
288    }
289    for (i = 0; i < available; i++) {
290	font_list[font_cnt].name = fonts[i];
291
292	if (long_list >= L_MEDIUM) {
293	    font_list[font_cnt].info = info[i];
294	    font_list[font_cnt].pi = props[i];
295	    font_list[font_cnt].po = offsets[i];
296	    font_list[font_cnt].pd = pdata[i];
297	} else
298	    font_list[font_cnt].info = NULL;
299	font_cnt++;
300    }
301}
302
303static int
304compare(const void *f1, const void *f2)
305{
306    const char *p1 = ((const FontList *)f1)->name,
307               *p2 = ((const FontList *)f2)->name;
308
309    while (*p1 && *p2 && *p1 == *p2)
310	p1++, p2++;
311    return (*p1 - *p2);
312}
313
314static void
315show_fonts(void)
316{
317    unsigned int i;
318
319    if (font_cnt == 0)
320	return;
321
322    /* first sort the output */
323    if (sort_output)
324	qsort(font_list, font_cnt, sizeof(FontList), compare);
325
326    if (long_list > L_MEDIUM) {
327	print_font_header();
328	for (i = 0; i < font_cnt; i++) {
329	    show_font_header(&font_list[i]);
330	    show_font_props(&font_list[i]);
331	}
332	return;
333    }
334    if (long_list == L_MEDIUM) {
335	print_font_header();
336
337	for (i = 0; i < font_cnt; i++) {
338	    show_font_header(&font_list[i]);
339	}
340
341	return;
342    }
343    if ((columns == 0 && isatty(1)) || columns > 1) {
344	unsigned int width,
345	            max_width = 0,
346	            lines_per_column,
347	            j,
348	            index;
349
350	for (i = 0; i < font_cnt; i++) {
351	    width = (unsigned int) strlen(font_list[i].name);
352	    if (width > max_width)
353		max_width = width;
354	}
355	if (max_width == 0) {
356	    fprintf(stderr, "all %d fontnames listed are zero length",
357		    font_cnt);
358	    exit(-1);
359	}
360	if (columns == 0) {
361	    if ((max_width * 2) + output_line_padding >
362		    max_output_line_width) {
363		columns = 1;
364	    } else {
365		max_width += output_line_padding;
366		columns = ((max_output_line_width +
367			    output_line_padding) / max_width);
368	    }
369	} else {
370	    max_width += output_line_padding;
371	}
372	if (columns <= 1)
373	    goto single_column;
374
375	if (font_cnt < columns)
376	    columns = font_cnt;
377	lines_per_column = (font_cnt + columns - 1) / columns;
378
379	for (i = 0; i < lines_per_column; i++) {
380	    for (j = 0; j < columns; j++) {
381		index = j * lines_per_column + i;
382		if (index >= font_cnt)
383		    break;
384		if (j + 1 == columns)
385		    printf("%s", font_list[index].name);
386		else
387		    printf("%-*s",
388			   max_width,
389			   font_list[index].name);
390	    }
391	    printf("\n");
392	}
393	return;
394    }
395single_column:
396    for (i = 0; i < font_cnt; i++)
397	printf("%s\n", font_list[i].name);
398}
399
400static void
401print_font_header(void)
402{
403    printf("DIR  ");
404    printf("MIN  ");
405    printf("MAX ");
406    printf("EXIST ");
407    printf("DFLT ");
408    printf("ASC ");
409    printf("DESC ");
410    printf("NAME");
411    printf("\n");
412}
413
414static void
415show_font_header(FontList *list)
416{
417    const char        *string;
418    FSXFontInfoHeader *pfh;
419
420    pfh = list->info;
421    if (!pfh) {
422	fprintf(stderr,
423		"%s:  no font information for font \"%s\".\n",
424		program_name, list->name ? list->name : "");
425	return;
426    }
427    if (pfh->draw_direction == LeftToRightDrawDirection)
428	string = "-->";
429    else
430	string = "<--";
431    printf("%-4s", string);
432    if (pfh->char_range.min_char.high == 0
433	    && pfh->char_range.max_char.high == 0) {
434	printf(" %3d ", pfh->char_range.min_char.low);
435	printf(" %3d ", pfh->char_range.max_char.low);
436    } else {
437	printf("*%3d ", pfh->char_range.min_char.high);
438	printf("*%3d ", pfh->char_range.max_char.high);
439    }
440    printf("%5s ", (pfh->flags & FontInfoAllCharsExist) ? "all" : "some");
441    printf("%4d ", (pfh->default_char.high << 8) + pfh->default_char.low);
442    printf("%3d ", pfh->font_ascent);
443    printf("%4d ", pfh->font_descent);
444    printf("%s\n", list->name);
445    if (min_max) {
446	char        min[BUFSIZ],
447	            max[BUFSIZ];
448	char       *pmax = max,
449	           *pmin = min;
450	char       *emin = min + sizeof(min),
451	           *emax = max + sizeof(max);
452
453	copy_number(&pmin, &pmax, &emin, &emax,
454		    pfh->min_bounds.left,
455		    pfh->max_bounds.left, ',');
456	copy_number(&pmin, &pmax, &emin, &emax,
457		    pfh->min_bounds.right,
458		    pfh->max_bounds.right, ',');
459	copy_number(&pmin, &pmax, &emin, &emax,
460		    pfh->min_bounds.width,
461		    pfh->max_bounds.width, ',');
462	copy_number(&pmin, &pmax, &emin, &emax,
463		    pfh->min_bounds.ascent,
464		    pfh->max_bounds.ascent, ',');
465	copy_number(&pmin, &pmax, &emin, &emax,
466		    pfh->min_bounds.descent,
467		    pfh->max_bounds.descent, '\0');
468	printf("     min(l,r,w,a,d) = (%s)\n", min);
469	printf("     max(l,r,w,a,d) = (%s)\n", max);
470    }
471}
472
473#ifndef max
474#define	max(a, b)	((a) > (b) ? (a) : (b))
475#endif
476
477/*
478 * Append string representations of n1 to pp1 and n2 to pp2,
479 * followed by the given suffix character,
480 * but not writing into or past ep1 & ep2, respectively.
481 * The string representations will be padded to the same width.
482 */
483static void
484copy_number(char **pp1, char **pp2, char **ep1, char **ep2, int n1, int n2,
485    char suffix)
486{
487    char       *p1 = *pp1;
488    char       *p2 = *pp2;
489    int         w, w1, w2;
490
491    w1 = snprintf(NULL, 0, "%d", n1);
492    w2 = snprintf(NULL, 0, "%d", n2);
493    w = (int) max(w1, w2);
494    assert(w > 0);
495    snprintf(p1, *ep1 - p1, "%*d%c", w, n1, suffix);
496    snprintf(p2, *ep2 - p2, "%*d%c", w, n2, suffix);
497    *pp1 = p1 + strlen(p1);
498    assert(*pp1 < *ep1);
499    *pp2 = p2 + strlen(p2);
500    assert(*pp2 < *ep2);
501}
502
503static void
504show_font_props(FontList *list)
505{
506    unsigned int  i;
507    FSPropInfo *pi = list->pi;
508    FSPropOffset *po = list->po;
509    unsigned char *pd = list->pd;
510    unsigned int  num_props;
511
512    num_props = pi->num_offsets;
513    for (i = 0; i < num_props; i++, po++) {
514	fwrite(pd + po->name.position, 1, po->name.length, stdout);
515	putc('\t', stdout);
516	switch (po->type) {
517	case PropTypeString:
518	    fwrite(pd + po->value.position, 1, po->value.length, stdout);
519	    putc('\n', stdout);
520	    break;
521	case PropTypeUnsigned:
522	    printf("%lu\n", (unsigned long) po->value.position);
523	    break;
524	case PropTypeSigned:
525	    printf("%lu\n", (long) po->value.position);
526	    break;
527	default:
528	    fprintf(stderr, "bogus property\n");
529	    break;
530	}
531
532    }
533}
534