~ubuntu-branches/ubuntu/karmic/grace/karmic

« back to all changes in this revision

Viewing changes to T1lib/t1lib/parseAFM.c

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Werner
  • Date: 2002-03-19 14:19:58 UTC
  • Revision ID: james.westby@ubuntu.com-20020319141958-5gxna6vo1ek3zjml
Tags: upstream-5.1.7
ImportĀ upstreamĀ versionĀ 5.1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*--------------------------------------------------------------------------
 
2
  ----- File:        parseAFM.c
 
3
  ----- Author:      Adobe Systems Inc., modifications by
 
4
                     Rainer Menzner (Rainer.Menzner@web.de)
 
5
  ----- Date:        2001-11-01
 
6
  ----- Description: This file is part of the t1-library. It is the original
 
7
                     parseAFM.h modified at a few points, especially for
 
8
                     reading MSDOS-style AFM files..
 
9
  ----- Copyright:   t1lib is copyrighted (c) Rainer Menzner, 1996-2001.
 
10
                     As of version 0.5, t1lib is distributed under the
 
11
                     GNU General Public Library Lincense. The
 
12
                     conditions can be found in the files LICENSE and
 
13
                     LGPL, which should reside in the toplevel
 
14
                     directory of the distribution.  Please note that 
 
15
                     there are parts of t1lib that are subject to
 
16
                     other licenses:
 
17
                     The parseAFM-package is copyrighted by Adobe Systems
 
18
                     Inc.
 
19
                     The type1 rasterizer is copyrighted by IBM and the
 
20
                     X11-consortium.
 
21
  ----- Warranties:  Of course, there's NO WARRANTY OF ANY KIND :-)
 
22
  ----- Credits:     I want to thank IBM and the X11-consortium for making
 
23
                     their rasterizer freely available.
 
24
                     Also thanks to Piet Tutelaers for his ps2pk, from
 
25
                     which I took the rasterizer sources in a format
 
26
                     independent from X11.
 
27
                     Thanks to all people who make free software living!
 
28
--------------------------------------------------------------------------*/
 
29
 
 
30
/*
 
31
 * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
 
32
 *
 
33
 * This file may be freely copied and redistributed as long as:
 
34
 *   1) This entire notice continues to be included in the file, 
 
35
 *   2) If the file has been modified in any way, a notice of such
 
36
 *      modification is conspicuously indicated.
 
37
 *
 
38
 * PostScript, Display PostScript, and Adobe are registered trademarks of
 
39
 * Adobe Systems Incorporated.
 
40
 * 
 
41
 * ************************************************************************
 
42
 * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
 
43
 * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
 
44
 * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR 
 
45
 * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY 
 
46
 * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION, 
 
47
 * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
 
48
 * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 
49
 * ************************************************************************
 
50
 */
 
51
 
 
52
/* parseAFM.c
 
53
 * 
 
54
 * This file is used in conjuction with the parseAFM.h header file.
 
55
 * This file contains several procedures that are used to parse AFM
 
56
 * files. It is intended to work with an application program that needs
 
57
 * font metric information. The program can be used as is by making a
 
58
 * procedure call to "parseFile" (passing in the expected parameters)
 
59
 * and having it fill in a data structure with the data from the 
 
60
 * AFM file, or an application developer may wish to customize this
 
61
 * code.
 
62
 *
 
63
 * There is also a file, parseAFMclient.c, that is a sample application
 
64
 * showing how to call the "parseFile" procedure and how to use the data
 
65
 * after "parseFile" has returned.
 
66
 *
 
67
 * Please read the comments in parseAFM.h and parseAFMclient.c.
 
68
 *
 
69
 * History:
 
70
 *      original: DSM  Thu Oct 20 17:39:59 PDT 1988
 
71
 *  modified: DSM  Mon Jul  3 14:17:50 PDT 1989
 
72
 *    - added 'storageProblem' return code
 
73
 *        - fixed bug of not allocating extra byte for string duplication
 
74
 *    - fixed typos
 
75
 *  modified: DSM  Tue Apr  3 11:18:34 PDT 1990
 
76
 *    - added free(ident) at end of parseFile routine
 
77
 *  modified: DSM  Tue Jun 19 10:16:29 PDT 1990
 
78
 *    - changed (width == 250) to (width = 250) in initializeArray
 
79
 */
 
80
 
 
81
#include <stdio.h>
 
82
#include <stdlib.h>
 
83
#include <errno.h>
 
84
#include <sys/types.h>  /* this seems to be necessary on some SCO-systems */
 
85
#if !defined(_MSC_VER)
 
86
#  include <sys/file.h>
 
87
#endif
 
88
#include <math.h>
 
89
#include <string.h>
 
90
#include "parseAFM.h"
 
91
 
 
92
#define lineterm EOL    /* line terminating character */
 
93
#define normalEOF 1     /* return code from parsing routines used only */
 
94
                        /* in this module */
 
95
#define Space "space"   /* used in string comparison to look for the width */
 
96
                        /* of the space character to init the widths array */
 
97
#define False "false"   /* used in string comparison to check the value of */
 
98
                        /* boolean keys (e.g. IsFixedPitch)  */
 
99
 
 
100
#define MATCH(A,B)              (strncmp((A),(B), MAX_NAME) == 0)
 
101
 
 
102
 
 
103
 
 
104
/* Note: The functions token and linetoken are  extended to be able
 
105
   to parse AFM files with DOS-style line-ends under UNIX. I don't know
 
106
   why AFM files which according to Adobe are explicitly intended to
 
107
   be used under UNIX have MSDOS-style line ends.
 
108
 
 
109
   However, we parse the tokens based on the following atoms. This should
 
110
   work on any system.
 
111
*/
 
112
#define CR       '\r'    /* a carriage return */
 
113
#define LF       '\n'    /* a linefeed, which is a newline under UNIX */
 
114
#define CTRL_Z   0x1A    /* some AFM files have this characters as an end
 
115
                            of file indicator. Who know why :) ? */
 
116
 
 
117
 
 
118
/*************************** GLOBALS ***********************/
 
119
 
 
120
static char *ident = NULL; /* storage buffer for keywords */
 
121
 
 
122
 
 
123
/* "shorts" for fast case statement 
 
124
 * The values of each of these enumerated items correspond to an entry in the
 
125
 * table of strings defined below. Therefore, if you add a new string as 
 
126
 * new keyword into the keyStrings table, you must also add a corresponding
 
127
 * parseKey AND it MUST be in the same position!
 
128
 *
 
129
 * IMPORTANT: since the sorting algorithm is a binary search, the strings of
 
130
 * keywords must be placed in lexicographical order, below. [Therefore, the 
 
131
 * enumerated items are not necessarily in lexicographical order, depending 
 
132
 * on the name chosen. BUT, they must be placed in the same position as the 
 
133
 * corresponding key string.] The NOPE shall remain in the last position, 
 
134
 * since it does not correspond to any key string, and it is used in the 
 
135
 * "recognize" procedure to calculate how many possible keys there are.
 
136
 */
 
137
 
 
138
typedef enum {
 
139
  ASCENDER, CHARBBOX, CODE, COMPCHAR, CAPHEIGHT, COMMENT, 
 
140
  DESCENDER, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, 
 
141
  ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN, 
 
142
  FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISFIXEDPITCH, 
 
143
  ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, CHARNAME, 
 
144
  NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, 
 
145
  STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS, 
 
146
  STARTTRACKKERN, TRACKKERN, UNDERLINEPOSITION, 
 
147
  UNDERLINETHICKNESS, VERSION, XYWIDTH, XWIDTH, WEIGHT, XHEIGHT,
 
148
  NOPE} PARSEKEY;
 
149
 
 
150
 
 
151
/* keywords for the system:  
 
152
 * This a table of all of the current strings that are vaild AFM keys.
 
153
 * Each entry can be referenced by the appropriate parseKey value (an
 
154
 * enumerated data type defined above). If you add a new keyword here, 
 
155
 * a corresponding parseKey MUST be added to the enumerated data type
 
156
 * defined above, AND it MUST be added in the same position as the 
 
157
 * string is in this table.
 
158
 *
 
159
 * IMPORTANT: since the sorting algorithm is a binary search, the keywords
 
160
 * must be placed in lexicographical order. And, NULL should remain at the
 
161
 * end.
 
162
 */
 
163
 
 
164
static char *keyStrings[] = {
 
165
  "Ascender", "B", "C", "CC", "CapHeight", "Comment",
 
166
  "Descender", "EncodingScheme", "EndCharMetrics", "EndComposites", 
 
167
  "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern", 
 
168
  "FamilyName", "FontBBox", "FontName", "FullName", "IsFixedPitch", 
 
169
  "ItalicAngle", "KP", "KPX", "L", "N", 
 
170
  "Notice", "PCC", "StartCharMetrics", "StartComposites", 
 
171
  "StartFontMetrics", "StartKernData", "StartKernPairs", 
 
172
  "StartTrackKern", "TrackKern", "UnderlinePosition", 
 
173
  "UnderlineThickness", "Version", "W", "WX", "Weight", "XHeight",
 
174
  NULL };
 
175
  
 
176
/*************************** PARSING ROUTINES **************/ 
 
177
  
 
178
/*************************** token *************************/
 
179
 
 
180
/*  A "AFM File Conventions" tokenizer. That means that it will
 
181
 *  return the next token delimited by white space.  See also
 
182
 *  the `linetoken' routine, which does a similar thing but 
 
183
 *  reads all tokens until the next end-of-line.
 
184
 */
 
185
static char *token(stream) 
 
186
  FILE *stream;
 
187
{
 
188
    int ch, idx;
 
189
 
 
190
    /* skip over white space, instead of the systems EOL-character we check
 
191
       explicitly for CR and LF as well as for ^Z. */
 
192
    while ((ch = fgetc(stream)) == ' ' || ch == CR || ch == LF || ch == CTRL_Z || 
 
193
           ch == ',' || ch == '\t' || ch == ';');
 
194
    
 
195
    idx = 0;
 
196
    
 
197
    while (ch != EOF && ch != ' ' && ch != CR  && ch != LF &&
 
198
           ch != CTRL_Z && ch != '\t' && ch != ':' && ch != ';'){
 
199
      ident[idx++] = ch;
 
200
      ch = fgetc(stream);
 
201
    } /* while */
 
202
    
 
203
    if (ch == EOF && idx < 1) {
 
204
      return ((char *)NULL);
 
205
    }
 
206
    if (idx >= 1 && ch != ':' ) {
 
207
      ungetc(ch, stream);
 
208
    }
 
209
    if (idx < 1 ) {
 
210
      ident[idx++] = ch;        /* single-character token */
 
211
    }
 
212
    ident[idx] = 0;
 
213
    
 
214
    return(ident);      /* returns pointer to the token */
 
215
 
 
216
} /* token */
 
217
 
 
218
 
 
219
/*************************** linetoken *************************/
 
220
 
 
221
/*  "linetoken" will get read all tokens until the EOL character from
 
222
 *  the given stream.  This is used to get any arguments that can be
 
223
 *  more than one word (like Comment lines and FullName).
 
224
 */
 
225
 
 
226
static char *linetoken(stream)
 
227
  FILE *stream;
 
228
{
 
229
    int ch, idx;
 
230
 
 
231
    while ((ch = fgetc(stream)) == ' ' || ch == '\t' ); 
 
232
    
 
233
    idx = 0;
 
234
    while (ch != EOF && ch != CR  && ch != LF && ch != CTRL_Z) 
 
235
    {
 
236
        ident[idx++] = ch;
 
237
        ch = fgetc(stream);
 
238
    } /* while */
 
239
    
 
240
    ungetc(ch, stream);
 
241
    ident[idx] = 0;
 
242
 
 
243
    return(ident);      /* returns pointer to the token */
 
244
 
 
245
} /* linetoken */
 
246
 
 
247
 
 
248
/*************************** recognize *************************/
 
249
 
 
250
/*  This function tries to match a string to a known list of
 
251
 *  valid AFM entries (check the keyStrings array above). 
 
252
 *  "ident" contains everything from white space through the
 
253
 *  next space, tab, or ":" character.
 
254
 *
 
255
 *  The algorithm is a standard Knuth binary search.
 
256
 */
 
257
 
 
258
static PARSEKEY recognize(ident)
 
259
  register char *ident;
 
260
{
 
261
    int lower = 0, upper = (int) NOPE, midpoint=NOPE, cmpvalue;
 
262
    BOOL found = T1LIB_FALSE;
 
263
 
 
264
    while ((upper >= lower) && !found)
 
265
    {
 
266
        midpoint = (lower + upper)/2;
 
267
        if (keyStrings[midpoint] == NULL) break;
 
268
        cmpvalue = strncmp(ident, keyStrings[midpoint], MAX_NAME);
 
269
        if (cmpvalue == 0) found = T1LIB_TRUE;
 
270
        else if (cmpvalue < 0) upper = midpoint - 1;
 
271
        else lower = midpoint + 1;
 
272
    } /* while */
 
273
 
 
274
    if (found) return (PARSEKEY) midpoint;
 
275
    else return NOPE;
 
276
    
 
277
} /* recognize */
 
278
 
 
279
 
 
280
/************************* parseGlobals *****************************/
 
281
 
 
282
/*  This function is called by "parseFile". It will parse the AFM File
 
283
 *  up to the "StartCharMetrics" keyword, which essentially marks the
 
284
 *  end of the Global Font Information and the beginning of the character
 
285
 *  metrics information. 
 
286
 *
 
287
 *  If the caller of "parseFile" specified that it wanted the Global
 
288
 *  Font Information (as defined by the "AFM File Specification"
 
289
 *  document), then that information will be stored in the returned 
 
290
 *  data structure.
 
291
 *
 
292
 *  Any Global Font Information entries that are not found in a 
 
293
 *  given file, will have the usual default initialization value
 
294
 *  for its type (i.e. entries of type int will be 0, etc).
 
295
 *
 
296
 *  This function returns an error code specifying whether there was 
 
297
 *  a premature EOF or a parsing error. This return value is used by 
 
298
 *  parseFile to determine if there is more file to parse.
 
299
 */
 
300
 
 
301
static BOOL parseGlobals(fp, gfi)
 
302
  FILE *fp;
 
303
  register GlobalFontInfo *gfi;
 
304
{  
 
305
    BOOL cont = T1LIB_TRUE, save = (gfi != NULL);
 
306
    int error = ok;
 
307
    register char *keyword;
 
308
    
 
309
    while (cont)
 
310
    {
 
311
        keyword = token(fp);
 
312
        
 
313
        if (keyword == NULL)
 
314
          /* Have reached an early and unexpected EOF. */
 
315
          /* Set flag and stop parsing */
 
316
        {
 
317
            error = earlyEOF;
 
318
            break;   /* get out of loop */
 
319
        }
 
320
        if (!save)      
 
321
          /* get tokens until the end of the Global Font info section */
 
322
          /* without saving any of the data */
 
323
            switch (recognize(keyword))  
 
324
            {                           
 
325
                case STARTCHARMETRICS:
 
326
                    cont = T1LIB_FALSE;
 
327
                    break;
 
328
                case ENDFONTMETRICS:    
 
329
                    cont = T1LIB_FALSE;
 
330
                    error = normalEOF;
 
331
                    break;
 
332
                default:
 
333
                    break;
 
334
            } /* switch */
 
335
        else
 
336
          /* otherwise parse entire global font info section, */
 
337
          /* saving the data */
 
338
            switch(recognize(keyword))
 
339
            {
 
340
                case STARTFONTMETRICS:
 
341
                    keyword = token(fp);
 
342
                    gfi->afmVersion = (char *) malloc(strlen(keyword) + 1);
 
343
                    strcpy(gfi->afmVersion, keyword);
 
344
                    break;
 
345
                case COMMENT:
 
346
                    keyword = linetoken(fp);
 
347
                    break;
 
348
                case FONTNAME:
 
349
                    keyword = linetoken(fp);
 
350
                    gfi->fontName = (char *) malloc(strlen(keyword) + 1);
 
351
                    strcpy(gfi->fontName, keyword);
 
352
                    break;
 
353
                case ENCODINGSCHEME:
 
354
                    keyword = linetoken(fp);
 
355
                    gfi->encodingScheme = (char *) 
 
356
                        malloc(strlen(keyword) + 1);
 
357
                    strcpy(gfi->encodingScheme, keyword);
 
358
                    break; 
 
359
                case FULLNAME:
 
360
                    keyword = linetoken(fp);
 
361
                    gfi->fullName = (char *) malloc(strlen(keyword) + 1);
 
362
                    strcpy(gfi->fullName, keyword);
 
363
                    break; 
 
364
                case FAMILYNAME:           
 
365
                   keyword = linetoken(fp);
 
366
                    gfi->familyName = (char *) malloc(strlen(keyword) + 1);
 
367
                    strcpy(gfi->familyName, keyword);
 
368
                    break; 
 
369
                case WEIGHT:
 
370
                    keyword = linetoken(fp);
 
371
                    gfi->weight = (char *) malloc(strlen(keyword) + 1);
 
372
                    strcpy(gfi->weight, keyword);
 
373
                    break;
 
374
                case ITALICANGLE:
 
375
                    keyword = token(fp);
 
376
                    gfi->italicAngle = atof(keyword);
 
377
                    if (errno == ERANGE) error = parseError;
 
378
                    break;
 
379
                case ISFIXEDPITCH:
 
380
                    keyword = token(fp);
 
381
                    if (MATCH(keyword, False))
 
382
                        gfi->isFixedPitch = 0;
 
383
                    else 
 
384
                        gfi->isFixedPitch = 1;
 
385
                    break; 
 
386
                    case UNDERLINEPOSITION:
 
387
                    keyword = token(fp);
 
388
                    gfi->underlinePosition = atoi(keyword);
 
389
                    break; 
 
390
                case UNDERLINETHICKNESS:
 
391
                    keyword = token(fp);
 
392
                    gfi->underlineThickness = atoi(keyword);
 
393
                    break;
 
394
                case VERSION:
 
395
                    keyword = linetoken(fp);
 
396
                    gfi->version = (char *) malloc(strlen(keyword) + 1);
 
397
                    strcpy(gfi->version, keyword);
 
398
                    break; 
 
399
                case NOTICE:
 
400
                    keyword = linetoken(fp);
 
401
                    gfi->notice = (char *) malloc(strlen(keyword) + 1);
 
402
                    strcpy(gfi->notice, keyword);
 
403
                    break; 
 
404
                case FONTBBOX:
 
405
                    keyword = token(fp);
 
406
                    gfi->fontBBox.llx = atoi(keyword);
 
407
                    keyword = token(fp);
 
408
                    gfi->fontBBox.lly = atoi(keyword);
 
409
                    keyword = token(fp);
 
410
                    gfi->fontBBox.urx = atoi(keyword);
 
411
                    keyword = token(fp);
 
412
                    gfi->fontBBox.ury = atoi(keyword);
 
413
                    break;
 
414
                case CAPHEIGHT:
 
415
                    keyword = token(fp);
 
416
                    gfi->capHeight = atoi(keyword);
 
417
                    break;
 
418
                case XHEIGHT:
 
419
                    keyword = token(fp);
 
420
                    gfi->xHeight = atoi(keyword);
 
421
                    break;
 
422
                case DESCENDER:
 
423
                    keyword = token(fp);
 
424
                    gfi->descender = atoi(keyword);
 
425
                    break;
 
426
                case ASCENDER:
 
427
                    keyword = token(fp);
 
428
                    gfi->ascender = atoi(keyword);
 
429
                    break;
 
430
                case STARTCHARMETRICS:
 
431
                    cont = T1LIB_FALSE;
 
432
                    break;
 
433
                case ENDFONTMETRICS:
 
434
                    cont = T1LIB_FALSE;
 
435
                    error = normalEOF;
 
436
                    break;
 
437
                case NOPE:
 
438
                default:
 
439
                    error = parseError;
 
440
                    break;
 
441
            } /* switch */
 
442
    } /* while */
 
443
    
 
444
    return(error);
 
445
    
 
446
} /* parseGlobals */    
 
447
 
 
448
 
 
449
 
 
450
/************************* initializeArray ************************/
 
451
 
 
452
/*  Unmapped character codes are (at Adobe Systems) assigned the
 
453
 *  width of the space character (if one exists) else they get the
 
454
 *  value of 250 ems. This function initializes all entries in the
 
455
 *  char widths array to have this value. Then any mapped character 
 
456
 *  codes will be replaced with the width of the appropriate character 
 
457
 *  when parsing the character metric section.
 
458
 
 
459
 *  This function parses the Character Metrics Section looking
 
460
 *  for a space character (by comparing character names). If found,
 
461
 *  the width of the space character will be used to initialize the
 
462
 *  values in the array of character widths. 
 
463
 *
 
464
 *  Before returning, the position of the read/write pointer of the
 
465
 *  file is reset to be where it was upon entering this function.
 
466
 */
 
467
 
 
468
/* We comment out the following function since it is not needed in t1lib
 
469
   and we don't want compiler warnings */
 
470
/*
 
471
static int initializeArray(fp, cwi) 
 
472
  FILE *fp;
 
473
  register int *cwi;
 
474
{  
 
475
    BOOL cont = T1LIB_TRUE, found = T1LIB_FALSE;
 
476
    long opos = ftell(fp);
 
477
    int code = 0, width = 0, i = 0, error = 0;
 
478
    register char *keyword;
 
479
  
 
480
    while (cont)
 
481
    {
 
482
        keyword = token(fp);
 
483
        if (keyword == NULL)
 
484
        {
 
485
            error = earlyEOF;
 
486
            break; 
 
487
        }
 
488
        switch(recognize(keyword))
 
489
        {
 
490
            case COMMENT:
 
491
                keyword = linetoken(fp);
 
492
                break;
 
493
            case CODE:
 
494
                code = atoi(token(fp));
 
495
                break;
 
496
            case XWIDTH:
 
497
                width = atoi(token(fp));
 
498
                break;
 
499
            case CHARNAME: 
 
500
                keyword = token(fp);
 
501
                if (MATCH(keyword, Space))
 
502
                {    
 
503
                    cont = T1LIB_FALSE;
 
504
                    found = T1LIB_TRUE;
 
505
                } 
 
506
                break;            
 
507
            case ENDCHARMETRICS:
 
508
                cont = T1LIB_FALSE;
 
509
                break; 
 
510
            case ENDFONTMETRICS:
 
511
                cont = T1LIB_FALSE;
 
512
                error = normalEOF;
 
513
                break;
 
514
            case NOPE:
 
515
            default: 
 
516
                error = parseError;
 
517
                break;
 
518
        } 
 
519
    } 
 
520
    
 
521
    if (!found)
 
522
        width = 250;
 
523
    
 
524
    for (i = 0; i < 256; ++i)
 
525
        cwi[i] = width;
 
526
    
 
527
    fseek(fp, opos, 0);
 
528
    
 
529
    return(error);
 
530
        
 
531
}
 
532
*/ 
 
533
 
 
534
/************************* parseCharWidths **************************/
 
535
 
 
536
/*  This function is called by "parseFile". It will parse the AFM File
 
537
 *  up to the "EndCharMetrics" keyword. It will save the character 
 
538
 *  width info (as opposed to all of the character metric information)
 
539
 *  if requested by the caller of parseFile. Otherwise, it will just
 
540
 *  parse through the section without saving any information.
 
541
 *
 
542
 *  If data is to be saved, parseCharWidths is passed in a pointer 
 
543
 *  to an array of widths that has already been initialized by the
 
544
 *  standard value for unmapped character codes. This function parses
 
545
 *  the Character Metrics section only storing the width information
 
546
 *  for the encoded characters into the array using the character code
 
547
 *  as the index into that array.
 
548
 *
 
549
 *  This function returns an error code specifying whether there was 
 
550
 *  a premature EOF or a parsing error. This return value is used by 
 
551
 *  parseFile to determine if there is more file to parse.
 
552
 */
 
553
 
 
554
static int parseCharWidths(fp, cwi)
 
555
  FILE *fp;
 
556
  register int *cwi;
 
557
{  
 
558
    BOOL cont = T1LIB_TRUE, save = (cwi != NULL);
 
559
    int pos = 0, error = ok;
 
560
    register char *keyword;
 
561
    
 
562
    while (cont)
 
563
    {
 
564
        keyword = token(fp);
 
565
          /* Have reached an early and unexpected EOF. */
 
566
          /* Set flag and stop parsing */
 
567
        if (keyword == NULL)
 
568
        {
 
569
            error = earlyEOF;
 
570
            break; /* get out of loop */
 
571
        }
 
572
        if (!save)      
 
573
          /* get tokens until the end of the Char Metrics section without */
 
574
          /* saving any of the data*/
 
575
            switch (recognize(keyword))  
 
576
            {                           
 
577
                case ENDCHARMETRICS:
 
578
                    cont = T1LIB_FALSE;
 
579
                    break; 
 
580
                case ENDFONTMETRICS:
 
581
                    cont = T1LIB_FALSE;
 
582
                    error = normalEOF;
 
583
                    break;
 
584
                default: 
 
585
                    break;
 
586
            } /* switch */
 
587
        else
 
588
          /* otherwise parse entire char metrics section, saving */
 
589
          /* only the char x-width info */
 
590
            switch(recognize(keyword))
 
591
            {
 
592
                case COMMENT:
 
593
                    keyword = linetoken(fp);
 
594
                    break;
 
595
                case CODE:
 
596
                    keyword = token(fp);
 
597
                    pos = atoi(keyword);
 
598
                    break;
 
599
                case XYWIDTH:
 
600
                /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
 
601
                    keyword = token(fp); keyword = token(fp); /* eat values */
 
602
                    error = parseError;
 
603
                    break;
 
604
                case XWIDTH:
 
605
                    keyword = token(fp);
 
606
                    if (pos >= 0) /* ignore unmapped chars */
 
607
                        cwi[pos] = atoi(keyword);
 
608
                    break;
 
609
                case ENDCHARMETRICS:
 
610
                    cont = T1LIB_FALSE;
 
611
                    break; 
 
612
                case ENDFONTMETRICS:
 
613
                    cont = T1LIB_FALSE;
 
614
                    error = normalEOF;
 
615
                    break;
 
616
                case CHARNAME:  /* eat values (so doesn't cause parseError) */
 
617
                    keyword = token(fp); 
 
618
                    break;
 
619
                case CHARBBOX: 
 
620
                    keyword = token(fp); keyword = token(fp);
 
621
                    keyword = token(fp); keyword = token(fp);
 
622
                    break;
 
623
                case LIGATURE:
 
624
                    keyword = token(fp); keyword = token(fp);
 
625
                    break;
 
626
                case NOPE:
 
627
                default: 
 
628
                    error = parseError;
 
629
                    break;
 
630
            } /* switch */
 
631
    } /* while */
 
632
    
 
633
    return(error);
 
634
    
 
635
} /* parseCharWidths */    
 
636
 
 
637
 
 
638
/************************* parseCharMetrics ************************/
 
639
 
 
640
/*  This function is called by parseFile if the caller of parseFile
 
641
 *  requested that all character metric information be saved
 
642
 *  (as opposed to only the character width information).
 
643
 *
 
644
 *  parseCharMetrics is passed in a pointer to an array of records
 
645
 *  to hold information on a per character basis. This function
 
646
 *  parses the Character Metrics section storing all character
 
647
 *  metric information for the ALL characters (mapped and unmapped) 
 
648
 *  into the array.
 
649
 *
 
650
 *  This function returns an error code specifying whether there was 
 
651
 *  a premature EOF or a parsing error. This return value is used by 
 
652
 *  parseFile to determine if there is more file to parse.
 
653
 */
 
654
 
 
655
static int parseCharMetrics(fp, fi)
 
656
  FILE *fp;
 
657
  register FontInfo *fi;
 
658
{  
 
659
    BOOL cont = T1LIB_TRUE, firstTime = T1LIB_TRUE;
 
660
    int error = ok, count = 0;
 
661
    register CharMetricInfo *temp = fi->cmi;
 
662
    register char *keyword;
 
663
  
 
664
    while (cont)
 
665
    {
 
666
        keyword = token(fp);
 
667
        if (keyword == NULL)
 
668
        {
 
669
            error = earlyEOF;
 
670
            break; /* get out of loop */
 
671
        }
 
672
        switch(recognize(keyword))
 
673
        {
 
674
            case COMMENT:
 
675
                keyword = linetoken(fp);
 
676
                break; 
 
677
            case CODE:
 
678
                if (count < fi->numOfChars)
 
679
                { 
 
680
                    if (firstTime) firstTime = T1LIB_FALSE;
 
681
                    else temp++;
 
682
                    temp->code = atoi(token(fp));
 
683
                    count++;
 
684
                }
 
685
                else
 
686
                {
 
687
                    error = parseError;
 
688
                    cont = T1LIB_FALSE;
 
689
                }
 
690
                break;
 
691
            case XYWIDTH:
 
692
                temp->wx = atoi(token(fp));
 
693
                temp->wy = atoi(token(fp));
 
694
                break;                 
 
695
            case XWIDTH: 
 
696
                temp->wx = atoi(token(fp));
 
697
                break;
 
698
            case CHARNAME: 
 
699
                keyword = token(fp);
 
700
                temp->name = (char *) malloc(strlen(keyword) + 1);
 
701
                strcpy(temp->name, keyword);
 
702
                break;            
 
703
            case CHARBBOX: 
 
704
                temp->charBBox.llx = atoi(token(fp));
 
705
                temp->charBBox.lly = atoi(token(fp));
 
706
                temp->charBBox.urx = atoi(token(fp));
 
707
                temp->charBBox.ury = atoi(token(fp));
 
708
                break;
 
709
            case LIGATURE: {
 
710
                Ligature **tail = &(temp->ligs);
 
711
                Ligature *node = *tail;
 
712
                
 
713
                if (*tail != NULL)
 
714
                {
 
715
                    while (node->next != NULL)
 
716
                        node = node->next;
 
717
                    tail = &(node->next); 
 
718
                }
 
719
                
 
720
                *tail = (Ligature *) calloc(1, sizeof(Ligature));
 
721
                keyword = token(fp);
 
722
                (*tail)->succ = (char *) malloc(strlen(keyword) + 1);
 
723
                strcpy((*tail)->succ, keyword);
 
724
                keyword = token(fp);
 
725
                (*tail)->lig = (char *) malloc(strlen(keyword) + 1);
 
726
                strcpy((*tail)->lig, keyword);
 
727
                break; }
 
728
            case ENDCHARMETRICS:
 
729
                cont = T1LIB_FALSE;;
 
730
                break; 
 
731
            case ENDFONTMETRICS: 
 
732
                cont = T1LIB_FALSE;
 
733
                error = normalEOF;
 
734
                break; 
 
735
            case NOPE:
 
736
            default:
 
737
                error = parseError; 
 
738
                break; 
 
739
        } /* switch */
 
740
    } /* while */
 
741
    
 
742
    if ((error == ok) && (count != fi->numOfChars))
 
743
        error = parseError;
 
744
    
 
745
    return(error);
 
746
    
 
747
} /* parseCharMetrics */    
 
748
 
 
749
 
 
750
 
 
751
/************************* parseTrackKernData ***********************/
 
752
 
 
753
/*  This function is called by "parseFile". It will parse the AFM File 
 
754
 *  up to the "EndTrackKern" or "EndKernData" keywords. It will save the
 
755
 *  track kerning data if requested by the caller of parseFile.
 
756
 *
 
757
 *  parseTrackKernData is passed in a pointer to the FontInfo record.
 
758
 *  If data is to be saved, the FontInfo record will already contain 
 
759
 *  a valid pointer to storage for the track kerning data.
 
760
 *
 
761
 *  This function returns an error code specifying whether there was 
 
762
 *  a premature EOF or a parsing error. This return value is used by 
 
763
 *  parseFile to determine if there is more file to parse.
 
764
 */
 
765
 
 
766
static int parseTrackKernData(fp, fi)
 
767
  FILE *fp;
 
768
  register FontInfo *fi;
 
769
{  
 
770
    BOOL cont = T1LIB_TRUE, save = (fi->tkd != NULL);
 
771
    int pos = 0, error = ok, tcount = 0;
 
772
    register char *keyword;
 
773
  
 
774
    while (cont)
 
775
    {
 
776
        keyword = token(fp);
 
777
        
 
778
        if (keyword == NULL)
 
779
        {
 
780
            error = earlyEOF;
 
781
            break; /* get out of loop */
 
782
        }
 
783
        if (!save)
 
784
          /* get tokens until the end of the Track Kerning Data */
 
785
          /* section without saving any of the data */
 
786
            switch(recognize(keyword))
 
787
            {
 
788
                case ENDTRACKKERN:
 
789
                case ENDKERNDATA:
 
790
                    cont = T1LIB_FALSE;
 
791
                    break;
 
792
                case ENDFONTMETRICS:
 
793
                    cont = T1LIB_FALSE;
 
794
                    error = normalEOF;
 
795
                    break;
 
796
                default:
 
797
                    break;
 
798
            } /* switch */
 
799
        else
 
800
          /* otherwise parse entire Track Kerning Data section, */
 
801
          /* saving the data */
 
802
            switch(recognize(keyword))
 
803
            {
 
804
                case COMMENT:
 
805
                    keyword = linetoken(fp);
 
806
                    break;
 
807
                case TRACKKERN:
 
808
                    if (tcount < fi->numOfTracks)
 
809
                    {
 
810
                        keyword = token(fp);
 
811
                        fi->tkd[pos].degree = atoi(keyword);
 
812
                        keyword = token(fp);
 
813
                        fi->tkd[pos].minPtSize = atof(keyword);
 
814
                        if (errno == ERANGE) error = parseError;
 
815
                        keyword = token(fp);
 
816
                        fi->tkd[pos].minKernAmt = atof(keyword);
 
817
                        if (errno == ERANGE) error = parseError;
 
818
                        keyword = token(fp);
 
819
                        fi->tkd[pos].maxPtSize = atof(keyword);
 
820
                        if (errno == ERANGE) error = parseError;
 
821
                        keyword = token(fp);
 
822
                        fi->tkd[pos++].maxKernAmt = atof(keyword);
 
823
                        if (errno == ERANGE) error = parseError;
 
824
                        tcount++;
 
825
                    }
 
826
                    else
 
827
                    {
 
828
                        error = parseError;
 
829
                        cont = T1LIB_FALSE;
 
830
                    }
 
831
                    break;
 
832
                case ENDTRACKKERN:
 
833
                case ENDKERNDATA:
 
834
                    cont = T1LIB_FALSE;
 
835
                    break;
 
836
                case ENDFONTMETRICS:
 
837
                    cont = T1LIB_FALSE;
 
838
                    error = normalEOF;
 
839
                    break;
 
840
                case NOPE:
 
841
                default:
 
842
                    error = parseError;
 
843
                    break;
 
844
            } /* switch */
 
845
    } /* while */
 
846
    
 
847
    if (error == ok && tcount != fi->numOfTracks)
 
848
        error = parseError;
 
849
        
 
850
    return(error);
 
851
    
 
852
} /* parseTrackKernData */    
 
853
 
 
854
 
 
855
/************************* parsePairKernData ************************/
 
856
 
 
857
/*  This function is called by "parseFile". It will parse the AFM File 
 
858
 *  up to the "EndKernPairs" or "EndKernData" keywords. It will save
 
859
 *  the pair kerning data if requested by the caller of parseFile.
 
860
 *
 
861
 *  parsePairKernData is passed in a pointer to the FontInfo record.
 
862
 *  If data is to be saved, the FontInfo record will already contain 
 
863
 *  a valid pointer to storage for the pair kerning data.
 
864
 *
 
865
 *  This function returns an error code specifying whether there was 
 
866
 *  a premature EOF or a parsing error. This return value is used by 
 
867
 *  parseFile to determine if there is more file to parse.
 
868
 */
 
869
 
 
870
static int parsePairKernData(fp, fi)
 
871
     FILE *fp;
 
872
     register FontInfo *fi;
 
873
{  
 
874
  BOOL cont = T1LIB_TRUE, save = (fi->pkd != NULL);
 
875
  int pos = 0, error = ok, pcount = 0;
 
876
  register char *keyword;
 
877
  
 
878
  while (cont)
 
879
    {
 
880
      keyword = token(fp);
 
881
      
 
882
      if (keyword == NULL)
 
883
        {
 
884
          error = earlyEOF;
 
885
          break; /* get out of loop */
 
886
        }
 
887
      if (!save)
 
888
        /* get tokens until the end of the Pair Kerning Data */
 
889
        /* section without saving any of the data */
 
890
        switch(recognize(keyword))
 
891
          {
 
892
          case ENDKERNPAIRS:
 
893
          case ENDKERNDATA:
 
894
            cont = T1LIB_FALSE;
 
895
            break;
 
896
          case ENDFONTMETRICS:
 
897
            cont = T1LIB_FALSE;
 
898
            error = normalEOF;
 
899
            break;
 
900
          default:
 
901
            break;
 
902
          } /* switch */
 
903
      else
 
904
        /* otherwise parse entire Pair Kerning Data section, */
 
905
        /* saving the data */
 
906
        switch(recognize(keyword))
 
907
          {
 
908
          case COMMENT:
 
909
            keyword = linetoken(fp);
 
910
            break;
 
911
          case KERNPAIR:
 
912
            if (pcount < fi->numOfPairs)
 
913
              {
 
914
                keyword = token(fp);
 
915
                fi->pkd[pos].name1 = (char *) 
 
916
                  malloc(strlen(keyword) + 1);
 
917
                strcpy(fi->pkd[pos].name1, keyword);
 
918
                keyword = token(fp);
 
919
                fi->pkd[pos].name2 = (char *) 
 
920
                  malloc(strlen(keyword) + 1);
 
921
                strcpy(fi->pkd[pos].name2, keyword);
 
922
                keyword = token(fp);
 
923
                fi->pkd[pos].xamt = atoi(keyword);
 
924
                keyword = token(fp);
 
925
                fi->pkd[pos++].yamt = atoi(keyword);
 
926
                pcount++;
 
927
              }
 
928
            else
 
929
              {
 
930
                error = parseError;
 
931
                cont = T1LIB_FALSE;
 
932
              }
 
933
            break;
 
934
          case KERNPAIRXAMT:
 
935
            if (pcount < fi->numOfPairs)
 
936
              {
 
937
                keyword = token(fp);
 
938
                fi->pkd[pos].name1 = (char *) 
 
939
                  malloc(strlen(keyword) + 1);
 
940
                strcpy(fi->pkd[pos].name1, keyword);
 
941
                keyword = token(fp);
 
942
                fi->pkd[pos].name2 = (char *) 
 
943
                  malloc(strlen(keyword) + 1);
 
944
                strcpy(fi->pkd[pos].name2, keyword);
 
945
                keyword = token(fp);
 
946
                fi->pkd[pos++].xamt = atoi(keyword);
 
947
                pcount++;
 
948
              }
 
949
            else
 
950
              {
 
951
                error = parseError;
 
952
                cont = T1LIB_FALSE;
 
953
              }
 
954
            break;
 
955
          case ENDKERNPAIRS:
 
956
          case ENDKERNDATA:
 
957
            cont = T1LIB_FALSE;
 
958
            break;
 
959
          case ENDFONTMETRICS:
 
960
            cont = T1LIB_FALSE;
 
961
            error = normalEOF;
 
962
            break;
 
963
          case NOPE:
 
964
          default:
 
965
            error = parseError;
 
966
            break;
 
967
          } /* switch */
 
968
    } /* while */
 
969
    
 
970
  if (error == ok && pcount != fi->numOfPairs)
 
971
    error = parseError;
 
972
        
 
973
  return(error);
 
974
    
 
975
} /* parsePairKernData */    
 
976
 
 
977
 
 
978
/************************* parseCompCharData **************************/
 
979
 
 
980
/*  This function is called by "parseFile". It will parse the AFM File 
 
981
 *  up to the "EndComposites" keyword. It will save the composite 
 
982
 *  character data if requested by the caller of parseFile.
 
983
 *
 
984
 *  parseCompCharData is passed in a pointer to the FontInfo record, and 
 
985
 *  a boolean representing if the data should be saved.
 
986
 *
 
987
 *  This function will create the appropriate amount of storage for
 
988
 *  the composite character data and store a pointer to the storage
 
989
 *  in the FontInfo record.
 
990
 *
 
991
 *  This function returns an error code specifying whether there was 
 
992
 *  a premature EOF or a parsing error. This return value is used by 
 
993
 *  parseFile to determine if there is more file to parse.
 
994
 */
 
995
 
 
996
static int parseCompCharData(fp, fi)
 
997
  FILE *fp;
 
998
  register FontInfo *fi;
 
999
{  
 
1000
    BOOL cont = T1LIB_TRUE, firstTime = T1LIB_TRUE, save = (fi->ccd != NULL);
 
1001
    int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0;
 
1002
    register char *keyword;
 
1003
  
 
1004
    while (cont)
 
1005
    {
 
1006
        keyword = token(fp);
 
1007
        if (keyword == NULL)
 
1008
          /* Have reached an early and unexpected EOF. */
 
1009
          /* Set flag and stop parsing */
 
1010
        {
 
1011
            error = earlyEOF;
 
1012
            break; /* get out of loop */
 
1013
        }
 
1014
        if (ccount > fi->numOfComps)
 
1015
        {
 
1016
            error = parseError;
 
1017
            break; /* get out of loop */
 
1018
        }
 
1019
        if (!save)
 
1020
          /* get tokens until the end of the Composite Character info */
 
1021
          /* section without saving any of the data */
 
1022
            switch(recognize(keyword))
 
1023
            {
 
1024
                case ENDCOMPOSITES:
 
1025
                    cont = T1LIB_FALSE;
 
1026
                    break;
 
1027
                case ENDFONTMETRICS:
 
1028
                    cont = T1LIB_FALSE;
 
1029
                    error = normalEOF;
 
1030
                    break;
 
1031
                default:
 
1032
                    break;
 
1033
            } /* switch */
 
1034
        else
 
1035
          /* otherwise parse entire Composite Character info section, */
 
1036
          /* saving the data */
 
1037
            switch(recognize(keyword))
 
1038
            {
 
1039
                case COMMENT:
 
1040
                    keyword = linetoken(fp);
 
1041
                    break;
 
1042
                case COMPCHAR:
 
1043
                    if (ccount < fi->numOfComps)
 
1044
                    {
 
1045
                        keyword = token(fp);
 
1046
                        if (pcount != fi->ccd[pos].numOfPieces)
 
1047
                            error = parseError;
 
1048
                        pcount = 0;
 
1049
                        if (firstTime) firstTime = T1LIB_FALSE;
 
1050
                        else pos++;
 
1051
                        fi->ccd[pos].ccName = (char *) 
 
1052
                            malloc(strlen(keyword) + 1);
 
1053
                        strcpy(fi->ccd[pos].ccName, keyword);
 
1054
                        keyword = token(fp);
 
1055
                        fi->ccd[pos].numOfPieces = atoi(keyword);
 
1056
                        fi->ccd[pos].pieces = (Pcc *)
 
1057
                            calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc));
 
1058
                        j = 0;
 
1059
                        ccount++;
 
1060
                    }
 
1061
                    else
 
1062
                    {
 
1063
                        error = parseError;
 
1064
                        cont = T1LIB_FALSE;
 
1065
                    }
 
1066
                    break;
 
1067
                case COMPCHARPIECE:
 
1068
                    if (pcount < fi->ccd[pos].numOfPieces)
 
1069
                    {
 
1070
                        keyword = token(fp);
 
1071
                        fi->ccd[pos].pieces[j].pccName = (char *) 
 
1072
                                malloc(strlen(keyword) + 1);
 
1073
                        strcpy(fi->ccd[pos].pieces[j].pccName, keyword);
 
1074
                        keyword = token(fp);
 
1075
                        fi->ccd[pos].pieces[j].deltax = atoi(keyword);
 
1076
                        keyword = token(fp);
 
1077
                        fi->ccd[pos].pieces[j++].deltay = atoi(keyword);
 
1078
                        pcount++;
 
1079
                    }
 
1080
                    else
 
1081
                        error = parseError;
 
1082
                    break;
 
1083
                case ENDCOMPOSITES:
 
1084
                    cont = T1LIB_FALSE;
 
1085
                    break;
 
1086
                case ENDFONTMETRICS:
 
1087
                    cont = T1LIB_FALSE;
 
1088
                    error = normalEOF;
 
1089
                    break;
 
1090
                case NOPE:
 
1091
                default:
 
1092
                    error = parseError;
 
1093
                    break;
 
1094
            } /* switch */
 
1095
    } /* while */
 
1096
    
 
1097
    if (error == ok && ccount != fi->numOfComps)
 
1098
        error = parseError;
 
1099
    
 
1100
    return(error);
 
1101
    
 
1102
} /* parseCompCharData */    
 
1103
 
 
1104
 
 
1105
 
 
1106
 
 
1107
/*************************** 'PUBLIC' FUNCTION ********************/ 
 
1108
 
 
1109
 
 
1110
/*************************** parseFile *****************************/
 
1111
 
 
1112
/*  parseFile is the only 'public' procedure available. It is called 
 
1113
 *  from an application wishing to get information from an AFM file.
 
1114
 *  The caller of this function is responsible for locating and opening
 
1115
 *  an AFM file and handling all errors associated with that task.
 
1116
 *
 
1117
 *  parseFile expects 3 parameters: a vaild file pointer, a pointer
 
1118
 *  to a (FontInfo *) variable (for which storage will be allocated and
 
1119
 *  the data requested filled in), and a mask specifying which
 
1120
 *  data from the AFM File should be saved in the FontInfo structure.
 
1121
 *
 
1122
 *  The file will be parsed and the requested data will be stored in 
 
1123
 *  a record of type FontInfo (refer to ParseAFM.h).
 
1124
 *
 
1125
 *  parseFile returns an error code as defined in parseAFM.h. 
 
1126
 *
 
1127
 *  The position of the read/write pointer associated with the file 
 
1128
 *  pointer upon return of this function is undefined.
 
1129
 */
 
1130
 
 
1131
/* Note: function renamed to T1lib_parseFile in order to avoid name clushes
 
1132
   with other libraries that also use the Adobe parseAFM-package (RMz) */
 
1133
int T1lib_parseFile (fp, fi, flags)
 
1134
  FILE *fp;
 
1135
  FontInfo **fi;
 
1136
  FLAGS flags;
 
1137
{
 
1138
    
 
1139
    int code = ok;      /* return code from each of the parsing routines */
 
1140
    int error = ok;     /* used as the return code from this function */
 
1141
    
 
1142
    register char *keyword; /* used to store a token */  
 
1143
    
 
1144
                              
 
1145
    /* storage data for the global variable ident */                          
 
1146
    ident = (char *) calloc(MAX_NAME, sizeof(char)); 
 
1147
    if (ident == NULL) {error = storageProblem; return(error);}      
 
1148
  
 
1149
    (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
 
1150
    if ((*fi) == NULL) {error = storageProblem; return(error);}      
 
1151
  
 
1152
    if (flags & P_G) 
 
1153
    {
 
1154
        (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
 
1155
        if ((*fi)->gfi == NULL) {error = storageProblem; return(error);}      
 
1156
    }
 
1157
    
 
1158
    /* The AFM File begins with Global Font Information. This section */
 
1159
    /* will be parsed whether or not information should be saved. */     
 
1160
    code = parseGlobals(fp, (*fi)->gfi); 
 
1161
    
 
1162
    if (code < 0) error = code;
 
1163
    
 
1164
    /* The Global Font Information is followed by the Character Metrics */
 
1165
    /* section. Which procedure is used to parse this section depends on */
 
1166
    /* how much information should be saved. If all of the metrics info */
 
1167
    /* is wanted, parseCharMetrics is called. If only the character widths */
 
1168
    /* is wanted, parseCharWidths is called. parseCharWidths will also */
 
1169
    /* be called in the case that no character data is to be saved, just */
 
1170
    /* to parse through the section. */
 
1171
  
 
1172
    if ((code != normalEOF) && (code != earlyEOF))
 
1173
    {
 
1174
        (*fi)->numOfChars = atoi(token(fp));
 
1175
            if (flags & (P_M ^ P_W))
 
1176
        {
 
1177
            (*fi)->cmi = (CharMetricInfo *) 
 
1178
                      calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
 
1179
           if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
 
1180
            code = parseCharMetrics(fp, *fi);             
 
1181
        }
 
1182
        else
 
1183
        {
 
1184
            if (flags & P_W)
 
1185
            { 
 
1186
                (*fi)->cwi = (int *) calloc(256, sizeof(int)); 
 
1187
                if ((*fi)->cwi == NULL) 
 
1188
                {
 
1189
                        error = storageProblem; 
 
1190
                        return(error);
 
1191
                }
 
1192
            }
 
1193
            /* parse section regardless */
 
1194
            code = parseCharWidths(fp, (*fi)->cwi);
 
1195
        } /* else */
 
1196
    } /* if */
 
1197
    
 
1198
    if ((error != earlyEOF) && (code < 0)) error = code;
 
1199
    
 
1200
    /* The remaining sections of the AFM are optional. This code will */
 
1201
    /* look at the next keyword in the file to determine what section */
 
1202
    /* is next, and then allocate the appropriate amount of storage */
 
1203
    /* for the data (if the data is to be saved) and call the */
 
1204
    /* appropriate parsing routine to parse the section. */
 
1205
    
 
1206
    while ((code != normalEOF) && (code != earlyEOF)) {
 
1207
      keyword = token(fp);
 
1208
      if (keyword == NULL)
 
1209
        /* Have reached an early and unexpected EOF. */
 
1210
        /* Set flag and stop parsing */
 
1211
        {
 
1212
          code = earlyEOF;
 
1213
          break; /* get out of loop */
 
1214
        }
 
1215
      switch(recognize(keyword))
 
1216
        {
 
1217
          /* this case has been added for t1lib because otherwise comment line
 
1218
             between (i.e., outside) the main sections would lead to parse
 
1219
             errors. The Adobe spec does not seem to forbid comments at
 
1220
             such locations (2001-05-14, RMz) */
 
1221
        case COMMENT:
 
1222
          keyword = linetoken(fp);
 
1223
          break;
 
1224
        case STARTKERNDATA:
 
1225
          break;
 
1226
        case ENDKERNDATA:
 
1227
          break;
 
1228
        case STARTTRACKKERN:
 
1229
          keyword = token(fp);
 
1230
          if (flags & P_T)
 
1231
            {
 
1232
              (*fi)->numOfTracks = atoi(keyword);
 
1233
              (*fi)->tkd = (TrackKernData *) 
 
1234
                calloc((*fi)->numOfTracks, sizeof(TrackKernData));
 
1235
              if ((*fi)->tkd == NULL) 
 
1236
                {
 
1237
                  error = storageProblem; 
 
1238
                  return(error);
 
1239
                }
 
1240
            } /* if */
 
1241
          code = parseTrackKernData(fp, *fi);
 
1242
          break;
 
1243
        case STARTKERNPAIRS:
 
1244
          keyword = token(fp);
 
1245
          if (flags & P_P)
 
1246
            {
 
1247
              (*fi)->numOfPairs = atoi(keyword);
 
1248
              (*fi)->pkd = (PairKernData *) 
 
1249
                calloc((*fi)->numOfPairs, sizeof(PairKernData));
 
1250
              if ((*fi)->pkd == NULL) 
 
1251
                {
 
1252
                  error = storageProblem; 
 
1253
                  return(error);
 
1254
                }
 
1255
            } /* if */
 
1256
          code = parsePairKernData(fp, *fi);
 
1257
          break;
 
1258
        case STARTCOMPOSITES:
 
1259
          keyword = token(fp);
 
1260
          if (flags & P_C)
 
1261
            { 
 
1262
              (*fi)->numOfComps = atoi(keyword);
 
1263
              (*fi)->ccd = (CompCharData *) 
 
1264
                calloc((*fi)->numOfComps, sizeof(CompCharData));
 
1265
              if ((*fi)->ccd == NULL) 
 
1266
                {
 
1267
                  error = storageProblem; 
 
1268
                  return(error);
 
1269
                }
 
1270
            } /* if */
 
1271
          code = parseCompCharData(fp, *fi); 
 
1272
          break;    
 
1273
        case ENDFONTMETRICS:
 
1274
          code = normalEOF;
 
1275
          break;
 
1276
        case NOPE:
 
1277
        default:
 
1278
          code = parseError;
 
1279
          break;
 
1280
        } /* switch */
 
1281
      
 
1282
      if ((error != earlyEOF) && (code < 0)) error = code;
 
1283
      
 
1284
    } /* while */
 
1285
    
 
1286
    if ((error != earlyEOF) && (code < 0)) error = code;
 
1287
    
 
1288
    if (ident != NULL) { free(ident); ident = NULL; }
 
1289
        
 
1290
    return(error);
 
1291
  
 
1292
} /* parseFile */