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-------------------------