1/*
2 * Copyright 1990 Network Computing Devices;
3 * Portions Copyright 1987 by Digital Equipment Corporation
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the names of Network Computing Devices or Digital
10 * not be used in advertising or publicity pertaining to distribution
11 * of the software without specific, written prior permission.
12 *
13 * NETWORK COMPUTING DEVICES AND DIGITAL DISCLAIM ALL WARRANTIES WITH
14 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL NETWORK COMPUTING DEVICES
16 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
20 * THIS SOFTWARE.
21 */
22/*
23
24Copyright (c) 1987  X Consortium
25
26Permission is hereby granted, free of charge, to any person obtaining
27a copy of this software and associated documentation files (the
28"Software"), to deal in the Software without restriction, including
29without limitation the rights to use, copy, modify, merge, publish,
30distribute, sublicense, and/or sell copies of the Software, and to
31permit persons to whom the Software is furnished to do so, subject to
32the following conditions:
33
34The above copyright notice and this permission notice shall be included
35in all copies or substantial portions of the Software.
36
37THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
38OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
40IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
41OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
42ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
43OTHER DEALINGS IN THE SOFTWARE.
44
45Except as contained in this notice, the name of the X Consortium shall
46not be used in advertising or otherwise to promote the sale, use or
47other dealings in this Software without prior written authorization
48from the X Consortium.
49
50*/
51
52#ifdef HAVE_CONFIG_H
53# include "config.h"
54#endif
55
56#include	<stdio.h>
57#include	<stdlib.h>
58#include	<string.h>
59#include	<ctype.h>
60#include	<X11/fonts/FSlib.h>
61
62/*
63 * the equivalent of showsnf
64 */
65
66#define	GLWIDTHBYTESPADDED(bits,nbytes) \
67	((nbytes) == 1 ? (((bits)+7)>>3)        /* pad to 1 byte */ \
68	:(nbytes) == 2 ? ((((bits)+15)>>3)&~1)  /* pad to 2 bytes */ \
69	:(nbytes) == 4 ? ((((bits)+31)>>3)&~3)  /* pad to 4 bytes */ \
70	:(nbytes) == 8 ? ((((bits)+63)>>3)&~7)  /* pad to 8 bytes */ \
71	: 0)
72
73static int	   byteorder = MSBFirst; /* -LSB or -MSB */
74static int	   bitorder = MSBFirst; /* -lsb or -msb */
75static int	   bitmap_pad = 0;	/* -bitmap_pad: ImageRect bitmap format */
76static int	   scan_pad = 8;	/* -pad: ScanlinePad */
77static int	   scan_unit = 8;	/* -unit: ScanlineUnit */
78static int	   first_ch = 0;	/* -start: first character*/
79static int	   end_ch = ~0;	/* -end: end character */
80static const char *ProgramName;
81static Bool	   no_props = False;	/* -noprops: don't show font properties */
82static Bool	   extents_only = False; /* -extents_only */
83
84static FSServer	  *svr;
85
86/* set from bitmap_pad to ImageRectMin, ImageMaxWidth, or ImageMax */
87static int	   bitmap_format;
88
89static FSBitmapFormat
90make_format(void)
91{
92    FSBitmapFormat format;
93
94    format = 0;
95    /* set up format */
96    switch (scan_pad) {
97    case 8:
98	format |= BitmapFormatScanlinePad8;
99	break;
100    case 16:
101	format |= BitmapFormatScanlinePad16;
102	break;
103    case 32:
104	format |= BitmapFormatScanlinePad32;
105	break;
106    case 64:
107	format |= BitmapFormatScanlinePad64;
108	break;
109    default:
110	fprintf(stderr, "bogus scanline pad value: %d\n", scan_pad);
111	break;
112    }
113    switch (scan_unit) {
114    case 8:
115	format |= BitmapFormatScanlineUnit8;
116	break;
117    case 16:
118	format |= BitmapFormatScanlineUnit16;
119	break;
120    case 32:
121	format |= BitmapFormatScanlineUnit32;
122	break;
123    case 64:
124	format |= BitmapFormatScanlineUnit64;
125	break;
126    default:
127	fprintf(stderr, "bogus scanline unit value: %d\n", scan_unit);
128	break;
129    }
130    switch (bitmap_pad) {
131    case 0:
132	bitmap_format = BitmapFormatImageRectMin;
133	break;
134    case 1:
135	bitmap_format = BitmapFormatImageRectMaxWidth;
136	break;
137    case 2:
138	bitmap_format = BitmapFormatImageRectMax;
139	break;
140    default:
141	fprintf(stderr, "bogus bitmap pad value: %d\n", bitmap_pad);
142	break;
143    }
144    format |= bitmap_format;
145
146    format |= (bitorder == MSBFirst) ? BitmapFormatBitOrderMSB :
147	BitmapFormatBitOrderLSB;
148    format |= (byteorder == MSBFirst) ? BitmapFormatByteOrderMSB :
149	BitmapFormatByteOrderLSB;
150
151    return format;
152}
153
154static void
155show_char_info(FSXCharInfo *ci)
156{
157    printf("Left: %-3d    Right: %-3d    Ascent: %-3d    Descent: %-3d    Width: %d\n",
158	   ci->left, ci->right, ci->ascent, ci->descent, ci->width);
159}
160
161static void
162show_glyphs(
163    Font        fid,
164    FSXFontInfoHeader *hdr,
165    Bool        show_all,
166    FSChar2b    first,
167    FSChar2b    last)
168{
169    FSXCharInfo *extents;
170    unsigned int   offset = 0;
171    unsigned char *glyphs;
172    FSOffset   *offsets;
173    int         scanpad;
174    FSChar2b    chars[2];
175    int         num_chars;
176
177    if (show_all) {
178	num_chars = 0;
179    } else {
180	chars[0] = first;
181	chars[1] = last;
182	num_chars = 2;
183    }
184    FSQueryXExtents16(svr, fid, True, chars, num_chars, &extents);
185
186    if (!extents_only) {
187	FSBitmapFormat format = make_format();
188	int err = FSQueryXBitmaps16(svr, fid, format, True, chars, num_chars,
189				    &offsets, &glyphs);
190
191	if (err != FSSuccess) {
192	    fprintf(stderr, "QueryGlyphs failed\n");
193	    exit(1);
194	}
195    }
196
197    scanpad = scan_pad >> 3;
198
199    for (int row = (int)first.high; row <= (int)last.high; row++) {
200	int start = first.low + (row << 8);
201	for (int col = (int)first.low; col <= (int)last.low; col++) {
202	    int		bottom,
203			bpr,
204	        	charwidth;
205
206	    int ch = ((row - (int)first.high)
207                      * ((int)last.low - (int)first.low + 1))
208		+ (col - (int)first.low);
209	    int temp_ch = start + (col - (int)first.low);
210	    printf("char #%d", temp_ch);
211	    if ((temp_ch >= 0) && (temp_ch <= 127) && isprint(temp_ch))
212		printf(" '%c'\n", (char) (temp_ch));
213	    else
214		printf(" 0x%04x\n", temp_ch);
215	    show_char_info(&extents[ch]);
216	    if (extents_only)
217		continue;
218	    if (offset != offsets[ch].position)
219		fprintf(stderr, "offset mismatch: expected %d, got %d\n",
220			offset, offsets[ch].position);
221	    switch (bitmap_format) {
222	    case BitmapFormatImageRectMin:
223		bottom = extents[ch].descent + extents[ch].ascent;
224		charwidth = extents[ch].right - extents[ch].left;
225		break;
226	    case BitmapFormatImageRectMaxWidth:
227		bottom = extents[ch].descent + extents[ch].ascent;
228		charwidth = hdr->max_bounds.right - hdr->min_bounds.left;
229		break;
230	    case BitmapFormatImageRectMax:
231		bottom = hdr->max_bounds.ascent +
232		    hdr->max_bounds.descent;
233		charwidth = hdr->max_bounds.right - hdr->min_bounds.left;
234		break;
235	    default:
236		bottom = 0;
237		charwidth = 0;
238	    }
239
240	    if (extents[ch].left == 0 &&
241		extents[ch].right == 0 &&
242		extents[ch].width == 0 &&
243		extents[ch].ascent == 0 &&
244		extents[ch].descent == 0) {
245		printf ("Nonexistent character\n");
246		continue;
247	    }
248	    bpr = GLWIDTHBYTESPADDED(charwidth, scanpad);
249	    if (offsets[ch].length != (unsigned)(bottom * bpr)) {
250		fprintf (stderr,
251			 "length mismatch: expected %d (%dx%d), got %d\n",
252			 bottom * bpr, bpr, bottom, offsets[ch].length);
253	    }
254	    offset = offsets[ch].position;
255	    for (int r = 0; r < bottom; r++) {
256		unsigned char *rowp = glyphs + offset;
257
258		for (int b = 0; b < charwidth; b++) {
259		    putchar((rowp[b >> 3] &
260			     (1 << (7 - (b & 7)))) ? '#' : '-');
261		}
262		putchar('\n');
263		offset += bpr;
264	    }
265	}
266    }
267    FSFree((char *) extents);
268    if (!extents_only) {
269	FSFree((char *) offsets);
270	FSFree((char *) glyphs);
271    }
272}
273
274static void
275show_props(
276    FSPropInfo *pi,
277    FSPropOffset *po,
278    unsigned char *pd)
279{
280    char        buf[512];
281    int         num_props;
282
283    num_props = pi->num_offsets;
284    for (int i = 0; i < num_props; i++, po++) {
285	strncpy(buf, (char *) (pd + po->name.position), po->name.length);
286	buf[po->name.length] = '\0';
287	printf("%s\t", buf);
288	switch (po->type) {
289	case PropTypeString:
290	    strncpy(buf, (char *)(pd + po->value.position), po->value.length);
291	    buf[po->value.length] = '\0';
292	    printf("%s\n", buf);
293	    break;
294	case PropTypeUnsigned:
295	    printf("%lu\n", (unsigned long) po->value.position);
296	    break;
297	case PropTypeSigned:
298	    printf("%ld\n", (long) po->value.position);
299	    break;
300	default:
301	    fprintf(stderr, "bogus property\n");
302	    break;
303	}
304    }
305}
306
307static void
308show_info(
309    Font        fid,
310    FSXFontInfoHeader *hdr,
311    FSChar2b   *first,
312    FSChar2b   *last)
313{
314    FSPropInfo  pi;
315    FSPropOffset *po;
316    unsigned char *pd;
317
318    FSQueryXInfo(svr, fid, hdr, &pi, &po, &pd);
319    printf("Direction: %s\n", (hdr->draw_direction == LeftToRightDrawDirection)
320	   ? "Left to Right" : "Right to Left");
321    *first = hdr->char_range.min_char;
322    *last = hdr->char_range.max_char;
323    printf("Range:	%d to %d\n",
324	   first->low + (first->high << 8),
325	   last->low + (last->high << 8));
326    if (hdr->flags & FontInfoAllCharsExist)
327	printf("All chars exist\n");
328    printf("Default char: %d\n",
329	   hdr->default_char.low + (hdr->default_char.high << 8));
330    printf("Min bounds: \n");
331    show_char_info(&hdr->min_bounds);
332    printf("Max bounds: \n");
333    show_char_info(&hdr->max_bounds);
334    printf("Font Ascent: %d  Font Descent: %d\n",
335	   hdr->font_ascent, hdr->font_descent);
336
337    if (!no_props)
338	show_props(&pi, po, pd);
339    FSFree((char *) po);
340    FSFree((char *) pd);
341}
342
343 _X_NORETURN static void
344usage(const char *msg, int exitval)
345{
346    if (msg)
347	fprintf(stderr, "%s: %s\n", ProgramName, msg);
348    fprintf(stderr,
349	    "Usage: %s [-server servername] [-extents_only] [-noprops]\n"
350	    "       [-lsb] [-msb] [-LSB] [-MSB] [-unit #] [-pad #] [-bitmap_pad value]\n"
351	    "       [-start first_char] [-end last_char] -fn fontname\n"
352	    "   or: %s -version\n",
353	    ProgramName, ProgramName);
354    exit(exitval);
355}
356
357int
358main(int argc, char **argv)
359{
360    const char *servername = "localhost:7100"; /* -server: font server name */
361    char *fontname = NULL; /* -fn: font name */
362    Font        fid,
363                dummy;
364    FSBitmapFormat format;
365    FSBitmapFormatMask fmask;
366
367    ProgramName = argv[0];
368
369    for (int i = 1; i < argc; i++) {
370	if (!strncmp(argv[i], "-se", 3)) {
371	    if (++i < argc)
372		servername = argv[i];
373	    else
374		usage("-server requires an argument", 1);
375	} else if (!strncmp(argv[i], "-ext", 4)) {
376	    extents_only = True;
377	} else if (!strncmp(argv[i], "-noprops", 7)) {
378	    no_props = True;
379	} else if (!strncmp(argv[i], "-lsb", 4)) {
380	    bitorder = LSBFirst;
381	} else if (!strncmp(argv[i], "-msb", 4)) {
382	    bitorder = MSBFirst;
383	} else if (!strncmp(argv[i], "-LSB", 4)) {
384	    byteorder = LSBFirst;
385	} else if (!strncmp(argv[i], "-MSB", 4)) {
386	    byteorder = MSBFirst;
387	} else if (!strncmp(argv[i], "-p", 2)) {
388	    if (++i < argc)
389		scan_pad = atoi(argv[i]);
390	    else
391		usage("-pad requires an argument", 1);
392	} else if (!strncmp(argv[i], "-u", 2)) {
393	    if (++i < argc)
394		scan_unit = atoi(argv[i]);
395	    else
396		usage("-unit requires an argument", 1);
397	} else if (!strncmp(argv[i], "-b", 2)) {
398	    if (++i < argc)
399		bitmap_pad = atoi(argv[i]);
400	    else
401		usage("-bitmap_pad requires an argument", 1);
402	} else if (!strncmp(argv[i], "-st", 3)) {
403	    if (++i < argc)
404		first_ch = atoi(argv[i]);
405	    else
406		usage("-start requires an argument", 1);
407	} else if (!strncmp(argv[i], "-e", 2)) {
408	    if (++i < argc)
409		end_ch = atoi(argv[i]);
410	    else
411		usage("-end requires an argument", 1);
412	} else if (!strncmp(argv[i], "-f", 2)) {
413	    if (++i < argc)
414		fontname = argv[i];
415	    else
416		usage("-fn requires an argument", 1);
417	} else if (!strcmp(argv[i], "-version") ||
418		   !strcmp(argv[i], "--version")) {
419	    puts(PACKAGE_STRING);
420	    exit(0);
421	} else if (!strcmp(argv[i], "-help") ||
422		   !strcmp(argv[i], "--help")) {
423	    usage(NULL, 0);
424	} else {
425	    char msg[128];
426	    snprintf(msg, sizeof(msg), "unrecognized argument: %s", argv[i]);
427	    usage(msg, 1);
428	}
429    }
430    if (fontname == NULL)
431	usage("no fontname specified", 1);
432
433    if (first_ch != 0 && end_ch != ~0 && end_ch < first_ch) {
434	fprintf(stderr,
435		"bad character range -- end (%d) is less than start (%d)\n",
436		end_ch, first_ch);
437	exit(1);
438    }
439    if ((svr = FSOpenServer(servername)) == NULL) {
440	if(FSServerName(servername) != NULL)
441		fprintf(stderr, "can't open server \"%s\"\n", FSServerName(servername));
442	else
443		fprintf(stderr, "can't open server \"\"\n");
444	exit(1);
445    }
446    format = make_format();
447    fmask = (BitmapFormatMaskByte | BitmapFormatMaskBit |
448	     BitmapFormatMaskImageRectangle | BitmapFormatMaskScanLinePad |
449	     BitmapFormatMaskScanLineUnit);
450    fid = FSOpenBitmapFont(svr, format, fmask, fontname, &dummy);
451    if (fid) {
452	Bool	    show_all = True;
453	FSChar2b    first,
454		    last;
455	FSXFontInfoHeader hdr;
456
457	printf("opened font %s\n", fontname);
458	show_info(fid, &hdr, &first, &last);
459	if (first_ch != 0 &&
460            ((unsigned)first_ch >= (first.low + ((unsigned)first.high << 8)))) {
461	    first.low = first_ch & 0xff;
462	    first.high = first_ch >> 8;
463	    show_all = False;
464	}
465	if (end_ch != ~0 &&
466            ((unsigned)end_ch <= (last.low + ((unsigned)last.high << 8)))) {
467	    last.low = end_ch & 0xff;
468	    last.high = end_ch >> 8;
469	    show_all = False;
470	}
471	/* make sure the range is legal */
472	if ((first.high > last.high) || (first.high == last.high &&
473					 first.low > last.low)) {
474	    last = first;
475	    fprintf(stderr,
476		    "adjusting range -- specified first char is after end\n");
477	}
478	show_glyphs(fid, &hdr, show_all, first, last);
479	FSCloseFont(svr, fid);
480    } else {
481	fprintf(stderr, "couldn't get font %s\n", fontname);
482	FSCloseServer(svr);
483	exit(1);
484    }
485    FSCloseServer(svr);
486    exit(0);
487}
488