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