GLUT_VERSION updates from John Fay
[freeglut] / genfonts / to_stroke.y
1 %{
2 /* $XConsortium: to_wfont.y /main/9 1996/06/11 07:38:48 kaleb $ */
3 /* $XFree86: xc/fonts/PEX/to_wfont.y,v 3.6.2.1 1998/12/22 11:23:04 hohndel Exp $ */
4
5 /*****************************************************************
6
7 Copyright (c) 1989,1990, 1991  X Consortium
8
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
22 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 Except as contained in this notice, the name of the X Consortium shall not be
27 used in advertising or otherwise to promote the sale, use or other dealings
28 in this Software without prior written authorization from the X Consortium.
29
30 Copyright (c) 1989,1990, 1991 by Sun Microsystems, Inc.
31
32                         All Rights Reserved
33
34 Permission to use, copy, modify, and distribute this software and its 
35 documentation for any purpose and without fee is hereby granted, 
36 provided that the above copyright notice appear in all copies and that
37 both that copyright notice and this permission notice appear in 
38 supporting documentation, and that the names of Sun Microsystems,
39 and the X Consortium, not be used in advertising or publicity 
40 pertaining to distribution of the software without specific, written 
41 prior permission.  
42
43 SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 
44 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT 
45 SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 
46 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
47 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
48 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
49 SOFTWARE.
50
51 ******************************************************************/
52
53
54 #define YYMAXDEPTH 10000
55 #define YY_NO_UNPUT
56
57 #include <unistd.h>
58 #include <fcntl.h>
59 #include <stdio.h>
60 #include <malloc.h>
61 #include <string.h>
62 #ifndef L_SET
63 #define L_SET SEEK_SET
64 #endif
65 #include "wfont.h"
66
67 typedef struct {
68         float   std_left,      /* NCGA standard left spacing */
69                 std_wide,      /* character width            */  
70                 std_rght;      /* Right spacing              */  
71 } Standard;
72
73
74 char            fname[80];
75 Dispatch        *Table;    /* dispatch table */
76 Standard        *sp_table; /* NCGA font spacings */
77 Path            *strokes;  /* strokes of each character */
78 Property        *property; /* property list */
79
80 struct {
81         int path, point, props;
82 } count, expect;
83
84 Path_subpath   *current_path;
85
86 Font_header     head;           /* font header */
87 int             tableindex;     /* which character */
88 int             yyerrno;        /* error number */
89
90 int yylex(void);
91
92 void yyerror(char *);
93 void set_num_ch(int);
94 void init_properties(int);
95 void check_num_props(void);
96 void add_property(char *, char *);
97 void check_num_ch(void);
98 void wf_header(char *, float, float);
99 void glyph_header(int, float, float, int);
100 void std_space(float, float, float);
101 void init_path(int, int);
102 void add_point(float, float);
103 void fini(void);
104 void freeall(void);
105 void check_nstroke(void);
106 void check_npts(void);
107
108 %}
109
110 %union {
111         int     nil;    /* void is reserved */
112         int     ival;
113         float   dval;
114         char    *cval;
115 }
116
117 %start font
118
119 %token <dval> REAL
120 %token <ival> INTEGER
121 %token <cval> STRING
122
123 %token <nil> BOTTOM
124 %token <nil> CENTER
125 %token <nil> CLOSE
126 %token <nil> FONTNAME
127 %token <nil> PROPERTIES
128 %token <nil> NUM_CH
129 %token <nil> INDEX
130 %token <nil> L_SPACE
131 %token <nil> MAGIC
132 %token <nil> OPEN
133 %token <nil> RIGHT
134 %token <nil> R_SPACE
135 %token <nil> STROKE
136 %token <nil> TOP
137 %token <nil> VERTICES
138 %token <nil> BEARING
139 %token <nil> WIDTH
140
141 %type <cval> fontname
142 %type <dval> top bottom center right
143 %type <ival> nstroke nvertice n_pts index num_ch
144 %type <ival> closeflag
145 %type <ival> counter
146 %type <dval> sp_left wide sp_right
147
148 %%
149
150 font : fontheader num_ch fontprops fontbody spacing { fini(); }|
151         fontheader fontbody  { fini(); };
152
153 fontheader : fontname top bottom 
154         { wf_header($1, $2, $3); };
155
156 fontname : FONTNAME STRING
157         { $$ = $2; };
158
159 top : TOP REAL { $$ = $2;};
160
161 bottom : BOTTOM REAL { $$ = $2;};
162
163 num_ch: NUM_CH INTEGER { set_num_ch($2);};
164
165 fontprops : /* empty */ | properties;
166
167 properties : PROPERTIES INTEGER { init_properties ($2); } property_list
168         { check_num_props (); }
169
170 property_list : /* empty */ | single_property property_list
171
172 single_property : STRING STRING { add_property($1, $2); };
173
174 fontbody :      /* empty */ 
175         | glyph fontbody;
176
177 glyph : glyph_header strokes
178         { check_nstroke(); };
179
180 glyph_header : index { tableindex = $1; } sym_headinfo;
181
182 sym_headinfo :  nstroke center right nvertice
183         { glyph_header($1, $2, $3, $4); };
184
185 index : INDEX INTEGER { check_num_ch(); $$ = $2; };
186
187 nstroke : STROKE INTEGER { $$ = $2; expect.path = $2; };
188
189 nvertice: {$$ = 0;} | VERTICES INTEGER  { $$ = $2; }  ;
190
191 center : CENTER REAL{ $$ = $2; };
192
193 right : RIGHT REAL{ $$ = $2; };
194
195 strokes :       /* empty */ | path strokes;
196
197 path : closeflag n_pts { init_path($1, $2); } points
198         { check_npts(); }
199
200 points :        /* empty */ | coord points;
201
202 closeflag : CLOSE { $$ = $1 == CLOSE; } | OPEN { $$ = $1 == CLOSE; } ;
203
204 n_pts : INTEGER { $$ = $1; };
205
206 coord : REAL REAL { add_point($1, $2); };
207
208 spacing :       /* empty */ 
209         | item spacing;
210
211 item : counter {tableindex = $1;} sp_left wide sp_right
212         { std_space($3, $4, $5); };
213
214 counter  : BEARING INTEGER {$$ = $2;};
215
216 sp_left: L_SPACE REAL {$$ = $2;};
217
218 wide :  WIDTH REAL {$$ = $2;};
219
220 sp_right: R_SPACE REAL {$$ = $2;};
221
222 %%
223
224 #define BYE(err)        yyerrno = (err), yyerror(NULL)
225
226 #define ERR_BASE        1000
227 #define OPEN_ERROR      1001
228 #define WRITE_ERROR     1002
229 #define WRONG_NAME      1003
230 #define NO_MEMORY       1004
231 #define EXCEED_PATH     1005
232 #define EXCEED_POINT    1006
233 #define PATH_MISMATCH   1007
234 #define POINT_MISMATCH  1008
235 #define PROP_MISMATCH   1009
236 #define EXCEED_PROPS    1010
237
238 #include "lex.c"
239
240 char    *prog;
241
242 int main(int argc, char **argv)
243 {
244         /* Usage : genstroke [-o outfile] [infile] */
245         char           *s;
246
247         fname[0] = 0;
248         tableindex = 0;
249         head.num_ch = -1;
250
251         prog = *argv;
252         while (--argc > 0 && *++argv != NULL)
253         {
254                 s = *argv;
255                 if (*s++ == '-')
256                 {
257                         switch (*s)
258                         {
259                         case 'o':
260                                 if (*++argv != NULL)
261                                 {
262                                         --argc;
263                                         (void) strcpy(fname, *argv);
264                                 }
265                                 break;
266                         default:      /* ignore other options */
267                                 ;
268                         }
269                 }
270                 else
271                 {
272                         int fd;
273
274                         /* standard input redirection */
275                         fd = open(*argv, O_RDONLY);
276                         if (fd > 0)
277                         {
278                                 if (close(fileno(stdin)) < 0)
279                                 {
280                                         perror(prog);
281                                         return (1);
282                                 }
283                                 if (dup(fd) < 0)
284                                 {
285                                         perror(prog);
286                                         return (1);
287                                 }
288                                 close(fd);
289                         }
290                 }
291         }
292         return (yyparse());
293 }
294
295 /* set number of characters */
296 void set_num_ch(int num_ch)
297 {
298         yyerrno = 0;
299         head.num_ch = num_ch;
300         if (num_ch > 0)
301         {
302           Table    = (Dispatch *) malloc(num_ch * sizeof(Dispatch));
303           sp_table = (Standard *) malloc(num_ch * sizeof(Standard));
304           strokes  = (Path *)     malloc(num_ch * sizeof(Path));
305         }
306
307         for (tableindex = 0; tableindex < num_ch; tableindex++)
308         {
309                 Table[tableindex].center = 0.0;
310                 Table[tableindex].right = 0.0;
311                 Table[tableindex].offset = 0;
312
313                 sp_table[tableindex].std_left = 0.0;
314                 sp_table[tableindex].std_wide = 0.0;
315                 sp_table[tableindex].std_rght = 0.0;
316
317                 strokes[tableindex].n_subpaths = 0;
318                 strokes[tableindex].n_vertices = 0;
319                 strokes[tableindex].subpaths = NULL;
320         }
321 }
322
323 /* initialize the property info in the header */
324 void init_properties(int num_props)
325 {
326         if (num_props > 0)
327         {
328                 head.properties = malloc(num_props * sizeof(Property));
329                 head.num_props = expect.props = num_props;
330         }
331         else
332         {
333                 head.properties = NULL;
334                 head.num_props = expect.props = 0;
335         }
336         count.props = -1;
337         property = head.properties;  /* initialize the list pointer */
338 }
339
340 void check_num_props(void)
341 {
342         count.props++;
343         if (count.props != expect.props)
344                 BYE (PROP_MISMATCH);
345 }
346
347 /* add individual property info into the buffer */
348 void add_property(char *name, char *value)
349 {
350         /* check if the property exceeds allocated space */
351
352         if (++count.props >= head.num_props)
353                 BYE(EXCEED_PROPS);
354
355         /* copy the strings into the buffer */
356
357         (void) strcpy(property->propname, name);
358         (void) strcpy(property->propvalue, value);
359
360         /* increment the property pointer */
361
362         property++;
363 }
364
365 void check_num_ch(void)
366 {
367         if (head.num_ch == -1)
368                 set_num_ch(128);
369 }
370
371 void yyerror(char *str)
372 {
373 #       define ERR_SIZE (sizeof(err_string) / sizeof(char *))
374         static char    *err_string[] = {
375                 "Cannot open file",
376                 "Write fails",
377                 "Illegal font name",
378                 "Memory allocation failure",
379                 "Specified number of strokes exceeded",
380                 "Specified number of points exceeded",
381                 "Number of strokes do not match",
382                 "Number of points do not match",
383                 "Number of properties do not match",
384                 "Specified number of properties exceeded",
385         0};
386
387         if (str == NULL)
388         {
389                 yyerrno -= ERR_BASE;
390                 if (yyerrno > 0 && yyerrno < ERR_SIZE)
391                         str = err_string[yyerrno-1];
392                 else
393                         str = "Syntax error";
394         }
395         fprintf(stderr, "%s.\n", str);
396         freeall();
397         (void) unlink(fname);
398         exit(1);
399 }
400
401 /* create wfont header */
402 void wf_header(char *name, float top, float bottom)
403 {
404         if (name == NULL)
405                 BYE(WRONG_NAME);
406         head.top = top;
407         head.bottom = bottom;
408         head.magic = WFONT_MAGIC_PEX;
409         (void) strcpy(head.name, name);
410         free(name);
411 }
412
413 /* create header for each glyph */
414 void glyph_header(int npath, float center, float right, int npts)
415 {
416         {
417                 register Path  *strk = strokes + tableindex;
418         
419                 if (npath > 0)     /* Don't allocate space unless the character
420                                       has strokes associated with it. */
421                 {
422                         strk->subpaths = malloc(npath * sizeof(Path_subpath));
423
424                         if (strk->subpaths == NULL)
425                                 BYE(NO_MEMORY);
426
427                         strk->type = PATH_2DF;
428                         strk->n_subpaths = npath;
429                         strk->n_vertices = npts;
430                 }
431                 else            /* Just initialize the entry */
432                 {
433                         strk->subpaths = NULL;
434                         strk->type = PATH_2DF;
435                         strk->n_subpaths = 0;
436                         strk->n_vertices = 0;
437                 }
438         }
439         {
440                 register Dispatch *tbl = Table + tableindex;
441
442                 tbl->offset = 0;
443                 tbl->center = center;
444                 tbl->right = right;
445         }
446         count.path = -1;               /* initialize path counter, not to
447                                         * exceed n_subpath */
448 }
449
450 /* create standard spacing info for each glyph  */
451 void std_space(float l_bear, float wide, float r_bear)
452 {
453         register Standard *tbl = sp_table + tableindex;
454         tbl->std_left = l_bear;
455         tbl->std_wide = wide;
456         tbl->std_rght = r_bear;
457 }
458
459 /* initialize each sub_path */
460 void init_path(int close, int n)
461 {
462         register Path_subpath *path;
463
464         if (++count.path >= strokes[tableindex].n_subpaths)
465                 BYE(EXCEED_PATH);
466         path = current_path = strokes[tableindex].subpaths + count.path;
467         path->n_pts = n;
468         path->closed = close;
469         if (n > 0) 
470                 path->pts.pt2df = malloc(n * sizeof(Path_point2df));
471         if (path->pts.pt2df == NULL)
472                 BYE(NO_MEMORY);
473         expect.point = path->n_pts;
474         count.point = -1;              /* initialize point counter, not to
475                                         * exceed n_pts */
476 }
477
478 /* accumulating points for each sub_path */
479 void add_point(float x, float y)
480 {
481         register Path_subpath   *path;
482         register Path_point2df  *pt_ptr;
483
484         path = current_path;
485         if (++count.point >= path->n_pts)
486                 BYE(EXCEED_POINT);
487         pt_ptr = path->pts.pt2df + count.point;
488         pt_ptr->x = x;
489         pt_ptr->y = y;
490 }
491
492 /* Path_type + n_subpaths + n_vertices */
493 #define STROKE_HEAD (sizeof(Path_type) + sizeof(int) + sizeof(int))
494
495 /* write out file, close everything, free everything */
496 void fini(void)
497 {
498         /* pointers used to walk the arrays */
499         register Path_subpath *spath;
500         register Dispatch *tbl_ptr;
501         register Path  *strptr;
502
503         FILE           *fp;
504         int             npath;
505         register int    i, j, k;
506         Standard        *sp_ptr;
507         Path_point2df   *pt;
508
509         if (fname[0] == 0)             /* default output file name */
510         {
511                 (void) strcpy(fname, head.name);
512                 (void) strcat(fname, ".c");
513         }
514
515         if ((fp = fopen(fname, "w")) == NULL)
516                 BYE(OPEN_ERROR);
517
518         fprintf(fp, "\n/* This file has been automatically generated by the genstroke utility. */\n");
519         fprintf(fp, "\n#include \"../include/GL/freeglut_internal.h\"\n");
520
521 #       define BY_BYE(err) fclose(fp), BYE(err)
522
523         /* adjust the characters for spacing, note max char width */
524         head.max_width = 0.0;
525         for (i = 0, tbl_ptr = Table, strptr = strokes, sp_ptr = sp_table;
526              i < head.num_ch; i++, tbl_ptr++, strptr++, sp_ptr++)
527         {
528                 tbl_ptr->center += sp_ptr->std_left;
529                 tbl_ptr->right += sp_ptr->std_left + sp_ptr->std_rght;
530                 if (tbl_ptr->right > head.max_width)
531                         head.max_width = tbl_ptr->right;
532                 npath = strptr->n_subpaths;
533                 if (npath > 0 || tbl_ptr->center != 0.0 ||
534                     tbl_ptr->right != 0.0)
535                 {
536                         for (j = 0, spath = strptr->subpaths;
537                              j < npath; j++, spath++)
538                         {
539                                 for(k=0, pt = spath->pts.pt2df;
540                                      k<spath->n_pts; k++, pt++)
541                                 {
542                                         pt->x += sp_ptr->std_left;
543                                 }
544                         }
545                 }
546         }
547
548         /* write the stroke table */
549         for (i = 0, tbl_ptr = Table, strptr = strokes;
550              i < head.num_ch; i++, tbl_ptr++, strptr++)
551         {
552                 npath = strptr->n_subpaths;
553
554                 if (npath > 0 || tbl_ptr->center != 0.0 ||
555                     tbl_ptr->right != 0.0)
556                 {
557                         fprintf(fp, "\n/* char: 0x%x */\n", i);
558                         
559                         for (j = 0, spath = strptr->subpaths;
560                              j < npath; j++, spath++)
561                         {
562                                 fprintf(fp, "\nstatic const SFG_StrokeVertex ch%ust%u[] =\n{\n", i, j);
563                                 for(k = 0; k < spath->n_pts; k++)
564                                 {
565                                         fprintf(fp, " {%g,%g}%s\n",
566                                                 spath->pts.pt2df[k].x,
567                                                 spath->pts.pt2df[k].y,
568                                                 k+1 < spath->n_pts ? "," : "");
569                                 }
570                                 fprintf(fp, "};\n");
571                         }
572
573                         fprintf(fp, "\nstatic const SFG_StrokeStrip ch%ust[] =\n{\n", i);
574                         for (j = 0, spath = strptr->subpaths;
575                              j < npath; j++, spath++)
576                         {
577                                 fprintf(fp, " {%u,ch%ust%u}%s\n", 
578                                         spath->n_pts, i, j,
579                                         j+1 < npath ? "," : "");
580                         }
581                         fprintf(fp, "};\n");
582
583                         fprintf(fp, "\nstatic const SFG_StrokeChar ch%u = {%g,%u,ch%ust};\n",
584                                 i, tbl_ptr->right, npath, i);
585                 }
586         }
587
588         fprintf(fp, "\nstatic const SFG_StrokeChar *chars[] =\n{\n");
589
590         for (i = 0, tbl_ptr = Table, strptr = strokes;
591              i < head.num_ch; )
592         {
593                 for (j = 0; j < 8 && i < head.num_ch;
594                      j++, i++, tbl_ptr++, strptr++)
595                 {
596                         fprintf(fp, " ");
597                         npath = strptr->n_subpaths;
598                         if (npath > 0 || tbl_ptr->center != 0.0 ||
599                             tbl_ptr->right != 0.0)
600                                 fprintf(fp, "&ch%u", i);
601                         else
602                                 fprintf(fp, "0");
603                         if (i+1 < head.num_ch)
604                                 fprintf(fp, ",");
605                 }
606                 fprintf(fp, "\n");
607         }
608         fprintf(fp, "};\n");
609
610         fprintf(fp, "\nconst SFG_StrokeFont fgStroke%s = {\"%s\",%d,%g,chars};\n",
611                 head.name, head.name, head.num_ch, head.top - head.bottom);
612
613         (void) fclose(fp);
614         freeall();
615 #       undef BY_BYE
616 }
617
618 void freeall(void)
619 {
620         register Path  *path;
621         register Path_subpath *spath;
622         register int    i, j, n;
623
624         path = strokes;
625         for (i = 0; i < head.num_ch; i++, path++)
626         {
627                 n = path->n_subpaths;
628                 if (n <= 0)
629                         continue;
630                 spath = path->subpaths;
631                 for (j = 0; j < n; j++, spath++)
632                         if (spath->pts.pt2df != NULL)
633                                 free((char *) spath->pts.pt2df);
634                 if (path->subpaths != NULL)
635                         free((char *) path->subpaths);
636         }
637         if (Table)
638                 free(Table);
639         if (sp_table)
640                 free(sp_table);
641         if (strokes)
642                 free(strokes);
643         if (head.properties != NULL)
644                 free((char *) head.properties);
645 }
646
647 void check_nstroke(void)
648 {
649         count.path++;
650         if (expect.path != count.path)
651                 BYE(PATH_MISMATCH);
652 }
653
654 void check_npts(void)
655 {
656         count.point++;
657         if (expect.point != count.point)
658                 BYE(POINT_MISMATCH);
659 }