/* * * This program was written with tabs set to every fourth column, * so things will look funny unless you have your tabs set the same way. * I haven't really finished the program, but it works and I doubt I'll * do anything else with it. * */ #include <stdio.h> #include <ctype.h> /* #include "glyph.h" */ #include "dev.h" #define NON_FATAL 0 #define FATAL 1 #define FALSE 0 #define TRUE 1 #define NOT_SET -1 /* variable has not been initialized */ #define RES 0 /* used in new_value() switch stmt */ #define UNIT 1 #define HOR 2 #define VERT 3 #define WIDTH 4 #define LENGTH 5 #define BMASK 0377 /* mask for characters */ #define CNAME 2 /* max length of special characters */ #define DNAME 10 /* max length of device name */ #define FNAME 10 /* max length of font name */ #define PNAME 50 /* longest allowed pathname */ #define MAX_BUFF 30 /* input strings are put here */ #define LINE_LENGTH 100 /* longest allowed line */ #define MAX_CHARS 255 /* most allowed chars per font */ #define SIZE_LENGTH 150 /* space allowed for new point sizes */ #define FONT_LENGTH 150 /* space for new default font list */ int use_rast = FALSE; /* get widths from raster tables? */ char path[PNAME+1]; /* path names built up here */ char *srcdir = "/usr/lib/font"; /* ASCII font files are kept here */ char *fontdir = "/usr/lib/font"; /* binary font and device files */ char *bitdir = "/usr/lib/font"; /* raster tables are located here */ char *changes = "FONTCHANGES"; /* interpret this file */ char mdev[DNAME+1] = ""; /* use this device's source files */ char tdev[DNAME+1] = ""; /* target device - for raster tables */ char cur_font[FNAME+1] = ""; /* font we are currently working on */ int unitwidth = NOT_SET; /* widths hold for this point size */ int res = NOT_SET; /* and this target device resolution */ int hor = NOT_SET; /* minimum horizontal step */ int vert = NOT_SET; /* minimum vertical step */ char fonts[FONT_LENGTH] = {0}; /* new default font list */ char sizes[SIZE_LENGTH] = {0}; /* and point size list */ float incr; /* add this to width after expansion */ float scale = NOT_SET; /* scale factor for width changes */ float dflt_chng = NOT_SET; /* default width change */ float font_chng = NOT_SET; /* width change for current font */ float dflt_incr = .5; /* add to width after expansion */ int dcount; /* index into following arrays */ char names[MAX_CHARS][CNAME+1]; /* special character strings go here */ float deltas[MAX_CHARS]; /* corresponding width changes */ float incrs[MAX_CHARS]; /* character increments */ struct dev dev; /* *mdev's DESC.out header goes here */ int nchtab; /* number of special chars in chtab */ short *pstab; /* point size table - not needed */ short *chtab; /* char's index in chname array */ char *chname; /* special character strings */ FILE *fp_change; /* file pointer for *changes */ FILE *fp_rast; /* raster table used for widths */ FILE *fp_in; /* input file for current font */ FILE *fp_out; /* output file for current font */ char **argv; /* let everyone use them */ int argc; /*****************************************************************************/ main(agc, agv) int agc; char *agv[]; { /******************************************************************** * * * This program reads the file *changes in the current * * directory which contains instructions on how to expand or * * contract the character widths for each of the fonts mentioned * * in the file. These changes will hopefully make the output for * * *tdev more readable. Admittedly there's quite a bit of overkill * * in this program, but I'm not going to change it. * * * * There are several different methods that can be used to * * make the desired width changes. Probably the simplest is to * * adjust the device resolution in the new DESC file up or down * * an appropriate ammount and leave the widths in the font tables * * unchanged. This approach results in a uniform width change for * * all the characters on every available font. This type of change * * can be obtained by specifying a default width change without * * defining a new device resolution. * * * * Since a uniform expansion may not always be appropriate * * you can also specify a width change for each for the new fonts. * * This type of expansion will replace any default font change * * that may have been specified. * * * ********************************************************************/ argv = agv; /* global so everyone can use them */ argc = agc; get_options(); /* process any command line options */ startchanges(); /* start reading the *changes file */ checkvalues(); /* make sure everything's defined */ getdesc(); /* read *mdev's DESC.out file */ makedesc(); /* make *tdev's new DESC file */ finishchanges(); /* read rest of the *changes file */ } /* End of main */ /******************************************************************************/ get_options() { /******************************************************************** * * * Called from the main program to read and process any * * command line options. * * * ********************************************************************/ while ( argc > 1 && argv[1][0] == '-' ) { switch ( argv[1][1] ) { case 'S': /* font source directory */ srcdir = &argv[1][2]; break; case 'F': /* binary font directory */ fontdir = &argv[1][2]; break; case 'R': /* raster table directory */ bitdir = &argv[1][2]; break; case 'm': /* get master device name */ if ( strlen(&argv[1][2]) > DNAME ) error(FATAL, "device name %s too long", &argv[1][2]); strcpy(mdev, &argv[1][2]); break; case 't': /* set target device name */ if ( strlen(&argv[1][2]) > DNAME ) error(FATAL, "device name %s too long", &argv[1][2]); strcpy(tdev, &argv[1][2]); break; default: error(FATAL, "illegal option %c", argv[1][1]); } /* End switch */ argv++; /* next argument */ argc--; } /* End while */ } /* End of get_options */ /*****************************************************************************/ startchanges() { char buff[MAX_BUFF]; /* input buffer */ int ch; /* used to skip comments */ /******************************************************************** * * * Called from the main program to read the font change file * * *changes. If there's still one command line argument left when * * we get here, we will use it as the name of the input file, * * otherwise the default file *changes is used. * * * ********************************************************************/ if ( argc > 1 ) changes = &argv[1][0]; if ( (fp_change = fopen(changes, "r")) == NULL ) error(FATAL, "can't open file %s", changes); while ( fscanf(fp_change, "%s", buff) != EOF ) { if ( strcmp(buff, "font") == 0 ) return; else if ( strcmp(buff, "master") == 0 ) get_mdev(); else if ( strcmp(buff, "target") == 0 ) get_tdev(); else if ( strcmp(buff, "unitwidth") == 0 ) get_int(fp_change, &unitwidth); else if ( strcmp(buff, "res") == 0 ) get_int(fp_change, &res); else if ( strcmp(buff, "hor") == 0 ) get_int(fp_change, &hor); else if ( strcmp(buff, "vert") == 0 ) get_int(fp_change, &vert); else if ( strcmp(buff, "sizes") == 0 ) get_sizes(); else if ( strcmp(buff, "fonts") == 0 ) get_fonts(); else if ( strcmp(buff, "default") == 0 ) { fscanf(fp_change, "%s", buff); if ( strcmp(buff, "change") != 0 ) error(FATAL, "syntax error - bad default change statement"); get_float(fp_change, &dflt_chng); } else if ( strcmp(buff, "round") == 0 ) { fscanf(fp_change, "%s", buff); if ( strcmp(buff, "up") == 0 ) dflt_incr = 1.0; else if ( strcmp(buff, "down") == 0 ) dflt_incr = 0.0; else error(FATAL, "syntax error - bad round statement"); } else if ( strcmp(buff, "use") == 0 ) { fscanf(fp_change, "%s", buff); if ( strcmp(buff, "raster") != 0 ) error(FATAL, "syntax error - bad use statement"); fscanf(fp_change, "%s", buff); if ( strcmp(buff, "tables") == 0 ) error(FATAL, "syntax error - bad use statement"); use_rast = TRUE; } else if ( buff[0] == '#' ) while ( (ch = getc(fp_change)) != EOF && ch != '\n' ) ; else error(FATAL, "don't know command %s", buff); } /* End while */ error(FATAL, "no font commands in file %s", changes); } /* End of startchanges */ /*****************************************************************************/ checkvalues() { /******************************************************************** * * * Called from the main program to make sure all the required * * parameters have been properly defined. * * * ********************************************************************/ if ( *mdev == '\0' ) error(FATAL, "missing master device name"); if ( use_rast == TRUE ) if ( *tdev == '\0' ) error(FATAL, "missing target device name"); else if ( res == NOT_SET ) error(FATAL, "missing target device resolution"); } /* End of checkvalues */ /*****************************************************************************/ get_mdev() { char buff[MAX_BUFF]; /* put the device name here */ /******************************************************************** * * * Read the name of the master device from *fp_change, and * * save the name in array mdev[]. If *mdev has already been set, * * possibly by an option, it won't be changed again. * * * ********************************************************************/ if ( fscanf(fp_change, " device %s", buff) != 1 ) error(FATAL, "missing master device name"); if ( strlen(buff) > DNAME ) error(FATAL, "master device name %s too long", buff); if ( *mdev == '\0' ) strcpy(mdev, buff); } /* End of get_mdev */ /*****************************************************************************/ get_tdev() { char buff[MAX_BUFF]; /* target device name put here */ /******************************************************************** * * * Called from startchanges() to read the name of the target * * typesetter from *fp_change, and store the result in the array * * tdev[]. If the device has already been specified nothing is * * done. * * * ********************************************************************/ if ( fscanf(fp_change, " device %s", buff) != 1 ) error(FATAL, "missing target device name"); if ( strlen(buff) > DNAME ) error(FATAL, "target device name %s too long", buff); if ( *tdev != '\0' ) strcpy(tdev, buff); } /* End of get_tdev */ /*****************************************************************************/ get_int(fp, num) FILE *fp; /* read an integer from this file */ int *num; /* and store it here */ { /******************************************************************** * * * Called to read an integer from the input file and store the * * result in num - this routine and get_float() really should be * * macros. * * * ********************************************************************/ if ( fscanf(fp, "%d", num) != 1 ) error(FATAL, "syntax error - integer not found"); } /* End of get_int */ /*****************************************************************************/ get_float(fp, num) FILE *fp; /* read a float from this file */ float *num; /* and store it here */ { /******************************************************************** * * * Called to read a floating point number from *fp_change and * * store the result in num. * * * ********************************************************************/ if ( fscanf(fp, "%f", num) != 1 ) error(FATAL, "syntax error - floating point number not found"); } /* End of get_float */ /*****************************************************************************/ get_sizes() { int i; /* index into sizes[] array */ /******************************************************************** * * * Called from startchanges() to read the new default point * * size list for the DESC file. The format expected for the size * * list in the *fp_change file is the same as in the ASCII DESC * * file. * * * ********************************************************************/ i = 0; while ( i < SIZE_LENGTH ) { while ( isspace(sizes[i++] = getc(fp_change)) ) ; if ( !isdigit(sizes[i-1]) ) error(FATAL, "syntax error - bad point size list"); if ( sizes[i-1] == '0' && (isspace(sizes[i++] = getc(fp_change))) ) { sizes[i-1] = '\0'; return; } /* End if */ while ( isdigit(sizes[i++] = getc(fp_change)) ) ; } /* End while */ error(FATAL, "point size list too long"); /* shouldn't get here */ } /* End of get_sizes */ /*****************************************************************************/ get_fonts() { int count; /* number of default fonts */ int i; /* index used for fonts[] array */ /******************************************************************** * * * Called from startchanges() to read a new default font list * * for the new DESC file. Again the format expected for the font * * list is the same as in the ASCII DESC file. * * * ********************************************************************/ count = -1; /* real value is the first string */ i = 0; /* next character goes here */ do { while ( isspace(fonts[i++] = getc(fp_changes)) ) ; while ( !isspace(fonts[i++] = getc(fp_changes)) ) ; if ( count < 0 ) /* string is the default font count */ count = atoi(fonts); } while ( count-- > 0 ); fonts[i-1] = '\0'; } /* End of get_fonts */ /*****************************************************************************/ getdesc() { int fin; /* DESC.out's file descriptor */ char *filebase; /* memory block for DESC.out file */ char *malloc(); /* memory allocation routine */ /******************************************************************** * * * Called from the main program to read the DESC.out file for * * *mdev. Most of the file is only needed if we are going to do * * the width lookups in the raster tables, but anyway we'll read * * the whole thing in. * * * ********************************************************************/ sprintf(path, "%s/dev%s/DESC.out", fontdir, mdev); if ( (fin = open(path, 0)) < 0 ) error(FATAL, "can't open file %s", path); read(fin, &dev, sizeof(struct dev)); /* struct dev comes first */ nchtab = dev.nchtab; if ( (filebase = malloc(dev.filesize)) == NULL ) error(FATAL, "no memory available"); read(fin, filebase, dev.filesize); /* get rest of the DESC.out file */ pstab = (short *) filebase; /* this table is never used */ chtab = pstab + dev.nsizes + 1; chname = (char *) (chtab + dev.nchtab); close(fin); /* won't need this guy again */ } /* End of getdesc */ /*****************************************************************************/ makedesc() { char buff[MAX_BUFF]; /* input strings are put here */ int ch; /* used in skipping over comments */ int temp; /* used to skip font and point sizes */ /******************************************************************** * * * Called from the main program to make the new ASCII DESC * * file for *tdev. * * * ********************************************************************/ sprintf(path, "%s/dev%s/DESC", srcdir, mdev); if ( (fp_in = fopen(path, "r")) == NULL ) error(FATAL, "can't read file %s", path); if ( (fp_out = fopen("DESC", "w")) == NULL ) error(FATAL, "can't write new DESC file"); while ( fscanf(fp_in, "%s", buff) != EOF ) { fprintf(fp_out, "%s", buff); if ( strcmp(buff, "res") == 0 ) new_value(RES); else if ( strcmp(buff, "hor") == 0 ) new_value(HOR); else if ( strcmp(buff, "vert") == 0 ) new_value(VERT); else if ( strcmp(buff, "unitwidth") == 0 ) new_value(UNIT); else if ( strcmp(buff, "paperwidth") == 0 ) new_value(WIDTH); else if ( strcmp(buff, "paperlength") == 0 ) new_value(LENGTH); else if ( strcmp(buff, "fonts") == 0 && fonts[0] ) { fprintf(fp_out, "%s\n", fonts); get_int(fp_in, &temp); while ( temp-- > 0 ) fscanf(fp_in, "%s", buff); } else if ( strcmp(buff, "sizes") == 0 && sizes[0] ) { fprintf(fp_out, "%s\n", sizes); do { get_int(fp_in, &temp); } while ( temp != 0 ); } else if ( strcmp(buff, "charset") == 0 ) while ( (ch = getc(fp_in)) != EOF ) putc(ch, fp_out); else copy_line(); } /* End while */ fclose(fp_in); fclose(fp_out); } /* End of makedesc */ /*****************************************************************************/ new_value(value) int value; /* used in the switch statement */ { int temp; /* next number read from *fp_in */ /******************************************************************** * * * Called from makedesc() to write a new value out to the DESC * * file for the parameter specified by value. * * * ********************************************************************/ get_int(fp_in, &temp); switch ( value ) { case RES: if ( res == NOT_SET ) if ( dflt_chng == NOT_SET ) { res = temp; dflt_chng = 0.0; } else res = temp / (1 + dflt_chng); temp = res; break; case UNIT: if ( unitwidth == NOT_SET ) unitwidth = temp; temp = unitwidth; break; case HOR: if ( hor == NOT_SET ) hor = temp; temp = hor; break; case VERT: if ( vert == NOT_SET ) vert = temp; temp = vert; break; case WIDTH: case LENGTH: temp = (temp * res) / dev.res; break; } /* End switch */ fprintf(fp_out, " %d\n", temp); } /* End of new_value */ /*****************************************************************************/ finishchanges() { char buff[MAX_BUFF]; int ch; int i; /******************************************************************** * * * Called from startchanges() to process all the new font * * commands. * * * ********************************************************************/ nextfont(); /* do initialization for next font */ while ( fscanf(fp_change, "%s", buff ) != EOF ) { if ( strcmp(buff, "font") == 0 ) { makefont(); nextfont(); } else if ( strcmp(buff, "increment") == 0 ) { if ( fscanf(fp_change, "%s by ", buff) != 1 ) error(FATAL, "syntax error - bad file format"); if ( strlen(buff) > CNAME ) error(FATAL, "special char %s too long", buff); i = lookup(buff); get_float(fp_change, &incrs[i]); if ( i == dcount ) { deltas[dcount] = NOT_SET; strcpy(&names[dcount++][0], buff); } /* End if */ } else if ( strcmp(buff, "change") == 0 ) { if ( fscanf(fp_change, "%s by ", buff) != 1 ) error(FATAL, "syntax error - bad file format"); if ( strcmp(buff, "widths") == 0 ) get_float(fp_change, &font_chng); else { if ( strlen(buff) > CNAME ) error(FATAL, "special char %s too long", buff); i = lookup(buff); get_float(fp_change, &deltas[i]); if ( i == dcount ) { incrs[dcount] = 0; strcpy(&names[dcount++][0], buff); } /* End if */ } /* End else */ } else if ( buff[0] == '#' ) while ( (ch = getc(fp_change)) != '\n' && ch != EOF ) ; } /* End while */ makefont(); } /* End of finishchanges */ /*****************************************************************************/ nextfont() { /******************************************************************** * * * Called from finishchanges() to get the name of the next * * font and do any other initialization that may be required. * * * ********************************************************************/ fscanf(fp_change, "%s", cur_font); /* name of the next font */ font_chng = NOT_SET; incr = dflt_incr; dcount = 0; if ( scale == NOT_SET ) if ( use_rast == TRUE ) scale = 1.0; else scale = ( float )(res * unitwidth) / (dev.res * dev.unitwidth); } /* End of nextfont */ /*****************************************************************************/ makefont() { char buff[MAX_BUFF]; /* temp buffer for *fp_change reads */ /******************************************************************** * * * This routine makes all the new ASCII font files. * * * ********************************************************************/ sprintf(path, "%s/dev%s/%s", srcdir, mdev, cur_font); if ( (fp_in = fopen(path, "r")) == NULL ) error(FATAL, "can't open font file %s", path); if ( (fp_out = fopen(cur_font, "w")) == NULL ) error(FATAL, "can't open output font file %s", cur_font); while ( fscanf(fp_in, "%s", buff) != EOF ) { fprintf(fp_out, "%s", buff); /* echo what we just read in */ if ( strcmp(buff, "charset") == 0 ) copy_chars(); else copy_line(); } /* End while */ fclose(fp_in); /* done with these files for now */ fclose(fp_out); } /* End of makefont */ /*****************************************************************************/ copy_chars() { char ch[10]; /* standard stuff from makedev */ char width[10]; char kern[10]; char code[10]; char buff[LINE_LENGTH]; /* next line from charset part */ /******************************************************************** * * * Called from makefont() to copy the charset portion of the * * current font file to the output file. The width entry for each * * character will be adjusted by routine newwidth(). * * * ********************************************************************/ putc('\n', fp_out); while ( fgets(buff, sizeof(buff), fp_in) != NULL ) { if ( sscanf(buff, "%s %s %s %s", ch, width, kern, code) < 2 ) continue; if ( width[0] == '"' ) { /* it's a synonym */ fprintf(fp_out, "%s", buff); continue; } /* End if */ newwidth(ch, width); /* calculate *ch's new width */ fprintf(fp_out, "%s\t%s\t%s\t%s\n", ch, width, kern, code); } /* End while */ } /* End of copy_chars */ /*****************************************************************************/ copy_line() { int ch; /******************************************************************** * * * Called from makefont() to copy the current line from fp_in * * to fp_out. * * * ********************************************************************/ while ( (ch = putc(getc(fp_in), fp_out)) != '\n' && ch != EOF ) ; } /* End of copy_line */ /*****************************************************************************/ newwidth(ch, width) char *ch; /* get the width for this character */ char *width; /* and store it here */ { int newwidth; /* character's new width */ float cwidth; /* char's current width */ float delta; /* width change for the character */ float getdelta(); float atof(); /******************************************************************** * * * Called from copy_chars() to get the new width for character * * ch, and store the ASCII representation for it in array width[]. * * If we are supposed to be getting the character widths from the * * raster tables we call getwidth() to do the work, otherwise we * * use the value obtained from the ASCII font file. * * * ********************************************************************/ if ( use_rast == TRUE ) cwidth = getwidth(ch); else cwidth = atof(width); delta = getdelta(ch); if ( (newwidth = cwidth * (1 + delta) * scale + incr) < 0 || newwidth > BMASK ) error(FATAL, "bad width %d for char %s", newwidth, ch); sprintf(width, "%d", newwidth); } /* End of newwidth */ /*****************************************************************************/ getwidth(ch) char *ch; /* get raster width for this char */ { /******************************************************************** * * * Called from newwidth() to get the raster table width for * * character ch form the raster table for the current font and in * * size unitwidth. * * * ********************************************************************/ return(1); } /* End of getwidth */ /*****************************************************************************/ float getdelta(ch) char *ch; /* get change for this char */ { int i; float change; /******************************************************************** * * * This routine gets the appropriate change in width that we * * should use for character ch in the new font table. * * * ********************************************************************/ change = font_chng == NOT_SET ? dflt_chng : font_chng; incr = dflt_incr; if ( (i = lookup(ch)) < dcount ) { change = ( deltas[i] == NOT_SET ) ? change : deltas[i]; incr += incrs[i]; } /* End if */ return(change); } /* End of getdelta */ /*****************************************************************************/ lookup(ch) char *ch; /* look this character string up */ { int i; /******************************************************************** * * * Called from finishchanges() to find the character string * * *ch in array names[]. If it isn't found dcount is returnd. * * * ********************************************************************/ for ( i = 0; i < dcount; i++ ) if ( strcmp(ch, &names[i][0]) == 0 ) break; return(i); } /* End of lookup */ /*****************************************************************************/ error(kind, mesg, arg1, arg2) int kind; /* FATAL or NON_FATAL error */ char *mesg; /* error message to be printed */ { /******************************************************************** * * * Write out the error message *mesg, and quit the program if * * kind is FATAL. * * * ********************************************************************/ fprintf(stderr, "makefonts: "); fprintf(stderr, mesg, arg1, arg2); fprintf(stderr, "\n"); if ( kind == FATAL ) exit(1); } /* End of error */ /*****************************************************************************/