Updating the changelog in the VERSION file, and version_sync.
[shapes.git] / source / afmyylex.ll
blob6f90e1789d36095cf665f15805f2de3f725af302
1 /* This file is part of Shapes.
2  *
3  * Shapes is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * any later version.
7  *
8  * Shapes is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with Shapes.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Copyright 2008 Henrik Tidefelt
17  */
21 #include <cmath>
23 #include "afmscanner.h"
24 #include "strrefdup.h"
25 #include "exitcodes.h"
27 #include <string.h>
28 #include <iostream>
30 #define YY_EXIT_FAILURE Shapes::Interaction::EXIT_INTERNAL_ERROR
32 // These functions must note be called with invalid arguments!
33 const char * strtoname( char * begin, char ** endp, const char * delim = " \t" );
34 const char * strtoname( char * begin, char ** endp, const char * delim, size_t delimSize );
36 /* The rule HorizontalWhiteSpace is not in agreement with the specification, as far as I can see,
37  * but it's the smallest change I can think of which should make this program work
38  * with DOS files as well as ordiary files.
39  */
43 HorizontalWhiteSpace [ \t\r]*
45 Integer [+-]?[0-9]+
46 HexInteger [0-9A-Fa-f]+
48 Boolean "true"|"false"
50 Number [+-]?(([0-9]*[.][0-9]+)|([0-9]+))
52 Name [^ \t\n\r]+
53 String [^\r\n]*
55 %option c++
56 %option noyywrap
58 %option prefix="afm"
59 %option yyclass="AfmScanner"
61 %x Global
62 %x FinishGlobalLine
63 %x ExpectEOF
64 %x Que
65 %x MetricsSets
66 %x FontName
67 %x FullName
68 %x FamilyName
69 %x Weight
70 %x FontBBox
71 %x Version
72 %x Notice
73 %x EncodingScheme
74 %x CharacterSet
75 %x Characters
76 %x IsBaseFont
77 %x VVector
78 %x IsFixedV
79 %x IsCIDFont
80 %x CapHeight
81 %x XHeight
82 %x Ascender
83 %x Descender
84 %x StdHW
85 %x StdVW
86 %x StartDirection
87 %x UnderlinePosition
88 %x UnderlineThickness
89 %x ItalicAngle
90 %x CharWidth
91 %x IsFixedPitch
92 %x StartCharMetrics
93 %x CharMetrics
94 %x C
95 %x CH
96 %x W0X
97 %x W1X
98 %x W0Y
99 %x W1Y
100 %x W0
101 %x W1
102 %x VV
103 %x N
104 %x B
105 %x L
106 %x KernData
107 %x StartKernPairs
108 %x KernPairs
109 %x StartTrackKern
110 %x TrackKern
114 <INITIAL>"StartFontMetrics ".*[\n] {
115         BEGIN( Global );
118 <Global>"EndFontMetrics"{HorizontalWhiteSpace}[\n] {
119         if( fontMetricsDst_->horizontalMetrics_ != NullPtr< FontMetrics::WritingDirectionMetrics >( ) )
120         {
121                 // I const cast because I'm too tired to think of something better.
122                 FontMetrics::CharacterMetrics * defaultChar = const_cast< FontMetrics::CharacterMetrics * >( fontMetricsDst_->horizontalMetrics_->charData_[ 0 ] );
123                 defaultChar->xmin_ = fontMetricsDst_->fontBBoxXMin_;
124                 defaultChar->ymin_ = fontMetricsDst_->fontBBoxYMin_;
125                 defaultChar->xmax_ = fontMetricsDst_->fontBBoxXMax_;
126                 defaultChar->ymax_ = fontMetricsDst_->fontBBoxYMax_;
127                 if( fontMetricsDst_->horizontalMetrics_->isFixedPitch_ )
128                 {
129                         defaultChar->horizontalCharWidthX_ = fontMetricsDst_->horizontalMetrics_->charWidthX_;
130                         defaultChar->horizontalCharWidthY_ = fontMetricsDst_->horizontalMetrics_->charWidthY_;
131                 }
132                 else
133                 {
134                         defaultChar->horizontalCharWidthX_ = defaultChar->xmax_;
135                         defaultChar->horizontalCharWidthY_ = defaultChar->ymax_;
136                 }
137         }
138         if( fontMetricsDst_->verticalMetrics_ != NullPtr< FontMetrics::WritingDirectionMetrics >( ) )
139         {
140                 // I const cast because I'm too tired to thing of something better.
141                 FontMetrics::CharacterMetrics * defaultChar = const_cast< FontMetrics::CharacterMetrics * >( fontMetricsDst_->verticalMetrics_->charData_[ 0 ] );
142                 defaultChar->xmin_ = fontMetricsDst_->fontBBoxXMin_;
143                 defaultChar->ymin_ = fontMetricsDst_->fontBBoxYMin_;
144                 defaultChar->xmax_ = fontMetricsDst_->fontBBoxXMax_;
145                 defaultChar->ymax_ = fontMetricsDst_->fontBBoxYMax_;
146                 if( fontMetricsDst_->verticalMetrics_->isFixedPitch_ )
147                 {
148                         defaultChar->verticalCharWidthX_ = fontMetricsDst_->verticalMetrics_->charWidthX_;
149                         defaultChar->verticalCharWidthY_ = fontMetricsDst_->verticalMetrics_->charWidthY_;
150                 }
151                 else
152                 {
153                         defaultChar->verticalCharWidthX_ = defaultChar->xmax_;
154                         defaultChar->verticalCharWidthY_ = defaultChar->ymax_;
155                 }
156         }
158         BEGIN( ExpectEOF );
160 <FinishGlobalLine>{HorizontalWhiteSpace}[\n] {
161         // Skip to next line.
162         BEGIN( Global );
164 <Global>^{HorizontalWhiteSpace} {
165         // Ignore leading whitespace.
168 <ExpectEOF>{HorizontalWhiteSpace}[\n] {
169         // ignore
171 <ExpectEOF><<EOF>> {
172         return 0;
175 <ExpectEOF>.|[\n] {
176         throwError( "Expected EOF." );
179 <Global>"MetricsSets"{HorizontalWhiteSpace} {
180         BEGIN( MetricsSets );
182 <MetricsSets>{Integer} {
183         char * endp;
184         long int tmp = strtol( yytext, & endp, 10 );
185         if( tmp < 0 || tmp > 2 )
186         {
187                 throwError( "MetricsSets out of range." );
188         }
189         metricsSets_ = tmp;
190         BEGIN( FinishGlobalLine );
193 <Global>"FontName"{HorizontalWhiteSpace} {
194         BEGIN( FontName );
196 <FontName>{String} {
197         fontMetricsDst_->fontName_ = strrefdup( yytext );
198         BEGIN( FinishGlobalLine );
201 <Global>"FullName"{HorizontalWhiteSpace} {
202         BEGIN( FullName );
204 <FullName>{String} {
205         fontMetricsDst_->fullName_ = strrefdup( yytext );
206         BEGIN( FinishGlobalLine );
209 <Global>"FamilyName"{HorizontalWhiteSpace} {
210         BEGIN( FamilyName );
212 <FamilyName>{String} {
213         fontMetricsDst_->familyName_ = strrefdup( yytext );
214         BEGIN( FinishGlobalLine );
217 <Global>"Weight"{HorizontalWhiteSpace} {
218         BEGIN( Weight );
220 <Weight>{String} {
221         fontMetricsDst_->weight_ = strrefdup( yytext );
222         BEGIN( FinishGlobalLine );
225 <Global>"FontBBox"{HorizontalWhiteSpace} {
226         BEGIN( FontBBox );
228 <FontBBox>{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number} {
229         char * src = yytext;
230         char * endp;
231         fontMetricsDst_->fontBBoxXMin_ = 0.001 * strtod( src, & endp );
232         src = endp;
233         fontMetricsDst_->fontBBoxYMin_ = 0.001 * strtod( src, & endp );
234         src = endp;
235         fontMetricsDst_->fontBBoxXMax_ = 0.001 * strtod( src, & endp );
236         src = endp;
237         fontMetricsDst_->fontBBoxYMax_ = 0.001 * strtod( src, & endp );
238         BEGIN( FinishGlobalLine );
241 <Global>"Version"{HorizontalWhiteSpace} {
242         BEGIN( Version );
244 <Version>{String} {
245         fontMetricsDst_->version_ = strrefdup( yytext );
246         BEGIN( FinishGlobalLine );
249 <Global>"Notice"{HorizontalWhiteSpace} {
250         BEGIN( Notice );
252 <Notice>{String} {
253         fontMetricsDst_->notice_ = strrefdup( yytext );
254         BEGIN( FinishGlobalLine );
257 <Global>"EncodingScheme"{HorizontalWhiteSpace} {
258         BEGIN( EncodingScheme );
260 <EncodingScheme>{String} {
261         fontMetricsDst_->encodingScheme_ = strrefdup( yytext );
262         BEGIN( FinishGlobalLine );
265 <Global>"CharacterSet"{HorizontalWhiteSpace} {
266         BEGIN( CharacterSet );
268 <CharacterSet>{String} {
269         fontMetricsDst_->characterSet_ = strrefdup( yytext );
270         BEGIN( FinishGlobalLine );
273 <Global>"Characters"{HorizontalWhiteSpace} {
274         BEGIN( Characters );
276 <Characters>{Integer} {
277         char * endp;
278         fontMetricsDst_->charCount_ = strtol( yytext, & endp, 10 );
279         BEGIN( FinishGlobalLine );
282 <Global>"IsBaseFont"{HorizontalWhiteSpace} {
283         BEGIN( IsBaseFont );
285 <IsBaseFont>{Boolean} {
286         if( yytext[ 0 ] != 't' )
287         {
288                 throwError( "Expected \"IsBaseFont true\"." );
289         }
290         BEGIN( FinishGlobalLine );
293 <Global>"VVector"{HorizontalWhiteSpace} {
294         BEGIN( VVector );
296 <FontBBox>{Number}{HorizontalWhiteSpace}{Number} {
297         char * src = yytext;
298         char * endp;
299         fontMetricsDst_->vVectorX_ = 0.001 * strtod( src, & endp );
300         src = endp;
301         fontMetricsDst_->vVectorY_ = 0.001 * strtod( src, & endp );
302         fontMetricsDst_->isFixedV_ = true;
303         BEGIN( FinishGlobalLine );
306 <Global>"IsFixedV"{HorizontalWhiteSpace} {
307         BEGIN( IsFixedV );
309 <IsFixedV>{Boolean} {
310         fontMetricsDst_->isFixedV_ = yytext[0] == 't';
311         BEGIN( FinishGlobalLine );
314 <Global>"IsCIDFont"{HorizontalWhiteSpace} {
315         BEGIN( IsCIDFont );
317 <IsCIDFont>{Boolean} {
318         fontMetricsDst_->isCIDFont_ = yytext[0] == 't';
319         BEGIN( FinishGlobalLine );
322 <Global>"CapHeight"{HorizontalWhiteSpace} {
323         BEGIN( CapHeight );
325 <CapHeight>{Number} {
326         char * endp;
327         fontMetricsDst_->capHeight_ = 0.001 * strtod( yytext, & endp );
328         BEGIN( FinishGlobalLine );
331 <Global>"XHeight"{HorizontalWhiteSpace} {
332         BEGIN( XHeight );
334 <XHeight>{Number} {
335         char * endp;
336         fontMetricsDst_->xHeight_ = 0.001 * strtod( yytext, & endp );
337         BEGIN( FinishGlobalLine );
340 <Global>"Ascender"{HorizontalWhiteSpace} {
341         BEGIN( Ascender );
343 <Ascender>{Number} {
344         char * endp;
345         fontMetricsDst_->ascender_ = 0.001 * strtod( yytext, & endp );
346         BEGIN( FinishGlobalLine );
349 <Global>"Descender"{HorizontalWhiteSpace} {
350         BEGIN( Descender );
352 <Descender>{Number} {
353         char * endp;
354         fontMetricsDst_->descender_ = 0.001 * strtod( yytext, & endp );
355         BEGIN( FinishGlobalLine );
358 <Global>"StdHW"{HorizontalWhiteSpace} {
359         BEGIN( StdHW );
361 <StdHW>{Number} {
362         char * endp;
363         fontMetricsDst_->stdHW_ = 0.001 * strtod( yytext, & endp );
364         BEGIN( FinishGlobalLine );
367 <Global>"StdVW"{HorizontalWhiteSpace} {
368         BEGIN( StdVW );
370 <StdVW>{Number} {
371         char * endp;
372         fontMetricsDst_->stdVW_ = 0.001 * strtod( yytext, & endp );
373         BEGIN( FinishGlobalLine );
377 <Global>"StartDirection"{HorizontalWhiteSpace} {
378         BEGIN( StartDirection );
380 <StartDirection>{Integer} {
381         char * endp;
382         long int tmp = strtol( yytext, & endp, 10 );
383         if( tmp < 0 || tmp > 2 )
384         {
385                 throwError( "StartDirection out of range." );
386         }
387         activateDirectionID_ = tmp;
388         BEGIN( FinishGlobalLine );
391 <Global>"EndDirection"{HorizontalWhiteSpace} {
392         activateDirectionID_ = 0; // This is probably not necessary.
393         BEGIN( FinishGlobalLine );
396 <Global>"UnderlinePosition"{HorizontalWhiteSpace} {
397         BEGIN( UnderlinePosition );
399 <UnderlinePosition>{Number} {
400         synchWritingDirection( );
401         char * endp;
402         currentDirectionDst_->underlinePosition_ = 0.001 * strtod( yytext, & endp );
403         BEGIN( FinishGlobalLine );
406 <Global>"UnderlineThickness"{HorizontalWhiteSpace} {
407         BEGIN( UnderlineThickness );
409 <UnderlineThickness>{Number} {
410         synchWritingDirection( );
411         char * endp;
412         currentDirectionDst_->underlineThickness_ = 0.001 * strtod( yytext, & endp );
413         BEGIN( FinishGlobalLine );
416 <Global>"ItalicAngle"{HorizontalWhiteSpace} {
417         BEGIN( ItalicAngle );
419 <ItalicAngle>{Number} {
420         synchWritingDirection( );
421         char * endp;
422         currentDirectionDst_->italicAngleRadians_ = strtod( yytext, & endp ) * ( M_PI / 180 );  // Note: Don't scale by 0.001!
423         BEGIN( FinishGlobalLine );
426 <Global>"CharWidth"{HorizontalWhiteSpace} {
427         BEGIN( CharWidth );
429 <CharWidth>{Number}{HorizontalWhiteSpace}{Number} {
430         synchWritingDirection( );
431         char * src = yytext;
432         char * endp;
433         currentDirectionDst_->charWidthX_ = 0.001 * strtod( yytext, & endp );
434         src = endp;
435         currentDirectionDst_->charWidthY_ = 0.001 * strtod( yytext, & endp );
436         BEGIN( FinishGlobalLine );
439 <Global>"IsFixedPitch"{HorizontalWhiteSpace} {
440         BEGIN( IsFixedPitch );
442 <IsFixedPitch>{Boolean} {
443         synchWritingDirection( );
444         currentDirectionDst_->isFixedPitch_ = yytext[0] == 't';
445         BEGIN( FinishGlobalLine );
448 <Global>"StartCharMetrics"{HorizontalWhiteSpace} {
449         BEGIN( StartCharMetrics );
451 <StartCharMetrics>{Integer}{HorizontalWhiteSpace}[\n] {
452         synchWritingDirection( );
453         if( currentDirectionDst_->charData_.size( ) > 1 )       // the first entry is the default values
454         {
455                 throwError( "Multiply specified character metrics in this writing direction." );
456         }
457         char * endp;
458         long int tmp = strtol( yytext, & endp, 10 );
459         currentDirectionDst_->charData_.reserve( tmp + 1 ); // the first entry is the default values
460         currentCharacter_ = new FontMetrics::CharacterMetrics( currentDirectionDst_->charData_.size( ) );
461         BEGIN( CharMetrics );
464 <CharMetrics>"EndCharMetrics" {
465         delete currentCharacter_;
466         BEGIN( FinishGlobalLine );
469 <CharMetrics>[\r] {
470         // Ignore DOS crap.
472 <CharMetrics>[\n] {
473         currentDirectionDst_->charData_.push_back( currentCharacter_ );
474         currentCharacter_ = new FontMetrics::CharacterMetrics( currentDirectionDst_->charData_.size( ) );
477 <CharMetrics>^{HorizontalWhiteSpace}[\n] {
478         // A newline at the end of an empty line does not insert the current character.
480 <CharMetrics>{HorizontalWhiteSpace} {
481         // Ingore
484 <CharMetrics>"C"{HorizontalWhiteSpace} {
485         BEGIN( C );
487 <C>{Integer}{HorizontalWhiteSpace}[;] {
488         char * endp;
489         currentCharacter_->characterCode_ = strtol( yytext, & endp, 10 );
490         if( currentCharacter_->characterCode_ >= 0 )
491         {
492                 currentDirectionDst_->codeMap_[ currentCharacter_->characterCode_ ] = currentCharacter_->internalPosition_;
493         }
494         BEGIN( CharMetrics );
497 <CharMetrics>"CH"{HorizontalWhiteSpace} {
498         BEGIN( CH );
500 <CH>{HexInteger}{HorizontalWhiteSpace}[;] {
501         char * endp;
502         currentCharacter_->characterCode_ = strtol( yytext, & endp, 16 );
503         if( currentCharacter_->characterCode_ >= 0 )
504         {
505                 currentDirectionDst_->codeMap_[ currentCharacter_->characterCode_ ] = currentCharacter_->internalPosition_;
506         }
507         BEGIN( CharMetrics );
510 <CharMetrics>("WX"|"W0X"){HorizontalWhiteSpace} {
511         BEGIN( W0X );
513 <W0X>{Number}{HorizontalWhiteSpace}[;] {
514         char * endp;
515         currentCharacter_->horizontalCharWidthX_ = 0.001 * strtod( yytext, & endp );
516         BEGIN( CharMetrics );
519 <CharMetrics>("WY"|"W0Y"){HorizontalWhiteSpace} {
520         BEGIN( W0Y );
522 <W0Y>{Number}{HorizontalWhiteSpace}[;] {
523         char * endp;
524         currentCharacter_->horizontalCharWidthY_ = 0.001 * strtod( yytext, & endp );
525         BEGIN( CharMetrics );
528 <CharMetrics>"W1X"{HorizontalWhiteSpace} {
529         BEGIN( W1X );
531 <W1X>{Number}{HorizontalWhiteSpace}[;] {
532         char * endp;
533         currentCharacter_->verticalCharWidthX_ = 0.001 * strtod( yytext, & endp );
534         BEGIN( CharMetrics );
537 <CharMetrics>"W1Y"{HorizontalWhiteSpace} {
538         BEGIN( W1Y );
540 <W1Y>{Number}{HorizontalWhiteSpace}[;] {
541         char * endp;
542         currentCharacter_->verticalCharWidthY_ = 0.001 * strtod( yytext, & endp );
543         BEGIN( CharMetrics );
546 <CharMetrics>"W0"{HorizontalWhiteSpace} {
547         BEGIN( W0 );
549 <W0>{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[;] {
550         char * src = yytext;
551         char * endp;
552         currentCharacter_->horizontalCharWidthX_ = 0.001 * strtod( src, & endp );
553         src = endp;
554         currentCharacter_->horizontalCharWidthY_ = 0.001 * strtod( src, & endp );
555         BEGIN( CharMetrics );
558 <CharMetrics>"W1"{HorizontalWhiteSpace} {
559         BEGIN( W1 );
561 <W1>{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[;] {
562         char * src = yytext;
563         char * endp;
564         currentCharacter_->verticalCharWidthX_ = 0.001 * strtod( src, & endp );
565         src = endp;
566         currentCharacter_->verticalCharWidthY_ = 0.001 * strtod( src, & endp );
567         BEGIN( CharMetrics );
570 <CharMetrics>"VV"{HorizontalWhiteSpace} {
571         BEGIN( VV );
573 <VV>{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[;] {
574         char * src = yytext;
575         char * endp;
576         currentCharacter_->vX_ = 0.001 * strtod( src, & endp );
577         src = endp;
578         currentCharacter_->vY_ = 0.001 * strtod( src, & endp );
579         BEGIN( CharMetrics );
582 <CharMetrics>"N"{HorizontalWhiteSpace} {
583         BEGIN( N );
585 <N>{Name}{HorizontalWhiteSpace}[;] {
586         char * end = yytext;
587         for( ; *end != ' ' && *end != '\t' && *end != ';'; ++end )
588                 ;
589         *end = '\0';
590         currentDirectionDst_->nameMap_[ strrefdup( yytext ) ] = currentCharacter_->internalPosition_;
591         if( currentCharacter_->characterCode_ < 0 )
592                 {
593                         unsigned char pos;
594                         if( encoding_->name_to_position( yytext, & pos ) )
595                                 {
596                                         currentCharacter_->characterCode_ = pos;
597                                         currentDirectionDst_->codeMap_[ currentCharacter_->characterCode_ ] = currentCharacter_->internalPosition_;
598                                 }
599                 }
601         BEGIN( CharMetrics );
604 <CharMetrics>"B"{HorizontalWhiteSpace} {
605         BEGIN( B );
607 <B>{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[;] {
608         char * src = yytext;
609         char * endp;
610         currentCharacter_->xmin_ = 0.001 * strtod( src, & endp );
611         src = endp;
612         currentCharacter_->ymin_ = 0.001 * strtod( src, & endp );
613         src = endp;
614         currentCharacter_->xmax_ = 0.001 * strtod( src, & endp );
615         src = endp;
616         currentCharacter_->ymax_ = 0.001 * strtod( src, & endp );
617         BEGIN( CharMetrics );
620 <CharMetrics>"L"{HorizontalWhiteSpace} {
621         BEGIN( L );
623 <L>{Name}{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}[;] {
624         char * end1;
625         const char * begin1 = strtoname( yytext, & end1, " \t", 2 );
626         char * end2;
627         const char * begin2 = strtoname( end1, & end2, " ;\t", 3 );
629         currentCharacter_->addLigature( strrefdup( begin1 ), strrefdup( begin2 ) );
630         BEGIN( CharMetrics );
633 <Global>"StartKernData"{HorizontalWhiteSpace}[\n] {
634         BEGIN( KernData );
636 <KernData>"EndKernData"{HorizontalWhiteSpace} {
637         BEGIN( FinishGlobalLine );
639 <KernData>"StartKernPairs"([0]?){HorizontalWhiteSpace} {
640         currentKernPairMapX_ = & fontMetricsDst_->horizontalKernPairsX_;
641         currentKernPairMapY_ = & fontMetricsDst_->horizontalKernPairsY_;
642         if( fontMetricsDst_->horizontalMetrics_ == NullPtr< FontMetrics::WritingDirectionMetrics >( ) )
643                 {
644                         throw "It would be nice if the character metrics appeared before the kern pairs.";
645                 }
646         currentNameMap_ = & fontMetricsDst_->horizontalMetrics_->nameMap_;
647         BEGIN( StartKernPairs );
649 <KernData>"StartKernPairs1"{HorizontalWhiteSpace} {
650         currentKernPairMapX_ = & fontMetricsDst_->verticalKernPairsX_;
651         currentKernPairMapY_ = & fontMetricsDst_->verticalKernPairsY_;
652         if( fontMetricsDst_->verticalMetrics_ == NullPtr< FontMetrics::WritingDirectionMetrics >( ) )
653                 {
654                         throw "It would be nice if the character metrics appeared before the kern pairs.";
655                 }
656         currentNameMap_ = & fontMetricsDst_->verticalMetrics_->nameMap_;
657         BEGIN( StartKernPairs );
659 <StartKernPairs>{Integer}{HorizontalWhiteSpace}[\n] {
660         // The number of pairs is not used.
661         BEGIN( KernPairs );
663 <KernPairs>"EndKernPairs"{HorizontalWhiteSpace}[\n] {
664         BEGIN( KernData );
666 <KernData>"StartTrackKern"{HorizontalWhiteSpace} {
667         BEGIN( StartTrackKern );
669 <StartTrackKern>{Integer}{HorizontalWhiteSpace}[\n] {
670         // The number of entries is not used.
671         BEGIN( TrackKern );
673 <TrackKern>"EndTrackKern"{HorizontalWhiteSpace}[\n] {
674         BEGIN( KernData );
677 <KernPairs>"KP"{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[\n] {
678         char * src = yytext + 2;
679         char * end;
680         const char * name1 = strtoname( src, & end, " \t", 2 );
681         src = end;
682         const char * name2 = strtoname( src, & end, " \t", 2 );
683         src = end;
684         double x = 0.001 * strtod( src, & end );
685         src = end;
686         double y = 0.001 * strtod( src, & end );
687         typedef typeof *currentNameMap_ NameMapType;
688         NameMapType::const_iterator i1 = currentNameMap_->find( strrefdup( name1 ) );
689         if( i1 == currentNameMap_->end( ) )
690         {
691                 throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
692         }
693         NameMapType::const_iterator i2 = currentNameMap_->find( strrefdup( name2 ) );
694         if( i2 == currentNameMap_->end( ) )
695         {
696                 throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
697         }
698         (*currentKernPairMapX_)[ std::pair< size_t, size_t >( i1->second, i2->second ) ] = x;
699         (*currentKernPairMapY_)[ std::pair< size_t, size_t >( i1->second, i2->second ) ] = y;
702 <KernPairs>"KPH"{HorizontalWhiteSpace}"<"{Name}">"{HorizontalWhiteSpace}"<"{Name}">"{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[\n] {
703 //      char * src = yytext + 3;
704 //      char * end;
705         throw "Kern pairs with hexadecimal names are not understood.";
708 <KernPairs>"KPX"{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[\n] {
709         char * src = yytext + 3;
710         char * end;
711         const char * name1 = strtoname( src, & end, " \t", 2 );
712         src = end;
713         const char * name2 = strtoname( src, & end, " \t", 2 );
714         src = end;
715         double x = 0.001 * strtod( src, & end );
716         typedef typeof *currentNameMap_ NameMapType;
717         NameMapType::const_iterator i1 = currentNameMap_->find( strrefdup( name1 ) );
718         if( i1 == currentNameMap_->end( ) )
719         {
720                 throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
721         }
722         NameMapType::const_iterator i2 = currentNameMap_->find( strrefdup( name2 ) );
723         if( i2 == currentNameMap_->end( ) )
724         {
725                 throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
726         }
727         (*currentKernPairMapX_)[ std::pair< size_t, size_t >( i1->second, i2->second ) ] = x;
730 <KernPairs>"KPY"{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Name}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[\n] {
731         char * src = yytext + 3;
732         char * end;
733         const char * name1 = strtoname( src, & end, " \t", 2 );
734         src = end;
735         const char * name2 = strtoname( src, & end, " \t", 2 );
736         src = end;
737         double y = 0.001 * strtod( src, & end );
738         typedef typeof *currentNameMap_ NameMapType;
739         NameMapType::const_iterator i1 = currentNameMap_->find( strrefdup( name1 ) );
740         if( i1 == currentNameMap_->end( ) )
741         {
742                 throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
743         }
744         NameMapType::const_iterator i2 = currentNameMap_->find( strrefdup( name2 ) );
745         if( i2 == currentNameMap_->end( ) )
746         {
747                 throw "Unable to resolve character name in kern pair.   Perhaps kern pairs appear before character metrics.";
748         }
749         (*currentKernPairMapY_)[ std::pair< size_t, size_t >( i1->second, i2->second ) ] = y;
753 <TrackKern>{HorizontalWhiteSpace}{Integer}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}{Number}{HorizontalWhiteSpace}[\n] {
754         char * src = yytext;
755         char * endp;
756         int degree = strtol( src, & endp, 10 );
757         src = endp;
758         double sizeLow = strtod( src, & endp );
759         src = endp;
760         double trackLow = 0.001 * strtod( src, & endp );
761         src = endp;
762         double sizeHigh = strtod( src, & endp );
763         src = endp;
764         double trackHigh = 0.001 * strtod( src, & endp );
765         typedef typeof fontMetricsDst_->trackKernings_ MapType;
766         fontMetricsDst_->trackKernings_.insert( MapType::value_type( degree, RefCountPtr< FontMetrics::TrackKerning >( new FontMetrics::TrackKerning( sizeLow, trackLow, sizeHigh, trackHigh ) ) ) );
770 <*>^"Comment"{HorizontalWhiteSpace}.*[\n] {
771         // Ignore comments.
774 <Global>{Name} {
775         // If we match the whole line here, it will be a _very_ good match for anything.        Hence we do things in two steps.
776         if( tellQue_ )
777         {
778                 std::cerr << "The afm parser was unable to understand the key \"" << yytext << "\", with data: " ;
779         }
780         BEGIN( Que ); 
782 <Que>{String} {
783         // Ignore things we don't understand.
784         if( tellQue_ )
785         {
786                 std::cerr << yytext << std::endl ;
787         }
788         BEGIN( FinishGlobalLine );
791 <*>. { throwError( "Unrecognized token." ); }
794 /* The closing %% above marks the end of the Rules section and the beginning
795  * of the User Subroutines section. All text from here to the end of the
796  * file is copied verbatim to the end of the generated lex.pdf.c file.
797  * This section is where you put definitions of helper functions.
798  */
800 const char *
801 strtoname( char * begin, char ** endp, const char * delim )
803         for( ; memchr( " \t", *begin, 2 ) != 0; ++begin )
804                 ;
806         char * end = begin;
807         for( ; strchr( delim, *end ) == 0; ++end )
808                 ;
810         *end = '\0';
811         *endp = end + 1;
812         return begin;
815 const char *
816 strtoname( char * begin, char ** endp, const char * delim, size_t delimSize )
818         for( ; memchr( " \t", *begin, 2 ) != 0; ++begin )
819                 ;
821         char * end = begin;
822         for( ; memchr( delim, *end, delimSize ) == 0; ++end )
823                 ;
825         *end = '\0';
826         *endp = end + 1;
827         return begin;