rwa@auvax.UUCP (Ross Alexander) (11/22/87)
Many apologies to Mr Turner, whom I cannot seem to reach via email; here's the code I kept threatening to post ;-). [ I really would prefer to do this the right way, but its been 6 weeks now...] The following program attempts to convert Berkeley "Varian Fonts" (vfonts) to Atari GDOS fonts, with middling success. It is written in MWC (I use version 2.0, but I know of no reason why it wouldn't go together in version 1.2 just as easily). You Lattice and/or Megamax users are welcome to see what can be done with this stuff; I can't do it myself. I suspect Alcyon owners are SOL. I hereby place this code in the public domain; do whatever you like with it, attribute it to me or not as you please, et c., et c. I make no representation of fitness for any purpose, neither will I be held responsible for any damage direct or indirect, or any claims arising from the use of this code in any way. In a word it's a gift and you shouldn't expect too much from it ;-). Enjoy. Ross Alexander @ Athabasca University, alberta!auvax!rwa --------------------------makefile---------------------------- CFLAGS=-A vtoa.prg: vtoa.o cc -o vtoa.prg vtoa.o vtoa.o: \include\stdio.h \include\stat.h \include\ctype.h clean: rm *.o vtoa.prg --------------------------C source--------------------------- /* *----------------------------------------------------------------------------- * Vfont - to - Atari font conversion utility * * vtoa [-a] [-d] [-v] <infile> <outfile> * * -a: generate Atari (MC68000) ordered font; defaults to Intel order * -d: generate char info dump on stdout * -v: generate char map output on stdout * * Beyond all the bl**dy byte-sex problems, this is pretty straight- * forward code. I refer you to /usr/man/man5/vfont.5 and Appendix G, * D.R. VDI Programmers Guide for specifics. *----------------------------------------------------------------------------- */ #include <stdio.h> #include <stat.h> #include <ctype.h> extern char * malloc(); /* mem allocator function */ #define VGLYPHS 256 /* how many glyphs in a vfont file */ #define VMAGIC 0x011E /* magic at start of vfont file */ #define VCIGAM 0x1E01 /* what it looks like to a vax :-) */ int sflag = 0; /* input byte-swapping flag */ int aflag = 0; /* output byte-swapping flag */ int dflag = 0; /* dump flag */ int vflag = 0; /* verbose dump flag */ struct v_header { /* Bezerkely vfont file header */ short magic; /* file id 'magic number' == VMAGIC */ unsigned short size; /* bytes in the glyphs' bitmaps */ short maxx; /* pixels wide, widest glyph */ short maxy; /* pixels high, highest glyph */ short xtnd; /* spare field for future expansion */ }; struct v_dispatch { /* descriptor entry for a glyph */ unsigned short addr; /* offset from start of glyphs */ short nbytes; /* how many bytes in the bitmap */ char up; /* pixels above basepoint */ char down; /* pixels below basepoint */ char left; /* pixels to left of basepoint */ char right; /* pixels to right of basepoint */ short width; /* offset to next glyph basepoint */ }; /* *----------------------------------------------------------------------------- * Read a Bezerkely vfont file into internal datastructures. Try to be clever. *----------------------------------------------------------------------------- */ struct v_header * v_info; struct v_dispatch * v_glyph; char * v_bitmap[ VGLYPHS ]; char * read_vfont( name ) char * name; { struct stat statbuf; int handle; int t, max_x, max_y, high, wide; /* * make sure the input is a real file and not a directory */ if ( stat( name, & statbuf ) == -1 ) return "file not found"; if ( ( statbuf.st_mode & ( S_IJVOL | S_IJDIR ) ) != 0 ) return "not a file"; /* * allocate a chunk of ram big enough to hold the whole file */ if ( ( v_info = (struct v_header *) malloc( (unsigned int) statbuf.st_size ) ) == (struct v_header *) NULL ) return "not enough memory"; /* * suck in the file and close it */ if ( ( handle = open( name, 0 ) ) == -1 ) return "open failed"; if ( read( handle, (char *) v_info, (int) statbuf.st_size ) != (int) statbuf.st_size ) return "read failed"; close( handle ); /* * establish the byte sex by examining the 'magic number'. * then flip words as appropriate, in the header and the * glyph descriptor array. */ sflag = v_info->magic == VCIGAM; if ( v_info->magic != VMAGIC && v_info->magic != VCIGAM ) return "bad magic number"; if ( sflag ) /* need to swap some bytes... */ swab( (char *) v_info, (char *) v_info, /* info struct is q&d */ sizeof (struct v_header) ); v_glyph = (struct v_dispatch *) ( (char *) v_info + sizeof (struct v_dispatch) ); if ( sflag ) /* need to swap some bytes... */ for ( t = 0; t < VGLYPHS; ++ t ) { swab( (char *) & v_glyph[ t ].addr, (char *) & v_glyph[ t ].addr, 2 * sizeof (short int) ); swab( (char *) & v_glyph[ t ].width, (char *) & v_glyph[ t ].width, sizeof (short int) ); } /* * build the edge vector to point at the glyph bitmaps. this isn't * really essential, but makes other parts of the code simpler. */ for ( t = 0; t < VGLYPHS; ++ t ) v_bitmap[ t ] = v_glyph[ t ].nbytes ? (char *) ( v_glyph + VGLYPHS ) + v_glyph[ t ].addr : (char *) NULL; /* * run a consistency check: see that the header's idea of the * largest cell and the descriptor's idea of the largest cell * agree. the manual entry for the data structure is a little * vague on whether they really do or not. */ for ( max_x = max_y = t = 0; t < VGLYPHS; ++ t ) if ( v_glyph[ t ].nbytes ) { high = v_glyph[ t ].up + v_glyph[ t ].down; if ( high > max_y ) max_y = high; wide = v_glyph[ t ].left + v_glyph[ t ].right; if ( wide > max_x ) max_x = wide; } v_info->maxx = max_x; v_info->maxy = max_y; if ( dflag ) fprintf( stderr, "max x = %d, max y = %d\n", v_info->maxx, v_info->maxy ); return (char *) NULL; } /* *----------------------------------------------------------------------------- * utility function to test a bit in a vfont glyph image. PFM technique code. *----------------------------------------------------------------------------- */ int test_v_bit( glyph, x, y ) int glyph, x, y; { register int wide; register char * pix_base; wide = ( v_glyph[ glyph ].right + v_glyph[ glyph ].left + 7 ) >> 3; pix_base = v_bitmap[ glyph ] + y * wide; return ( * ( pix_base + ( x >> 3 ) ) & ( 0x80 >> ( x & 7 ) ) ) != 0; } /* *----------------------------------------------------------------------------- * Dump out info on a vfont file. Never trust the documentation :-) *----------------------------------------------------------------------------- */ void dump_vfont() { int t; fprintf( stderr, "Header: @ %08lx = magic = %04x, size = %d, maxx= %d, maxy = %d\n", v_info, v_info->magic, v_info->size, v_info->maxx, v_info->maxy ); for ( t = 0; t < VGLYPHS; ++ t ) if ( v_glyph[ t ].nbytes ) { fprintf( stderr, "%03o %c @ %08lx : nbytes = %d, ", t, isprint( t ) ? t : ' ', v_bitmap[ t ], v_glyph[ t ].nbytes ); fprintf( stderr, "u = %d, d = %d, l = %d, r = %d, w = %d\n", v_glyph[ t ].up, v_glyph[ t ].down, v_glyph[ t ].right, v_glyph[ t ].left, v_glyph[ t ].width ); if ( vflag ) { /* * this code drops out 'tty' plots of the glyph images, * and was written mainly to confirm that I understood the * internal representation of the glyphs correctly */ int x, y, high, wide, until_base; wide = v_glyph[ t ].right + v_glyph[ t ].left; high = v_glyph[ t ].up + v_glyph[ t ].down; until_base = v_glyph[ t ].up * wide + v_glyph[ t ].left; for ( y = 0; y < high; ++ y ) { for ( x = 0; x < wide; ++ x ) fprintf( stderr, "%c%c", test_v_bit( t, x, y ) ? '@' : ' ', -- until_base ? ' ' : '.' ); fprintf( stderr, "\n" ); } } } } /* *----------------------------------------------------------------------------- * take the bezerkley stuff and build one of ours from it. *----------------------------------------------------------------------------- */ struct font_hdr { /* atari font header */ int id; /* id for vst_font() */ int size; /* font size in points */ char facename[32]; /* face name for vqt_name() */ int ADE_lo; /* lowest ADE in the font */ int ADE_hi; /* highest ADE in the font */ int top_dist; /* top line distance */ int asc_dist; /* ascent line distance */ int hlf_dist; /* half line distance */ int des_dist; /* descent line distance */ int bot_dist; /* bottom line distance */ int wchr_wdt; /* width of widest char */ int wcel_wdt; /* width of widest cell */ int lft_ofst; /* left offset */ int rgt_ofst; /* right offset */ int thckning; /* pixels to thicken by */ int undrline; /* width of underline */ int lghtng_m; /* fading mask */ int skewng_m; /* skewing mask */ int flags; /* default|horz offset|byte sex|mono */ char *hz_ofst; /* horizontal offset table */ int *ch_ofst; /* char offset table */ char *fnt_dta; /* font table proper */ int frm_wdt; /* form width */ int frm_hgt; /* and height */ char *nxt_fnt; /* link to next font */ }; struct font_hdr * a_info; /* global data block for atari */ char * a_glyph; /* place for the form block */ int * a_offset; /* place for char pixel offsets */ /* *----------------------------------------------------------------------------- * set a bit in the atari charset form to a specified value. *----------------------------------------------------------------------------- */ void set_a_bit( glyph, x, y, to ) int glyph, x, y, to; { register int form_x_bit, form_x_byte; form_x_bit = ( a_offset[ glyph ] + x ) & 7; form_x_byte = ( ( a_offset[ glyph ] + x ) >> 3 ) + a_info->frm_wdt * y; if ( to ) a_glyph[ form_x_byte ] |= 0x0080 >> form_x_bit; else a_glyph[ form_x_byte ] &= 0xFF7F >> form_x_bit; } /* *----------------------------------------------------------------------------- * another utility function, to swap words analgous to swab() *----------------------------------------------------------------------------- */ void swaw( f, t, wc ) int * f, * t, wc; { register int tmp; do { tmp = f[ 0 ]; t[ 0 ] = f[ 1 ]; t[ 1 ] = tmp; f += 2; t += 2; } while ( ( wc -= 2 ) > 0 ); } /* *----------------------------------------------------------------------------- * build an atari font description and write it out to a file. lots of * guessing and patching to slide over the empty places in the doc :-). *----------------------------------------------------------------------------- */ char * write_afont( name ) char * name; { int t, pix_wide, pix_above, pix_below, handle; /* * begin by allocating ram for font global information */ if ( ( a_info = (struct font_hdr *) malloc( (unsigned) sizeof (struct font_hdr) ) ) == (struct font_hdr *) NULL ) return "can't allocate header"; /* allocate and zero out the pixel-offset array */ if ( ( a_offset = (int *) malloc( (unsigned) sizeof (int) * ( VGLYPHS + 1 ) ) ) == (int *) NULL ) return "can't allocate offset vector"; for ( t = 0; t < VGLYPHS; ++ t ) a_offset[ t ] = 0; /* * this stuff needs to be set up with a tool like GEMFED or * whatever; there's not enough information available to me * to do it now. */ a_info->id = 0; a_info->size = v_info->maxy; /* this is all 'best-guess' */ strcpy( a_info->facename, name ); /* * figure out the low and high ADE values */ for ( t = 0; t < VGLYPHS; ++ t ) if ( v_glyph[ t ].nbytes ) break; a_info->ADE_lo = t; for ( t = VGLYPHS; t --; ) if ( v_glyph[ t ].nbytes ) break; a_info->ADE_hi = t; /* * scan through the descriptor list, collecting three pieces of * information: total width of the 'form', and the maximum number * of scan lines above and below the base line. From this we can * figure out how much memory to allocate for the form array. * the descision to allocate 8 pixel-wide cells to null chars is * entirely arbitrary, but it had to be made :-). while doing this, * set up the pixel-offset values in a_offset. */ pix_wide = pix_above = pix_below = 0; for ( t = a_info->ADE_lo; t <= a_info->ADE_hi; ++ t ) { a_offset[ t ] = pix_wide; if ( v_glyph[ t ].nbytes ) { pix_wide += v_glyph[ t ].left + v_glyph[ t ].right; if ( pix_above < v_glyph[ t ].up ) pix_above = v_glyph[ t ].up; if ( pix_below < v_glyph[ t ].down ) pix_below = v_glyph[ t ].down; } else pix_wide += 8; } a_offset[ t ] = pix_wide; /* to establish width of last char */ /* * allocate the form array, handling the pad-to-word-length requirement * and including enough scan lines for the tallest and lowest char cells */ a_info->frm_wdt = ( ( pix_wide + 15 ) >> 4 ) << 1; a_info->frm_hgt = pix_above + pix_below; if ( ( a_glyph = malloc( (unsigned) a_info->frm_wdt * a_info->frm_hgt ) ) == (char *) NULL ) return "can't allocate form"; /* * make further guesses as to the values of stuff; use GEMFED to * clean this up, or else ignore the d*mned things. */ if ( dflag ) fprintf( stderr, "above = %d, below = %d\n", pix_above, pix_below ); a_info->top_dist = pix_above; a_info->asc_dist = pix_above - 1; a_info->hlf_dist = pix_above / 2; a_info->des_dist = pix_below - 1; a_info->bot_dist = pix_below; /* * describe maximum cell and char. */ a_info->wchr_wdt = a_info->wcel_wdt = v_info->maxx; a_info->lft_ofst = a_info->rgt_ofst = 1; /* * just keep on guessing... */ a_info->thckning = a_info->undrline = 1; a_info->lghtng_m = a_info->skewng_m = 0x5555; /* * for now, flags == 4 (intel format, no other options) */ a_info->flags = 4; /* * set up both offset tables just past the global info structure */ a_info->hz_ofst = (char *) NULL; a_info->ch_ofst = (int *) sizeof (struct font_hdr); /* * this field is required to be null */ a_info->nxt_fnt = (char *) NULL; /* * and now la piece de resistance: insert the glyph info into the * atari form. Remember that characters in the form do not observe * any byte alignment, and also that Intel word order may be enforced * later (blechh). */ for ( t = a_info->ADE_lo; t <= a_info->ADE_hi; ++ t ) if ( v_glyph[ t ].nbytes ) { register int x, y; int wide, high; high = v_glyph[ t ].up + v_glyph[ t ].down; wide = v_glyph[ t ].left + v_glyph[ t ].right; for ( x = 0; x < wide; ++ x ) for ( y = 0; y < high; ++ y ) set_a_bit( t, x, y, test_v_bit( t, x, y ) ); } /* * now the great tediousness of writing all this stuff back * figure out offset to font form data, etc, flip bytes, etc. * note also that the byte flipping means _we_ can't read the * d*mned info structs anymore, hence the caching of the ADE * values :-( */ { int high, low, wide, deep; high = a_info->ADE_hi; low = a_info->ADE_lo; wide = a_info->frm_wdt; deep = a_info->frm_hgt; a_info->fnt_dta = (char *) ( a_info->ch_ofst + ( a_info->ADE_hi - a_info->ADE_lo + 2 ) ); swab( (char *) & a_info->id, (char *) & a_info->id, 2 * sizeof (int) ); swab( (char *) & a_info->ADE_lo, (char *) & a_info->ADE_lo, 18 * sizeof (int) + 3 * sizeof (char *) + sizeof (int *) ); swaw( (int *) & a_info->hz_ofst, (int *) & a_info->hz_ofst, 2 ); swaw( (int *) & a_info->ch_ofst, (int *) & a_info->ch_ofst, 2 ); swaw( (int *) & a_info->fnt_dta, (int *) & a_info->fnt_dta, 2 ); swaw( (int *) & a_info->nxt_fnt, (int *) & a_info->nxt_fnt, 2 ); swab( (char *) a_offset, (char *) a_offset, VGLYPHS * sizeof (int) ); swab( a_glyph, a_glyph, wide * deep ); if ( ( handle = creat( name, 0 ) ) == -1 ) return "creat failed"; if ( write( handle, (char *) a_info, sizeof * a_info ) != sizeof * a_info ) return "header write failure"; if ( write( handle, (char *) & a_offset[ low ], ( high - low + 2 ) * sizeof (int) ) != ( high - low + 2 ) * sizeof (int) ) return "offset table write failure"; if ( write( handle, a_glyph, wide * deep ) != wide * deep ) return "char form write failure"; close( handle ); } return (char *) NULL; } /* *----------------------------------------------------------------------------- * Go away, leaving only a bad smell and a grease spot. *----------------------------------------------------------------------------- */ void abrt( msg, status ) char * msg; int status; { fputs( msg, stderr ); fputc( '\n', stderr ); exit( status ); } /* *----------------------------------------------------------------------------- * and now for that anti-climax, main(). The linker says ya gotta have one. *----------------------------------------------------------------------------- */ int main( argc, argv ) int argc; char * * argv; { char * err_msg; while ( -- argc && * * ++ argv == '-' ) switch ( ( * argv )[ 1 ] ) { case 'v' : ++ vflag; case 'd' : ++ dflag; break; case 'a' : ++ aflag; break; default: abrt( "bad switch", 2 ); } if ( argc != 2 ) abrt( "usage: vtoa [-v] [-d] [-a] <vfont-file> <afont-file>", 3 ); fprintf( stdout, "%s ", argv[ 0 ] ); if ( ( err_msg = read_vfont( argv[ 0 ] ) ) != (char *) NULL ) abrt( err_msg, 1 ); if ( dflag ) dump_vfont(); fprintf( stdout, "-> %s", argv[ 1 ] ); if ( ( err_msg = write_afont( argv[ 1 ] ) ) != (char *) NULL ) abrt( err_msg, 4 ); fprintf( stdout, "\n" ); exit( 0 ); } ---------------------the end-------------------------