tizen 2.3.1 release
[framework/uifw/xorg/util/x11-utils.git] / xlsfonts / xlsfonts.c
1 /*
2  * $Xorg: xlsfonts.c,v 1.4 2001/02/09 02:05:54 xorgcvs Exp $
3  *
4  * 
5 Copyright 1989, 1998  The Open Group
6
7 Permission to use, copy, modify, distribute, and sell this software and its
8 documentation for any purpose is hereby granted without fee, provided that
9 the above copyright notice appear in all copies and that both that
10 copyright notice and this permission notice appear in supporting
11 documentation.
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Except as contained in this notice, the name of The Open Group shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from The Open Group.
26  * */
27 /* $XFree86: xc/programs/xlsfonts/xlsfonts.c,v 1.9 2003/09/08 14:25:33 eich Exp $ */
28
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xos.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <limits.h>
35 #include "dsimple.h"
36
37 #define N_START INT_MAX  /* Maximum # of fonts to start with (should
38                           * always be be > 10000 as modern OSes like 
39                           * Solaris 8 already have more than 9000 XLFD
40                           * fonts available) */
41
42 #define L_SHORT    0
43 #define L_MEDIUM   1
44 #define L_LONG     2
45 #define L_VERYLONG 3
46
47 static int  max_output_line_width     = 79;
48 static int  output_line_padding       = 3;
49 static int  columns                   = 0;
50
51 static Bool sort_output               = True;
52 static Bool open_instead_of_list      = False;
53 static int  long_list                 = L_SHORT;
54 static int  nnames                    = N_START;
55 static int  font_cnt                  = 0;
56 static int  min_max;
57
58 typedef struct {
59   char           *name;
60   XFontStruct    *info;
61 } FontList;
62
63 static FontList *font_list = NULL;
64
65 /* Local prototypes */
66 static void get_list(char *pattern);
67 static int  compare(const void *arg1, const void *arg2);
68 static void show_fonts(void);
69 static void copy_number(char **pp1, char**pp2, int n1, int n2);
70 static int  IgnoreError(Display *disp, XErrorEvent *event);
71 static void PrintProperty(XFontProp *prop);
72 static void ComputeFontType(XFontStruct *fs);
73 static void print_character_metrics(register XFontStruct *info);
74 static void do_query_font (Display *dpy, char *name);
75
76 void usage(void)
77 {
78     fprintf (stderr, "usage:  %s [-options] [-fn pattern]\n", program_name);
79     fprintf (stderr, "where options include:\n");
80     fprintf (stderr, "    -l[l[l]]                 give long info about each font\n");
81     fprintf (stderr, "    -m                       give character min and max bounds\n");
82     fprintf (stderr, "    -C                       force columns\n");
83     fprintf (stderr, "    -1                       force single column\n");
84     fprintf (stderr, "    -u                       keep output unsorted\n");
85     fprintf (stderr, "    -o                       use OpenFont/QueryFont instead of ListFonts\n");
86     fprintf (stderr, "    -w width                 maximum width for multiple columns\n");
87     fprintf (stderr, "    -n columns               number of columns if multi column\n");
88     fprintf (stderr, "    -display displayname     X server to contact\n");
89     fprintf (stderr, "    -d displayname           (alias for -display displayname)\n");
90     fprintf (stderr, "\n");
91     Close_Display();
92     exit(EXIT_FAILURE);
93 }
94
95 int main(int argc, char **argv)
96 {
97     int argcnt = 0, i;
98
99     INIT_NAME;
100
101     /* Handle command line arguments, open display */
102     Setup_Display_And_Screen(&argc, argv);
103
104     for (argv++, argc--; argc; argv++, argc--) {
105         if (argv[0][0] == '-') {
106             if (argcnt > 0) usage ();
107             for (i=1; argv[0][i]; i++)
108                 switch(argv[0][i]) {
109                 case 'l':
110                     long_list++;
111                     break;
112                 case 'm':
113                     min_max++;
114                     break;
115                 case 'C':
116                     columns = 0;
117                     break;
118                 case '1':
119                     columns = 1;
120                     break;
121                 case 'f': /* "-fn" */
122                     if (--argc <= 0) usage ();
123                     if (argv[0][i+1] != 'n') usage ();
124                     argcnt++;
125                     argv++;
126                     get_list(argv[0]);
127                     goto next;
128                 case 'w':
129                     if (--argc <= 0) usage ();
130                     argv++;
131                     max_output_line_width = atoi(argv[0]);
132                     goto next;
133                 case 'n':
134                     if (--argc <= 0) usage ();
135                     argv++;
136                     columns = atoi(argv[0]);
137                     goto next;
138                 case 'o':
139                     open_instead_of_list = True;
140                     break;
141                 case 'u':
142                     sort_output = False;
143                     break;
144                 default:
145                     usage();
146                     break;
147                 }
148             if (i == 1)
149                 usage();
150         } else {
151             argcnt++;
152             get_list(argv[0]);
153         }
154       next: ;
155     }
156
157     if (argcnt == 0)
158         get_list("*");
159
160     show_fonts();
161     
162     Close_Display();
163     return EXIT_SUCCESS;
164 }
165
166
167 static
168 void get_list(char *pattern)
169 {
170     int           available = nnames+1,
171                   i;
172     char        **fonts;
173     XFontStruct  *info;
174
175     /* Get list of fonts matching pattern */
176     for (;;) {
177         if (open_instead_of_list) {
178             info = XLoadQueryFont (dpy, pattern);
179
180             if (info) {
181                 fonts = &pattern;
182                 available = 1;
183                 XUnloadFont (dpy, info->fid);
184             } else {
185                 fonts = NULL;
186             }
187             break;
188         }
189             
190         if (long_list == L_MEDIUM)
191             fonts = XListFontsWithInfo(dpy, pattern, nnames, &available, &info);
192         else
193             fonts = XListFonts(dpy, pattern, nnames, &available);
194         if (fonts == NULL || available < nnames)
195             break;
196         if (long_list == L_MEDIUM)
197             XFreeFontInfo(fonts, info, available);
198         else
199             XFreeFontNames(fonts);
200         nnames = available * 2;
201     }
202
203     if (fonts == NULL) {
204         fprintf(stderr, "%s: pattern \"%s\" unmatched\n",
205                 program_name, pattern);
206         return;
207     }
208
209     font_list = (FontList *)Realloc((char *)font_list,
210             (font_cnt + available) * sizeof(FontList));
211     for (i=0; i<available; i++) {
212         font_list[font_cnt].name = fonts[i];
213         if (long_list == L_MEDIUM)
214             font_list[font_cnt].info = info + i;
215         else
216             font_list[font_cnt].info = NULL;
217         
218         font_cnt++;
219     }
220 }
221
222 static
223 int compare(const void *arg1, const void *arg2)
224 {
225     const FontList *f1 = arg1;
226     const FontList *f2 = arg2;
227     const char *p1 = f1->name;
228     const char *p2 = f2->name;
229
230     while (*p1 && *p2 && *p1 == *p2)
231             p1++, p2++;
232     return(*p1 - *p2);
233 }
234
235 static
236 void show_fonts(void)
237 {
238     int i;
239
240     if (font_cnt == 0)
241         return;
242
243     /* first sort the output */
244     if (sort_output) qsort(font_list, font_cnt, sizeof(FontList), compare);
245
246     if (long_list > L_MEDIUM) {
247         for (i = 0; i < font_cnt; i++) {
248             do_query_font (dpy, font_list[i].name);
249         }
250         return;
251     }
252
253     if (long_list == L_MEDIUM) {
254         XFontStruct *pfi;
255         char        *string;
256
257         printf("DIR  ");
258         printf("MIN  ");
259         printf("MAX ");
260         printf("EXIST ");
261         printf("DFLT ");
262         printf("PROP ");
263         printf("ASC ");
264         printf("DESC ");
265         printf("NAME");
266         printf("\n");
267         for (i=0; i<font_cnt; i++) {
268             pfi = font_list[i].info;
269             if (!pfi) {
270                 fprintf(stderr, "%s:  no font information for font \"%s\".\n",
271                         program_name, 
272                         font_list[i].name ? 
273                         font_list[i].name : "");
274                 continue;
275             }
276             switch(pfi->direction) {
277                 case FontLeftToRight: string = "-->"; break;
278                 case FontRightToLeft: string = "<--"; break;
279                 default:              string = "???"; break;
280             }
281             printf("%-4s", string);
282             if (pfi->min_byte1 == 0 &&
283                 pfi->max_byte1 == 0) {
284                 printf(" %3d ", pfi->min_char_or_byte2);
285                 printf(" %3d ", pfi->max_char_or_byte2);
286             } else {
287                 printf("*%3d ", pfi->min_byte1);
288                 printf("*%3d ", pfi->max_byte1);
289             }
290             printf("%5s ", pfi->all_chars_exist ? "all" : "some");
291             printf("%4d ", pfi->default_char);
292             printf("%4d ", pfi->n_properties);
293             printf("%3d ", pfi->ascent);
294             printf("%4d ", pfi->descent);
295             printf("%s\n", font_list[i].name);
296             if (min_max) {
297                 char  min[ BUFSIZ ],
298                       max[ BUFSIZ ];
299                 char *pmax = max,
300                      *pmin = min;
301
302                 strcpy(pmin, "     min(l,r,w,a,d) = (");
303                 strcpy(pmax, "     max(l,r,w,a,d) = (");
304                 pmin += strlen(pmin);
305                 pmax += strlen(pmax);
306
307                 copy_number(&pmin, &pmax,
308                             pfi->min_bounds.lbearing,
309                             pfi->max_bounds.lbearing);
310                 *pmin++ = *pmax++ = ',';
311                 copy_number(&pmin, &pmax,
312                             pfi->min_bounds.rbearing,
313                             pfi->max_bounds.rbearing);
314                 *pmin++ = *pmax++ = ',';
315                 copy_number(&pmin, &pmax,
316                             pfi->min_bounds.width,
317                             pfi->max_bounds.width);
318                 *pmin++ = *pmax++ = ',';
319                 copy_number(&pmin, &pmax,
320                             pfi->min_bounds.ascent,
321                             pfi->max_bounds.ascent);
322                 *pmin++ = *pmax++ = ',';
323                 copy_number(&pmin, &pmax,
324                             pfi->min_bounds.descent,
325                             pfi->max_bounds.descent);
326                 *pmin++ = *pmax++ = ')';
327                 *pmin = *pmax = '\0';
328                 printf("%s\n", min);
329                 printf("%s\n", max);
330             }
331         }
332         return;
333     }
334
335     if ((columns == 0 && isatty(1)) || columns > 1) {
336         int width,
337             max_width = 0,
338             lines_per_column,
339             j,
340             index;
341
342         for (i=0; i<font_cnt; i++) {
343             width = strlen(font_list[i].name);
344             if (width > max_width)
345                 max_width = width;
346         }
347         if (max_width == 0)
348             Fatal_Error("all %d fontnames listed are zero length", font_cnt);
349
350         if (columns == 0) {
351             if ((max_width * 2) + output_line_padding >
352                 max_output_line_width) {
353                 columns = 1;
354             } else {
355                 max_width += output_line_padding;
356                 columns = ((max_output_line_width +
357                             output_line_padding) / max_width);
358             }
359         } else {
360             max_width += output_line_padding;
361         }
362         if (columns <= 1) goto single_column;
363
364         if (font_cnt < columns)
365             columns = font_cnt;
366         lines_per_column = (font_cnt + columns - 1) / columns;
367
368         for (i=0; i<lines_per_column; i++) {
369             for (j=0; j<columns; j++) {
370                 index = j * lines_per_column + i;
371                 if (index >= font_cnt)
372                     break;
373                 if (j+1 == columns)
374                     printf("%s", font_list[ index ].name);
375                 else
376                     printf("%-*s",
377                            max_width, 
378                            font_list[ index ].name);
379             }
380             printf("\n");
381         }
382         return;
383     }
384
385   single_column:
386     for (i=0; i<font_cnt; i++)
387         printf("%s\n", font_list[i].name);
388 }
389
390 static
391 void copy_number(char **pp1, char**pp2, int n1, int n2)
392 {
393     char *p1 = *pp1;
394     char *p2 = *pp2;
395     int   w;
396
397     sprintf(p1, "%d", n1);
398     sprintf(p2, "%d", n2);
399     w = MAX(strlen(p1), strlen(p2));
400     sprintf(p1, "%*d", w, n1);
401     sprintf(p2, "%*d", w, n2);
402     p1 += strlen(p1);
403     p2 += strlen(p2);
404     *pp1 = p1;
405     *pp2 = p2;
406 }
407
408
409
410 /* ARGSUSED */
411 static
412 int IgnoreError(Display *disp, XErrorEvent *event)
413 {
414     return 0;
415 }
416
417 static char *bounds_metrics_title =
418                       "width left  right  asc  desc   attr   keysym\n";
419
420 #define PrintBounds(_what,_ptr) \
421 {   register XCharStruct *p = (_ptr); \
422     printf ("\t%3s\t\t%4d  %4d  %4d  %4d  %4d  0x%04x\n", \
423           (_what), p->width, p->lbearing, \
424           p->rbearing, p->ascent, p->descent, p->attributes); }
425
426
427 static char* stringValued [] = { /* values are atoms */
428     /* font name components (see section 3.2 of the XLFD) */
429     "FOUNDRY",
430     "FAMILY_NAME",
431     "WEIGHT_NAME",
432     "SLANT",
433     "SETWIDTH_NAME",
434     "ADD_STYLE_NAME",
435     "SPACING",
436     "CHARSET_REGISTRY",
437     "CHARSET_ENCODING",
438
439     /* other standard X font properties (see section 3.2 of the XLFD) */
440     "FONT",
441     "FACE_NAME",
442     "FULL_NAME",              /* deprecated */
443     "COPYRIGHT",
444     "NOTICE",
445     "FONT_TYPE",
446     "FONT_VERSION",
447     "RASTERIZER_NAME",
448     "RASTERIZER_VERSION",
449
450     /* other registered font properties (see the X.org Registry, sec. 15) */
451     "_ADOBE_POSTSCRIPT_FONTNAME",
452     
453     /* unregistered font properties */
454     "CHARSET_COLLECTIONS",
455     "CLASSIFICATION",
456     "DEVICE_FONT_NAME",
457     "FONTNAME_REGISTRY",
458     "MONOSPACED",
459     "QUALITY",
460     "RELATIVE_SET",
461     "STYLE",
462      NULL
463     };
464
465 static
466 void PrintProperty(XFontProp *prop)
467 {
468     char *atom, *value;
469     char nosuch[40];
470     int i;
471     XErrorHandler oldhandler = XSetErrorHandler(IgnoreError);
472
473     atom = XGetAtomName(dpy, prop->name);
474     if (!atom) {
475         atom = nosuch;
476         nosuch[0] = '\0';
477         (void)sprintf (atom, "No such atom = %ld", prop->name);
478     }
479     printf ("      %s", atom);
480
481     /* Pad out to a column width of 22, but ensure there is always at
482        least one space between property name & value. */
483     for (i = strlen(atom); i < 21; i++) putchar (' ');
484     putchar(' ');
485
486     for (i = 0; ; i++) {
487         if (stringValued[i] == NULL) {
488             printf ("%ld\n", prop->card32);
489             break;
490         }
491         if (strcmp(stringValued[i], atom) == 0) {
492             value = XGetAtomName(dpy, prop->card32);
493             if (value == NULL)
494                 printf ("%ld (expected string value)\n", prop->card32);
495             else {
496                 printf ("%s\n", value);
497                 XFree (value);
498             }
499             break;
500         }
501     } 
502     if (atom != nosuch) XFree (atom);
503     XSetErrorHandler (oldhandler);
504 }
505
506
507 static void
508 ComputeFontType(XFontStruct *fs)
509 {
510     int i;
511     Bool char_cell = True;
512     char *reason = NULL;
513     XCharStruct *cs;
514     Atom awatom = XInternAtom (dpy, "AVERAGE_WIDTH", False);
515
516     printf ("  font type:\t\t");
517     if (fs->min_bounds.width != fs->max_bounds.width) {
518         printf ("Proportional (min and max widths not equal)\n");
519         return;
520     }
521
522     if (awatom) {
523         for (i = 0; i < fs->n_properties; i++) {
524             if (fs->properties[i].name == awatom &&
525                 (fs->max_bounds.width * 10) != fs->properties[i].card32) {
526                 char_cell = False;
527                 reason = "font width not equal to AVERAGE_WIDTH";
528                 break;
529             }
530         }
531     }
532
533     if (fs->per_char) {
534         for (i = fs->min_char_or_byte2, cs = fs->per_char;
535              i <= fs->max_char_or_byte2; i++, cs++) {
536             if (cs->width == 0) continue;
537             if (cs->width != fs->max_bounds.width) {
538                 /* this shouldn't happen since we checked above */
539                 printf ("Proportional (characters not all the same width)\n");
540                 return;
541             }
542             if (char_cell) {
543                 if (cs->width < 0) {
544                     if (!(cs->width <= cs->lbearing &&
545                           cs->lbearing <= cs->rbearing &&
546                           cs->rbearing <= 0)) {
547                         char_cell = False;
548                         reason = "ink outside bounding box";
549                     }
550                 } else {
551                     if (!(0 <= cs->lbearing &&
552                           cs->lbearing <= cs->rbearing &&
553                           cs->rbearing <= cs->width)) {
554                         char_cell = False;
555                         reason = "ink outside bounding box";
556                     }
557                 }
558                 if (!(cs->ascent <= fs->ascent &&
559                       cs->descent <= fs->descent)) {
560                     char_cell  = False;
561                     reason = "characters not all same ascent or descent";
562                 }
563             }
564         }
565     }
566
567     printf ("%s", char_cell ? "Character Cell" : "Monospaced");
568     if (reason) printf (" (%s)", reason);
569     printf ("\n");
570         
571     return;
572 }
573
574
575 static void
576 print_character_metrics(register XFontStruct *info)
577 {
578     register XCharStruct *pc = info->per_char;
579     register int i, j;
580     unsigned n, saven;
581
582     printf ("  character metrics:\n");
583     saven = ((info->min_byte1 << 8) | info->min_char_or_byte2);
584     for (j = info->min_byte1; j <= info->max_byte1; j++) {
585         n = saven;
586         for (i = info->min_char_or_byte2; i <= info->max_char_or_byte2; i++) {
587             char *s = XKeysymToString ((KeySym) n);
588             printf ("\t0x%02x%02x (%u)\t%4d  %4d  %4d  %4d  %4d  0x%04x  %s\n",
589                     j, i, n, pc->width, pc->lbearing,
590                     pc->rbearing, pc->ascent, pc->descent, pc->attributes,
591                     s ? s : ".");
592             pc++;
593             n++;
594         }
595         saven += 256;
596     }
597 }
598
599 static
600 void do_query_font (Display *dpy, char *name)
601 {
602     register int i;
603     register XFontStruct *info = XLoadQueryFont (dpy, name);
604
605     if (!info) {
606         fprintf (stderr, "%s:  unable to get info about font \"%s\"\n",
607                  program_name, name);
608         return;
609     }
610     printf ("name:  %s\n", name ? name : "(nil)");
611     printf ("  direction:\t\t%s\n", ((info->direction == FontLeftToRight)
612                                      ? "left to right" : "right to left"));
613     printf ("  indexing:\t\t%s\n", 
614             ((info->min_byte1 == 0 && info->max_byte1 == 0) ? "linear" :
615              "matrix"));
616     printf ("  rows:\t\t\t0x%02x thru 0x%02x (%d thru %d)\n",
617             info->min_byte1, info->max_byte1,
618             info->min_byte1, info->max_byte1);
619     printf ("  columns:\t\t0x%02x thru 0x%02x (%d thru %d)\n",
620             info->min_char_or_byte2, info->max_char_or_byte2,
621             info->min_char_or_byte2, info->max_char_or_byte2);
622     printf ("  all chars exist:\t%s\n",
623         (info->all_chars_exist) ? "yes" : "no");
624     printf ("  default char:\t\t0x%04x (%d)\n",
625             info->default_char, info->default_char);
626     printf ("  ascent:\t\t%d\n", info->ascent);
627     printf ("  descent:\t\t%d\n", info->descent);
628     ComputeFontType (info);
629     printf ("  bounds:\t\t%s", bounds_metrics_title);
630     PrintBounds ("min", &info->min_bounds);
631     PrintBounds ("max", &info->max_bounds);
632     if (info->per_char && long_list >= L_VERYLONG) 
633         print_character_metrics (info);
634     printf ("  properties:\t\t%d\n", info->n_properties);
635     for (i = 0; i < info->n_properties; i++)
636         PrintProperty (&info->properties[i]);
637     printf ("\n");
638
639     XFreeFontInfo (NULL, info, 1);
640 }
641
642