/*
 * (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved.
 *
 * This file may be freely copied and redistributed as long as:
 *   1) This entire notice continues to be included in the file, 
 *   2) If the file has been modified in any way, a notice of such
 *      modification is conspicuously indicated.
 *
 * PostScript, Display PostScript, and Adobe are registered trademarks of
 * Adobe Systems Incorporated.
 * 
 * ************************************************************************
 * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
 * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
 * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR 
 * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY 
 * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION, 
 * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 * ************************************************************************
 */

/*  parseAFMclient.c
 *
 *  This file is an example of how an application might use the provided
 *  AFM Parser (parseAFM.c).
 *
 *  In a nutshell, the client of the parser (like this file) chooses
 *  the AFM File that it wishes to have parsed, opens the file for 
 *  reading (and does any/all error handling associated with that task),
 *  and passes the resulting file pointer to the procedure "parseFile"
 *  (in parseAFM.c). In addition to the file pointer, the client also
 *  needs to pass a pointer to a FontInfo record type (for which storage
 *  will be allocated and data filled in), and a mask representing which
 *  sections of the AFM should be saved in the FontInfo record.
 *
 *  In the procedure "main", the mask is built from command line switches, 
 *  but your application, of course, can set that mask any way you prefer.
 *  "main" then calls the "parseFile" procedure (of parseAFM.c) to do the
 *  grunt work, and checks the error codes upon "parseFile"'s return.
 *
 *  The rest of this sample application is a collection of print routines 
 *  that show how to reference each of the sections of data and a 
 *  "freeStorage" routine (that many unix programmers may feel they 
 *  don't need but is included for portability to other systems that do 
 *  need to manage storage). The print procedures are there just to
 *  give meaning to this application, and hopefully your application
 *  will use the data collected from the AFM file in a more useful way.
 *  
 * History:
 *	original: DSM  Thu Oct 20 17:39:59 PDT 1988
 *  modified: DSM  Mon Jul  3 14:17:50 PDT 1989
 *    - added 'storageProblem' check in main
 */

#include <stdio.h>
#include "parseAFM.h"


/*************************** GLOBALS ***************************/
FontInfo *fi;
FLAGS myflags = 0;
  

/*************************** printGlobals **********************/

printGlobals()
{
    printf("\nThis AFM is of Version %s\n", fi->gfi->afmVersion);
    printf("The font name is %s\n", fi->gfi->fontName);
    printf("The full name is %s\n", fi->gfi->fullName);
    printf("The family name is %s\n", fi->gfi->familyName);
    printf("The weight is %s\n", fi->gfi->weight);
    printf("Italic Angle is %3.1f\n", fi->gfi->italicAngle);
    if (fi->gfi->isFixedPitch)
        printf("This font IS fixed-pitch\n");
    else
        printf("This font is NOT fixed-pitch\n");
    printf("Underline position is %d\n", fi->gfi->underlinePosition);
    printf("Underline thickness is %d\n", fi->gfi->underlineThickness);
    printf("Version is %s\n", fi->gfi->version);
    printf("FontBBox is [%d, %d, %d, %d]\n", 
        fi->gfi->fontBBox.llx, fi->gfi->fontBBox.lly, 
        fi->gfi->fontBBox.urx, fi->gfi->fontBBox.ury);
    printf("%s\n", fi->gfi->notice);
    printf("Encoding Scheme is %s\n", fi->gfi->encodingScheme);
    printf("CapHeight is %d\n", fi->gfi->capHeight);
    printf("XHeight is %d\n", fi->gfi->xHeight);
    printf("Descender is %d\n", fi->gfi->descender);
    printf("Ascender is %d\n\n", fi->gfi->ascender);
    
} /* printGlobals */


/*************************** printCharWidths *********************/
printCharWidths()
{
    int i = 0;
    printf("Here come some character widths ...\n");
    for (i = 0; i < 256; ++i)
        printf("  code: %3d   width: %4d\n", i, fi->cwi[i]);
    printf("\n");
 
} /* printCharWidths */


/*************************** printAllCharMetrics *****************/
printAllCharMetrics()
{
    int i = 0;
    CharMetricInfo *temp = fi->cmi;
    Ligature *node = temp->ligs;
  
    printf("Here come some character metrics ...\n");
    for (i = 0; i < fi->numOfChars; ++i)
    {
        printf(
          "  code: %3d   x-width: %4d   y-width: %4d   name: %-12s   bbox: [%d, %d, %d, %d]\n",
            temp->code, temp->wx, temp->wy, temp->name, temp->charBBox.llx, 
            temp->charBBox.lly, temp->charBBox.urx, temp->charBBox.ury);
        for (node = temp->ligs; node != NULL; node = node->next)
        {
            printf("      Ligatures:  successor: %s  ligature: %s\n", 
                node->succ, node->lig);
        }
        temp++;
    } /* for */
    printf("\n");

} /* printAllCharMetrics */


/*************************** printKernPairData ******************/
printKernPairData()
{
    int i = 0;
    PairKernData *pkd = fi->pkd;
    
    if (fi->numOfPairs != 0)
    {
        printf("Here comes the pair kerning data ...\n");
        for (i = 0; i < fi->numOfPairs; ++i)
        printf(
          "  char 1: %-12s   char 2: %-12s   x-amount: %d    y-amount: %d\n", 
            pkd[i].name1, pkd[i].name2, pkd[i].xamt, pkd[i].yamt);
    }
    else printf("There isn't any pair kerning data.\n");
    printf("\n");
    
} /* printKernPairData */


/*************************** printKernTrackData *******************/
printKernTrackData()
{
    int i = 0;
    TrackKernData *tkd = fi->tkd;
    
    if (fi->numOfTracks != 0)
    {
        printf("Here comes the track kerning data ...\n");
        for (i = 0; i < fi->numOfTracks; ++i)
            printf(
              "  degree: %d   min-pt: %5.2f   min-kern: %5.2f   max-pt: %5.2f   max-kern: %5.2f\n", 
                tkd[i].degree, tkd[i].minPtSize, tkd[i].minKernAmt, 
                tkd[i].maxPtSize, tkd[i].maxKernAmt);
    }
    else printf("There isn't any track kerning data.\n");
    printf("\n");
    
} /* printKernTrackData */


/*************************** printCompCharData ********************/
printCompCharData()
{
    int i = 0, j = 0;
    CompCharData *ccd = fi->ccd;
    
    if (fi->numOfComps != 0)
    {
        printf("Here comes the composite character data ...\n");
        for (i = 0; i < fi->numOfComps; ++i)
        {
            printf("  comp char: %-12s   pieces: %d\n", 
                ccd[i].ccName, ccd[i].numOfPieces);
            for (j = 0; j < ccd[i].numOfPieces; ++j)
                printf(
                  "      Part # %d   Name: %-12s   Delta X: %d Delta Y: %d\n", 
                    (j + 1), ccd[i].pieces[j].pccName, 
                    ccd[i].pieces[j].deltax, ccd[i].pieces[j].deltay);
        }
    }
    else printf("There aren't any composites characters. \n");
    printf("\n");
    
} /* printCompCharData */



/*************************** freeStorage ***********************/

freeStorage()
{
    if (fi != NULL)
    {
        if (fi->gfi != NULL)
        { 
            free(fi->gfi->afmVersion); fi->gfi->afmVersion = NULL;
            free(fi->gfi->fontName); fi->gfi->fontName = NULL;
            free(fi->gfi->fullName); fi->gfi->fullName = NULL;
            free(fi->gfi->familyName); fi->gfi->familyName = NULL;
            free(fi->gfi->weight); fi->gfi->weight = NULL;
            free(fi->gfi->version); fi->gfi->version = NULL;
            free(fi->gfi->notice); fi->gfi->notice = NULL;
            free(fi->gfi->encodingScheme); fi->gfi->encodingScheme = NULL;
            free(fi->gfi); fi->gfi = NULL;
        }
  
        if (fi->cwi != NULL)
        { free(fi->cwi); fi->cwi = NULL; }

        if (fi->cmi != NULL)
        { 
            int i = 0;
            CharMetricInfo *temp = fi->cmi;
            Ligature *node = temp->ligs;
            
            for (i = 0; i < fi->numOfChars; ++i)
            {
                for (node = temp->ligs; node != NULL; node = node->next)
                {
                    free(node->succ); node->succ = NULL;
                    free(node->lig); node->lig = NULL;
                }
                
                free(temp->name); temp->name = NULL;
                temp++;
            }
            
            free(fi->cmi); fi->cmi = NULL;
        }

        if (fi->tkd != NULL)
        { free(fi->tkd); fi->tkd = NULL; }
  
        if (fi->pkd != NULL)
        { 
            free(fi->pkd->name1); fi->pkd->name1 = NULL;
            free(fi->pkd->name2); fi->pkd->name2 = NULL;
            free(fi->pkd); fi->pkd = NULL;
        }

        if (fi->ccd != NULL)
        { 
            int i = 0, j = 0;
    	    CompCharData *ccd = fi->ccd;
    	    
    	    for (i = 0; i < fi->numOfComps; ++i)
    	    {
    	        for (j = 0; j < ccd[i].numOfPieces; ++j)
    	        {
    	            free(ccd[i].pieces[j].pccName); 
    	            ccd[i].pieces[j].pccName = NULL;
    	        }
    	        
    	        free(ccd[i].ccName); ccd[i].ccName = NULL;
    	    }
    
            free(fi->ccd); fi->ccd = NULL;
        }
        
        free(fi);

    } /* if */ 
  
} /* freeStorage */


/*************************** printValues **************************/

printValues()
{
    if ((myflags & P_G) && (fi->gfi != NULL)) printGlobals();
    if ((myflags & (P_M ^ P_W)) && (fi->cmi != NULL)) printAllCharMetrics();
    else if ((myflags & P_W) && (fi->cwi != NULL)) printCharWidths();
    if ((myflags & P_P) && (fi->pkd != NULL)) printKernPairData();
    if ((myflags & P_T) && (fi->tkd != NULL)) printKernTrackData(); 
    if ((myflags & P_C) && (fi->ccd != NULL)) printCompCharData();
    
} /* printValues */



/*************************** main *********************************/

main (argc, argv) 
  int argc; 
  char **argv;
{
    char *filename, *prog = *argv;
    FILE *fp;
    
    ++argv; --argc;
    while (argc > 0 && **argv == '-')
        {
        switch ((*argv)[1])
            {
            case 'g':   /* save Globals */
                myflags |= P_G; 
                break;
            case 'w':   /* save Char Widths */
                myflags |= P_W; 
                break;
	   		case 'm':   /* save All Char Metrics */
	        	myflags |= P_M; 
	        	break;
            case 'p':   /* save Kern Pair Data */
                myflags |= P_P; 
                break;
            case 't':   /* save Kern Track Data */
                myflags |= P_T; 
                break;
	    	case 'c':   /* save Comp Char Data */
	       	 	myflags |= P_C; 
	       		break;
            default: 
                printf("    usage: parseAFM [-g] [-w] [-p] [-t] [-c] [AFM File]\nOR: usage: parseAFM [-g] [-m] [-p] [-t] [-c] [AFM File]\n");
                exit(0);
            }
        ++argv; --argc;
        }
    
    if (!argc)
    {
        printf("    usage: parseAFM [-g] [-w] [-p] [-t] [-c] [AFM File]\nOR: usage: parseAFM [-g] [-m] [-p] [-t] [-c] [AFM File]\n");
        exit(0);
    }
    else 
        filename = *argv;

    if (!filename[0]) 
    {
	printf ("*** ERROR: can't open. filename is missing.\n",
		filename );
	return 0;
    }
       
    fp = fopen(filename, "r" );
    if (fp == NULL) 
    {
	printf ("*** ERROR: can't find: %s\n", filename );
        exit(1);
    }
    
    switch (parseFile(fp, &fi, myflags))
    {
        case parseError:
            printf("*** ERROR: problem in parsing the AFM File.\n");
        case ok:
            fclose(fp);
            printValues();
            freeStorage();
            break;
        case earlyEOF:
            printf("The AFM File ended prematurely.\n");
            break;
        case storageProblem:
            printf("*** ERROR: problem allocating storage.\n");
            break;
        default:
            break;
    }
    
} /* main */
