|  | /* | 
|  | * | 
|  | * Program that converts IBM font files to a format that works on Unix systems. | 
|  | * Essentially all the information needed came from the Adobe paper "Supporting | 
|  | * Downloadable PostScript Fonts". To use the program type, | 
|  | * | 
|  | *	ibmfont font.ibm >font.unix | 
|  | * | 
|  | * where font.ibm is the font file, exactly as it came over from an IBM PC, | 
|  | * and font.unix is equivalent host resident font file usable on Unix systems. | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <signal.h> | 
|  |  | 
|  | #define OFF		0 | 
|  | #define ON		1 | 
|  |  | 
|  | #define NON_FATAL	0 | 
|  | #define FATAL		1 | 
|  |  | 
|  | #define FALSE		0 | 
|  | #define TRUE		1 | 
|  |  | 
|  | char	**argv; | 
|  | int	argc; | 
|  |  | 
|  | char	*prog_name; | 
|  |  | 
|  | int	x_stat; | 
|  | int	debug = OFF; | 
|  | int	ignore = OFF; | 
|  |  | 
|  | FILE	*fp_in; | 
|  | FILE	*fp_out; | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  | 
|  | main(agc, agv) | 
|  |  | 
|  | int		agc; | 
|  | char	*agv[]; | 
|  |  | 
|  | { | 
|  |  | 
|  | /* | 
|  | * | 
|  | * IBM PC to Unix font converter. | 
|  | * | 
|  | */ | 
|  |  | 
|  | argc = agc; | 
|  | argv = agv; | 
|  | prog_name = argv[0]; | 
|  |  | 
|  | fp_in = stdin; | 
|  | fp_out = stdout; | 
|  |  | 
|  | options(); | 
|  | arguments(); | 
|  | exit(x_stat); | 
|  |  | 
|  | }   /* End of main */ | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  | 
|  | options() | 
|  |  | 
|  | { | 
|  |  | 
|  | int		ch; | 
|  | char	*names = "DI"; | 
|  |  | 
|  | extern char	*optarg; | 
|  | extern int	optind; | 
|  |  | 
|  | /* | 
|  | * | 
|  | * Command line options. | 
|  | * | 
|  | */ | 
|  |  | 
|  | while ( (ch = getopt(argc, argv, names)) != EOF ) { | 
|  | switch ( ch ) { | 
|  | case 'D':			/* debug flag */ | 
|  | debug = ON; | 
|  | break; | 
|  |  | 
|  | case 'I':			/* ignore FATAL errors */ | 
|  | ignore = ON; | 
|  | break; | 
|  |  | 
|  | case '?':			/* don't understand the option */ | 
|  | error(FATAL, ""); | 
|  | break; | 
|  |  | 
|  | default:			/* don't know what to do for ch */ | 
|  | error(FATAL, "missing case for option %c\n", ch); | 
|  | break; | 
|  | }   /* End switch */ | 
|  | }   /* End while */ | 
|  |  | 
|  | argc -= optind; | 
|  | argv += optind; | 
|  |  | 
|  | }   /* End of options */ | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  | 
|  | arguments() | 
|  |  | 
|  | { | 
|  |  | 
|  | /* | 
|  | * | 
|  | * Everything esle is an input file. No arguments or '-' means stdin. | 
|  | * | 
|  | */ | 
|  |  | 
|  |  | 
|  | if ( argc < 1 ) | 
|  | conv(); | 
|  | else | 
|  | while ( argc > 0 ) { | 
|  | if ( strcmp(*argv, "-") == 0 ) | 
|  | fp_in = stdin; | 
|  | else if ( (fp_in = fopen(*argv, "r")) == NULL ) | 
|  | error(FATAL, "can't open %s", *argv); | 
|  | conv(); | 
|  | if ( fp_in != stdin ) | 
|  | fclose(fp_in); | 
|  | argc--; | 
|  | argv++; | 
|  | }   /* End while */ | 
|  |  | 
|  | }   /* End of arguments */ | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  | 
|  | conv() | 
|  |  | 
|  | { | 
|  |  | 
|  | int		blocksize; | 
|  | int		blocktype; | 
|  | int		seg; | 
|  | long	ftell(); | 
|  |  | 
|  | /* | 
|  | * | 
|  | * Font files on the IBM PC are stored in a compressed binary format. Individual | 
|  | * segments in the file are preceeded by a header that looks like, | 
|  | * | 
|  | *		Byte 1:		128 | 
|  | *		Byte 2:		segment type (1=ASCII, 2=TOHEX, or 3=EOF) | 
|  | *		Bytes 3-6:	length of the segment | 
|  | *		Bytes 7 ...	data | 
|  | * | 
|  | */ | 
|  |  | 
|  | while ( 1 ) { | 
|  | seg = ftell(fp_in); | 
|  | if ( getc(fp_in) != 128 ) | 
|  | error(FATAL, "bad file format"); | 
|  | blocktype = getc(fp_in); | 
|  | blocksize = getint(fp_in); | 
|  | if ( debug == ON ) { | 
|  | fprintf(stderr, "blocktype = %d, blocksize = %d\n", blocktype, blocksize); | 
|  | fprintf(stderr, "start=0%o, end=0%o\n", seg, seg+blocksize+6); | 
|  | fprintf(stderr, "start=%d, end=%d\n", seg, seg+blocksize+6); | 
|  | }   /* End if */ | 
|  | switch ( blocktype ) { | 
|  | case 1: | 
|  | asciitext(blocksize); | 
|  | break; | 
|  |  | 
|  | case 2: | 
|  | hexdata(blocksize); | 
|  | break; | 
|  |  | 
|  | case 3: | 
|  | return; | 
|  |  | 
|  | default: | 
|  | error(FATAL, "unknown resource type %d", blocktype); | 
|  | }   /* End switch */ | 
|  | }	/* End while */ | 
|  |  | 
|  | }   /* End of conv */ | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  | 
|  | asciitext(count) | 
|  |  | 
|  | int		count;			/* bytes left in the block */ | 
|  |  | 
|  | { | 
|  |  | 
|  | int		ch; | 
|  | int		i = 0; | 
|  |  | 
|  | /* | 
|  | * | 
|  | * Handles type 1 (ie. ASCII text) blocks. Changing carriage returns to newlines | 
|  | * is all I've done. | 
|  | * | 
|  | */ | 
|  |  | 
|  | for ( i = 0; i < count; i++ ) { | 
|  | if ( (ch = getc(fp_in)) == '\r' ) | 
|  | ch = '\n'; | 
|  | putc(ch, fp_out); | 
|  | }	/* End for */ | 
|  |  | 
|  | }   /* End of asciitext */ | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  | 
|  | hexdata(count) | 
|  |  | 
|  | int		count;			/* bytes left in the block */ | 
|  |  | 
|  | { | 
|  |  | 
|  | int		i; | 
|  | int		n; | 
|  |  | 
|  | /* | 
|  | * | 
|  | * Reads the next count bytes and converts each byte to hex. Also starts a new | 
|  | * line every 80 hex characters. | 
|  | * | 
|  | */ | 
|  |  | 
|  | for ( i = 0, n = 0; i < count; i++ ) { | 
|  | fprintf(fp_out, "%.2X", getc(fp_in)); | 
|  | if ( (++n % 40) == 0 ) | 
|  | putc('\n', fp_out); | 
|  | }	/* End for */ | 
|  |  | 
|  | }   /* End of hexdata */ | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  | 
|  | getint() | 
|  |  | 
|  | { | 
|  |  | 
|  | int		val; | 
|  |  | 
|  | /* | 
|  | * | 
|  | * Reads the next four bytes into an integer and returns the value to the caller. | 
|  | * First two bytes are probably always 0. | 
|  | * | 
|  | */ | 
|  |  | 
|  | val = getc(fp_in); | 
|  | val |= (getc(fp_in) << 8); | 
|  | val |= (getc(fp_in) << 16); | 
|  | val |= (getc(fp_in) << 24); | 
|  |  | 
|  | return(val); | 
|  |  | 
|  | }   /* End of getint */ | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  | 
|  | error(kind, mesg, a1, a2, a3) | 
|  |  | 
|  | int		kind; | 
|  | char	*mesg; | 
|  | unsigned	a1, a2, a3; | 
|  |  | 
|  | { | 
|  |  | 
|  | /* | 
|  | * | 
|  | * Print mesg and quit if kind is FATAL. | 
|  | * | 
|  | */ | 
|  |  | 
|  | if ( mesg != NULL && *mesg != '\0' ) { | 
|  | fprintf(stderr, "%s: ", prog_name); | 
|  | fprintf(stderr, mesg, a1, a2, a3); | 
|  | putc('\n', stderr); | 
|  | }	/* End if */ | 
|  |  | 
|  | if ( kind == FATAL && ignore == OFF ) | 
|  | exit(x_stat | 01); | 
|  |  | 
|  | }   /* End of error */ | 
|  |  | 
|  | /*****************************************************************************/ | 
|  |  |