Fix OTS warning about `maxp.maxSizeOfInstructions`.
[ttfautohint.git] / lib / tacontrol.bison
blobaa231ec1d8a2dac516992388b9e8b64ef5189dca
1 /* tacontrol.bison */
3 /*
4 * Copyright (C) 2014-2022 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
17 * grammar for parsing ttfautohint control instructions
19 * Parsing errors that essentially belong to the lexing stage are handled
20 * with `store_error_data'; in case the lexer detects an error, it returns
21 * the right token type but sets `context->error'. Syntax errors and fatal
22 * lexer errors (token `INTERNAL_FLEX_ERROR') are handled with
23 * `TA_control_error'.
27 * Edsko de Vries's article `Writing a Reentrant Parser with Flex and Bison'
28 * (https://web.archive.org/web/20160130155657/http://www.phpcompiler.org:80/articles/reentrantparser.html)
29 * was extremely helpful in writing this code.
32 %require "2.5" /* we use named references */
34 %define api.pure
35 %error-verbose
36 %expect 7
37 %glr-parser
38 %lex-param { void* scanner }
39 %locations
40 %name-prefix "TA_control_"
41 %parse-param { Control_Context* context }
43 %code requires {
44 #include "ta.h"
45 #include "tashaper.h"
47 /* we don't change the name prefix of flex functions */
48 #define TA_control_lex yylex
51 %union {
52 char character;
53 Control_Type type;
54 long integer;
55 char* name;
56 number_range* range;
57 double real;
58 Control* control;
62 #include <limits.h>
63 #include "tacontrol-flex.h"
65 void
66 TA_control_error(YYLTYPE *locp,
67 Control_Context* context,
68 char const* msg);
70 void
71 store_error_data(const YYLTYPE *locp,
72 Control_Context* context,
73 TA_Error error);
76 /* calls to `yylex' in the generated bison code use `scanner' directly */
77 #define scanner context->scanner
80 /* INVALID_CHARACTER and INTERNAL_FLEX_ERROR are flex errors */
81 %token EOE
82 %token <integer> INTEGER "integer number"
83 %token INTERNAL_FLEX_ERROR "internal flex error"
84 %token <character> INVALID_CHARACTER "invalid character"
85 %token <name> LEFT "left"
86 %token <name> NAME "glyph name"
87 %token <name> NODIR "no direction"
88 %token <name> POINT "point"
89 %token <real> REAL "real number"
90 %token <name> RIGHT "right"
91 %token <name> TOUCH "touch"
92 %token <name> WIDTH "width"
93 %token <name> XSHIFT "x shift"
94 %token <name> YSHIFT "y shift"
96 %type <control> entry
97 %type <integer> font_idx
98 %type <integer> glyph_idx
99 %type <range> glyph_idx_range
100 %type <range> glyph_idx_range_elem
101 %type <range> glyph_idx_range_elems
102 %type <range> glyph_idx_set
103 %type <name> glyph_name
104 %type <name> glyph_name_
105 %type <control> input
106 %type <integer> integer
107 %type <type> left_right
108 %type <type> left_right_
109 %type <type> point_touch
110 %type <type> point_touch_
111 %type <range> left_limited
112 %type <type> no_dir
113 %type <range> number_set
114 %type <integer> offset
115 %type <range> ppem_set
116 %type <range> range
117 %type <range> range_elem
118 %type <range> range_elems
119 %type <real> real
120 %type <range> right_limited
121 %type <integer> script_feature
122 %type <real> shift
123 %type <integer> signed_integer
124 %type <range> unlimited
125 %type <range> width_elem
126 %type <range> width_elems
127 %type <range> width_set
128 %type <integer> wildcard_script_feature
129 %type <real> x_shift
130 %type <real> y_shift
132 %destructor { TA_control_free($$); } <control>
133 %destructor { number_set_free($$); } <range>
135 %printer { fprintf(yyoutput, "`%ld'", $$); } <integer>
136 %printer { fprintf(yyoutput, "`%s'", $$); } <name>
137 %printer { fprintf(yyoutput, "`%g'", $$); } <real>
138 %printer {
139 char* s;
140 number_range* nr;
143 nr = number_set_reverse($$);
144 s = number_set_show(nr, -1, -1);
145 (void)number_set_reverse(nr);
146 if (s)
148 fprintf(yyoutput, "`%s'", s);
149 free(s);
151 else
152 fprintf(yyoutput, "allocation error");
153 } <range>
154 %printer { fprintf(yyoutput, "`%c'", $$); } INVALID_CHARACTER
160 /* `number_range' list elements are stored in reversed order; */
161 /* the call to `TA_control_new' fixes this */
163 /* `Control' list elements are stored in reversed order, too; */
164 /* this gets fixed by an explicit call to `TA_control_reverse' */
166 start:
167 input
168 { context->result = TA_control_reverse($input); }
171 input[result]:
172 /* empty */
173 { $result = NULL; }
174 | input[left] entry
175 { $result = TA_control_prepend($left, $entry); }
178 entry:
180 { $entry = NULL; }
181 | font_idx glyph_idx point_touch number_set x_shift y_shift ppem_set EOE
183 $entry = TA_control_new($point_touch,
184 $font_idx,
185 $glyph_idx,
186 $number_set,
187 $x_shift,
188 $y_shift,
189 $ppem_set,
190 @$.first_line);
191 if (!$entry)
193 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
194 YYABORT;
197 | font_idx glyph_idx left_right number_set EOE
199 $entry = TA_control_new($left_right,
200 $font_idx,
201 $glyph_idx,
202 $number_set,
205 NULL,
206 @$.first_line);
207 if (!$entry)
209 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
210 YYABORT;
213 | font_idx glyph_idx left_right number_set '(' offset[left] ',' offset[right] ')' EOE
215 $entry = TA_control_new($left_right,
216 $font_idx,
217 $glyph_idx,
218 $number_set,
219 $left,
220 $right,
221 NULL,
222 @$.first_line);
223 if (!$entry)
225 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
226 YYABORT;
229 | font_idx glyph_idx no_dir number_set EOE
231 $entry = TA_control_new($no_dir,
232 $font_idx,
233 $glyph_idx,
234 $number_set,
237 NULL,
238 @$.first_line);
239 if (!$entry)
241 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
242 YYABORT;
245 | font_idx script_feature glyph_idx_set EOE
247 $entry = TA_control_new(Control_Script_Feature_Glyphs,
248 $font_idx,
249 $script_feature,
250 $glyph_idx_set,
253 NULL,
254 @$.first_line);
255 if (!$entry)
257 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
258 YYABORT;
261 | font_idx wildcard_script_feature width_set EOE
263 $entry = TA_control_new(Control_Script_Feature_Widths,
264 $font_idx,
265 $wildcard_script_feature,
266 $width_set,
269 NULL,
270 @$.first_line);
271 if (!$entry)
273 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
274 YYABORT;
279 font_idx:
280 /* empty */
282 $font_idx = 0;
283 context->font_idx = $font_idx;
285 | integer
287 $font_idx = $integer;
288 if ($font_idx >= context->font->num_sfnts)
290 store_error_data(&@$, context, TA_Err_Control_Invalid_Font_Index);
291 YYABORT;
293 context->font_idx = $font_idx;
297 glyph_idx:
298 integer
300 FT_Face face = context->font->sfnts[context->font_idx].face;
303 $glyph_idx = $integer;
304 if ($glyph_idx >= face->num_glyphs)
306 store_error_data(&@$, context, TA_Err_Control_Invalid_Glyph_Index);
307 YYABORT;
309 context->glyph_idx = $glyph_idx;
311 | glyph_name
313 FT_Face face = context->font->sfnts[context->font_idx].face;
316 /* explicitly compare with `.notdef' */
317 /* since `FT_Get_Name_Index' returns glyph index 0 */
318 /* for both this glyph name and invalid ones */
319 if (!strcmp($glyph_name, ".notdef"))
320 $glyph_idx = 0;
321 else
323 $glyph_idx = (long)FT_Get_Name_Index(face, $glyph_name);
324 if ($glyph_idx == 0)
325 $glyph_idx = -1;
328 free($glyph_name);
330 if ($glyph_idx < 0)
332 store_error_data(&@$, context, TA_Err_Control_Invalid_Glyph_Name);
333 YYABORT;
335 context->glyph_idx = $glyph_idx;
339 glyph_name:
340 glyph_name_
342 /* `$glyph_name_' was allocated in the lexer */
343 if (context->error)
345 /* lexing error */
346 store_error_data(&@$, context, context->error);
347 YYABORT;
350 $glyph_name = $glyph_name_;
354 glyph_name_:
355 LEFT
356 | NAME
357 | NODIR
358 | POINT
359 | RIGHT
360 | TOUCH
361 | WIDTH
362 | XSHIFT
363 | YSHIFT
366 point_touch:
367 point_touch_
369 FT_Error error;
370 FT_Face face = context->font->sfnts[context->font_idx].face;
371 int num_points;
374 error = FT_Load_Glyph(face,
375 (FT_UInt)context->glyph_idx,
376 FT_LOAD_NO_SCALE);
377 if (error)
379 store_error_data(&@$, context, TA_Err_Control_Invalid_Glyph);
380 YYABORT;
383 num_points = face->glyph->outline.n_points;
385 context->number_set_min = 0;
386 context->number_set_max = num_points - 1;
388 $point_touch = $point_touch_;
392 point_touch_:
393 POINT
395 $point_touch_ = Control_Delta_after_IUP;
396 free($POINT);
398 | TOUCH
400 $point_touch_ = Control_Delta_before_IUP;
401 free($TOUCH);
405 left_right:
406 left_right_
408 FT_Error error;
409 FT_Face face = context->font->sfnts[context->font_idx].face;
410 int num_points;
413 error = FT_Load_Glyph(face,
414 (FT_UInt)context->glyph_idx,
415 FT_LOAD_NO_SCALE);
416 if (error)
418 store_error_data(&@$, context, TA_Err_Control_Invalid_Glyph);
419 YYABORT;
422 num_points = face->glyph->outline.n_points;
424 context->number_set_min = 0;
425 context->number_set_max = num_points - 1;
427 $left_right = $left_right_;
431 left_right_:
432 LEFT
434 $left_right_ = Control_Single_Point_Segment_Left;
435 free($LEFT);
437 | RIGHT
439 $left_right_ = Control_Single_Point_Segment_Right;
440 free($RIGHT);
444 no_dir:
445 NODIR
447 FT_Error error;
448 FT_Face face = context->font->sfnts[context->font_idx].face;
449 int num_points;
452 error = FT_Load_Glyph(face,
453 (FT_UInt)context->glyph_idx,
454 FT_LOAD_NO_SCALE);
455 if (error)
457 store_error_data(&@$, context, TA_Err_Control_Invalid_Glyph);
458 YYABORT;
461 num_points = face->glyph->outline.n_points;
463 context->number_set_min = 0;
464 context->number_set_max = num_points - 1;
466 $no_dir = Control_Single_Point_Segment_None;
467 free($NODIR);
471 wildcard_script_feature:
472 script_feature
473 { $wildcard_script_feature = $script_feature; }
474 | '*' glyph_name[feature]
476 size_t i;
477 size_t feature_idx = 0;
478 char feature_name[5];
481 feature_name[4] = '\0';
483 for (i = 0; i < feature_tags_size; i++)
485 hb_tag_to_string(feature_tags[i], feature_name);
487 if (!strcmp($feature, feature_name))
489 feature_idx = i;
490 break;
494 free($feature);
496 if (i == feature_tags_size)
498 store_error_data(&@2, context, TA_Err_Control_Invalid_Feature);
499 YYABORT;
502 /* simply use negative values for features applied to all scripts */
503 $wildcard_script_feature = -(long)feature_idx;
506 script_feature:
507 glyph_name[script] glyph_name[feature]
509 long ss;
510 size_t i, j;
511 size_t script_idx = 0;
512 size_t feature_idx = 0;
513 char feature_name[5];
516 for (i = 0; i < script_names_size; i++)
518 if (!strcmp($script, script_names[i]))
520 script_idx = i;
521 break;
525 feature_name[4] = '\0';
527 for (j = 0; j < feature_tags_size; j++)
529 hb_tag_to_string(feature_tags[j], feature_name);
531 if (!strcmp($feature, feature_name))
533 feature_idx = j;
534 break;
538 free($script);
539 free($feature);
541 if (i == script_names_size)
543 store_error_data(&@1, context, TA_Err_Control_Invalid_Script);
544 YYABORT;
546 if (j == feature_tags_size)
548 store_error_data(&@2, context, TA_Err_Control_Invalid_Feature);
549 YYABORT;
552 for (ss = 0; ta_style_classes[ss]; ss++)
554 TA_StyleClass style_class = ta_style_classes[ss];
557 if (script_idx == style_class->script
558 && feature_idx == style_class->coverage)
560 $script_feature = ss;
561 break;
564 if (!ta_style_classes[ss])
566 store_error_data(&@$, context, TA_Err_Control_Invalid_Style);
567 YYABORT;
572 x_shift:
573 /* empty */
574 { $x_shift = 0; }
575 | XSHIFT shift
577 $x_shift = $shift;
578 free($XSHIFT);
582 y_shift:
583 /* empty */
584 { $y_shift = 0; }
585 | YSHIFT shift
587 $y_shift = $shift;
588 free($YSHIFT);
592 shift:
593 real
595 if ($real < CONTROL_DELTA_SHIFT_MIN || $real > CONTROL_DELTA_SHIFT_MAX)
597 store_error_data(&@$, context, TA_Err_Control_Invalid_Shift);
598 YYABORT;
600 $shift = $real;
604 offset:
605 signed_integer
607 if ($signed_integer < SHRT_MIN || $signed_integer > SHRT_MAX)
609 store_error_data(&@$, context, TA_Err_Control_Invalid_Offset);
610 YYABORT;
612 $offset = $signed_integer;
616 ppem_set:
619 context->number_set_min = CONTROL_DELTA_PPEM_MIN;
620 context->number_set_max = CONTROL_DELTA_PPEM_MAX;
622 number_set
623 { $ppem_set = $number_set; }
626 integer:
628 { $integer = 0; }
629 | INTEGER
631 if (context->error)
633 /* lexing error */
634 store_error_data(&@$, context, context->error);
635 YYABORT;
638 $integer = $INTEGER;
642 signed_integer:
643 integer
644 { $signed_integer = $integer; }
645 | '+' integer
646 { $signed_integer = $integer; }
647 | '-' integer
648 { $signed_integer = -$integer; }
651 real:
652 signed_integer
653 { $real = $signed_integer; }
654 | REAL
656 if (context->error)
658 /* lexing error */
659 store_error_data(&@$, context, context->error);
660 YYABORT;
663 $real = $REAL;
665 | '+' REAL
666 { $real = $REAL; }
667 | '-' REAL
668 { $real = -$REAL; }
671 number_set:
672 unlimited
673 { $number_set = $unlimited; }
674 | right_limited
675 { $number_set = $right_limited; }
676 | left_limited
677 { $number_set = $left_limited; }
678 | range_elems
679 { $number_set = $range_elems; }
680 | right_limited ',' range_elems
682 $number_set = number_set_prepend($right_limited, $range_elems);
683 if ($number_set == NUMBERSET_NOT_ASCENDING)
685 number_set_free($right_limited);
686 number_set_free($range_elems);
687 store_error_data(&@3, context, TA_Err_Control_Ranges_Not_Ascending);
688 YYABORT;
690 if ($number_set == NUMBERSET_OVERLAPPING_RANGES)
692 number_set_free($right_limited);
693 number_set_free($range_elems);
694 store_error_data(&@3, context, TA_Err_Control_Overlapping_Ranges);
695 YYABORT;
698 | range_elems ',' left_limited
700 $number_set = number_set_prepend($range_elems, $left_limited);
701 if ($number_set == NUMBERSET_NOT_ASCENDING)
703 number_set_free($range_elems);
704 number_set_free($left_limited);
705 store_error_data(&@3, context, TA_Err_Control_Ranges_Not_Ascending);
706 YYABORT;
708 if ($number_set == NUMBERSET_OVERLAPPING_RANGES)
710 number_set_free($range_elems);
711 number_set_free($left_limited);
712 store_error_data(&@3, context, TA_Err_Control_Overlapping_Ranges);
713 YYABORT;
718 unlimited:
721 $unlimited = number_set_new(context->number_set_min,
722 context->number_set_max,
723 context->number_set_min,
724 context->number_set_max);
725 /* range of `$unlimited' is always valid */
726 if ($unlimited == NUMBERSET_ALLOCATION_ERROR)
728 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
729 YYABORT;
734 right_limited:
735 '-' integer
737 $right_limited = number_set_new(context->number_set_min,
738 (int)$integer,
739 context->number_set_min,
740 context->number_set_max);
741 if ($right_limited == NUMBERSET_INVALID_RANGE)
743 store_error_data(&@$, context, TA_Err_Control_Invalid_Range);
744 YYABORT;
746 if ($right_limited == NUMBERSET_ALLOCATION_ERROR)
748 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
749 YYABORT;
754 left_limited:
755 integer '-'
757 $left_limited = number_set_new((int)$integer,
758 context->number_set_max,
759 context->number_set_min,
760 context->number_set_max);
761 if ($left_limited == NUMBERSET_INVALID_RANGE)
763 store_error_data(&@$, context, TA_Err_Control_Invalid_Range);
764 YYABORT;
766 if ($left_limited == NUMBERSET_ALLOCATION_ERROR)
768 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
769 YYABORT;
774 range_elems[result]:
775 range_elem
776 { $result = $range_elem; }
777 | range_elems[left] ',' range_elem
779 $result = number_set_prepend($left, $range_elem);
780 if ($result == NUMBERSET_NOT_ASCENDING)
782 number_set_free($left);
783 number_set_free($range_elem);
784 store_error_data(&@3, context, TA_Err_Control_Ranges_Not_Ascending);
785 YYABORT;
787 if ($result == NUMBERSET_OVERLAPPING_RANGES)
789 number_set_free($left);
790 number_set_free($range_elem);
791 store_error_data(&@3, context, TA_Err_Control_Overlapping_Ranges);
792 YYABORT;
797 range_elem:
798 integer
800 $range_elem = number_set_new((int)$integer,
801 (int)$integer,
802 context->number_set_min,
803 context->number_set_max);
804 if ($range_elem == NUMBERSET_INVALID_RANGE)
806 store_error_data(&@$, context, TA_Err_Control_Invalid_Range);
807 YYABORT;
809 if ($range_elem == NUMBERSET_ALLOCATION_ERROR)
811 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
812 YYABORT;
815 | range
816 { $range_elem = $range; }
819 range:
820 integer[left] '-' integer[right]
822 $range = number_set_new((int)$left,
823 (int)$right,
824 context->number_set_min,
825 context->number_set_max);
826 if ($range == NUMBERSET_INVALID_RANGE)
828 store_error_data(&@$, context, TA_Err_Control_Invalid_Range);
829 YYABORT;
831 if ($range == NUMBERSET_ALLOCATION_ERROR)
833 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
834 YYABORT;
839 glyph_idx_set:
842 FT_Face face = context->font->sfnts[context->font_idx].face;
845 context->number_set_min = 0;
846 context->number_set_max = (int)(face->num_glyphs - 1);
848 glyph_idx_range_elems
849 { $glyph_idx_set = $glyph_idx_range_elems; }
852 glyph_idx_range_elems[result]:
853 glyph_idx_range_elem
854 { $result = $glyph_idx_range_elem; }
855 | glyph_idx_range_elems[left] ',' glyph_idx_range_elem
857 /* for glyph_idx_set, ascending order is not enforced */
858 $result = number_set_insert($left, $glyph_idx_range_elem);
859 if ($result == NUMBERSET_OVERLAPPING_RANGES)
861 number_set_free($left);
862 number_set_free($glyph_idx_range_elem);
863 store_error_data(&@3, context, TA_Err_Control_Overlapping_Ranges);
864 YYABORT;
869 glyph_idx_range_elem:
870 glyph_idx
872 $glyph_idx_range_elem = number_set_new((int)$glyph_idx,
873 (int)$glyph_idx,
874 context->number_set_min,
875 context->number_set_max);
876 /* glyph_idx is always valid */
877 /* since its value was already tested for validity */
878 if ($glyph_idx_range_elem == NUMBERSET_ALLOCATION_ERROR)
880 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
881 YYABORT;
884 | glyph_idx_range
885 { $glyph_idx_range_elem = $glyph_idx_range; }
888 glyph_idx_range:
889 glyph_idx[left] '-' glyph_idx[right]
891 $glyph_idx_range = number_set_new((int)$left,
892 (int)$right,
893 context->number_set_min,
894 context->number_set_max);
895 /* glyph range is always valid */
896 /* since both `glyph_idx' values were already tested for validity */
897 if ($glyph_idx_range == NUMBERSET_ALLOCATION_ERROR)
899 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
900 YYABORT;
905 width_set:
906 WIDTH
908 context->number_set_min = 1;
909 context->number_set_max = 65535;
910 context->number_set_num_elems = 0;
912 width_elems
913 { $width_set = $width_elems; }
916 width_elems[result]:
917 width_elem
919 context->number_set_num_elems++;
920 $result = $width_elem;
922 | width_elems[left] ',' width_elem
924 context->number_set_num_elems++;
925 if (context->number_set_num_elems > TA_LATIN_MAX_WIDTHS)
927 number_set_free($left);
928 number_set_free($width_elem);
929 store_error_data(&@3, context, TA_Err_Control_Too_Much_Widths);
930 YYABORT;
933 /* for width_set, the order of entries is preserved */
934 $result = number_set_prepend_unsorted($left, $width_elem);
938 width_elem:
939 integer
941 $width_elem = number_set_new($integer,
942 $integer,
943 context->number_set_min,
944 context->number_set_max);
945 if ($width_elem == NUMBERSET_ALLOCATION_ERROR)
947 store_error_data(&@$, context, TA_Err_Control_Allocation_Error);
948 YYABORT;
957 void
958 TA_control_error(YYLTYPE *locp,
959 Control_Context* context,
960 char const* msg)
962 /* if `error' is already set, we have a fatal flex error */
963 if (!context->error)
965 context->error = TA_Err_Control_Syntax_Error;
966 strncpy(context->errmsg, msg, sizeof (context->errmsg));
969 context->errline_num = locp->first_line;
970 context->errline_pos_left = locp->first_column;
971 context->errline_pos_right = locp->last_column;
975 void
976 store_error_data(const YYLTYPE *locp,
977 Control_Context* context,
978 TA_Error error)
980 context->error = error;
982 context->errline_num = locp->first_line;
983 context->errline_pos_left = locp->first_column;
984 context->errline_pos_right = locp->last_column;
986 context->errmsg[0] = '\0';
990 #if 0
993 * compile this test program with
995 * make libnumberset.la
997 * flex -d tacontrol.flex \
998 * && bison -t tacontrol.bison \
999 * && gcc -g3 -O0 \
1000 * -Wall -W \
1001 * -I.. \
1002 * -I. \
1003 * -I/usr/local/include/freetype2 \
1004 * -I/usr/local/include/harfbuzz \
1005 * -L.libs \
1006 * -o tacontrol-bison \
1007 * tacontrol-bison.c \
1008 * tacontrol-flex.c \
1009 * tacontrol.c \
1010 * -lfreetype \
1011 * -lnumberset
1014 const char* input =
1015 "# Test\n"
1016 "\n"
1017 "# 0 a p 1-3 x 0.3 y -0.2 @ 20-30; \\\n"
1018 "0 exclam p 2-4 x 0.7 y -0.4 @ 6,7,9,10,11; \\\n"
1019 "a p / 12 x 0.5 @ 23-25";
1022 #undef scanner
1025 main(int argc,
1026 char** argv)
1028 TA_Error error;
1029 int bison_error;
1030 int retval = 1;
1032 Control_Context context;
1033 FONT font;
1034 SFNT sfnts[1];
1035 FT_Library library;
1036 FT_Face face;
1037 const char* filename;
1040 if (argc != 2)
1042 fprintf(stderr, "need an outline font as an argument\n");
1043 goto Exit0;
1046 filename = argv[1];
1048 error = FT_Init_FreeType(&library);
1049 if (error)
1051 fprintf(stderr, "error while initializing FreeType library (0x%X)\n",
1052 error);
1053 goto Exit0;
1056 error = FT_New_Face(library, filename, 0, &face);
1057 if (error)
1059 fprintf(stderr, "error while loading font `%s' (0x%X)\n",
1060 filename,
1061 error);
1062 goto Exit1;
1065 /* we construct a minumum `Font' object */
1066 sfnts[0].face = face;
1068 font.num_sfnts = 1;
1069 font.sfnts = sfnts;
1070 font.control_buf = (char*)input;
1071 font.control_len = strlen(input);
1073 TA_control_debug = 1;
1075 TA_control_scanner_init(&context, &font);
1076 if (context.error)
1077 goto Exit2;
1079 bison_error = TA_control_parse(&context);
1080 if (bison_error)
1081 goto Exit3;
1083 retval = 0;
1085 Exit3:
1086 TA_control_scanner_done(&context);
1087 TA_control_free(context.result);
1089 Exit2:
1090 FT_Done_Face(face);
1092 Exit1:
1093 FT_Done_FreeType(library);
1095 Exit0:
1096 return retval;
1099 #endif
1101 /* end of tacontrol.bison */