Annotation of loncom/cgi/mimeTeX/gfuntype.c, revision 1.2

1.1       albertel    1: /****************************************************************************
                      2:  *
                      3:  * Copyright (c) 2002, John Forkosh Associates, Inc.  All rights reserved.
                      4:  * --------------------------------------------------------------------------
                      5:  * This file is part of mimeTeX, which is free software. You may redistribute
                      6:  * and/or modify it under the terms of the GNU General Public License,
                      7:  * version 2 or later, as published by the Free Software Foundation.
                      8:  *      MimeTeX is distributed in the hope that it will be useful, but
                      9:  * WITHOUT ANY WARRANTY, not even the implied warranty of MERCHANTABILITY.
                     10:  * See the GNU General Public License for specific details.
                     11:  *      By using mimeTeX, you warrant that you have read, understood and
                     12:  * agreed to these terms and conditions, and that you are at least 18 years
                     13:  * of age and possess the legal right and ability to enter into this
                     14:  * agreement and to use mimeTeX in accordance with it.
                     15:  *      Your mimeTeX distribution should contain a copy of the GNU General
                     16:  * Public License.  If not, write to the Free Software Foundation, Inc.,
                     17:  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     18:  * --------------------------------------------------------------------------
                     19:  *
1.2     ! albertel   20:  * Program:	gfuntype  [-g gformat]  [-u isnoname] [-m msglevel]
        !            21:  *		[-n fontname]  [infile [outfile]]
1.1       albertel   22:  *
                     23:  * Purpose:	Parses output from  gftype -i
                     24:  *		and writes pixel bitmap data of the characters
                     25:  *		in a format suitable for a C header file, etc.
                     26:  *
                     27:  * --------------------------------------------------------------------------
                     28:  *
                     29:  * Command-line Arguments:
                     30:  *		--- args can be in any order ---
                     31:  *		infile		name of input file
                     32:  *				(defaults to stdin if no filenames given)
                     33:  *		outfile		name of output file
                     34:  *				(defaults to stdout if <2 filenames given)
1.2     ! albertel   35:  *		-g gformat	gformat=1(default) for bitmap representation,
        !            36:  *				or 2,3 for 8-bit,4-bit .gf-like compression,
        !            37:  *				or 0 to choose smallest format.
        !            38:  *				Add 10 (gformat=10,12,13,14) to embed scan
        !            39:  *				line repeat counts in format.
        !            40:  *		-u isnoname	isnoname=1(default) to output symbols not
        !            41:  *				defined/named in mimetex.h, or 0 to omit them
1.1       albertel   42:  *		-m msglevel	verbose if msglevel>=9 (vv if >=99)
                     43:  *		-n fontname	string used for fontname
                     44:  *				(defaults to noname)
                     45:  *
                     46:  * Exits:	0=success,  1=some error
                     47:  *
                     48:  * Notes:     o	To compile
                     49:  *		cc gfuntype.c mimetex.c -lm -o gfuntype
                     50:  *		needs mimetex.c and mimetex.h
                     51:  *
                     52:  * Source:	gfuntype.c
                     53:  *
                     54:  * --------------------------------------------------------------------------
                     55:  * Revision History:
                     56:  * 09/22/02	J.Forkosh	Installation.
1.2     ! albertel   57:  * 10/11/05	J.Forkosh	.gf-style format options added.
1.1       albertel   58:  *
                     59:  ****************************************************************************/
                     60: 
                     61: /* --------------------------------------------------------------------------
                     62: standard headers, program parameters, global data and macros
                     63: -------------------------------------------------------------------------- */
                     64: /* --- standard headers --- */
                     65: #include <stdio.h>
                     66: #include <stdlib.h>
                     67: #include <string.h>
                     68: #include <ctype.h>
                     69: /* --- application headers --- */
                     70: /* #define SIGNEDCHAR */
                     71: #include "mimetex.h"
                     72: /* --- parameters either -D defined on cc line, or defaulted here --- */
                     73: #ifndef	MSGLEVEL
1.2     ! albertel   74:   #define MSGLEVEL 0
        !            75: #endif
        !            76: #ifndef	GFORMAT
        !            77:   #define GFORMAT 1
        !            78: #endif
        !            79: #ifndef ISREPEAT
        !            80:   #define ISREPEAT 1
1.1       albertel   81: #endif
                     82: /* --- message level (verbose test) --- */
                     83: static	int msglevel = MSGLEVEL;	/* verbose if msglevel >= 9 */
                     84: static	FILE *msgfp;			/* verbose output goes here */
1.2     ! albertel   85: /* --- output file format --- */
        !            86: static	int isnoname = 1;		/* true to output unnamed symbols */
        !            87: static	char *noname = "(noname)";	/* char name used if lookup fails */
        !            88: static	int gformat = GFORMAT;		/* 1=bitmap, 2=.gf-like */
        !            89: static	int isrepeat = ISREPEAT;	/* true to store line repeat counts*/
        !            90: /* extern int imageformat; */		/* as per gformat, 1=bitmap,2=.gf */
1.1       albertel   91: /* --- miscellaneous other data --- */
                     92: #define	CORNER_STUB ".<--"		/* start of upper,lower-left line */
1.2     ! albertel   93: #define	BLANKCHAR_STUB "character is entirely blank" /* signals blank char */
1.1       albertel   94: #define	TYPECAST    "(pixbyte *)"	/* typecast for pixmap string */
                     95: 
                     96: /* ==========================================================================
                     97:  * Function:	main() for gfuntype.c
                     98:  * Purpose:	interprets command-line args, etc
                     99:  * --------------------------------------------------------------------------
                    100:  * Command-Line Arguments:
                    101:  *		See above
                    102:  * --------------------------------------------------------------------------
                    103:  * Returns:	0=success, 1=some error
                    104:  * --------------------------------------------------------------------------
                    105:  * Notes:     o
                    106:  * ======================================================================= */
                    107: /* --- entry point --- */
                    108: int	main ( int argc, char *argv[] )
                    109: {
                    110: /* --------------------------------------------------------------------------
                    111: Allocations and Declarations
                    112: -------------------------------------------------------------------------- */
                    113: int	argnum = 0;		/* argv[] index for command-line args */
                    114: int	inarg=0, outarg=0;	/* argv[] indexes for infile, outfile */
                    115: int	iserror = 1;		/* error signal */
                    116: int	charnum,		/* character number (nextchar->charnum) */
                    117: 	nchars = 0;		/* #chars in font */
                    118: char	fontname[99] = "noname", /* font name */
                    119: 	*getcharname();		/* get character name from its number */
                    120: FILE	/* *fopen(),*/ *infp=stdin, *outfp=stdout; /* init file pointers */
                    121: chardef	*getnextchar(), *nextchar, /* read and parse next char in infp */
                    122: 	*fontdef[256];		/* chars stored using charnum as index */
                    123: int	cstruct_chardef();	/* emit C struct for a character map */
                    124: int	type_raster();		/* display debugging output */
                    125: char	*copyright =		/* copyright, gnu/gpl notice */
                    126:  "+-----------------------------------------------------------------------+\n"
                    127:  "|gfuntype ver 1.00, Copyright(c) 2002-2003, John Forkosh Associates, Inc|\n"
                    128:  "+-----------------------------------------------------------------------+\n"
                    129:  "| gfuntype is free software licensed to you under terms of the GNU/GPL, |\n"
                    130:  "|           and comes with absolutely no warranty whatsoever.           |\n"
                    131:  "+-----------------------------------------------------------------------+";
                    132: /* --------------------------------------------------------------------------
                    133: interpret command-line arguments
                    134: -------------------------------------------------------------------------- */
                    135: while ( argc > ++argnum )	/* check for flags and filenames */
                    136:     if ( *argv[argnum] == '-' )	/* got some '-' flag */
                    137:       {
                    138:       char flag = tolower(*(argv[argnum]+1)); /* char following '-' */
                    139:       argnum++;			/* arg following flag is usually its value */
                    140:       switch ( flag )		/* see what user wants to tell us */
                    141: 	{
                    142: 	/* --- no usage for clueless users yet --- */
                    143: 	default:  exit(iserror); /* exit quietly for unrecognized input */
                    144: 	/* --- adjustable program parameters (not checking input) --- */
1.2     ! albertel  145: 	case 'g': gformat  = atoi(argv[argnum]);
        !           146: 		  isrepeat = (gformat>=10?1:0);
        !           147: 		  gformat  = gformat%10;         break;
        !           148: 	case 'u': isnoname = atoi(argv[argnum]); break;
        !           149: 	case 'm': msglevel = atoi(argv[argnum]); break;
1.1       albertel  150: 	case 'n': strcpy(fontname,argv[argnum]); break;
                    151: 	} /* --- end-of-switch() --- */
                    152:       } /* --- end-of-if(*argv[]=='-') --- */
                    153:     else			/* this arg not a -flag, so it must be... */
                    154:       if ( inarg == 0 )		/* no infile arg yet */
                    155: 	inarg = argnum;		/* so use this one */
                    156:       else			/* we already have an infile arg */
                    157: 	if ( outarg == 0 )	/* but no outfile arg yet */
                    158: 	  outarg = argnum;	/* so use this one */
                    159: /* --- set verbose file ptr --- */
                    160: msgfp = (outarg>0? stdout : stderr); /* use stdout or stderr */
                    161: /* --- emit copyright, gnu/gpl notice --- */
                    162: fprintf(msgfp,"%s\n",copyright); /* display copyright, gnu/gpl info */
                    163: /* --- display input args if verbose output --- */
                    164: if ( msglevel >= 9 )		/* verbose output requested */
1.2     ! albertel  165:   fprintf(msgfp,"gfuntype> infile=%s outfile=%s, fontname=%s format=%d.%d\n",
        !           166:   (inarg>0?argv[inarg]:"stdin"), (outarg>0?argv[outarg]:"stdout"),
        !           167:   fontname, gformat,isrepeat);
1.1       albertel  168: /* --------------------------------------------------------------------------
                    169: initialization
                    170: -------------------------------------------------------------------------- */
                    171: /* --- initialize font[] array --- */
                    172: for ( charnum=0; charnum<256; charnum++ ) /*for each possible char in font*/
                    173:   fontdef[charnum] = (chardef *)NULL;	/* char doesn't exist yet */
                    174: /* --- open input file (if necessary) --- */
                    175: if ( inarg > 0 )		/* input from file, not from stdin */
                    176:   if ( (infp = fopen(argv[inarg],"r")) == NULL ) /*try to open input file*/
                    177:     { fprintf(msgfp,"gfuntype> can't open %s for read\n",argv[inarg]);
                    178:       goto end_of_job; }	/* report error and quit */
1.2     ! albertel  179: /* --- set format for mimetex.c functions --- */
        !           180: if ( gformat<0 || gformat>3 ) gformat=1; /* sanity check */
        !           181: /* if ( gformat == 1 ) imageformat = 1;	*/ /* force bitmap format */
        !           182: /* else gformat = imageformat = 2; */	/* or force .gf format */
1.1       albertel  183: /* --------------------------------------------------------------------------
                    184: process input file
                    185: -------------------------------------------------------------------------- */
                    186: while ( (nextchar=getnextchar(infp)) != NULL ) /* get each char in file */
                    187:   {
                    188:   /* --- display character info --- */
                    189:   if ( msglevel >= 9 )			/* verbose output requested */
                    190:     fprintf(msgfp,"gfuntype> Char#%3d, loc %4d: ul=(%d,%d) ll=(%d,%d)\n",
                    191:     nextchar->charnum, nextchar->location,
                    192:     nextchar->topleftcol,nextchar->toprow,
                    193:     nextchar->botleftcol,nextchar->botrow);
                    194:   if ( msglevel >= 19 )			/* if a bit more verbose */
                    195:     type_raster(&(nextchar->image),msgfp); /*display ascii image of raster*/
                    196:   /* --- store character in font */
                    197:   charnum = nextchar->charnum;		/* get char number of char in font */
                    198:   if ( charnum>=0 && charnum<=255 )	/* check for valid range */
                    199:     fontdef[charnum] = nextchar;	/* store char in font */
                    200:   } /* --- end-of-while(charnum>0) --- */
                    201: /* --------------------------------------------------------------------------
                    202: generate output file
                    203: -------------------------------------------------------------------------- */
                    204: /* --- open output file (if necessary) --- */
                    205: if ( outarg > 0 )		/* output to a file, not to stdout */
                    206:   if ( (outfp = fopen(argv[outarg],"w")) == NULL ) /*try to open output file*/
                    207:     { fprintf(msgfp,"gfuntype> can't open %s for write\n",argv[outarg]);
                    208:       goto end_of_job; }	/* report error and quit */
                    209: /* --- header lines --- */
                    210: fprintf(outfp,"/%c --- fontdef for %s --- %c/\n", '*',fontname,'*');
                    211: fprintf(outfp,"static\tchardef %c%s[] =\n   {\n", ' ',fontname);
                    212: /* --- write characters comprising font --- */
                    213: for ( charnum=0; charnum<256; charnum++ ) /*for each possible char in font*/
1.2     ! albertel  214:  if ( fontdef[charnum] != (chardef *)NULL ) /*check if char exists in font*/
        !           215:   { char *charname = getcharname(fontname,charnum);
        !           216:     if ( charname!=NULL || isnoname ) {	/* char defined or want undefined */
        !           217:      if ( ++nchars > 1 )		/* bump count */
        !           218:       fprintf(outfp,",\n");		/* and terminate preceding chardef */
        !           219:      fprintf(outfp,"      /%c --- pixel bitmap for %s char#%d %s --- %c/\n",
        !           220:       '*',fontname,charnum,(charname==NULL?noname:charname),'*');
        !           221:      cstruct_chardef(fontdef[charnum],outfp,6); } /*emit chardef struct*/
        !           222:     else
        !           223:      if(0)fprintf(outfp,"NULL");	/* no character in this position */
        !           224:   } /* --- end-of-if(fontdef[]!=NULL) --- */
        !           225:  else
        !           226:   if(0)fprintf(outfp,"NULL");		/* no character in this position */
1.1       albertel  227: /* --- write trailer chardef and closing brace --- */
                    228: fprintf(outfp,",\n");			/* finish up last map from loop */
                    229: fprintf(outfp,"      /%c --- trailer  --- %c/\n",'*','*'); /* trailer... */
1.2     ! albertel  230: fprintf(outfp,"      { -99, -999,  0,0,0,0, { 0,0,0,0, %s\"\\0\" }  }\n",
1.1       albertel  231:      TYPECAST);
                    232: fprintf(outfp,"   } ;\n");		/* terminating }; for fontdef */
                    233: /* --------------------------------------------------------------------------
                    234: end-of-job
                    235: -------------------------------------------------------------------------- */
                    236: /* --- reset error status for okay exit --- */
                    237: iserror = 0;
                    238: /* --- close files (if they're open and not stdin/out) --- */
                    239: end_of_job:
                    240:   if (  infp!=NULL &&  infp!=stdin  ) fclose( infp);
                    241:   if ( outfp!=NULL && outfp!=stdout ) fclose(outfp);
                    242: exit ( iserror );
                    243: } /* --- end-of-function main() --- */
                    244: 
                    245: 
                    246: /* ==========================================================================
                    247:  * Function:	getnextchar ( fp )
                    248:  * Purpose:	Reads and parses the next character definition on fp,
                    249:  *		and returns a new chardef struct describing that character.
                    250:  * --------------------------------------------------------------------------
                    251:  * Arguments:	fp (I)		FILE *  to input file
                    252:  *				(containing output from  gftype -i)
                    253:  * Returns:	( chardef * )	ptr to chardef struct describing character,
                    254:  *				or NULL for eof or any error
                    255:  * --------------------------------------------------------------------------
                    256:  * Notes:     o	fp is left so the next line read from it will be
                    257:  *		the one following the final .<-- line.
                    258:  * ======================================================================= */
                    259: /* --- entry point --- */
                    260: chardef	*getnextchar ( FILE *fp )
                    261: {
                    262: /* --------------------------------------------------------------------------
                    263: Allocations and Declarations
                    264: -------------------------------------------------------------------------- */
                    265: chardef	*new_chardef(), *nextchar=(chardef *)NULL; /*ptr returned to caller*/
                    266: int	delete_chardef();		/* free allocated memory if error */
                    267: int	findnextchar(), charnum,location; /* get header line for next char */
                    268: int	rasterizechar();		/* ascii image --> raster pixmap */
1.2     ! albertel  269: int	parsestat=(-999), parsecorner(); /* get col,row from ".<--" line */
1.1       albertel  270: char	*readaline();			/* read next line from fp */
                    271: /* --------------------------------------------------------------------------
                    272: initialization
                    273: -------------------------------------------------------------------------- */
1.2     ! albertel  274: while ( parsestat == (-999) ) {		/* flush entirely blank characters */
        !           275:   /* --- find and interpret header line for next character --- */
        !           276:   charnum = findnextchar(fp,&location);	/* read and parse header line */
        !           277:   if ( charnum < 0 ) goto error;	/* eof or error, no more chars */
        !           278:   /* --- allocate a new chardef struct and begin populating it --- */
        !           279:   if ( nextchar == (chardef *)NULL )	/* haven't allocated chardef yet */
        !           280:     if ( (nextchar=new_chardef())	/* allocate a new chardef */
        !           281:     ==   (chardef *)NULL ) goto error;	/* and quit if we failed */
        !           282:   nextchar->charnum = charnum;		/* store charnum in struct */
        !           283:   nextchar->location = location;	/* and location */
        !           284:   /* --- get upper-left corner line --- */
        !           285:   parsestat = parsecorner(readaline(fp), /* parse corner line */
        !           286:     &(nextchar->toprow),&(nextchar->topleftcol)); /* row and col from line */
        !           287:   } /* --- end-of-while(parsestat)  --- */
        !           288: if ( !parsestat ) goto error;		/* quit if parsecorner() failed */
1.1       albertel  289: /* --------------------------------------------------------------------------
                    290: interpret character image (and parse terminating corner line)
                    291: -------------------------------------------------------------------------- */
                    292: /* --- read ascii character image and interpret as integer bitmap --- */
                    293: if ( rasterizechar(fp,&nextchar->image) != 1 ) /* parse image of char */
                    294:   goto error;				/* and quit if failed */
                    295: /* --- get lower-left corner line --- */
                    296: if ( !parsecorner(readaline(NULL),	/* reread and parse corner line */
                    297: &(nextchar->botrow),&(nextchar->botleftcol)) ) /* row and col from line */
                    298:   goto error;				/* and quit if failed */
                    299: /* --------------------------------------------------------------------------
                    300: done
                    301: -------------------------------------------------------------------------- */
                    302: goto end_of_job;			/* skip error return if successful */
                    303: error:
                    304:   if ( nextchar != (chardef *)NULL )	/* have an allocated chardef */
                    305:     delete_chardef(nextchar);		/* so deallocate it */
                    306:   nextchar = (chardef *)NULL;		/* and reset ptr to null for error */
                    307: end_of_job:
                    308:   return ( nextchar );			/* back with chardef or null */
                    309: } /* --- end-of-function getnextchar() --- */
                    310: 
                    311: 
                    312: /* ==========================================================================
                    313:  * Function:	getcharname ( fontname, charnum )
                    314:  * Purpose:	Looks up charnum for the family specified by fontname
                    315:  *		and returns the corresponding charname.
                    316:  * --------------------------------------------------------------------------
                    317:  * Arguments:	fontname (I)	char * containing fontname for font family
1.2     ! albertel  318:  *				(from -n switch on command line)
1.1       albertel  319:  *		charnum (I)	int containing the character number
                    320:  *				whose corresponding name is wanted.
                    321:  * Returns:	( char * )	ptr to character name
                    322:  *				or NULL if charnum not found in table
                    323:  * --------------------------------------------------------------------------
                    324:  * Notes:     o
                    325:  * ======================================================================= */
                    326: /* --- entry point --- */
                    327: char	*getcharname ( char *fontname, int charnum )
                    328: {
                    329: /* --------------------------------------------------------------------------
                    330: Allocations and Declarations
                    331: -------------------------------------------------------------------------- */
                    332: /* --- recognized font family names and our corresponding numbers --- */
1.2     ! albertel  333: static	char *fnames[] =	/*font name from -n switch on command line*/
        !           334: 	{ "cmr","cmmib","cmmi","cmsy","cmex","bbold","rsfs","stmary", NULL };
        !           335: static	int    fnums[] =	/* corresponding mimetex fontfamily number*/
        !           336: 	{ CMR10,CMMIB10,CMMI10,CMSY10,CMEX10,BBOLD10,RSFS10,STMARY10,  -1 };
        !           337: static	int    offsets[] =	/* symtable[ichar].charnum = charnum-offset*/
        !           338: 	{     0,      0,     0,     0,     0,      0,    65,       0,  -1 };
1.1       albertel  339: /* --- other local declarations --- */
1.2     ! albertel  340: char	*charname = NULL;	/* character name returned to caller */
1.1       albertel  341: char	flower[99] = "noname";	/* lowercase caller's fontname */
1.2     ! albertel  342: int	ifamily = 0,		/* fnames[] (and fnums[],offsets[]) index */
        !           343: 	offset = 0,		/* offsets[ifamily] */
        !           344: 	ichar = 0;		/* loop index */
1.1       albertel  345: /* --------------------------------------------------------------------------
                    346: lowercase caller's fontname and look it up in fnames[]
                    347: -------------------------------------------------------------------------- */
                    348: /* --- lowercase caller's fontname --- */
                    349: for ( ichar=0; *fontname!='\000'; ichar++,fontname++ )/*lowercase each char*/
                    350:   flower[ichar] = (isalpha(*fontname)? tolower(*fontname) : *fontname);
                    351: flower[ichar] = '\000';		/* null-terminate lowercase fontname */
                    352: if ( strlen(flower) < 2 ) goto end_of_job; /* no lookup match possible */
                    353: /* --- look up lowercase fontname in our fnames[] table --- */
                    354: for ( ifamily=0; ;ifamily++ )	/* check fnames[] for flower */
                    355:   if ( fnames[ifamily] == NULL ) goto end_of_job; /* quit at end-of-table */
                    356:   else if ( strstr(flower,fnames[ifamily]) != NULL ) break; /* found it */
1.2     ! albertel  357: offset = offsets[ifamily];	/* symtable[ichar].charnum = charnum-offset*/
1.1       albertel  358: ifamily = fnums[ifamily];	/* xlate index to font family number */
                    359: /* --------------------------------------------------------------------------
                    360: now look up name for caller's charnum in ifamily, and return it to caller
                    361: -------------------------------------------------------------------------- */
                    362: /* --- search symtable[] for charnum in ifamily --- */
                    363: for ( ichar=0; ;ichar++ )	/*search symtable[] for charnum in ifamily*/
                    364:   if ( symtable[ichar].symbol == NULL ) goto end_of_job; /* end-of-table */
                    365:   else
                    366:     if ( symtable[ichar].family == ifamily /* found desired family */
                    367:     &&   symtable[ichar].handler == NULL ) /* and char isn't a "dummy" */
1.2     ! albertel  368:       if ( symtable[ichar].charnum == charnum-offset ) break; /*got charnum*/
1.1       albertel  369: /* --- return corresponding charname to caller --- */
                    370: charname = symtable[ichar].symbol; /* pointer to symbol name in table */
                    371: end_of_job:
1.2     ! albertel  372:   if ( charname==NULL && isnoname ) /* want unnamed/undefined chars */
        !           373:     charname = noname;		/* so replace null return with noname */
1.1       albertel  374:   return ( charname );
                    375: } /* --- end-of-function getcharname() --- */
                    376: 
                    377: 
                    378: /* ==========================================================================
                    379:  * Function:	findnextchar ( fp, location )
                    380:  * Purpose:	Finds next "beginning of char" line in fp
                    381:  *		and returns the character number,
                    382:  *		and (optionally) location if arg provided.
                    383:  * --------------------------------------------------------------------------
                    384:  * Arguments:	fp (I)		FILE *  to input file
                    385:  *				(containing output from  gftype -i)
                    386:  *		location (O)	int *  returning "location" of character
                    387:  *				(or pass NULL and it won't be returned)
                    388:  * Returns:	( int )		character number,
                    389:  *				or -1 for eof or any error
                    390:  * --------------------------------------------------------------------------
                    391:  * Notes:     o	fp is left so the next line read from it will be
                    392:  *		the one following the "beginning of char" line
                    393:  * ======================================================================= */
                    394: /* --- entry point --- */
                    395: int	findnextchar ( FILE *fp, int *location )
                    396: {
                    397: /* --------------------------------------------------------------------------
                    398: Allocations and Declarations
                    399: -------------------------------------------------------------------------- */
                    400: static	char keyword[99]="beginning of char "; /*signals start of next char*/
                    401: char	*readaline(), *line;	/* read next line from fp */
                    402: char	*strstr(), *strchr(), *delim; /* search line for substring, char */
                    403: char	token[99];		/* token extracted from line */
                    404: int	charnum = (-1);		/* character number returned to caller */
                    405: /* --------------------------------------------------------------------------
                    406: keep reading lines until eof or keyword found
                    407: -------------------------------------------------------------------------- */
                    408: while ( (line=readaline(fp)) != NULL ) /* read lines until eof */
                    409:   {
                    410:   if ( msglevel >= 999 )	/* very, very verbose output requested */
                    411:     fprintf(msgfp,"nextchar> line = %s\n",line);
                    412:   if ( (delim=strstr(line,keyword)) != NULL ) /* found keyword on line */
                    413:     {
                    414:     /* --- get character number from line --- */
                    415:     strcpy(token,delim+strlen(keyword)); /* char num follows keyword */
                    416:     charnum = atoi(token);	/* interpret token as integer charnum */
                    417:     /* --- get location at beginning of line --- */
                    418:     if ( location != (int *)NULL )  /* caller wants location returned */
                    419:       if ( (delim=strchr(line,':')) != NULL ) /* location precedes colon */
                    420: 	{ *delim = '\000';	/* terminate line after location */
                    421: 	  *location = atoi(line); } /* interpret location as integer */
                    422:     break;			/* back to caller with charnum */
                    423:     } /* --- end-of-if(delim!=NULL) --- */
                    424:   } /* --- end-of-while(line!=NULL) --- */
                    425: return ( charnum );		/* back to caller with char number or -1 */
                    426: } /* --- end-of-function findnextchar() --- */
                    427: 
                    428: 
                    429: /* ==========================================================================
                    430:  * Function:	rasterizechar ( fp, rp )
                    431:  * Purpose:	Reads and parses subsequent lines from fp
                    432:  *		(until a terminating ".<--" line),
                    433:  *		representing the ascii image of the character in fp,
                    434:  *		and returns the results in raster struct rp
                    435:  * --------------------------------------------------------------------------
                    436:  * Arguments:	fp (I)		FILE *  to input file
                    437:  *				(containing output from  gftype -i)
                    438:  *				positioned immediately after top .<-- line,
                    439:  *				ready to read first line of ascii image
                    440:  *		rp (O)		raster *  returning the rasterized
                    441:  *				character represented on fp as an ascii image
                    442:  * Returns:	( int )		1=okay, or 0=eof or any error
                    443:  * --------------------------------------------------------------------------
                    444:  * Notes:     o	fp is left so the last line (already) read from it
                    445:  *		contains the terminating .<-- corner information
                    446:  *		(readaline(NULL) will reread this last line)
                    447:  *	      o	char images on fp can be no wider than 31 pixels
                    448:  * ======================================================================= */
                    449: /* --- entry point --- */
                    450: int	rasterizechar ( FILE *fp, raster *image )
                    451: {
                    452: /* --------------------------------------------------------------------------
                    453: Allocations and Declarations
                    454: -------------------------------------------------------------------------- */
                    455: char	*readaline(), *line;	/* read next scan line for char from fp */
1.2     ! albertel  456: unsigned char bitvec[1024][128]; /* scan lines parsed up to 1024x1024 bits */
        !           457: int	bitcmp();		/* compare bit strings */
1.1       albertel  458: int	height = 0,		/* #scan lines in fp comprising char */
1.2     ! albertel  459: 	width = 0;		/* #chars on longest scan line */
        !           460: int	iscan,			/* bitvec[] index */
1.1       albertel  461: 	ibit;			/* bit along scan (i.e., 0...width-1) */
                    462: int	isokay = 0;		/* returned status, init for failure */
1.2     ! albertel  463: /* --- bitmap and .gf-formatted image info (we'll choose smallest) --- */
        !           464: int	iformat = gformat;	/*0=best, 1=bitmap, 2=8-bit.gf, 3=4-bit.gf*/
        !           465: unsigned char gfpixcount[2][65536]; /* .gf black/white flips (max=64K) */
        !           466: int	npixcounts[2] = {9999999,9999999}; /* #counts for 8-bit,4-bit .gf */
        !           467: int	nbytes1=9999999,nbytes2=9999999,nbytes3=9999999;/*#bytes for format*/
1.1       albertel  468: /* --------------------------------------------------------------------------
                    469: read lines till ".<--" terminator, and construct one vector[] int per line
                    470: -------------------------------------------------------------------------- */
1.2     ! albertel  471: memset(bitvec,0,128*1024);	/* zero-fill bitvec[] */
1.1       albertel  472: while ( (line=readaline(fp)) != NULL ) /* read lines until eof */
                    473:   {
                    474:   /* --- allocations and declarations --- */
                    475:   int	icol, ncols=strlen(line); /* line[] column index, #cols in line[] */
                    476:   /* --- check for end-of-char (when we encounter corner line) --- */
                    477:   if ( memcmp(line,CORNER_STUB,strlen(CORNER_STUB)) == 0 ) /* corner line */
                    478:     break;			/* so done with loop */
                    479:   /* --- parse line (encode asterisks comprising character image) --- */
1.2     ! albertel  480:   memset(bitvec[height],0,128);	/* first zero out all bits */
1.1       albertel  481:   for ( icol=0; icol<ncols; icol++ ) /* now check line[] for asterisks */
                    482:     if ( line[icol] == '*' )	/* we want to set this bit */
                    483:       {	setlongbit(bitvec[height],icol); /* set bit */
                    484: 	if ( icol >= width ) width=icol+1; } /* and check for new width */
                    485:   height++;			/* bump character height */
                    486:   } /* --- end-of-while(line!=NULL) --- */
                    487: if ( height<1 || width<1 )	/* some problem parsing character */
                    488:   goto end_of_job;		/* so quit */
                    489: /* --------------------------------------------------------------------------
1.2     ! albertel  490: init image values
1.1       albertel  491: -------------------------------------------------------------------------- */
                    492: if ( image->pixmap != NULL )	/* hmm, somebody already allocated memory */
1.2     ! albertel  493:   free((void *)image->pixmap);	/* so just free it */
1.1       albertel  494: image->width = width;		/* set image width within raster struct */
                    495: image->height = height;		/* and height */
1.2     ! albertel  496: image->format = gformat;	/* set format (will be reset below) */
        !           497: image->pixsz = 1;		/* #bits per pixel (or #counts in .gf fmt) */
        !           498: if ( gformat==0 || gformat==1 )	/* bitmap representation allowed */
        !           499:   { nbytes1 = pixmapsz(image);	/* #bytes needed for bitmap */
        !           500:     iformat = 1; }		/* default to bitmap format */
        !           501: /* --------------------------------------------------------------------------
        !           502: perform .gf-like compression on image in bitvec
        !           503: -------------------------------------------------------------------------- */
        !           504: if ( gformat == 0		/* choose optimal/smallest respresentation */
        !           505: ||   gformat==2 || gformat==3 )	/* .gf-like compressed representation */
        !           506:  {
        !           507:  /* --- try both 8-bits/count and 4-bits/count for best compression --- */
        !           508:  int	maxbitcount[2] = {254,14}; /* don't count too much in one byte */
        !           509:  int	repeatcmds[2]  = {255,15}; /* opcode for repeat/duplicate count */
        !           510:  int	minbytes = 0;		/* #bytes needed for smallest format */
        !           511:  for ( iformat=2; iformat<=3; iformat++ ) { /* 2=8-bit packing, 3=4-bit */
        !           512:   int	gfbitcount = 0,		/* count of consecutive gfbitval's */
        !           513: 	gfbitval = 0,		/* begin with count of leading 0's */
        !           514: 	pixcount = 0;		/* #packed bytes (#black/white flips) */
        !           515:   unsigned char *gfcount = gfpixcount[iformat-2]; /*counts for this format*/
        !           516:   if ( gformat!=0 && gformat!=iformat ) /* this format not allowed */
        !           517:     continue;			/* so just skip it */
        !           518:   for ( iscan=0; iscan<height; iscan++ ) /* for each integer in bitvec[] */
        !           519:    {
        !           520:    int	bitval = 0;		/* current actual pixel value */
        !           521:    int	nrepeats=0, nextreps=0;	/* #duplicate lines below current,next line*/
        !           522:    /* --- check for repeated/duplicate scan lines --- */
        !           523:    if ( isrepeat		/* we're storing scan line repeat counts */
        !           524:    &&   iscan < height-1 ) {	/* current scan line isn't the last line */
        !           525:     /* --- count repeats --- */
        !           526:     int jscan = iscan;		/* compare current scan with lines below it*/
        !           527:     while ( ++jscan < height ) { /* until last scan line */
        !           528:      if (nrepeats == jscan-iscan-1) /*no intervening non-identical lines*/
        !           529:       if ( bitcmp(bitvec[iscan],bitvec[jscan],width) == 0 ) /* identical */
        !           530:        nrepeats++;		/* so bump repeat count */
        !           531:      if ( jscan > iscan+1 )	/* we're below next line */
        !           532:       if (nextreps == jscan-iscan-2) /*no intervening non-identical lines*/
        !           533:        if ( bitcmp(bitvec[iscan+1],bitvec[jscan],width) == 0 )/*identical*/
        !           534: 	nextreps++; }		/* so bump next lline repeat count */
        !           535:     /* --- set repeat command and count --- */
        !           536:     if ( nrepeats > 0 ) {	/* found repeated lines below current */
        !           537:      int maxrepeats = maxbitcount[iformat-2]; /*max count/repeats per byte*/
        !           538:      if ( nrepeats > maxrepeats ) nrepeats=maxrepeats; /* don't exceed max */
        !           539:      {setbyfmt(iformat,gfcount,pixcount,repeatcmds[iformat-2]);} /*set cmd*/
        !           540:      {setbyfmt(iformat,gfcount,pixcount+1,nrepeats);} /* set #repeats */
        !           541:      pixcount += 2; }		/* don't bump pixcount within macros */
        !           542:     } /* --- end-of-if(isrepeat) --- */
        !           543:    /* --- set bit counts for current scan line --- */
        !           544:    for ( ibit=0; ibit<width; ibit++ )	/* for all bits in this scanline */
        !           545:     {
        !           546:     bitval = getlongbit(bitvec[iscan],ibit); /* check actual pixel value */
        !           547:     if ( bitval != gfbitval ) {	/* black-to-white edge (or vice versa) */
        !           548:       {setbyfmt(iformat,gfcount,pixcount,gfbitcount);} /*set byte or nibble*/
        !           549:       pixcount++;		/* don't bump pixcount within macro */
        !           550:       gfbitcount = 0;		/* reset consecutive bit count */
        !           551:       gfbitval = 1-gfbitval; }	/* flip bit to be counted */
        !           552:     else			/* check count if continuing with same val */
        !           553:      if ( gfbitcount >= maxbitcount[iformat-2] ) { /* max count per byte */
        !           554:       {setbyfmt(iformat,gfcount,pixcount,gfbitcount);} /*set byte or nibble*/
        !           555:       clearbyfmt(iformat,gfcount,pixcount+1); /*followed by dummy 0 count*/
        !           556:       pixcount += 2;		/* don't bump pixcount within macros */
        !           557:       gfbitcount = 0; }		/* reset consecutive bit count */
        !           558:     if ( bitval == gfbitval )	/* same bit val as preceding, or first new */
        !           559:       gfbitcount++;		/* so just count another pixel */
        !           560:     } /* --- end-of-for(ibit) --- */
        !           561:    /* --- adjust for repeated scan lines --- */
        !           562:    iscan += nrepeats;		/* skip repeated/duplicate scan lines */
        !           563:    if ( nrepeats>0 || nextreps>0 ) /* emit count to align on full scan */
        !           564:     if ( iscan < height-1 )	/* have another scan line below this one */
        !           565:      if ( gfbitcount > 0 ) {	/* should always have some final count */
        !           566:       {setbyfmt(iformat,gfcount,pixcount,gfbitcount);} /*set byte or nibble*/
        !           567:       pixcount++;		/* don't bump pixcount within macro */
        !           568:       gfbitcount = 0;		/* reset consecutive bit count */
        !           569:       if ( bitval == getlongbit(bitvec[iscan+1],0) ) { /* same bit value */
        !           570:        clearbyfmt(iformat,gfcount,pixcount); /*so we need a dummy 0 count*/
        !           571:        pixcount++; }		/* don't bump pixcount within macros */
        !           572:       else			/* bitval flips at start of next line */
        !           573:        gfbitval = 1-gfbitval;	/* so flip bit to be counted */
        !           574:       } /* --- end-of-if(nrepeats...gfbitcount>0) --- */
        !           575:    } /* --- end-of-for(iscan) --- */
        !           576:    /* --- store final count --- */
        !           577:    if ( gfbitcount > 0 ) {	/* have a final count */
        !           578:      {setbyfmt(iformat,gfcount,pixcount,gfbitcount);} /*set byte or nibble*/
        !           579:      pixcount++; }		/* don't bump pixcount within macro */
        !           580:    else				/* ended exactly after maxbitcount? */
        !           581:     if ( getbyfmt(iformat,gfcount,pixcount-1) == 0 )/*have dummy 0 trailer?*/
        !           582:      pixcount--;		/* remove unneeded dummy trailer */
        !           583:    /* --- save count to choose smallest --- */
        !           584:    npixcounts[iformat-2] = pixcount; /* save count */
        !           585:    } /* --- end-of-for(iformat) --- */
        !           586:  /* --- check for optimal/smallest format --- */
        !           587:  nbytes2=npixcounts[0];  nbytes3=(1+npixcounts[1])/2; /* #bytes for count */
        !           588:  iformat = (nbytes2<nbytes3? 2:3); /* choose smallest format */
        !           589:  minbytes = (iformat==2?nbytes2:nbytes3); /* #bytes for smallest format */
        !           590:  if ( gformat == 0 )		/* bitmap representation also permitted */
        !           591:   if ( nbytes1 <= minbytes )	/* and it's the optimal/smallest format */
        !           592:    iformat = 1;			/* so flip format */
        !           593:  /* --- move results to returned image --- */
        !           594:  if ( iformat != 1 ) {		/* using a .gf format */
        !           595:   if ( (image->pixmap = (unsigned char *)malloc(minbytes)) /* alloc pixmap */
        !           596:   == NULL ) goto end_of_job;	/* quit if failed to allocate pixmap */
        !           597:   memcpy(image->pixmap,gfpixcount[iformat-2],minbytes); /*copy local counts*/
        !           598:   image->format = iformat;	/* signal byte counts or nibble counts */
        !           599:   image->pixsz = npixcounts[iformat-2]; /*#counts in pixmap for gformat=2,3*/
        !           600:   } /* --- end-of-if(iformat!=1) --- */
        !           601:  } /* --- end-of-if(gformat==2) --- */
1.1       albertel  602: /* --------------------------------------------------------------------------
                    603: copy each integer in bitvec[] to raster pixmap, bit by bit
                    604: -------------------------------------------------------------------------- */
1.2     ! albertel  605: if ( iformat == 1 )		/* bit-by-bit representation of image */
        !           606:  {
        !           607:  int	ipixel = 0;		/* pixmap index */
        !           608:  /* --- first allocate image raster pixmap for character --- */
        !           609:  if ( (image->pixmap = (unsigned char *)malloc(pixmapsz(image)))
        !           610:  == NULL ) goto end_of_job;	/* quit if failed to allocate pixmap */
        !           611:  image->format = iformat;	/* reset format */
        !           612:  /* --- now store bit image in allocated raster --- */
        !           613:  for ( iscan=0; iscan<height; iscan++ )	/* for each integer in bitvec[] */
        !           614:   for ( ibit=0; ibit<width; ibit++ )	/* for all bits in this scanline */
1.1       albertel  615:     {
                    616:     if ( getlongbit(bitvec[iscan],ibit) != 0 ) /* check current scan pixel */
                    617:       { setlongbit(image->pixmap,ipixel); }
                    618:     else				/*turn off corresponding raster bit*/
                    619:       { unsetlongbit(image->pixmap,ipixel); }
                    620:     ipixel++;				/* bump image raster pixel */
                    621:     } /* --- end-of-for(iscan,ibit) --- */
1.2     ! albertel  622:  } /* --- end-of-if(gformat==1) --- */
1.1       albertel  623: /* --------------------------------------------------------------------------
                    624: done
                    625: -------------------------------------------------------------------------- */
                    626: isokay = 1;				/* reset flag for success */
                    627:  end_of_job:
                    628:   return ( isokay );			/* back with 1=success, 0=failure */
                    629: } /* --- end-of-function rasterizechar() --- */
                    630: 
                    631: 
                    632: /* ==========================================================================
                    633:  * Function:	parsecorner ( line, row, col )
                    634:  * Purpose:	Parses a "pixel corner" line (upper left or lower left)
                    635:  *		and returns the (col,row) information on it as integers.
                    636:  * --------------------------------------------------------------------------
                    637:  * Arguments:	line (I)	char *  to input line containing
                    638:  *				".<--This pixel's..." to be parsed
                    639:  *		row (O)		int *  returning the (,row)
                    640:  *		col (O)		int *  returning the (col,)
                    641:  * Returns:	( int )		1 if successful, or 0 for any error
                    642:  * --------------------------------------------------------------------------
                    643:  * Notes:     o
                    644:  * ======================================================================= */
                    645: /* --- entry point --- */
                    646: int	parsecorner ( char *line, int *row, int *col )
                    647: {
                    648: /* --------------------------------------------------------------------------
                    649: Allocations and Declarations
                    650: -------------------------------------------------------------------------- */
                    651: int	isokay = 0;		/* success/fail flag, init for failure */
                    652: char	field[99], *delim;	/*(col,row) field and ptr to various delims*/
                    653: /* --------------------------------------------------------------------------
                    654: extract (col,row) field from line, and interpret col and row as integers
                    655: -------------------------------------------------------------------------- */
                    656: /* --- first, check beginning of line --- */
                    657: if ( line == (char *)NULL ) goto end_of_job; /* no line supplied by caller */
1.2     ! albertel  658: /* --- check for blank line --- */
        !           659: if ( strstr(line,BLANKCHAR_STUB) != NULL ) /* got entirely blank character */
        !           660:   return ( -999 );			/* so return special -999 signal */
        !           661: /* --- check for corner --- */
1.1       albertel  662: if ( memcmp(line,CORNER_STUB,strlen(CORNER_STUB)) != 0 ) /*not valid corner*/
                    663:   goto end_of_job;			/* so quit */
                    664: /* --- extract  col,row  field from line --- */
                    665: if ( (delim=strchr(line,'(')) == NULL ) goto end_of_job; /*find open paren*/
                    666: strncpy(field,delim+1,10);		/* extract next 10 chars */
                    667: field[10] = '\000';			/* and null-terminate field */
                    668: if ( (delim=strchr(field,')')) == NULL ) goto end_of_job; /*find close paren*/
                    669: *delim = '\000';			/* terminate field at close paren */
                    670: /* --- interpret col,row as integers --- */
                    671: if ( (delim=strchr(field,',')) == NULL ) goto end_of_job; /* find comma */
                    672: *delim = '\000';			/* break field into col and row */
                    673: if ( col != (int *)NULL )		/* caller gave us ptr for col */
                    674:   *col = atoi(field);			/* so return it to him */
                    675: if ( row != (int *)NULL )		/* caller gave us ptr for row */
                    676:   *row = atoi(delim+1);			/* so return it to him */
                    677: /* --------------------------------------------------------------------------
                    678: done
                    679: -------------------------------------------------------------------------- */
                    680: isokay = 1;				/* reset flag for success */
                    681:  end_of_job:
                    682:   return ( isokay );			/* back with success/fail flag */
                    683: } /* --- end-of-function parsecorner() --- */
                    684: 
                    685: 
                    686: /* ==========================================================================
                    687:  * Function:	readaline ( fp )
                    688:  * Purpose:	Reads a line from fp, strips terminating newline,
                    689:  *		and returns ptr to internal buffer
                    690:  * --------------------------------------------------------------------------
                    691:  * Arguments:	fp (I)		FILE *  to input file to be read.
                    692:  *				If null, returns line previously read.
                    693:  * Returns:	( char * )	internal buffer containing line read,
                    694:  *				or NULL for eof or error.
                    695:  * --------------------------------------------------------------------------
                    696:  * Notes:     o	fp is left on the line following the returned line
                    697:  * ======================================================================= */
                    698: /* --- entry point --- */
                    699: char	*readaline ( FILE *fp )
                    700: {
                    701: /* --------------------------------------------------------------------------
                    702: Allocations and Declarations
                    703: -------------------------------------------------------------------------- */
1.2     ! albertel  704: static	char buffer[2048];	/* static buffer returned to caller */
1.1       albertel  705: char	*fgets(), *bufptr=buffer; /* read line from fp */
                    706: char	*strchr(), *delim;	/* remove terminating newline */
                    707: /* --------------------------------------------------------------------------
                    708: Read line and strip trailing newline
                    709: -------------------------------------------------------------------------- */
                    710: if ( fp != NULL )			/*if null, return previous line read*/
1.2     ! albertel  711:   if ( (bufptr=fgets(buffer,2047,fp))	/* read next line from fp */
1.1       albertel  712:   != NULL )				/* and check that we succeeded */
                    713:     {
                    714:     if ( (delim=strchr(bufptr,'\n'))	/* look for terminating newline */
                    715:     != NULL )				/* and check that we found it */
                    716:       *delim = '\000';			/* truncate line at newline */
                    717:     } /* --- end-of-if(fgets()!=NULL) --- */
                    718: return ( bufptr );			/*back to caller with buffer or null*/
                    719: } /* --- end-of-function readaline() --- */
1.2     ! albertel  720: 
        !           721: 
        !           722: /* ==========================================================================
        !           723:  * Function:	bitcmp ( bs1, bs2, n )
        !           724:  * Purpose:	compares the first n bits of two strings
        !           725:  * --------------------------------------------------------------------------
        !           726:  * Arguments:	bs1 (I)		unsigned char * to first bit string
        !           727:  *		bs2 (I)		unsigned char * to second bit string
        !           728:  *		n (I)		int containing #bits to compare
        !           729:  * Returns:	( int )		0 if first n bits are identical
        !           730:  *				-1 if first unmatching bit of bs1 is 0
        !           731:  *				+1 if first unmatching bit of bs2 id 0
        !           732:  * --------------------------------------------------------------------------
        !           733:  * Notes:     o
        !           734:  * ======================================================================= */
        !           735: /* --- entry point --- */
        !           736: int	bitcmp ( unsigned char *bs1, unsigned char *bs2, int n )
        !           737: {
        !           738: /* --------------------------------------------------------------------------
        !           739: Allocations and Declarations
        !           740: -------------------------------------------------------------------------- */
        !           741: int	icmp = 0;		/* returned to caller */
        !           742: int	nbytes = n/8,		/* #full bytes we can compare with memcmp()*/
        !           743: 	nbits  = n%8,  ibit=0;	/* #trailing bits in last byte, index */
        !           744: /* --------------------------------------------------------------------------
        !           745: compare leading bytes, then trailing bits
        !           746: -------------------------------------------------------------------------- */
        !           747: if ( nbytes > 0 ) icmp = memcmp(bs1,bs2,nbytes); /* compare leading bytes */
        !           748: if ( icmp == 0 )		/* leading bytes identical */
        !           749:  if ( nbits > 0 )		/* and we have trailing bits */
        !           750:   for ( ibit=0; ibit<nbits; ibit++ ) /* check each bit */
        !           751:    { icmp = (int)get1bit(bs1[nbytes],ibit) - (int)get1bit(bs2[nbytes],ibit);
        !           752:      if ( icmp != 0 ) break; }	/* done at first unmatched bit */
        !           753: return ( icmp );		/* back to caller with -1,0,+1 */
        !           754: } /* --- end-of-function bitcmp() --- */
1.1       albertel  755: /* --- end-of-file gfuntype.c --- */
                    756: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>