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