(main): Fix checking number of arguments.
[m17n/libotf.git] / example / otfview.c
1 /* otfview.c -- View glyphs of OpenType fonts.
2
3 Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010
4   National Institute of Advanced Industrial Science and Technology (AIST)
5   Registration Number H15PRO167
6
7 This file is part of libotf.
8
9 Libotf is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 Libotf is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17 License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library, in a file named COPYING; if not,
21 write to the Free Software Foundation, Inc., 59 Temple Place, Suite
22 330, Boston, MA 02111-1307, USA.  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <libgen.h>
30
31 #include "config.h"
32
33 #ifdef HAVE_X11_XAW_COMMAND_H
34
35 #include <X11/Xatom.h>
36 #include <X11/Intrinsic.h>
37 #include <X11/StringDefs.h>
38 #include <X11/Shell.h>
39 #include <X11/Xaw/Command.h>
40 #include <X11/Xaw/Toggle.h>
41 #include <X11/Xaw/Box.h>
42 #include <X11/Xaw/Form.h>
43 #include <X11/Xaw/Viewport.h>
44
45 #include <ft2build.h>
46 #include FT_FREETYPE_H
47
48 #include <otf.h>
49
50 #define CAST_FROM_XTPOINTER(TYPE, DATA, VAR)    \
51   do {                                          \
52     long TYPE temp = (long TYPE) (DATA);        \
53     (VAR) = temp;                               \
54   } while (0)
55
56 #define XtAddCallbackWithCast(TYPE, W, PROC, VAR)               \
57   do {                                                          \
58     long TYPE temp = (long TYPE) (VAR);                         \
59     XtAddCallback (W, XtNcallback, PROC, (XtPointer) temp);     \
60   } while (0)
61
62
63 #define DEFAULT_PIXEL_SIZE 30
64 int pixel_size;
65
66 #define DEFAULT_FONT_NAME "6x13"
67 XFontStruct *font;
68 #define FONT_HEIGHT (font->ascent + font->descent)
69 #define FONT_ASCENT (font->ascent)
70 #define FONT_DESCENT (font->descent)
71 #define FONT_WIDTH (font->max_bounds.width)
72
73 XtAppContext context;
74 /* Widget structure.
75    +--- frame (form) -------------------------+
76    | +--- command_area (box) ---------------+ |
77    | | quit dump charmap ...                | |
78    | +--------------------------------------+ |
79    | +---- navi_area (box) -----------------+ |
80    | | FIRST PREV prev range next NEXT LAST | |
81    | +--------------------------------------+ |
82    | +--- glyph_area (form) ----------------+ |
83    | | idxh[0] glyph[0]    ...    glyph[15] | |
84    | |   ...                        ...     | |
85    | | idxh[7] glyph[112]  ...    glyph[127]| |
86    | |         idxl[0]     ...    idxl[15]  | |
87    | +--------------------------------------+ |
88    | +--- script_area (box) ----------------+ |
89    | | script(langsys) DFLT ...             | |
90    | +--------------------------------------+ |
91    | +---- uvs_area (box) (optional) -------+ |
92    | | uvs[?].w ...                         | |
93    | +--------------------------------------+ |
94    | +--- render_area (form) ---------------+ |
95    | | clear del bidi alt_subst             | |
96    | | +--- raw (box) --------------------+ | |
97    | | | raw_label raw_image              | | |
98    | | +----------------------------------+ | |
99    | | GSUB all none features...            | |
100    | | GPOS all none features...            | |
101    | | +--- seq (box) --------------------+ | |
102    | | | seq_label seq_image              | | |
103    | | +----------------------------------+ | |
104    | | +--- code (box) -------------------+ | |
105    | | | code_label code_list ...         | | |   
106    | | +----------------------------------+ | |
107    | +--------------------------------------+ |
108    +------------------------------------------+ */
109 Widget shell, frame;
110 Widget command_area, quit, dump, *charmap;
111 Widget navi_area, FIRST, PREV, prev, range, next, NEXT, LAST;
112 Widget glyph_area, glyph[128], index_label[8];
113 Widget uvs_area, uvs_label;
114 Widget render_area, clear, del, bidi, alt_subst, raw, seq, code;
115 Widget raw_label, raw_image, seq_label, seq_image, code_label, code_list;
116 unsigned long foreground, background;
117
118 typedef struct
119 {
120   OTF_Tag tag;
121   int on;
122   Widget w;
123 } FeatureElement;
124
125 typedef struct
126 {
127   char *label;
128   OTF_GSUB_GPOS *gsub_gpos;
129   OTF_LangSys *langsys;
130   int num_features;
131   FeatureElement *features;
132   Widget parent;
133 } FeatureRec;
134
135 FeatureRec gsub, gpos;
136
137 /* Currently selected script and langsys.  */
138 OTF_Tag script_tag, langsys_tag;
139
140 int glyph_char[128];
141
142 Display *display;
143 GC gc, gc_set, gc_or, gc_inv;
144
145 typedef struct {
146   Pixmap pixmap;
147   unsigned width, height;
148   int x, y;
149   int advance;
150 } BitmapRec;
151
152 BitmapRec bitmap[0x110000];
153
154 int render_width, render_height;
155 Pixmap raw_pixmap, seq_pixmap, gsub_pixmap, gpos_pixmap;
156 Pixmap none_pixmap;
157
158 FT_Face face;
159
160 struct {
161   int platform_id;
162   int encoding_id;
163   char name[20];
164 } charmap_rec[10];
165
166 int charmap_index;
167
168 int reversed;
169 int do_alternate_subst;
170 unsigned glyph_width, glyph_height;
171 int glyph_x, glyph_y;
172 int glyph_index;
173
174 struct {
175   int n_glyphs;
176   int glyphs[64];
177   int codes[64];
178 } glyph_rec;
179
180 OTF_EncodingSubtable14 *sub14 = NULL;
181
182 struct {
183   Widget w;
184   int c;
185 } uvs[256];
186
187 OTF *otf;
188 char *filename;
189 int fontindex;
190
191 void
192 create_pixmap (int index)
193 {
194   int err = FT_Load_Glyph (face, index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
195   XImage ximage;
196   Pixmap pixmap;
197   
198   if (err)
199     {
200       bitmap[index].pixmap = none_pixmap;
201       return;
202     }
203   ximage.height = face->glyph->bitmap.rows;
204   ximage.width = face->glyph->bitmap.width;
205   ximage.depth = 1;
206   ximage.bits_per_pixel = 1;
207   ximage.xoffset = 0;
208   ximage.format = XYPixmap;
209   ximage.data = (char *) face->glyph->bitmap.buffer;
210   ximage.byte_order = MSBFirst;
211   ximage.bitmap_unit = 8;
212   ximage.bitmap_bit_order = MSBFirst;
213   ximage.bitmap_pad = 8;
214   ximage.bytes_per_line = face->glyph->bitmap.pitch;
215   XInitImage (&ximage);
216   pixmap = XCreatePixmap (display, DefaultRootWindow (display),
217                           glyph_width, glyph_height, 1);
218   XFillRectangle (display, pixmap, gc, 0, 0, glyph_width, glyph_height);
219   XPutImage (display, pixmap, gc, &ximage, 0, 0,
220              glyph_x + face->glyph->bitmap_left,
221              glyph_y - face->glyph->bitmap_top,
222              ximage.width, ximage.height);
223   bitmap[index].pixmap = pixmap;
224   bitmap[index].width = ximage.width;
225   bitmap[index].height = ximage.height;
226   bitmap[index].x = face->glyph->bitmap_left;
227   bitmap[index].y = - face->glyph->bitmap_top;
228   bitmap[index].advance = face->glyph->metrics.horiAdvance >> 6;
229 }
230
231 void
232 update_glyph_area ()
233 {
234   int i;
235   Arg arg[2];
236   char buf[16];
237   int msb;
238
239   for (i = 0; i < 128; i++)
240     {
241       int index = glyph_index + i;
242
243       if (charmap_index >= 0)
244         index = FT_Get_Char_Index (face, (FT_ULong) index);
245       if (charmap_index >= 0 && ! index)
246         XtSetArg (arg[0], XtNbitmap, none_pixmap);
247       else
248         {
249           if (! bitmap[index].pixmap)
250             create_pixmap (index);
251           XtSetArg (arg[0], XtNbitmap, bitmap[index].pixmap);
252         }
253       XtSetValues (glyph[i], arg, 1);
254     }
255
256   msb = (glyph_index >> 7) % 2 ? 8 : 0;
257   for (i = 0; i < 8; i++)
258     {
259       char str[3];
260
261       sprintf (str, "%XX", i | msb );
262       XtSetArg (arg[0], XtNheight, glyph_height + 5);
263       XtSetArg (arg[1], XtNlabel, str);
264       XtSetValues (index_label[i], arg, 2);
265     }
266
267   if (glyph_index < 0x10000)
268     sprintf (buf, "  %04X-%04X  ", glyph_index, glyph_index + 0x7F);
269   else
270     sprintf (buf, "%06X-%06X", glyph_index, glyph_index + 0x7F);
271   XtSetArg (arg[0], XtNlabel, buf);
272   XtSetValues (range, arg, 1);
273 }
274
275 void
276 update_uvs_area (int c)
277 {
278   OTF_GlyphID code[256];
279   Arg arg[1];
280   int i;
281
282   OTF_get_variation_glyphs (otf, c, code);
283
284   for (i = 0; i < 256; i++)
285     if (uvs[i].w)
286       {
287         if (code[i])
288           XtSetArg (arg[0], XtNsensitive, True);
289         else
290           XtSetArg (arg[0], XtNsensitive, False);
291         XtSetValues (uvs[i].w, arg, 1);
292       }
293 }
294
295
296 char *
297 get_features (OTF_FeatureList *list, FeatureRec *rec)
298 {
299   int i, n;
300   char *str, *p;
301
302   if (! rec->langsys || ! rec->features)
303     return NULL;
304   for (i = n = 0; i < rec->langsys->FeatureCount; i++)
305     if (rec->features[i].on)
306       n++;
307   if (n == 0)
308     return NULL;
309   str = malloc (n * 5);
310   for (i = 0, p = str; i < rec->langsys->FeatureCount; i++)
311     if (rec->features[i].on)
312       {
313         OTF_tag_name (rec->features[i].tag, p);
314         p[4] = ',';
315         p += 5;
316       }
317   p[-1] = '\0';
318   return str;
319 }
320
321
322 #define DEVICE_DELTA(table, size)                                       \
323   (((table).DeltaValue                                                  \
324     && ((size) >= (table).StartSize && (size) <= (table).EndSize))      \
325    ? (table).DeltaValue[(size) >= (table).StartSize]                    \
326    : 0)
327
328 void
329 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
330                OTF_Glyph *g, int *x, int *y)
331 {
332   if (anchor->AnchorFormat == 2)
333     {
334       FT_Outline *outline;
335       int ap = anchor->f.f1.AnchorPoint;
336
337       FT_Load_Glyph (ft_face, (FT_UInt) g->glyph_id, FT_LOAD_MONOCHROME);
338       outline = &ft_face->glyph->outline;
339       if (ap < outline->n_points)
340         {
341           *x = outline->points[ap].x;
342           *y = outline->points[ap].y;
343         }
344     }
345   else if (anchor->AnchorFormat == 3)
346     {
347       *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, pixel_size);
348       *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, pixel_size);
349     }
350 }
351
352 void
353 update_seq_area ()
354 {
355   int i, x;
356   OTF_GlyphString gstring;
357   OTF_Glyph *g, *prev, *base, *mark;
358   int base_width;
359   int len = glyph_rec.n_glyphs;
360   Arg arg[1];
361   int unitsPerEm = face->units_per_EM;
362   OTF_Tag *log = NULL;
363   int logsize;
364
365   gstring.size = gstring.used = len;
366   gstring.glyphs = malloc (sizeof (OTF_Glyph) * len);
367   memset (gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
368   for (i = 0; i < len; i++)
369     {
370       gstring.glyphs[i].c = glyph_rec.codes[i];
371       if (charmap_index < 0)
372         gstring.glyphs[i].glyph_id = glyph_rec.glyphs[i];
373     }
374
375   XFillRectangle (display, seq_pixmap, gc, 0, 0, render_width, render_height);
376   XDrawLine (display, seq_pixmap, gc_set, 0, glyph_y, render_width, glyph_y);
377   if (otf)
378     {
379       char *script_name = NULL, *langsys_name = NULL, buf[10];
380       char *str;
381
382       if (script_tag)
383         {
384           script_name = buf;
385           OTF_tag_name (script_tag, script_name);
386         }
387       if (langsys_tag)
388         {
389           langsys_name = buf + 5;
390           OTF_tag_name (langsys_tag, langsys_name);
391         }
392
393       OTF_drive_cmap (otf, &gstring);
394       OTF_drive_gdef (otf, &gstring);
395       if (otf->gsub)
396         {
397           str = get_features (&otf->gsub->FeatureList, &gsub);
398           if (str)
399             {
400               if (do_alternate_subst)
401                 OTF_drive_gsub_alternate (otf, &gstring,
402                                           script_name, langsys_name, str);
403               else
404                 {
405                   OTF_drive_gsub_with_log (otf, &gstring,
406                                            script_name, langsys_name, str);
407                   logsize = gstring.used * 2;
408                   log = alloca (sizeof (OTF_Tag) * logsize);
409                   for (i = 0; i < gstring.used; i++)
410                     {
411                       int idx = gstring.glyphs[i].positioning_type >> 4;
412                       if (idx)
413                         log[i] = otf->gsub->FeatureList.Feature[idx - 1].FeatureTag;
414                       else
415                         log[i] = 0;
416                     }
417                 }
418               free (str);
419             }
420         }
421       if (otf->gpos)
422         {
423           str = get_features (&otf->gpos->FeatureList, &gpos);
424           if (str)
425             {
426               OTF_drive_gpos_with_log (otf, &gstring,
427                                        script_name, langsys_name, str);
428               if (log)
429                 {
430                   if (logsize < gstring.used)
431                     {
432                       OTF_Tag *log2 = alloca (sizeof (OTF_Tag) * gstring.used);
433                       memset (log2, 0, sizeof (OTF_Tag) * gstring.used);
434                       memcpy (log2, log, sizeof (OTF_Tag) * logsize);
435                       logsize = gstring.used;
436                       log = log2;
437                     }
438                 }
439               else
440                 {
441                   logsize = gstring.used;
442                   log = alloca (sizeof (OTF_Tag) * logsize);
443                   memset (log, 0, sizeof (OTF_Tag) * logsize);
444                 }
445               for (i = 0; i < gstring.used; i++)
446                 {
447                   int idx = gstring.glyphs[i].positioning_type >> 4;
448                   if (idx)
449                     log[i] = otf->gpos->FeatureList.Feature[idx - 1].FeatureTag;
450
451                 }
452               free (str);
453             }
454         }
455     }
456
457   prev = NULL;
458   if (reversed)
459     {
460       OTF_Glyph temp;
461
462       for (prev = gstring.glyphs, g = gstring.glyphs + gstring.used - 1;
463            prev < g; prev++, g--)
464         temp = *prev, *prev = *g, *g = temp;
465       for (g = gstring.glyphs; g < gstring.glyphs + gstring.used; g++)
466         if (g->GlyphClass == 3)
467           {
468             OTF_Glyph *g0;
469             prev = g++;
470             while (g < gstring.glyphs + gstring.used && g->GlyphClass == 3)
471               g++;
472             for (g0 = g; prev < g0; prev++, g0--)
473               temp = *prev, *prev = *g, *g = temp;
474           }
475     }
476
477
478   mark = base = NULL;
479   for (i = 0, x = glyph_x, prev = NULL, g = gstring.glyphs;
480        i < gstring.used; i++, prev = g++)
481     {
482       BitmapRec *bmp = bitmap + gstring.glyphs[i].glyph_id;
483       int xoff = 0, yoff = 0;
484       int prev_width;
485       int advance = bmp->advance;
486
487       if (gstring.glyphs[i].glyph_id && ! bmp->pixmap)
488         {
489           create_pixmap (gstring.glyphs[i].glyph_id);
490           if (! bmp->pixmap)
491             continue;
492           advance = bmp->advance;
493         }
494       if (g->positioning_type & 0xF)
495         {
496           while (1)
497             {
498               switch (g->positioning_type & 0xF)
499                 {
500                 case 1: case 2:
501                   {
502                     int format = g->f.f1.format;
503
504                     if (format & OTF_XPlacement)
505                       xoff += g->f.f1.value->XPlacement * pixel_size / unitsPerEm;
506                     if (format & OTF_XPlaDevice)
507                       xoff += DEVICE_DELTA (g->f.f1.value->XPlaDevice, pixel_size);
508                     if (format & OTF_YPlacement)
509                       yoff += g->f.f1.value->YPlacement * pixel_size / unitsPerEm;
510                     if (format & OTF_YPlaDevice)
511                       yoff += DEVICE_DELTA (g->f.f1.value->YPlaDevice, pixel_size);
512                     if (format & OTF_XAdvance)
513                       advance += g->f.f1.value->XAdvance * pixel_size / unitsPerEm;
514                     if (format & OTF_XAdvDevice)
515                       advance += DEVICE_DELTA (g->f.f1.value->XAdvDevice,
516                                                pixel_size);
517                   }
518                   break;
519
520                 case 3:
521                   /* Not yet supported.  */
522                   break;
523                 case 4: case 5:
524                   if (! base)
525                     break;
526                   prev = base;
527                   prev_width = base_width;
528                   goto label_adjust_anchor;
529                 default:                /* i.e. case 6 */
530                   if (! mark)
531                     break;
532                   prev = mark;
533                   prev_width = 0;
534                 label_adjust_anchor:
535                   {
536                     int base_x, base_y, mark_x, mark_y;
537
538                     base_x = g->f.f4.base_anchor->XCoordinate * pixel_size / unitsPerEm;
539                     base_y = g->f.f4.base_anchor->YCoordinate * pixel_size / unitsPerEm;
540                     mark_x = g->f.f4.mark_anchor->XCoordinate * pixel_size / unitsPerEm;
541                     mark_y = g->f.f4.mark_anchor->YCoordinate * pixel_size / unitsPerEm;
542
543                     if (g->f.f4.base_anchor->AnchorFormat != 1)
544                       adjust_anchor (g->f.f4.base_anchor, face, prev, &base_x, &base_y);
545                     if (g->f.f4.mark_anchor->AnchorFormat != 1)
546                       adjust_anchor (g->f.f4.mark_anchor, face, g, &mark_x, &mark_y);
547                     xoff = (base_x - prev_width) - mark_x;
548                     yoff = base_y - mark_y;
549                   }
550                 }
551               if (i + 1 == gstring.used
552                   || gstring.glyphs[i + 1].glyph_id
553                   || ! (gstring.glyphs[i + 1].positioning_type & 0xF))
554                 break;
555               i++, g++;
556             }
557         }
558
559       XCopyArea (display, bmp->pixmap, seq_pixmap, gc_or,
560                  glyph_x + bmp->x, glyph_y + bmp->y, bmp->width, bmp->height,
561                  x + bmp->x + xoff, glyph_y + bmp->y - yoff);
562       x += advance;
563
564       if (g->GlyphClass == OTF_GlyphClass0)
565         base = mark = g, base_width = advance;
566       else if (g->GlyphClass == OTF_GlyphClassMark)
567         mark = g;
568       else
569         base = g, base_width = advance;
570     }
571
572   XtSetArg (arg[0], XtNbitmap, seq_pixmap);
573   XtSetValues (seq_image, arg, 1);
574
575   if (gstring.used > 0)
576     {
577       int size = render_width / FONT_WIDTH;
578       char *buf = alloca (size + 1);
579       char name[5];
580
581       sprintf (buf, "%04X", gstring.glyphs[0].glyph_id);
582       if (log && log[0])
583         {
584           OTF_tag_name (log[0], name);
585           sprintf (buf + 4, " (%s)", name);
586           x = 11;
587         }
588       else
589         x = 4;
590       for (i = 1; i < gstring.used && x + 5 < size; i++, x += 5)
591         {
592           sprintf (buf + x, " %04X", gstring.glyphs[i].glyph_id);
593           if (log && log[i] && x + 11 < size)
594             {
595               OTF_tag_name (log[i], name);
596               sprintf (buf + x + 5, "(%s)", name);
597               x += 6;
598             }
599         }
600       while (x < size)
601         buf[x++] = ' ';
602       buf[x] = '\0';
603       XtSetArg (arg[0], XtNlabel, buf);
604       XtSetValues (code_list, arg, 1);
605     }
606
607   free (gstring.glyphs);
608 }
609
610
611 void
612 update_render_area ()
613 {
614   int i;
615   int x;
616   Arg arg[1];
617
618   XFillRectangle (display, raw_pixmap, gc, 0, 0, render_width, render_height);
619   for (i = 0, x = glyph_x; i < glyph_rec.n_glyphs; i++)
620     {
621       if (glyph_rec.glyphs[i] >= 0)
622         {
623           BitmapRec *bmp = bitmap + glyph_rec.glyphs[i];
624           char buf[5];
625
626           XCopyArea (display, bmp->pixmap, raw_pixmap, gc,
627                      0, 0, glyph_width, glyph_height,
628                      (glyph_width + 4) * i + 1, 1);
629           XDrawRectangle (display, raw_pixmap, gc_set,
630                           (glyph_width + 4) * i, 0,
631                           glyph_width + 1, glyph_height + 1);
632           XDrawLine (display, raw_pixmap, gc_set,
633                      (glyph_width + 4) * i + 1 + glyph_x, 1,
634                      (glyph_width + 4) * i + 1 + glyph_x, glyph_height + 1);
635           XDrawLine (display, raw_pixmap, gc_set,
636                      (glyph_width + 4) * i + 1 + glyph_x + bmp->advance, 1,
637                      (glyph_width + 4) * i + 1 + glyph_x + bmp->advance,
638                      glyph_height + 1);
639
640           sprintf (buf, "%04X", glyph_rec.codes[i]);
641           XDrawString (display, raw_pixmap, gc_inv, 
642                        (glyph_width + 4) * i + 1
643                        + (glyph_width - XTextWidth (font, buf, 4)) / 2,
644                        glyph_height + 2 + FONT_HEIGHT, buf, 4);
645         }
646       else
647         {
648           /* Variation Selector */
649           int idx = - glyph_rec.glyphs[i];
650           char buf[4];
651
652           sprintf (buf, "%03d", idx);
653           XDrawRectangle (display, raw_pixmap, gc_set,
654                           (glyph_width + 4) * i, 0,
655                           glyph_width + 1, glyph_height + 1);
656           XDrawString (display, raw_pixmap, gc_set,
657                        (glyph_width + 4) * i + 1
658                        + (glyph_width - XTextWidth (font, "VS", 2)) / 2,
659                        1 + glyph_height / 2, "VS", 2);
660           XDrawString (display, raw_pixmap, gc_set,
661                        (glyph_width + 4) * i + 1
662                        + (glyph_width - XTextWidth (font, buf, 3)) / 2,
663                        1 + glyph_height / 2 + FONT_ASCENT, buf, 3);
664         }
665     }
666   XtSetArg (arg[0], XtNbitmap, raw_pixmap);
667   XtSetValues (raw_image, arg, 1);
668   update_seq_area ();
669 }
670
671 void
672 QuitProc (Widget w, XtPointer client_data, XtPointer call_data)
673 {
674   XtAppSetExitFlag (XtWidgetToApplicationContext (w));
675 }
676
677 void
678 DumpProc (Widget w, XtPointer client_data, XtPointer call_data)
679 {
680   int g_width, g_height;
681   float g_x, g_y;
682   /* unit in points (1/72 inch); to fit in both US-letter and A4 */
683   static int xoff = 30, yoff = 30;
684   static int unit = 30;
685   static int margin = 2;
686   static int title_height = 20, label_height = 10;
687   int total_width = (unit + margin * 2) * 16;
688   int total_height = (unit + margin * 2 + label_height) * 16 + title_height;
689   /* pixel size (dots) */
690   int size = 128;
691   int i, j, k, l;
692   char *name = alloca (strlen (filename) + 10);
693   FILE *fp;
694   int index = (glyph_index / 0x100) * 0x100;
695   float scale;
696
697   g_width = face->bbox.xMax - face->bbox.xMin;
698   g_height = face->bbox.yMax - face->bbox.yMin;
699   if (g_width > g_height)
700     {
701       scale = g_width * size;
702       g_x = face->bbox.xMin * unit / g_width;
703       g_y = face->bbox.yMin * unit / g_width;
704     }
705   else
706     {
707       scale = g_height * size;
708       g_x = face->bbox.xMin * unit / g_height;
709       g_y = face->bbox.yMin * unit / g_height;
710     }
711   scale /= face->units_per_EM;
712
713   FT_Set_Pixel_Sizes (face, 0, size);
714
715   sprintf (name, "%s-%04X.ps", face->family_name, index);
716   printf ("Writing %s ... ", name);
717   fflush (stdout);
718   fp = fopen (name, "w");
719
720   fprintf (fp, "%s\n", "%!PS-Adobe-2.0 EPSF-2.0");
721   fprintf (fp, "%s\n", "%%Creater: otfview");
722   fprintf (fp, "%s %s(%s)-%04X\n", "%%Title:",
723            face->family_name, face->style_name, index);
724   fprintf (fp, "%s\n", "%%Pages: 1");
725   fprintf (fp, "%s %d %d %d %d\n", "%%BoundingBox:",
726            xoff, yoff, xoff + total_width, yoff + total_height);
727   fprintf (fp, "%s\n", "%%EndComments");
728   fprintf (fp, "%s\n", "%%BeginProlog");
729   fprintf (fp, "/W %d def\n", unit + margin * 2);
730   fprintf (fp, "/H %d def\n", unit + margin * 2 + label_height);
731   fprintf (fp, "/STR 10 string def\n");
732   fprintf (fp, "/DrawIndex {\n");
733   fprintf (fp, "  I 16 lt { (000) show } { I 256 lt { (00) show } { I 4096 lt { (0) show} if } ifelse } ifelse I 16 STR cvrs show\n");
734   fprintf (fp, "} def\n");
735   fprintf (fp, "/DrawTitle {\n");
736   fprintf (fp, "  /Courier findfont 20 scalefont setfont\n");
737   fprintf (fp, "  %d %d 4 add moveto\n", xoff + total_width / 2,
738            yoff + total_height - title_height + 2);
739   fprintf (fp, "  (%s(%s)-%04X) dup stringwidth pop 2 div neg 0 rmoveto show\n",
740            face->family_name, face->style_name, index);
741   fprintf (fp, "} def\n");
742   fprintf (fp, "/DrawFrame { gsave %d %d translate 0 setlinewidth\n",
743            xoff, yoff);
744   fprintf (fp, "  /Courier findfont 10 scalefont setfont\n");
745   fprintf (fp, "  /I %d def\n", index);
746   fprintf (fp, "  0 1 16 { W mul 0 moveto 0 H 16 mul rlineto stroke } for\n");
747   fprintf (fp, "  0 1 16 { H mul 0 exch moveto W 16 mul 0 rlineto stroke } for\n");
748   fprintf (fp, "  0 1 15 { H mul %d add 0 exch moveto W 16 mul 0 rlineto stroke } for\n", label_height);
749   fprintf (fp, "  15 -1 0 { gsave H mul 0 exch translate 0 0 moveto\n");
750   fprintf (fp, "    0 1 15 { gsave W mul 0 moveto\n");
751   fprintf (fp, "      4 2 rmoveto DrawIndex /I I 1 add def grestore} for\n");
752   fprintf (fp, "    grestore } for grestore } def\n");
753   fprintf (fp, "%s\n", "%%EndProlog");
754   fprintf (fp, "DrawTitle DrawFrame\n");
755
756   for (i = 0; i < 16; i++)
757     for (j = 0; j < 16; j++, index++)
758       {
759         int idx;
760
761         if (charmap_index >= 0) 
762           idx = FT_Get_Char_Index (face, (FT_ULong) index);
763         else
764           idx = index;
765         if (idx > 0
766             && FT_Load_Glyph (face, idx, FT_LOAD_RENDER | FT_LOAD_MONOCHROME) == 0
767             && face->glyph->bitmap.rows > 0
768             && face->glyph->bitmap.width > 0)
769           {
770             unsigned char *p = face->glyph->bitmap.buffer;
771             int width = (face->glyph->bitmap.width - 1) / 8 + 1;
772
773             fprintf (fp, "gsave %f %f translate %d %d scale 0 0 moveto\n",
774                      xoff + (unit + margin * 2) * j + margin - g_x,
775                      yoff + (unit + label_height + margin * 2) * (15 - i) + label_height + margin - g_y,
776                      unit, unit);
777             fprintf (fp, "%d %d true [%f 0 0 %f %d %d]\n",
778                      width * 8, face->glyph->bitmap.rows,
779                      scale, -scale, -face->glyph->bitmap_left,
780                      face->glyph->bitmap_top);
781             fprintf (fp, "{< ");
782             for (k = 0; k < face->glyph->bitmap.rows;
783                  k++, p += face->glyph->bitmap.pitch)
784               {
785                 for (l = 0; l < width; l++)
786                   fprintf (fp, "%02X", p[l]);
787                 fprintf (fp, "\n");
788               }
789             fprintf (fp, ">} imagemask grestore\n");
790           }
791         else
792           {
793             int boxsize = unit + margin * 2;
794
795             fprintf (fp, "gsave 0 setlinewidth %d %d translate\n",
796                      xoff + boxsize * j,
797                      yoff + (boxsize + label_height) * (15 - i) + label_height);
798             fprintf (fp, "0 0 moveto %d %d lineto stroke\n",
799                      boxsize, boxsize);
800             fprintf (fp, "0 %d moveto %d 0 lineto stroke grestore\n",
801                      boxsize, boxsize);
802           }
803       }
804   fprintf (fp, "showpage\n");
805   fclose (fp);
806   printf ("done\n");
807
808   FT_Set_Pixel_Sizes (face, 0, (int) pixel_size);
809 }
810
811
812 void
813 GlyphProc (Widget w, XtPointer client_data, XtPointer call_data)
814 {
815   int old_glyph_index = glyph_index;
816   int data;
817
818   CAST_FROM_XTPOINTER (int, client_data, data);
819
820   if (data == -3 && glyph_index > 0)
821     glyph_index = 0;
822   else if (data == -2 && glyph_index > 0)
823     glyph_index = (glyph_index - 1) & 0x1FF000;
824   else if (data == -1 && glyph_index > 0)
825     glyph_index -= 0x80;
826   else if (data == 1 && glyph_index < 0x10FF80)
827     glyph_index += 0x80;
828   else if (data == 2 && glyph_index < 0x10F000)
829     glyph_index = (glyph_index + 0x1000) & 0x1FF000;
830   else if (data == 3 && glyph_index < 0x10F000)
831     glyph_index = 0x10FF80;
832   if (glyph_index != old_glyph_index)
833     update_glyph_area ();
834 }
835
836 void
837 CharmapProc (Widget w, XtPointer client_data, XtPointer call_data)
838 {
839   int data;
840
841   CAST_FROM_XTPOINTER (int, client_data, data);
842
843   if (charmap_index == data)
844     return;
845   charmap_index = data;
846   if (charmap_index >= 0)
847     FT_Set_Charmap (face, face->charmaps[charmap_index]);
848   update_glyph_area ();
849 }
850
851 void
852 UVSProc (Widget w, XtPointer client_data, XtPointer call_data)
853 {
854   unsigned idx;
855   int selector;
856   OTF_VariationSelectorRecord *record;
857   int i;
858
859   CAST_FROM_XTPOINTER (unsigned, client_data, idx);
860   selector = uvs[idx].c;
861
862   if (glyph_rec.n_glyphs >= 64)
863     return;
864   for (i = 0; i < sub14->nRecords; i++)
865     {
866       record = sub14->Records + i;
867       if (record->varSelector == selector)
868         break;
869     }
870   if (i < sub14->nRecords)
871     {
872       if (glyph_rec.n_glyphs > 0
873           && glyph_rec.glyphs[glyph_rec.n_glyphs - 1] < 0)
874         glyph_rec.n_glyphs--;
875       glyph_rec.codes[glyph_rec.n_glyphs] = selector;
876       glyph_rec.glyphs[glyph_rec.n_glyphs++] = - idx - 1;
877       update_render_area ();
878     }
879 }
880
881 void
882 RenderProc (Widget w, XtPointer client_data, XtPointer call_data)
883 {
884   int data;
885
886   CAST_FROM_XTPOINTER (int, client_data, data);
887
888   if (data < 0)
889     {
890       if (glyph_rec.n_glyphs > 0)
891         {
892           if (data == -2)
893             glyph_rec.n_glyphs--;
894           else
895             glyph_rec.n_glyphs = 0;
896           update_render_area ();
897         }
898     }
899   else if (glyph_rec.n_glyphs < 64)
900     {
901       int index = glyph_index + data;
902
903       if (charmap_index >= 0)
904         index = FT_Get_Char_Index (face, (FT_ULong) index);
905       if (bitmap[index].pixmap)
906         {
907           glyph_rec.codes[glyph_rec.n_glyphs] = glyph_index + data;
908           glyph_rec.glyphs[glyph_rec.n_glyphs++] = index;
909           if (otf)
910             update_uvs_area (glyph_index + data);
911           update_render_area ();
912         }
913     }
914 }
915
916 void
917 BidiProc (Widget w, XtPointer client_data, XtPointer call_data)
918 {
919   Arg arg[1];
920
921   reversed = ! reversed;
922   if (reversed)
923     XtSetArg (arg[0], XtNlabel, "L<-R");
924   else
925     XtSetArg (arg[0], XtNlabel, "L->R");
926   XtSetValues (w, arg, 1);
927   update_seq_area ();
928 }
929
930 void
931 AltSubstProc (Widget w, XtPointer client_data, XtPointer call_data)
932 {
933   do_alternate_subst = ! do_alternate_subst;
934   update_seq_area ();
935 }
936
937 void
938 FeatureProc (Widget w, XtPointer client_data, XtPointer call_data)
939 {
940   FeatureRec *rec = (FeatureRec *) client_data;
941   int idx, i, j;
942   Arg arg[4];
943   char *label;
944
945   if (! rec->langsys)
946     return;
947   XtSetArg (arg[0], XtNlabel, &label);
948   XtGetValues (w, arg, 1);
949   if (! strcmp (label, "all"))
950     idx = -2;
951   else if (! strcmp (label, "none"))
952     idx = -1;
953   else
954     {
955       for (idx = 0; idx < rec->langsys->FeatureCount; idx++)
956         if (rec->features[idx].w == w)
957           break;
958       if (idx == rec->langsys->FeatureCount)
959         idx = -1;
960     }
961   if (idx < 0)
962     {
963       int on = idx == -2;
964       char str[5];
965
966       for (i = 0; i < rec->langsys->FeatureCount; i++)
967         if (rec->features[i].on != on)
968           {
969             rec->features[i].on = on;
970             if (on)
971               {
972                 XtSetArg (arg[0], XtNborderWidth, 3);
973                 XtSetArg (arg[1], XtNinternalHeight, 2);
974                 XtSetArg (arg[2], XtNinternalWidth, 2);
975               }
976             else
977               {
978                 XtSetArg (arg[0], XtNborderWidth, 1);
979                 XtSetArg (arg[1], XtNinternalHeight, 4);
980                 XtSetArg (arg[2], XtNinternalWidth, 4);
981               }
982             OTF_tag_name (rec->features[i].tag, str);
983             XtSetArg (arg[3], XtNlabel, str);
984             XtSetValues (rec->features[i].w, arg, 4);
985           }
986     }
987   else
988     {
989       char str[5];
990
991       rec->features[idx].on = ! rec->features[idx].on;
992       if (rec->features[idx].on)
993         {
994           XtSetArg (arg[0], XtNborderWidth, 3);
995           XtSetArg (arg[1], XtNinternalHeight, 2);
996           XtSetArg (arg[2], XtNinternalWidth, 2);
997         }
998       else
999         {
1000           XtSetArg (arg[0], XtNborderWidth, 1);
1001           XtSetArg (arg[1], XtNinternalHeight, 4);
1002           XtSetArg (arg[2], XtNinternalWidth, 4);
1003         }
1004       OTF_tag_name (rec->features[idx].tag, str);
1005       XtSetArg (arg[3], XtNlabel, str);
1006       XtSetValues (rec->features[idx].w, arg, 4);
1007     }
1008   update_seq_area ();
1009 }
1010
1011 void
1012 setup_feature_rec (FeatureRec *rec)
1013 {
1014   int i, j;
1015   Arg arg[10];
1016
1017   rec->langsys = NULL;
1018   if (! rec->gsub_gpos)
1019     return;
1020   for (i = 0; i < rec->gsub_gpos->ScriptList.ScriptCount; i++)
1021     if (rec->gsub_gpos->ScriptList.Script[i].ScriptTag == script_tag)
1022       {
1023         OTF_Script *script = rec->gsub_gpos->ScriptList.Script + i;
1024
1025         if (langsys_tag)
1026           {
1027             for (j = 0; j < script->LangSysCount; j++)
1028               if (script->LangSysRecord[j].LangSysTag == langsys_tag)
1029                 {
1030                   rec->langsys = script->LangSys + j;
1031                   break;
1032                 }
1033           }
1034         if (! rec->langsys)
1035           rec->langsys = &rec->gsub_gpos->ScriptList.Script[i].DefaultLangSys;
1036         break;
1037       }
1038
1039   if (! rec->langsys)
1040     i = 0;
1041   else
1042     {
1043       XtSetArg (arg[0], XtNborderWidth, 1);
1044       XtSetArg (arg[1], XtNinternalHeight, 4);
1045       XtSetArg (arg[2], XtNinternalWidth, 4);
1046       XtSetArg (arg[3], XtNborderColor, foreground);
1047       XtSetArg (arg[4], XtNsensitive, True);
1048       for (i = 0; i < rec->langsys->FeatureCount; i++)
1049         {
1050           OTF_Feature *feature = rec->gsub_gpos->FeatureList.Feature;
1051           int index = rec->langsys->FeatureIndex[i];
1052           char label[5];
1053
1054           if (! rec->features[i].w)
1055             {
1056               Widget w = XtCreateManagedWidget ("", commandWidgetClass,
1057                                                 rec->parent, arg, 0);
1058               XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1059               rec->features[i].w = w;
1060             }
1061
1062           rec->features[i].tag = feature[index].FeatureTag;
1063           rec->features[i].on = 0;
1064           OTF_tag_name (rec->features[i].tag, label);
1065           XtSetArg (arg[5], XtNlabel, label);
1066           XtSetValues (rec->features[i].w, arg, 6);
1067         }
1068     }
1069   XtSetArg (arg[0], XtNborderColor, background);
1070   XtSetArg (arg[1], XtNsensitive, False);
1071   XtSetArg (arg[2], XtNlabel, "    ");
1072   for (; i < rec->num_features; i++)
1073     {
1074       if (! rec->features[i].w)
1075         {
1076           Widget w = XtCreateManagedWidget ("", commandWidgetClass,
1077                                             rec->parent, arg, 0);
1078           XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1079           rec->features[i].w = w;
1080         }
1081       XtSetValues (rec->features[i].w, arg, 3);
1082     }
1083 }
1084
1085 void
1086 compose_script_langsys (OTF_Tag script, OTF_Tag langsys, char *name)
1087 {
1088   OTF_tag_name (script, name);
1089   if (langsys)
1090     {
1091       name[4] = '(';
1092       OTF_tag_name (langsys, name + 5);
1093       name[9] = ')';
1094       name[10] = '\0';
1095     }
1096 }
1097
1098 void
1099 decompose_script_langsys (OTF_Tag *script, OTF_Tag *langsys, char *name)
1100 {
1101   *script = OTF_tag (name);
1102   if (name[4])
1103     *langsys = OTF_tag (name + 5);
1104   else
1105     *langsys = 0;
1106 }
1107
1108 void
1109 ScriptProc (Widget w, XtPointer client_data, XtPointer call_data)
1110 {
1111   char *name;
1112   OTF_Tag script, langsys;
1113   Arg arg[1];
1114
1115   XtSetArg (arg[0], XtNlabel, &name);
1116   XtGetValues (w, arg, 1);
1117   decompose_script_langsys (&script, &langsys, name);
1118   if (script_tag == script && langsys_tag == langsys)
1119     return;
1120   script_tag = script;
1121   langsys_tag = langsys;
1122   setup_feature_rec (&gsub);
1123   setup_feature_rec (&gpos);
1124   update_seq_area ();
1125 }
1126
1127 Widget
1128 create_otf_script_widgets (Widget prev)
1129 {
1130   Widget w;
1131   Arg arg[10];
1132   int n, prev_n, i, j;
1133   struct {
1134     OTF_Tag script;
1135     OTF_Tag langsys;
1136   } *script_langsys;
1137   char name[11];
1138   int nfeatures;
1139
1140   XtSetArg (arg[0], XtNborderWidth, 0);
1141   XtSetArg (arg[1], XtNleft, XawChainLeft);
1142   XtSetArg (arg[2], XtNright, XawChainLeft);
1143   XtSetArg (arg[3], XtNtop, XawChainTop);
1144   XtSetArg (arg[4], XtNbottom, XawChainTop);
1145   XtSetArg (arg[5], XtNfromVert, prev);
1146   XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1147   prev = XtCreateManagedWidget ("Script", boxWidgetClass, render_area, arg, 7);
1148   XtCreateManagedWidget ("script(langsys)", labelWidgetClass, prev, arg, 1);
1149
1150   n = 0;
1151   if (otf->gsub)
1152     for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
1153       n += otf->gsub->ScriptList.Script[i].LangSysCount + 1;
1154   if (otf->gpos)
1155     for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
1156       n += otf->gpos->ScriptList.Script[i].LangSysCount + 1;
1157   script_langsys = alloca ((sizeof script_langsys[0]) * n);
1158   n = 0;
1159   nfeatures = 0;
1160   if (otf->gsub)
1161     for (i = 0; i < otf->gsub->ScriptList.ScriptCount; i++)
1162       {
1163         OTF_Tag tag = otf->gsub->ScriptList.Script[i].ScriptTag;
1164
1165         script_langsys[n].script = tag;
1166         script_langsys[n++].langsys = 0;
1167         if (nfeatures
1168             < otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount)
1169           nfeatures
1170             = otf->gsub->ScriptList.Script[i].DefaultLangSys.FeatureCount;
1171         for (j = 0; j < otf->gsub->ScriptList.Script[i].LangSysCount; j++)
1172           {
1173             script_langsys[n].script = tag;
1174             script_langsys[n++].langsys
1175               = otf->gsub->ScriptList.Script[i].LangSysRecord[j].LangSysTag;
1176             if (nfeatures
1177                 < otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount)
1178               nfeatures
1179                 = otf->gsub->ScriptList.Script[i].LangSys[j].FeatureCount;
1180           }
1181       }
1182   gsub.num_features = nfeatures;
1183   if (nfeatures > 0)
1184     {
1185       gsub.num_features = nfeatures;
1186       gsub.features = malloc ((sizeof (FeatureElement)) * nfeatures);
1187       memset (gsub.features, 0, (sizeof (FeatureElement)) * nfeatures);
1188     }
1189   prev_n = n;
1190   nfeatures = 0;
1191   if (otf->gpos)
1192     for (i = 0; i < otf->gpos->ScriptList.ScriptCount; i++)
1193       {
1194         OTF_Tag tag = otf->gpos->ScriptList.Script[i].ScriptTag;
1195         int k;
1196
1197         if (nfeatures
1198             < otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount)
1199           nfeatures
1200             = otf->gpos->ScriptList.Script[i].DefaultLangSys.FeatureCount;
1201         for (k = 0; k < prev_n; k++)
1202           if (tag == script_langsys[k].script)
1203             break;
1204         if (k == prev_n)
1205           {
1206             script_langsys[n].script = tag;
1207             script_langsys[n++].langsys = 0;
1208           }
1209         for (j = 0; j < otf->gpos->ScriptList.Script[i].LangSysCount; j++)
1210           {
1211             int l;
1212
1213             if (k < prev_n)
1214               {
1215                 OTF_Script *script = otf->gpos->ScriptList.Script + i;
1216
1217                 for (l = k; l < prev_n && tag == script_langsys[l].script; l++)
1218                   if (script->LangSysRecord[j].LangSysTag
1219                       == script_langsys[l].langsys)
1220                     break;
1221               }
1222             else
1223               l = prev_n;
1224             if (l == prev_n)
1225               {
1226                 script_langsys[n].script = tag;
1227                 script_langsys[n++].langsys = 0;
1228               }
1229             if (nfeatures
1230                 < otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount)
1231               nfeatures
1232                 = otf->gpos->ScriptList.Script[i].LangSys[j].FeatureCount;
1233           }
1234       }
1235
1236   if (nfeatures > 0)
1237     {
1238       gpos.num_features = nfeatures;
1239       gpos.features = malloc ((sizeof (FeatureElement)) * nfeatures);
1240       memset (gpos.features, 0, (sizeof (FeatureElement)) * nfeatures);
1241     }
1242
1243   if (n == 0)
1244     return prev;
1245
1246   script_tag = script_langsys[0].script;
1247   langsys_tag = script_langsys[0].langsys;
1248   compose_script_langsys (script_tag, langsys_tag, name);
1249
1250   if (n == 1)
1251     {
1252       XtSetArg (arg[0], XtNforeground, background);
1253       XtSetArg (arg[1], XtNbackground, foreground);
1254       XtCreateManagedWidget (name, labelWidgetClass, prev, arg, 2);
1255     }
1256   else
1257     {
1258       Widget box;
1259       XtSetArg (arg[0], XtNborderWidth, 0);
1260       XtSetArg (arg[1], XtNwidth, render_width - (FONT_WIDTH * 15));
1261       XtSetArg (arg[2], XtNorientation, XtorientHorizontal);
1262       box = XtCreateManagedWidget ("scritp-list", boxWidgetClass, prev, arg, 2);
1263       XtSetArg (arg[0], XtNstate, True);
1264       w = XtCreateManagedWidget (name, toggleWidgetClass, box, arg, 1);
1265       XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1266       XtSetArg (arg[0], XtNradioGroup, w);
1267       for (i = 1; i < n; i++)
1268         {
1269           compose_script_langsys (script_langsys[i].script,
1270                                   script_langsys[i].langsys, name);
1271           w = XtCreateManagedWidget (name, toggleWidgetClass, box, arg, 1);
1272           XtAddCallback (w, XtNcallback, ScriptProc, NULL);
1273         }         
1274     }
1275   return prev;
1276 }
1277
1278
1279 Widget
1280 create_otf_widgets (Widget prev, FeatureRec *rec)
1281 {
1282   Arg arg[10];
1283   Widget w;
1284
1285   XtSetArg (arg[0], XtNborderWidth, 0);
1286   XtSetArg (arg[1], XtNleft, XawChainLeft);
1287   XtSetArg (arg[2], XtNright, XawChainLeft);
1288   XtSetArg (arg[3], XtNtop, XawChainTop);
1289   XtSetArg (arg[4], XtNbottom, XawChainTop);
1290   XtSetArg (arg[5], XtNfromVert, prev);
1291   XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1292   prev = XtCreateManagedWidget (rec->label, boxWidgetClass, render_area,
1293                                 arg, 7);
1294   XtCreateManagedWidget (rec->label, labelWidgetClass, prev, arg, 1);
1295   XtSetArg (arg[0], XtNborderWidth, 1);
1296   XtSetArg (arg[1], XtNinternalHeight, 4);
1297   XtSetArg (arg[2], XtNinternalWidth, 4);
1298   w = XtCreateManagedWidget ("all", commandWidgetClass, prev, arg, 3);
1299   XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1300   w = XtCreateManagedWidget ("none", commandWidgetClass, prev, arg, 3);
1301   XtAddCallback (w, XtNcallback, FeatureProc, (XtPointer) rec);
1302
1303   rec->parent = prev;
1304   setup_feature_rec (rec);
1305   return prev;
1306 }
1307
1308 void
1309 create_widgets ()
1310 {
1311   String quit_action = "<KeyPress>q: set() notify() unset()";
1312   String FIRST_action = "<KeyPress>f: set() notify() unset()\n\
1313                          <KeyPress>Home: set() notify() unset()";
1314   String PREV_action = "Shift<KeyPress>p: set() notify() unset()\n\
1315                          <KeyPress>Up: set() notify() unset()";
1316   String prev_action = "~Shift<KeyPress>p: set() notify() unset()\n\
1317                          <KeyPress>Left: set() notify() unset()";
1318   String next_action = "~Shift<KeyPress>n: set() notify() unset()\n\
1319                          <KeyPress>Right: set() notify() unset()";
1320   String NEXT_action = "Shift<KeyPress>n: set() notify() unset()\n\
1321                          <KeyPress>Down: set() notify() unset()";
1322   String LAST_action = "<KeyPress>l: set() notify() unset()\n\
1323                          <KeyPress>End: set() notify() unset()";
1324   Arg arg[10];
1325   int i, j;
1326   Widget prev, w;
1327   String trans = "<Expose>: Expose()";
1328
1329   XtSetArg (arg[0], XtNtranslations, XtParseTranslationTable (trans));
1330   frame = XtCreateManagedWidget ("frame", formWidgetClass, shell, arg, 1);
1331
1332   XtSetArg (arg[0], XtNleft, XawChainLeft);
1333   XtSetArg (arg[1], XtNright, XawChainLeft);
1334   XtSetArg (arg[2], XtNtop, XawChainTop);
1335   XtSetArg (arg[3], XtNbottom, XawChainTop);
1336   XtSetArg (arg[4], XtNborderWidth, 0);
1337   XtSetArg (arg[5], XtNorientation, XtorientHorizontal);
1338   command_area = XtCreateManagedWidget ("command-area", boxWidgetClass,
1339                                         frame, arg, 6);
1340   XtSetArg (arg[6], XtNfromVert, command_area);
1341   navi_area = XtCreateManagedWidget ("navi-area", boxWidgetClass,
1342                                      frame, arg, 7);
1343   XtSetArg (arg[4], XtNborderWidth, 0);
1344   XtSetArg (arg[5], XtNfromVert, navi_area);
1345   XtSetArg (arg[6], XtNdefaultDistance, 0);
1346   glyph_area = XtCreateManagedWidget ("glyph-area", formWidgetClass,
1347                                       frame, arg, 7);
1348
1349   XtSetArg (arg[5], XtNfromVert, glyph_area);
1350   if (sub14)
1351     {
1352       Arg arg2[3];
1353
1354       XtSetArg (arg[6], XtNorientation, XtorientHorizontal);
1355       uvs_area = XtCreateManagedWidget ("uvs-area", boxWidgetClass,
1356                                         frame, arg, 7);
1357       XtSetArg (arg2[0], XtNborderWidth, 0);
1358       XtSetArg (arg2[1], XtNlabel, "Variation Selector: ");
1359       uvs_label = XtCreateManagedWidget ("uvs-label", labelWidgetClass,
1360                                          uvs_area, arg2, 2);
1361       XtSetArg (arg2[0], XtNborderWidth, 1);
1362       for (i = 0; i < sub14->nRecords; i++)
1363         {
1364           OTF_VariationSelectorRecord *record = sub14->Records + i;
1365           unsigned selector = record->varSelector;
1366           unsigned idx;
1367           char lbl[4];
1368           
1369           idx = (selector <= 0xFE0F ? selector - 0xFE00
1370                  : selector - 0xE0100 + 16);
1371           if (uvs[idx].c)
1372             continue;
1373           uvs[idx].c = selector;
1374           sprintf (lbl, "%03d", idx + 1);
1375           XtSetArg (arg2[1], XtNlabel, lbl);
1376           XtSetArg (arg2[2], XtNsensitive, False);
1377           uvs[idx].w = XtCreateManagedWidget ("lbl", commandWidgetClass,
1378                                                    uvs_area, arg2, 3);
1379           XtAddCallbackWithCast (unsigned, uvs[idx].w, UVSProc, idx);
1380         }
1381       XtSetArg (arg[5], XtNfromVert, uvs_area);
1382     }
1383   render_area = XtCreateManagedWidget ("render-area", formWidgetClass,
1384                                        frame, arg, 6);
1385
1386   XtSetArg (arg[0], XtNaccelerators, XtParseAcceleratorTable (quit_action));
1387   quit = XtCreateManagedWidget ("Quit", commandWidgetClass,
1388                                 command_area, arg, 1);
1389   XtAddCallback (quit, XtNcallback, QuitProc, NULL);
1390
1391   dump = XtCreateManagedWidget ("DumpImage", commandWidgetClass,
1392                                 command_area, arg, 1);
1393   XtAddCallback (dump, XtNcallback, DumpProc, NULL);
1394
1395   XtSetArg (arg[0], XtNborderWidth, 0);
1396   XtSetArg (arg[1], XtNwidth, 10);
1397   XtCreateManagedWidget ("spacer", boxWidgetClass, command_area, arg, 2);
1398
1399   charmap = alloca (sizeof (Widget) * (face->num_charmaps + 1));
1400   XtSetArg (arg[0], XtNstate, True);
1401   charmap[0] = XtCreateManagedWidget (charmap_rec[0].name, toggleWidgetClass,
1402                                       command_area, arg, 1);
1403   XtAddCallback (charmap[0], XtNcallback, CharmapProc, (XtPointer) -1);
1404   XtSetArg (arg[0], XtNradioGroup, charmap[0]);
1405   for (i = 0; i < face->num_charmaps; i++)
1406     {
1407       charmap[i + 1] = XtCreateManagedWidget (charmap_rec[i + 1].name,
1408                                               toggleWidgetClass,
1409                                               command_area, arg, 1);
1410       XtAddCallbackWithCast (int, charmap[i + 1], CharmapProc, i);
1411     }
1412
1413   XtSetArg (arg[0], XtNlabel, " |< (f)");
1414   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (FIRST_action));
1415   FIRST = XtCreateManagedWidget ("FIRST", commandWidgetClass,
1416                                  navi_area, arg, 2);
1417   XtAddCallback (FIRST, XtNcallback, GlyphProc, (XtPointer) -3);
1418   XtSetArg (arg[0], XtNlabel, "<< (P)");
1419   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (PREV_action));
1420   PREV = XtCreateManagedWidget ("PREV", commandWidgetClass,
1421                                 navi_area, arg, 2);
1422   XtAddCallback (PREV, XtNcallback, GlyphProc, (XtPointer) -2);
1423   XtSetArg (arg[0], XtNlabel, "< (p)");
1424   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (prev_action));
1425   prev = XtCreateManagedWidget ("prev", commandWidgetClass,
1426                                 navi_area, arg, 2);
1427   XtAddCallback (prev, XtNcallback, GlyphProc, (XtPointer) -1);
1428   XtSetArg (arg[0], XtNlabel, " 0000 ");
1429   range = XtCreateManagedWidget ("range", labelWidgetClass,
1430                                  navi_area, arg, 1);
1431   XtSetArg (arg[0], XtNforeground, &foreground);
1432   XtSetArg (arg[1], XtNbackground, &background);
1433   XtGetValues (range, arg, 2);
1434
1435   XtSetArg (arg[0], XtNlabel, "> (n)");
1436   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (next_action));
1437   next = XtCreateManagedWidget ("next", commandWidgetClass,
1438                                 navi_area, arg, 2);
1439   XtAddCallback (next, XtNcallback, GlyphProc, (XtPointer) 1);
1440   XtSetArg (arg[0], XtNlabel, ">> (N)");
1441   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (NEXT_action));
1442   NEXT = XtCreateManagedWidget ("NEXT", commandWidgetClass,
1443                                 navi_area, arg, 2);
1444   XtAddCallback (NEXT, XtNcallback, GlyphProc, (XtPointer) 2);
1445   XtSetArg (arg[0], XtNlabel, ">| (l)");
1446   XtSetArg (arg[1], XtNaccelerators, XtParseAcceleratorTable (LAST_action));
1447   LAST = XtCreateManagedWidget ("LAST", commandWidgetClass,
1448                                 navi_area, arg, 2);
1449   XtAddCallback (LAST, XtNcallback, GlyphProc, (XtPointer) 3);
1450
1451   XtSetArg (arg[0], XtNleft, XawChainLeft);
1452   XtSetArg (arg[1], XtNright, XawChainLeft);
1453   XtSetArg (arg[2], XtNtop, XawChainTop);
1454   XtSetArg (arg[3], XtNbottom, XawChainTop);
1455
1456   for (i = 0; i < 8; i++)
1457     {
1458       char str[3];
1459       int n = 4;
1460       Widget head;
1461
1462       sprintf (str, "%XX", i);
1463       XtSetArg (arg[n], XtNheight, glyph_height + 5), n++;
1464       XtSetArg (arg[n], XtNlabel, str), n++;
1465       XtSetArg (arg[n], XtNborderWidth, 0), n++;
1466       if (i > 0)
1467         XtSetArg (arg[n], XtNfromVert, w), n++;
1468       head = XtCreateManagedWidget (str, labelWidgetClass, glyph_area, arg, n);
1469       index_label[i] = head;
1470       for (j = 0; j < 16; j++)
1471         {
1472           int k = i * 16 + j;
1473
1474           n = 4;
1475           if (i > 0)
1476             XtSetArg (arg[n], XtNfromVert, w), n++;
1477           if (j == 0)
1478             XtSetArg (arg[n], XtNfromHoriz, head), n++;
1479           else
1480             XtSetArg (arg[n], XtNfromHoriz, glyph[k - 1]), n++;
1481           XtSetArg (arg[n], XtNbitmap, none_pixmap), n++;
1482           glyph[k] = XtCreateManagedWidget ("glyph", commandWidgetClass,
1483                                             glyph_area, arg, n);
1484           XtAddCallbackWithCast (int, glyph[k], RenderProc, k);
1485         }
1486       w = head;
1487     }
1488   /* 10 = (1 (border_width) + 4 (inner_width)) * 2 */
1489   XtSetArg(arg[4], XtNwidth, glyph_width + 10);
1490   XtSetArg (arg[5], XtNfromVert, glyph[112]);
1491   XtSetArg (arg[6], XtNfromHoriz, w);
1492   XtSetArg (arg[7], XtNborderWidth, 0);
1493
1494   for (j = 0; j < 16; j++)
1495     {
1496       char str[3];
1497
1498       sprintf (str, "X%X", j);
1499       XtSetArg (arg[8], XtNlabel, str);
1500       w = XtCreateManagedWidget ("idx", labelWidgetClass, glyph_area, arg, 9);
1501       XtSetArg (arg[6], XtNfromHoriz, w);
1502     }
1503
1504   XtSetArg (arg[0], XtNleft, XawChainLeft);
1505   XtSetArg (arg[1], XtNright, XawChainLeft);
1506   XtSetArg (arg[2], XtNtop, XawChainTop);
1507   XtSetArg (arg[3], XtNbottom, XawChainTop);
1508   XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1509   XtSetArg (arg[5], XtNborderWidth, 0);
1510   w = XtCreateManagedWidget ("clear-box", boxWidgetClass, render_area, arg, 6);
1511   clear = XtCreateManagedWidget ("clear", commandWidgetClass, w, arg, 0);
1512   XtAddCallback (clear, XtNcallback, RenderProc, (XtPointer) -1);
1513   del = XtCreateManagedWidget ("delete", commandWidgetClass, w, arg, 0);
1514   XtAddCallback (del, XtNcallback, RenderProc, (XtPointer) -2);
1515   bidi = XtCreateManagedWidget ("L->R", toggleWidgetClass, w, arg, 0);
1516   XtAddCallback (bidi, XtNcallback, BidiProc, NULL);
1517   alt_subst = XtCreateManagedWidget ("AltSubst", toggleWidgetClass, w, arg, 0);
1518   XtAddCallback (alt_subst, XtNcallback, AltSubstProc, NULL);
1519
1520   XtSetArg (arg[4], XtNorientation, XtorientHorizontal);
1521   XtSetArg (arg[5], XtNborderWidth, 0);
1522   XtSetArg (arg[6], XtNfromVert, w);
1523   raw = XtCreateManagedWidget ("raw", boxWidgetClass, render_area, arg, 7);
1524
1525   XtSetArg (arg[0], XtNborderWidth, 0);
1526   XtSetArg (arg[1], XtNlabel, "raw: ");
1527   raw_label = XtCreateManagedWidget ("raw-label", labelWidgetClass,
1528                                       raw, arg, 2);
1529   XtSetArg (arg[1], XtNbitmap, raw_pixmap);
1530   raw_image = XtCreateManagedWidget ("raw-image", labelWidgetClass,
1531                                       raw, arg, 2);
1532   w = raw;
1533   if (otf)
1534     {
1535       OTF_get_table (otf, "GSUB");
1536       OTF_get_table (otf, "GPOS");
1537       w = create_otf_script_widgets (w);
1538       if (otf->gsub)
1539         {
1540           gsub.label = "GSUB";
1541           gsub.gsub_gpos = otf->gsub;
1542           w = create_otf_widgets (w, &gsub);
1543         }
1544       if (otf->gpos)
1545         {
1546           gpos.label = "GPOS";
1547           gpos.gsub_gpos = otf->gpos;
1548           w = create_otf_widgets (w, &gpos);
1549         }
1550     }
1551
1552   XtSetArg (arg[6], XtNfromVert, w);
1553   seq = XtCreateManagedWidget ("seq", boxWidgetClass, render_area, arg, 7);
1554   XtSetArg (arg[0], XtNborderWidth, 0);
1555   XtSetArg (arg[1], XtNlabel, "seq: ");
1556   seq_label = XtCreateManagedWidget ("seq-label", labelWidgetClass,
1557                                      seq, arg, 2);
1558   XtSetArg (arg[1], XtNbitmap, seq_pixmap);
1559   seq_image = XtCreateManagedWidget ("seq-image", labelWidgetClass,
1560                                      seq, arg, 2);
1561   XtSetArg (arg[6], XtNfromVert, seq);
1562   code = XtCreateManagedWidget ("code", boxWidgetClass, render_area, arg, 7);
1563   XtSetArg (arg[0], XtNborderWidth, 0);
1564   XtSetArg (arg[1], XtNlabel, "code:");
1565   code_label = XtCreateManagedWidget ("code-label", labelWidgetClass,
1566                                      code, arg, 2);
1567   XtSetArg (arg[1], XtNlabel, "");
1568   XtSetArg (arg[2], XtNwidth, render_width);
1569   code_list = XtCreateManagedWidget ("code-list", labelWidgetClass,
1570                                      code, arg, 3);
1571   XtInstallAllAccelerators (shell, shell);
1572 }
1573
1574 static void
1575 ExposeProc (Widget w, XEvent *event, String *str, Cardinal *num)
1576 {
1577   XTextProperty text_prop;
1578   char *pname = "otfview";
1579   char *fname = basename (filename);
1580   char *name = alloca (strlen (fname) + 3 + strlen (pname) + 1);
1581
1582   sprintf (name, "%s - %s", pname, fname);
1583   text_prop.value = (unsigned char *) name;
1584   text_prop.encoding = XA_STRING;
1585   text_prop.format = 8;
1586   text_prop.nitems = strlen (name);
1587   XSetWMName (display, XtWindow (shell), &text_prop);
1588 }
1589
1590 /* Format MSG by FMT and print the result to the stderr, and exit.  */
1591
1592 #define FATAL_ERROR(fmt, arg)   \
1593   do {                          \
1594     fprintf (stderr, fmt, arg); \
1595     exit (1);                   \
1596   } while (0)
1597
1598 static int
1599 x_error_handler (Display *display, XErrorEvent *error)
1600 {
1601   return 0;
1602 }
1603
1604 void
1605 help (char **argv, int err)
1606 {
1607   FILE *fp = err ? stderr : stdout;
1608
1609   fprintf (fp, "Usage: %s [ X-OPTION ... ]  OTF-FILE [INDEX]\n",
1610            basename (argv[0]));
1611   fprintf (fp, "  Environment variable PIXEL_SIZE specifies the pixel size.\n");
1612   fprintf (fp, "  The default pixel size is %d, but is reduced\n",
1613            DEFAULT_PIXEL_SIZE);
1614   fprintf (fp, "  if your screen is not that wide.\n");
1615   exit (err);
1616 }
1617
1618 int
1619 main (int argc, char **argv)
1620 {
1621   XtActionsRec actions[] = { {"Expose", ExposeProc} };
1622   Arg arg[10];
1623
1624   FT_Library library;
1625   OTF_GlyphString gstring;
1626   OTF_Glyph *g;
1627
1628   int err;
1629   int i;
1630   int fixed_pixel_size = 0;
1631   int display_width;
1632
1633   pixel_size = DEFAULT_PIXEL_SIZE;
1634   {
1635     char *str = getenv ("PIXEL_SIZE");
1636
1637     if (str && (i = atoi (str)) > 0)
1638       {
1639         pixel_size = i;
1640         fixed_pixel_size = 1;
1641       }
1642   }
1643
1644   gstring.size = gstring.used = 256;
1645   g = calloc (256, sizeof (OTF_Glyph));
1646   gstring.glyphs = g;
1647
1648   shell = XtOpenApplication (&context, "OTFView", NULL, 0, &argc, argv, NULL,
1649                              shellWidgetClass, arg, 0);
1650   display = XtDisplay (shell);
1651   /*XSynchronize (display, True);*/
1652   XSetErrorHandler (x_error_handler);
1653   display_width = DisplayWidth (display,
1654                                 XScreenNumberOfScreen (XtScreen (shell)));
1655   font = XLoadQueryFont (display, DEFAULT_FONT_NAME);
1656   if (! font)
1657     font = XLoadQueryFont (display, "fixed");
1658
1659   if (argc < 2)
1660     help (argv, 1);
1661   if (!strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1662     help (argv, 0);
1663   filename = argv[1];
1664   if (argc > 2)
1665     {
1666       fontindex = atoi (argv[2]);
1667       if (fontindex < 0)
1668         FATAL_ERROR ("Invalid font index: %d\n", fontindex);
1669     }
1670
1671   if ((err = FT_Init_FreeType (&library)))
1672     FATAL_ERROR ("%s\n", "FT_Init_FreeType: error");
1673   err = FT_New_Face (library, filename, fontindex, &face);
1674   if (err == FT_Err_Unknown_File_Format)
1675     FATAL_ERROR ("%s\n", "FT_New_Face: unknown file format");
1676   else if (err)
1677     FATAL_ERROR ("%s\n", "FT_New_Face: unknown error (invalid face index?)");
1678   if ((err = FT_Set_Pixel_Sizes (face, 0, pixel_size)))
1679     FATAL_ERROR ("%s\n", "FT_Set_Pixel_Sizes: error");
1680
1681   if (strstr (filename, ".ttf")
1682       || strstr (filename, ".TTF")
1683       || strstr (filename, ".otf")
1684       || strstr (filename, ".OTF"))
1685     {
1686       otf = OTF_open_ft_face (face);
1687       if (otf)
1688         {
1689           if (OTF_get_table (otf, "head") < 0
1690               || OTF_get_table (otf, "cmap") < 0
1691               || (OTF_check_table (otf, "GSUB") < 0
1692                   && OTF_check_table (otf, "GPOS") < 0))
1693             {
1694               OTF_close (otf);
1695               otf = NULL;
1696             }
1697         }
1698       if (otf)
1699         for (i = 0; i < otf->cmap->numTables; i++)
1700           if (otf->cmap->EncodingRecord[i].subtable.format == 14)
1701             {
1702               sub14 = otf->cmap->EncodingRecord[i].subtable.f.f14;
1703               break;
1704             }
1705     }
1706
1707   {
1708     char title[256];
1709     Arg arg[1];
1710
1711     filename = basename (filename);
1712     sprintf (title, "%s family:%s style:%s",
1713              filename, face->family_name, face->style_name);
1714     XtSetArg (arg[0], XtNtitle, title);
1715     XtSetValues (shell, arg, 1);
1716   }
1717
1718   glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1719                  * pixel_size / face->units_per_EM);
1720   if (! fixed_pixel_size && glyph_width * 16 > display_width * 0.8)
1721     {
1722       pixel_size = (pixel_size * display_width * 0.8 / 16 / glyph_width);
1723       FT_Set_Pixel_Sizes (face, 0, pixel_size);
1724       glyph_width = ((face->bbox.xMax - face->bbox.xMin)
1725                      * pixel_size / face->units_per_EM);
1726     }
1727   if (glyph_width < FONT_WIDTH * 4)
1728     glyph_width = FONT_WIDTH * 4;
1729
1730   glyph_height = ((face->bbox.yMax - face->bbox.yMin)
1731                   *  pixel_size / face->units_per_EM);
1732
1733   glyph_x = - (face->bbox.xMin * pixel_size / face->units_per_EM);
1734   glyph_y = face->bbox.yMax * pixel_size / face->units_per_EM;
1735   none_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1736                                glyph_width, glyph_height, 1);
1737
1738   {
1739     unsigned long valuemask =  GCFunction | GCLineWidth;
1740     XGCValues values;
1741
1742     gc = XCreateGC (display, none_pixmap, (unsigned long) 0, NULL);
1743     XSetFont (display, gc, font->fid);
1744     values.function = GXset;
1745     values.line_width = 1;
1746     gc_set = XCreateGC (display, none_pixmap, valuemask, &values);
1747     XSetFont (display, gc_set, font->fid);
1748     values.function = GXor;
1749     gc_or = XCreateGC (display, none_pixmap, valuemask, &values);
1750     values.function = GXcopyInverted;
1751     gc_inv = XCreateGC (display, none_pixmap, valuemask, &values);
1752   }
1753
1754   XFillRectangle (display, none_pixmap, gc, 0, 0,
1755                   glyph_width, glyph_height);
1756   XDrawString (display, none_pixmap, gc_inv,
1757                (glyph_width - XTextWidth (font, "none", 4)) / 2,
1758                glyph_height / 2, "none", 4);
1759
1760   render_width = (glyph_width + 4) * 15 + 1;
1761   render_height = glyph_height + 2;
1762
1763   charmap_rec[0].platform_id = -1;
1764   charmap_rec[0].encoding_id = -1;
1765   strcpy (charmap_rec[0].name, "no charmap");
1766
1767   for (i = 0; i < face->num_charmaps; i++)
1768     {
1769       charmap_rec[i + 1].platform_id = face->charmaps[i]->platform_id;
1770       charmap_rec[i + 1].encoding_id = face->charmaps[i]->encoding_id;
1771       sprintf (charmap_rec[i + 1].name, "%d-%d",
1772                charmap_rec[i + 1].platform_id, charmap_rec[i + 1].encoding_id);
1773       if (face->charmaps[i]->platform_id == 0
1774           || (face->charmaps[i]->platform_id == 3
1775               && face->charmaps[i]->encoding_id == 1))
1776         strcat (charmap_rec[i + 1].name, " (unicode)");
1777       else if (face->charmaps[i]->platform_id == 1
1778                && face->charmaps[i]->encoding_id == 0)
1779         strcat (charmap_rec[i + 1].name, " (apple-roman)");
1780     }
1781
1782   raw_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1783                               render_width, render_height, 1);
1784   seq_pixmap = XCreatePixmap (display, DefaultRootWindow (display),
1785                               render_width, render_height, 1);
1786
1787   memset (bitmap, 0, sizeof (bitmap));
1788   create_widgets ();
1789   glyph_index = 0;
1790   charmap_index = -1;
1791   update_glyph_area ();
1792   update_render_area ();
1793
1794   XtAppAddActions (context, actions, XtNumber (actions));
1795   XtRealizeWidget (shell);
1796   XtAppMainLoop (context);
1797
1798   exit (0);
1799 }
1800
1801 #else /* not HAVE_X11_XAW_COMMAND_H */
1802
1803 int
1804 main (int argc, char **argv)
1805 {
1806   fprintf (stderr, 
1807            "Building of this program failed (lack of some header files)\n");
1808   exit (1);
1809 }
1810
1811 #endif