/*  %kw # %v    %n    %d    %t # */
/* Version # 2    BDF2META.C    12-Jan-94    16:17:04 # */
/* ***********************************************************
   METAGRAPHICS SOFTWARE CORPORATION (c) 1988      
   FILE: BDF2META.C                                
   Converts fonts from BDF format to MetaWINDOW bitmap fonts            
************************************************************** */

#define make_exe    1         /* define for stand alone program */
#define debug       1      

#include "stdio.h"
#include "stdlib.h"
#include "ctype.h"
#include "string.h"
#include "conio.h"

/* determine if running 32 bit compiler */
#ifdef MetawareC
#define __386__      /* already defined for Watcom C 386 */
#endif

/* need farmalloc and farfree ? */
#ifndef __386__
#include <alloc.h>
#else
#define farmalloc malloc
#define farfree free
#endif

#include "metawndo.h"      /* master MetaWINDOW include file */

/* special stack size declaration if using Turbo or Borland C++ */
#ifdef      TurboC
extern unsigned _stklen = 14336U;  /* stack size 14K */
#endif


/* error code defines */
#define ER_INP_NAME -100      /* can't open input file name */
#define ER_FORMAT   -101      /* input file is not in proper format */
#define ER_TMCHARS  -102      /* more characters defines that stated */
#define ER_BMAP     -103      /* character bitmap info bad format */
#define ER_SIZE     -104      /* font bitmap size larger than stated */
#define ER_TOOBIG   -105      /* font record would exceed 64K */
#define ER_NOMEM    -106      /* not enough memory to allocate font record */
#define ER_OUT_NAME -107      /* can't open output file name */
#define ER_WRITE    -108      /* error writing file */
#define ER_DEFAULT  -109      /* default char not included in set */
#define ER_PIXBIT   -110      /* not single bit per pixel */
#define ER_PIXPLANE -111      /* not single plane */
#define ER_BITMAPSZ -112      /* bitmap width exceeds 32767 pixels */

/* inform function codes */
#define IN_SAY           1         /* print string */
#define IN_CHAR_CNT      2         /* character count */
#define IN_CHAR_NUM      3         /* character encoding */
#define IN_LINE          4         /* line number */
#define IN_WARN          5         /* warning */

#define OK                    0
#define ERROR                 -1
#define MAX_LINE              255
#define MAX_STRING            40
#define FONT_VER              0x22     /* should be ver 2.2 */ 

/* bdf file keywords */
char *key_words[] =
{
   "STARTCHAR",           
   "ENCODING",
   "SWIDTH",
   "DWIDTH",
   "BBX",
   "BITMAP",
   "ENDCHAR",
   "STARTFONT",           
   "COMMENT",
   "ENDFONT",
   "FONT",
   "SIZE",
   "FONTBOUNDINGBOX",     
   "STARTPROPERTIES",     
   "FONT_DESCENT",
   "FONT_ASCENT",
   "DEFAULT_CHAR",
   "COPYRIGHT",
   "OWNERSHIP",
   "ENDPROPERTIES",
   "CHARS"               
};

#define   STARTCHAR           0           
#define   ENCODING            1
#define   SWIDTH              2
#define   DWIDTH              3
#define   BBX                 4
#define   BITMAP              5
#define   ENDCHAR             6
#define   STARTFONT           7 
#define   COMMENT             8
#define   ENDFONT             9
#define   FONT                10
#define   SIZE                11
#define   FONTBOUNDINGBOX     12   
#define   STARTPROPERTIES     13   
#define   FONT_DESCENT        14
#define   FONT_ASCENT         15
#define   DEFAULT_CHAR        16
#define   COPYRIGHT           17
#define   OWNERSHIP           18
#define   ENDPROPERTIES       19
#define   CHARS               20             

/* bdf file global info */
struct bdf_global_info {
     char      font_name[MAX_STRING];
     char      face_name[MAX_STRING];
     int       total_chars;
     int       point_size;
     point     bbx;
     point     origin;
     int       ascent;
     int       descent;
     int       default_char;
     char      copyright[MAX_STRING];
     char      info[MAX_STRING];
     char      date[MAX_STRING];
     int       max;
     int       min;
     int       icon;
     point     res;
} bdf;

/* bdf file character info */
struct bdf_char_info {
     char           name[MAX_STRING];
     int            num;
     unsigned char  width;
     point          bbx;
     point          origin;
};

/* pointers to tables in the font record */
struct font_rec_ptrs {
     fontRcd      *hd;      /* font header */
     grafMap      *bm;      /* bit map */
     Byte *       *rtbl;    /* row table */
     short        *loc;     /* location table */
     ofswid       *ofwd;    /* offset/width table */
     char         *str[5];  /* misc strings */
     Byte         *fnt;     /* font table */
} frec;

/* pointers for the port on entry, the port we will use */
grafPort *oldport, myport;

/* pointer to an image structure where we will build font chars */
imageHeader *font_image;


/* function definitions */
void main ( int, char *[] );
int bdf2meta( char *, char *, void (*inform )( int, void * ) );
int get_global_info( FILE *, void (*inform)( int, void * ) );
int get_char_info( FILE *, void (*inform)( int, void * ) );
void init_font_rec( fontRcd *, long int );
void init_misc_str( void );

int bdf2meta( char * inname, char *outname, void (*inform )( int, void * ) )

/*
Convert file name 'inname' from bdf format to metawindow format and write
to file name 'outname'.
Returns OK if ok, error code if had problems.
*/
{
     FILE *input, *output;
     int i, rowbytes, *p;
     unsigned int total_psbl;
     size_t fontPages, filePages;
     fontRcd *fnt;
     dirRec dir_info;
     long int font_rec_size, l;
#ifdef __386__
     Byte *hp;
#else
     Byte huge *hp;
#endif

     /* open input file */
     input = fopen( inname, "rb" );
     if( input == NULL )
          return ER_INP_NAME;

     /* open output file */
     output = fopen( outname, "wb" );
     if( output == NULL )
          return ER_OUT_NAME;

     /* get the input file date */
     FileQuery( inname, &dir_info, 1 );
     sprintf( bdf.date, "%d/%d/%d", (dir_info.fileDate >> 5) & 0x0F,
                                     dir_info.fileDate & 0x1F,
                                  ( (dir_info.fileDate >> 9) & 0x7F ) + 80 );

      /* scan the file for global info */
     if( i = get_global_info( input, inform ) )
          return i;

     /*
     calculate the total number of possible character entries
     note that this may be more than total_chars if some characters
     are missing from the sequence of the font. Also, we must add an
     additional entry for the terminating location
     */
     total_psbl = bdf.max - bdf.min + 2;

     /* find the relative table offsets and required font record size */
     frec.hd    = (fontRcd *) 0;
     frec.bm    = (grafMap *) ( (long) frec.hd   + (long) sizeof( fontRcd ) );
//     frec.rtbl  = (Byte **)     ( (long) frec.bm   + (long) sizeof( grafMap ) ); 
     frec.rtbl  = (Byte **)     ( (long) frec.bm   + 512L ); 
     frec.loc   = (short *)      ( (long) frec.rtbl + (long) (bdf.bbx.Y * sizeof( Byte * ) ) );
     frec.ofwd  = (ofswid *)     ( (long) frec.loc  + (long) (total_psbl * sizeof( short ) ) );
     frec.str[0] = ( char *)     ( (long) frec.ofwd + (long) (total_psbl * sizeof( short ) ) );
     frec.str[1] = ( char *)     ( (long) frec.str[0] + (long) MAX_STRING );
     frec.str[2] = ( char *)     ( (long) frec.str[1] + (long) MAX_STRING );
     frec.str[3] = ( char *)     ( (long) frec.str[2] + (long) MAX_STRING );
     frec.str[4] = ( char *)     ( (long) frec.str[3] + (long) MAX_STRING );
     frec.fnt   = (Byte *)       ( (long) frec.str[4] + (long) MAX_STRING );
     rowbytes =  (bdf.total_chars * bdf.bbx.X + 7 ) / 8;
     font_rec_size = (long) frec.fnt + (long) rowbytes * (long) bdf.bbx.Y * (long) sizeof( Byte );

#ifdef debug
     printf("font header size = %ld\n", (long) frec.fnt );
     printf("font record size = %ld\n", font_rec_size );
     printf("font bitmap width = %u\n", rowbytes * 8 );
#endif

#ifndef __386__

     /* check header < 64K (only for fonts used in non 386) */
     if( (long) frec.fnt > 0xFFFF )
          return ER_TOOBIG;
#endif

     /* check bitmap < 32767 pixels wide */
     if( rowbytes >= 4096 )
          return ER_BITMAPSZ;


     /* get a chunk of memory for the font record */
     fnt = (fontRcd *) farmalloc( font_rec_size );
     if( fnt == NULL )
          return ER_NOMEM;

     /* clear out the memory */ 
#ifdef __386__
     hp = ( Byte *) fnt;
#else
     hp = ( Byte huge *) fnt;
#endif
     for( l = 0; l < font_rec_size; l++ )
         *hp++ = 0;      

     /* initialize the font record (with relative table offsets) */
#ifdef __386__
     init_font_rec( fnt, font_rec_size );       
#else
     init_font_rec( fnt, (font_rec_size + 255) & 0xFFFFFF00 );       
#endif

     /* change relative font record table offsets to absolute */
     /* so we can access them now */
     frec.hd    = fnt;
     frec.bm    = (grafMap *) ( (long) fnt + (long) frec.bm );
     frec.rtbl  = (Byte **)     ( (long) fnt + (long) frec.rtbl );
     frec.loc   = (short *)      ( (long) fnt + (long) frec.loc );
     frec.ofwd  = (ofswid *)     ( (long) fnt + (long) frec.ofwd );
     frec.str[0] = ( char *)     ( (long) fnt + (long) frec.str[0] );
     frec.str[1] = ( char *)     ( (long) fnt + (long) frec.str[1] );
     frec.str[2] = ( char *)     ( (long) fnt + (long) frec.str[2] );
     frec.str[3] = ( char *)     ( (long) fnt + (long) frec.str[3] );
     frec.str[4] = ( char *)     ( (long) fnt + (long) frec.str[4] );
     frec.fnt   = (Byte *)       ( (long) fnt + (long) frec.fnt );

     /* initialize bitmap and rowtable  */
     frec.bm->pixWidth = bdf.total_chars * bdf.bbx.X;
     frec.bm->pixHeight = bdf.bbx.Y;
     frec.bm->pixBits = 1;
     frec.bm->pixPlanes = 1;
     frec.bm->pixBytes = (short) rowbytes;
     frec.bm->pixResX = bdf.res.X;
     frec.bm->pixResY = bdf.res.Y;
     frec.bm->devTech = dtMono;

     if( InitBitmap( cUSER, frec.bm ) ) {
          free( fnt );
          fclose( input );
          fclose( output );
          return ER_NOMEM;
     }

     *frec.rtbl = frec.fnt;
     frec.bm->mapTable[0] = frec.rtbl;
     InitRowTable( frec.bm, 0, 0, 0 );

     /* initialize offset/width and location tables */
     p = (int *)(frec.ofwd);

     for( i = 0; i < total_psbl; i++ ) {
          *p++ = -1;
          frec.loc[i] = -1;
     }

     /* initialize strings */
     /* font notice */
     strcpy( frec.str[0], bdf.copyright );
     /* font supplier */
     strcpy( frec.str[1], "Converted from .BDF file" );
     /* font author */
     strcpy( frec.str[2], "" );
     /* font info */
     strcpy( frec.str[3], bdf.info );
     /* font date */
     strcpy( frec.str[4], bdf.date );

     /* get an image structure to build font chars in */
     rowbytes = ( frec.hd->chWidth + 7 ) / 8;
     font_image = malloc( frec.hd->chHeight * rowbytes + sizeof( imageHeader ) );


     if( font_image == NULL  ) {
          farfree( fnt );
          free( font_image );
          fclose( input );
          fclose( output );
          return ER_NOMEM;
     }

     /* setup our port */
     GetPort( &oldport );
     InitPort( &myport );
     PortBitmap( frec.bm );
     PortSize( frec.bm->pixWidth, frec.bm->pixHeight );
     ClipRect( &(myport.portRect) );


     /* bdf origins in lower left */
     PortOrigin( False );

     /* put back to old port for now */
     SetPort( oldport );

     /* initialize the image structure */
     font_image->imWidth = frec.hd->chWidth;
     font_image->imHeight = frec.hd->chHeight;
     font_image->imAlign = 0;
     font_image->imRowBytes = rowbytes;
     font_image->imBits = 1;
     font_image->imPlanes = 1;

     /* re-position the file to beginning */
     rewind( input );

     /* scan for character info */
     if( i = get_char_info( input, inform ) ) {
          /* had an error */
          farfree( fnt );
          free( font_image );
          fclose( input );
          fclose( output );
          return i;
     }

#ifdef __386__
     fontPages = font_rec_size;
     filePages = fwrite( fnt, 1, fontPages, output );
#else
     fontPages =(size_t) ( (font_rec_size + 255) / 256);
     filePages = fwrite( fnt, 256, (size_t) fontPages, output );
#endif

     /* close files */
     fclose( input );
     fclose( output );

     /* free memory */
     farfree( fnt );
     free( font_image );

     /* check for write error */
     if( fontPages != filePages )
          return ER_WRITE;

     return OK;

}


void init_font_rec( fontRcd *fnt, long int rec_size )
/*
This procedure initializes the font record using the global bdf information
and default values.
*/
{
     int i;

     /* initialize the fontheader */
     fnt->fontVer = FONT_VER;      
     fnt->fontRev =  0;       
     fnt->fontNameLen = (Byte) min( strlen(bdf.font_name), 15);   
          strncpy( fnt->fontBaseName, bdf.font_name, 15 );
     fnt->fontBaseName[15] = '\0';
     strncpy( fnt->fontSuffix1, bdf.face_name, 9 );
          fnt->fontSuffix1[9]= '\0';
     fnt->fontSuffix2[0] = '\0';
     fnt->fontSuffix3[0] = '\0';
     fnt->fontFacing = 0;    
     strcpy( fnt->fontSign, "METAFONT");   
     fnt->fontSize = rec_size;      
     fnt->fontMin = bdf.min;       
     fnt->fontMax = bdf.max;       
     fnt->fontWeight = 80;    
     fnt->fontCoding = 0;    
     fnt->fontPtSize = bdf.point_size;    
     fnt->fontfamily = bdf.icon;
     fnt->fontStyle = 0;    
     fnt->fontFlags = 0x00;     
     fnt->fontColor[1] = Black; fnt->fontColor[0] = White;  
     fnt->minChar = (char) (bdf.min & 0xFF);       
     fnt->maxChar = (char) (bdf.max & 0xFF);       
     fnt->chWidth = bdf.bbx.X;       
     fnt->chHeight = bdf.bbx.Y;      
     fnt->chKern = bdf.bbx.X;        
     fnt->ascent = bdf.ascent;        
     fnt->descent = bdf.descent;       
     fnt->lnSpacing = bdf.bbx.Y + 2;       
     fnt->chBad = (bdf.default_char == -1) ? bdf.min : bdf.default_char;         
     fnt->chCenter[0] = (bdf.origin.X < 0) ? bdf.bbx.X + bdf.origin.X : bdf.origin.X;   
     fnt->chCenter[1] = (bdf.origin.Y < 0) ? bdf.bbx.Y + bdf.origin.Y : bdf.origin.Y;   
     fnt->chAngle = -200;       
     fnt->chUnder = 1;       
     fnt->chScore = 1;       
     fnt->locTbl = (long) frec.loc;        
     fnt->ofwdTbl = (long) frec.ofwd;       
     fnt->kernTbl = NULL;       
     fnt->sizeTbl = NULL;       
     fnt->grafMapTbl = (long) frec.bm;     
     fnt->rowTbl = (long) frec.rtbl;        
     fnt->fontTbl = (long) frec.fnt;       
     fnt->fontNotice = (long) frec.str[0];
     fnt->fontSupplier = (long) frec.str[1];  
     fnt->fontAuthor = (long) frec.str[2];    
     fnt->fontInfo = (long) frec.str[3];      
     fnt->fontDate = (long) frec.str[4];

     /* these fields are for precision fonts only */
     fnt->fontSpacing.fr   = fnt->fontSpacing.wh   = 0;   
     fnt->fontLowHgt.fr    = fnt->fontLowHgt.wh    = 0;    
     fnt->fontCapHgt.fr    = fnt->fontCapHgt.wh    = 0;    
     fnt->fontAscent.fr    = fnt->fontAscent.wh    = 0;    
     fnt->fontDescent.fr   = fnt->fontDescent.wh   = 0;   
     fnt->fontMaxWid.fr    = fnt->fontMaxWid.wh    = 0;    
     fnt->fontAvgWid.fr    = fnt->fontAvgWid.wh    = 0;    
     fnt->fontEmWid.fr     =  fnt->fontEmWid.wh    = 0;     
     for( i = 0; i < 16; i++ ) 
          fnt->offwidTbl[i] = fnt->ofwdTbl; 

}



int find_keyword( char **, char *[], int);
void get_str( char *, char *, int );
int get_bmap_info( FILE *, char *, struct bdf_char_info * );
short store_char_info( short, struct bdf_char_info * );
void init_char_info( struct bdf_char_info *);
void clean_up( short );


int get_global_info( FILE *input, void (*inform)( int, void * ) )
/*
This function scans the entire file 'input' for global information,
and places it in the structure bdf.
It returns OK if 'input' is a valid format, ERROR if not.
*/
{
     int i, j, table_size, done, valid;
     int  enc, in_char_def,  default_ok;
     char buf[MAX_LINE], *p, *q;
     point bbx, origin;
     long line_num;

     table_size = sizeof( key_words ) / sizeof( char * );
     done = valid = in_char_def = default_ok = False;
     line_num = 0;

     if( inform )
          (*inform)( IN_SAY, "Scanning file for global font information" );

     /* initialize the global bdf info */
     bdf.font_name[0] = '\0';
     bdf.face_name[0] = '\0';
     bdf.total_chars = 0;
     bdf.point_size = 0;
     bdf.bbx.X = bdf.bbx.Y = 0;
     bdf.origin.X = bdf.origin.Y = 0;
     bdf.ascent = 0;
     bdf.descent = 0;
     bdf.default_char = -1;
     bdf.copyright[0] = '\0';
     bdf.info[0] = '\0';
     bdf.min = 32767;
     bdf.max = 0;
     bdf.icon = False;

     while( !done ) {

          if( fgets( buf, MAX_LINE, input) == NULL )
               break;

          line_num++;
          if( inform )
               (*inform)( IN_LINE, &line_num );


          p = buf;
          i = find_keyword( &p, key_words, table_size );

          switch( i ) {

               case STARTFONT:
                    valid = True;
                    break;

               case COMMENT:
                    get_str( bdf.info, p, MAX_STRING );
                    break;

               case FONT:
                    /* find a hyphen, if any, and make that a face name string */
                    q = p;
                    while( *q && *q != '-' )
                         q++;
                    if( *q == '-' ) {
                         *q++ = '\0';
                         get_str( bdf.face_name, q, MAX_STRING );
                    }

                    get_str( bdf.font_name, p, MAX_STRING );
                    break;

               case SIZE: 
                    sscanf( p, "%d%d%d", &bdf.point_size, &bdf.res.X, &bdf.res.Y );
                    break;

               case FONTBOUNDINGBOX:
                    sscanf( p, "%d%d%d%d", &bdf.bbx.X, &bdf.bbx.Y,
                                           &bdf.origin.X, &bdf.origin.Y );
                    break;

               case STARTPROPERTIES:    
                    break;

               case FONT_DESCENT: 
                    sscanf( p, "%d", &bdf.descent );
                    break;

               case FONT_ASCENT:        
                    sscanf( p, "%d", &bdf.ascent );
                    break;

               case DEFAULT_CHAR:       
                    sscanf( p, "%d", &bdf.default_char );
                    break;

               case OWNERSHIP:          
               case COPYRIGHT:        
                    get_str( bdf.copyright, p, MAX_STRING );
                    break;

               case ENDPROPERTIES:
                    break;

               case CHARS:              
                    sscanf( p, "%d", &bdf.total_chars );
                    break;

               case ENDFONT:            
                    done = True;
                    break;

               case STARTCHAR:
                    in_char_def = True;
                    break;

               case ENDCHAR:
                    in_char_def = False;
                    break;

               case ENCODING:    
                    enc = bdf.min;
                    j = 0;       
                    sscanf( p, "%d %d", &enc, &j );

                    if( enc < 0 ) {
                         enc = j;
                         bdf.icon = True;
                    }

                    if( enc > bdf.max )
                         bdf.max = enc;
                    if( enc < bdf.min )
                         bdf.min = enc;

                    if( enc == bdf.default_char )
                         default_ok = True;

                    break;

               case BBX:
                    sscanf( p, "%d%d%d%d", &bbx.X, &bbx.Y, &origin.X, &origin.Y );
                    if( bbx.X > bdf.bbx.X ) {
                         bdf.bbx.X = bbx.X;
                         bdf.origin.X = origin.X;
                    }
                    if( bbx.Y > bdf.bbx.Y ) {
                         bdf.bbx.Y = bbx.Y;
                         bdf.origin.Y = origin.Y;
                    }
                    break;


               case SWIDTH:             
               case DWIDTH:             
               case BITMAP:
#ifdef debug
                    if( !in_char_def )
                         printf("Keyword %d out of sequence, ignored\n%s\n",i,buf);
#endif
                    break;

               default:
                    if( in_char_def )
                         break;
#ifdef debug
                    printf("Unknown keyword found - ignored\n%s\n",buf);
#endif
                    break;

          }    /* end of switch */

     }    /* end of while */

#ifdef debug
     /* print out the bdf info */
     printf("Font name = %s\n", bdf.font_name );
     printf("Face name = %s\n", bdf.face_name );
     printf("Total characters = %d\n", bdf.total_chars );
     printf("Point size = %d\n", bdf.point_size );
     printf("Bounding box = %dx%d Origin = %d,%d\n", bdf.bbx.X, bdf.bbx.Y,
                                                     bdf.origin.X, bdf.origin.Y );

     printf("Ascent = %d descent = %d\n", bdf.ascent, bdf.descent );
     printf("Default Character = " );
     if( bdf.default_char == -1 )
          printf( "none\n" );
     else
          printf("0x%02x\n", bdf.default_char );
     printf("Copyright = %s\n", bdf.copyright );
     printf("Misc info = %s\n", bdf.info );
     printf("Min char value = 0x%x, max char value = 0x%x\n\n", bdf.min, bdf.max );
#endif

     if( !valid )
          return ER_FORMAT;

     /* if a default char WAS defined, but that char never appeared */
     if( bdf.default_char != -1 && !default_ok )
          return ER_DEFAULT;

     return OK;

}


int get_char_info( FILE *input, void (*inform)( int, void * ) )
/*
This function gets all the character information from the file 'input',
places it in the structure bdf_char, and calls store_char_info() for each
character.
It returns OK or an error code.
*/
{
     int i, j, num_chars, table_size, done;
     char buf[MAX_LINE], *p;
     short loc;
     struct bdf_char_info bdf_char;


     table_size = sizeof( key_words ) / sizeof( char * );
     done = False;
     num_chars = 0;
     loc = 0;

     init_char_info( &bdf_char );

     if( inform )
          (*inform)( IN_SAY, "Scanning file for font character information" );

     while( !done ) {

          if( fgets( buf, MAX_LINE, input) == NULL )
               break;

          p = buf;
          i = find_keyword( &p, key_words, table_size );

          switch( i ) {
          
               case ENDFONT:
                    done = True;
                    clean_up( loc );          
                    break;

               case STARTCHAR:
                    init_char_info( &bdf_char );
                    get_str( bdf_char.name, p, MAX_STRING );
                    if( ++num_chars > bdf.total_chars )
                         return ER_TMCHARS;
                    if( inform ) 
                         (*inform)( IN_CHAR_CNT, &num_chars );
                    break;

               case ENCODING:  
                    sscanf( p, "%d %d", &bdf_char.num, &j );
                    if( bdf_char.num < 0 ) 
                         bdf_char.num = j;
                         
                    if( inform ) 
                         (*inform)( IN_CHAR_NUM, &bdf_char.num ); 
                    break;

               case SWIDTH: 
                    break;

               case DWIDTH:
                    sscanf( p, "%d", &bdf_char.width );
                    break;

               case BBX:
                    sscanf( p, "%d%d%d%d", &bdf_char.bbx.X, &bdf_char.bbx.Y,
                                        &bdf_char.origin.X, &bdf_char.origin.Y );
                    break;

               case BITMAP:
                    if( get_bmap_info( input, buf, &bdf_char ) )
                         return ER_BMAP;
                    break;

               case ENDCHAR:
                    /* position location index to next bit after this char */
                    loc = store_char_info( loc, &bdf_char );
                    break;

               case STARTFONT:
               case COMMENT:
               case FONT:
               case SIZE: 
               case FONTBOUNDINGBOX:
               case STARTPROPERTIES:    
               case FONT_DESCENT: 
               case FONT_ASCENT:        
               case DEFAULT_CHAR:       
               case OWNERSHIP:          
               case COPYRIGHT:        
               case ENDPROPERTIES:
               case CHARS:              
                    break;

               default:
#ifdef debug
                    printf("No keyword found - ignored\n%s\n",buf);
#endif
                    break;

          }    /* end of switch */

     }    /* end of while */

     return OK;
}

int find_keyword( char **buf_pntr, char *kwrd_tbl[], int tbl_size )

/*
This function scans the buffer at buf_pntr looking for any keyword in the
kwrd_tbl table. If one is found, the key word code is returned, and buf_pntr
will point to a pointer, that points to the next character after the keyword.
If no keyword is found ERROR is returned.
*/
{

     int kwrd;
     char *k, *b, *buffer;


     /* for each keyword in the key_word table */
     for( kwrd = 0; kwrd < tbl_size; kwrd++ ) {

          /* start at the top of the buffer */
          buffer = *buf_pntr;

          /* while there is still buffer to process */
          while( *buffer ) {

               k = kwrd_tbl[ kwrd ];
               b = buffer;

               /* do they compare ? */
               while( *k && *b && *k ==  toupper(*b & 0x7F) ) {
                    k++;
                    b++;
               }
               if( *k == '\0' && ( *b == '\0' || *b == ' '|| *b == '\n' || *b == '\r' || *b == '\t' ) ) {
                    *buf_pntr = b;
                    return kwrd;
               }

               /* try next position in buffer */
               buffer++;
          }
     }

     /* no keywords found */
     return ERROR;

}


void get_str( char *str1, char *str2, int len )
/*
This procedure  gets upto len characters from str2 and puts them at str2.
Initial spaces are skipped, and new line or return characters are not
included.
*/
{
     len -= 1;      /* save one for the null */

     /* skip any lnspacing spaces */
     while( *str2 == ' ')  {
          str2++;
          len--;
     }

     /* copy string upto len, don't copy newlines or returns */
     while( *str2 && len-- > 0 ) {
          if( *str2 == '\n' || *str2 == '\r' )
               str2++;
          else
               *str1++ = *str2++ & 0x7F;
     }

     *str1 = '\0';
}

void init_char_info( struct bdf_char_info *char_info )
{
     char_info->name[0] = '\0';
     char_info->num = 0;
     char_info->width = 0;
     char_info->bbx.X = char_info->bbx.Y = 0;
     char_info->origin.X = char_info->origin.Y = 0;
}



int get_bmap_info( FILE *input, char *buf, struct bdf_char_info *char_info)

/*
This function gets the fonts bitmap information from file 'input' and places
it in the font_image image structure. It uses 'buf' for temp storage.
It returns OK or ER_BMAP if the file is not in the expected format.
*/
{
     int line, nibble, nib_num, eol;
     char *image_data, *p, *r, c; 


     /* calculate address of image portion of the image record */
     image_data = (char *) font_image + sizeof( imageHeader );

     /* clear out the image data */
     p = image_data;
     for( line = 0; line < ( (bdf.bbx.X + 7) / 8  * bdf.bbx.Y ); line++ )
          *p++ = 0;     

     /* calculate the number of nibbles per line rounded to nearest byte */
     nib_num = (char_info->bbx.X + 7) / 8 * 2;

     /* get bitmap information and place in image record */
     for( line = 0; line < char_info->bbx.Y; line++ ) {

          r = fgets( buf, MAX_LINE, input);
          if( r == NULL  )
               return ER_BMAP;

          p = buf;

          eol = False;
          *image_data = 0;

          /* get nibbles from left to right */
          for( nibble = 0; nibble < nib_num; nibble++ ) {

               if( *p == '\0' )
                    eol = True;

               if( isxdigit( *p ) && !eol ) {

                    /* convert from ascii */
                    c = toupper( *p );
                    c =  ( ( c < 'A' ) ? c - 0x30 : c - 0x37 );
               }
               else  
                    /* somethings bogus, just zero it out */
                    c = 0;

               p++;
          
               /* pack into a byte */
               if( nibble & 0x01  )      
                    *image_data++ |= c;      /* odd nibbles */
               else
                    *image_data = c << 4;    /* even nibbles */

          }
     }

     return OK;
}

short store_char_info( short location, struct bdf_char_info *char_info )
/*
Store the character info into the appropriate tables and font bitmap.
The characters bitmap will be stored based at 'location' pixels in the
X direction.
Returns the next 'location' available for the next character.
*/
{
     int index;
     rect r;
     int X, Y;

#ifdef debug1
     printf("\nCharacter name = \"%s\"\n", char_info->name );
     printf("Encoding = 0x%x\n", char_info->num );
     printf("Width = %d\n", char_info->width );
     printf("Bounding box = %dx%d, origin = %d,%d\n\n", char_info->bbx.X, char_info->bbx.Y,
                                                        char_info->origin.X, char_info->origin.Y );
#endif

     /* calculate an index into the tables */
     index = char_info->num - frec.hd->fontMin;

     frec.ofwd[ index ].wid = char_info->width;
     frec.ofwd[ index ].ofs = 0;
     frec.loc[ index ] =  location; 

     /* find the coordinates in the font bitmap to write the char bitmap  */
     X = location + ( 0 -  bdf.origin.X ) + char_info->origin.X;
     Y =            ( 0 -  bdf.origin.Y ) + char_info->origin.Y;

     /* write image record to font record bitmap */          
     SetRect( &r, X, Y, X + char_info->bbx.X, Y + char_info->bbx.Y );
     font_image->imWidth = char_info->bbx.X;
     font_image->imHeight = char_info->bbx.Y;
     font_image->imRowBytes = (char_info->bbx.X + 7 ) / 8;

     SetPort( &myport );
     WriteImage( &r, (image *)font_image );
     SetPort( oldport );

     /* return smaller of fonts bbx width or ending char width */
     location = min( location + bdf.bbx.X , r.Xmax + 1 );
     return location;
}

void clean_up( short location )
/* 
Put in the terminating location value. Also fill in any missing location
entries with the next valid location.
*/
{
     int i, last_index;


     /* calculate an index into the tables for the last char */
     last_index =  frec.hd->fontMax - frec.hd->fontMin + 1;

     /* put in terminating loctable entry */
     frec.loc[ last_index ] = location;
             
     /* duplicate location entries for undefined chars */
     for( i = last_index; i > 0; i-- ) {

          if( frec.loc[ i - 1 ] == -1 ) 
               frec.loc[ i - 1 ] = frec.loc[ i ]; 
     }

}

#ifdef make_exe

void print_me( int, void * );
void extend( char *, char *, int );

void
main (argc, argv)
int argc;
char *argv[];
{
     int i; 
     char *s, buf[80], *version, iname[15], oname[15];

#ifdef debug
     int j, line;
     FILE *fp;
     long fsize;
     rect scrnR;
     fontRcd *font;
#endif

     version = "BETA 1.3";

     if( argc < 3 ) {
          printf("Usage - BDF2META inname outname\n");
          printf("Converts:\nBitmap Distribution Format files to Metawindow font files.\n");
          printf("The file type .FNT or .BDF is assumed if not present.\n");
          printf("Version %s\n", version );
          exit(1);
     }


     i = InitGraphics( VGA640x480 );
     if( i ) {
          printf("Metawindow driver not loaded!\n");
          exit(1);
     }

     strncpy( iname, argv[1], 14 );
     iname[14] = '\0';
     extend( iname, ".bdf", False );
     strncpy( oname, argv[2], 14 );
     oname[14] = '\0';
     extend( oname, ".fnt", False );

     i = bdf2meta( iname, oname, print_me );

     printf("\n");

#ifdef debug

     if( i == OK ) {

          /* display the font */


          fp = fopen( oname, "rb" );

          fseek( fp, 0, SEEK_END );
          fsize = ftell( fp );
          fseek( fp, 0, SEEK_SET );

          font = (fontRcd *) farmalloc( fsize  );

#ifdef __386__
          fread( font, 1, (size_t) fsize, fp );
#else
          fread( font, 256, (size_t) (fsize / 256) + 1, fp );
#endif
          SetFont( font );

          SetDisplay( GrafPg0 );
          ScreenRect(&scrnR);
          EraseRect(&scrnR);

          TextFace( cProportional );

          line = 25;
          MoveTo(10,line );
          for( j = bdf.min; j <= bdf.max; j++ ) {

               DrawChar16( j );
               if( QueryX() > scrnR.Xmax - 10 ) {
                    line += 40;
                    if( line > scrnR.Ymax ) {
                       line = 25;
                       getch();
                       EraseRect(&scrnR);
                    }
                    MoveTo( 10,line );
               }
          }

          MoveTo(10,170);
          DrawString("Press a key to continue");
          getch();
          SetDisplay( TextPg0 );
          farfree(font);
     }

#endif /* debug */

     switch( i ) {

          case OK:
               s = "Conversion complete";
               break;

          case ER_INP_NAME:
               sprintf( buf, "Can't open input file name: %s", iname );
               s = buf;
               break;

          case ER_FORMAT:
               s = "Input file is not in proper BDF format";
               break;

          case ER_TMCHARS: 
               s = "More characters defines that stated";
               break;

          case ER_BMAP: 
               s = "BDF file bit map information is in a bad format";
               break;

          case ER_SIZE:
               s = "Resultant font size larger that stated in BDF file";
               break;

          case ER_TOOBIG:
               s = "Font header would exceed 64K";
               break;

          case ER_BITMAPSZ:
               s = "Fonts bitmap width exceeds 32767 pixels";
               break;

          case ER_NOMEM:
               s = "Not enough memory to allocate required workspace";
               break;

          case ER_OUT_NAME:
               sprintf( buf, "Can't open output file name: %s", oname );
               s = buf;
               break;

          case ER_WRITE:
               s = "Error writing file";
               break;

          case ER_DEFAULT:
               s = "Default character specified does not exist";
               break;

          default:
               sprintf( buf, "Internal error #%d", i);
               s = buf;
               break;
     }

     if( i != OK )
          printf("There has been an error.\n");

     printf("%s\n", s);

     StopGraphics();

#ifdef debug
     printf("Return value = %d\n", i);
     i = QueryError();
     printf("Query error = %d/%d\n", i >> 7, i & 127 );
#endif

}

void extend( char *name, char *ext, int force )
/*
Extend filename 'name' to include extention 'ext'. If force is true,
force it to have the 'ext' extention, if false, only put it on if one
doesn't already exist.
Note: 'name' buffer must be long enough to hold the added extention
      'ext' must include the '.'
*/
{
     char *p;

     p = name;
     while( *p ) {
        if( *p == '.' ) 
            if( *(p+1) != '.' && *(p+1) != '\\' )
                break;
          p++;
     }

     if( (*p != '.') || force )
          strcpy( p, ext );

}

void print_me( int code, void *var )
/*
Inform user of actions occuring in bdf2meta.
Code is an indicator of the action to inform, num is a gerneral purpose
parameter.
*/
{

     switch( code ) {

          case IN_SAY: 
               printf("%s\n", (char *) var);
               break;

          case IN_CHAR_CNT: 
               printf("Character #%05d ", * (int *) var );
               break;

          case IN_CHAR_NUM:
               printf("Code = %05d \r", * (int *) var );
               break;

          case IN_LINE:
               printf("Line %ld\r",  * (long *) var );
               break;

          default:
               break;
     }

}
#endif /* make_exe */


