V10/cmd/dimpress/dimpress.c
/*
*
* dimpress - cleaned up and modified code borrowed from di10.
*
*
* troff post-processor for Imagen printers. Output is written in
* version 2.0 Impress, although it does still work for earlier versions.
* Raster files in either the old format or in Imagen's Rst format can
* be used for character generation. Drawing functions are handled by
* the routines in file impdraw.c. I rewrote most of those routines so they
* use the graphics primitives avaliable in version 1.9 (and later) Impress.
* If you're printer is still running older systems you'll probably need
* to get the original version of draw.c and use it instead.
*
* All the code should work properly for any printer that accepts Impress.
* By default I've got things set up for the 8/300, but you can use the
* -T option to select a different printer. If you choose a new printer
* name not supported under the -T option you'll probably want to add code
* to do the proper initialization. There really are only six variables
* that need to be changed for different printers. They include realdev,
* penwidth, pres, xoff, yoff, and possibly bitdir. The printer variables
* are defined in dimpress.h (PR_INIT) and that's what's used to initialize
* the prdata[] array. If you make changes just be sure that the list ends
* with an entry that has its prname field set to NULL.
*
*
* output language from troff:
* all numbers are character strings
*
* sn size in points
* fn font as number from 1-n
* cx ascii character x
* Cxyz funny char xyz. terminated by white space
* Hn go to absolute horizontal position n
* Vn go to absolute vertical position n (down is positive)
* hn go n units horizontally (relative)
* vn ditto vertically
* nnc move right nn, then print c (exactly 2 digits!)
* (this wart is an optimization that shrinks output file size
* about 35% and run-time about 15% while preserving ascii-ness)
* Dt ...\n draw operation 't':
* Dl x y line from here by x,y
* Dc d circle of diameter d with left side here
* De x y ellipse of axes x,y with left side here
* Da x y r arc counter-clockwise by x,y of radius r
* D~ x y x y ... wiggly line by x,y then x,y ...
* nb a end of line (information only -- no action needed)
* b = space before line, a = after
* p new page begins -- set v to 0
* #...\n comment
* x ...\n device control functions:
* x i init
* x T s name of device is s
* x r n h v resolution is n/inch
* h = min horizontal motion, v = min vert
* x p pause (can restart)
* x s stop -- done for ever
* x t generate trailer
* x f n s font position n contains font s
* x H n set character height to n
* x S n set slant to N
*
* Subcommands like "i" are often spelled out like "init".
*
*/
#include <stdio.h>
#include <signal.h>
#include <math.h>
#include <ctype.h>
#include <time.h>
#include "gen.h" /* general purpose definitions */
#include "ext.h" /* external variable definitions */
#include "init.h" /* just used for BITDIR definition */
#include "rast.h" /* raster file definitions */
#include "dev.h" /* typesetter and font descriptions */
#include "impcodes.h" /* Impress 2.0 opcode definitions */
#include "dimpress.h" /* defs just used by this program */
#include "spectab.h"
/*
*
* A few names we'll need when we're printing files. devname[] is what troff
* thought was going to be the output device while realdev[] is the name
* of the printer we're really going to be using. There may be occasions when
* we want to send the output to a given printer (*realdev) but we want to
* use the raster tables that were built for a different one (*rastdev). If
* rastdev isn't NULL we'll assume that this is the name of the device's
* raster files that we want to use. In otherwords if *rastdev hasn't been
* set by an option *realdev will be used in combination with *bitdir to
* define *rastdir.
*
*/
char devname[20] = ""; /* troff's target printer */
char *realdev = NULL; /* name of the printer we're really using */
char *rastdev = NULL; /* use raster tables made for this guy */
/*
*
* There's a bunch of stuff we'll want to know about the raster files we're
* planning on using for this job. The most important, obviously is where
* they're located. The routines that access the raster files all assume
* they're in directory *rastdir, so it better be set up right before we
* try to print anything. I've decided to have this program build up the
* *rastdir string from *bitdir and either *rastdev or *realdev. All this
* stuff will be done after the options are read. One of the reasons I'm
* doing things this way is because we could want to do something like
* print a troff file generated for the APS-5 on an Imprint-10 using the
* raster files built for an 8/300. While that may sound rediculous the
* raster tables can use up a lot of disk space and we may not want to
* waste the space keeping complete sets of raster files for two or three
* different devices. Anyway we should be able to do something reasonable
* no matter what devices and raster files are requested.
*
* *bitdir is initialized to BITDIR (file init.h) and can be changed using
* the -B option. The raster files for a particular device, say the 8/300
* which is being called i300, will be found in directory *bitdir/rasti300.
* It's defined in file glob.c because resident font routines need the
* directory.
*
* We'll also need to know the format of the raster files we're using before
* we can have any characters printed. rastformat keeps track of which
* style is being used. It's initialized in routine rastsetup() using
* info in file *rastdir/RASTDATA - if it exists. Right now if rastsetup()
* can't read the RASTDATA file it assumes that the raster files are the
* old versetec format and have a resolution of 240 dots per inch. I've
* done things this way just to make sure we can use the post-processor
* with the old raster files without having to add an appropriate RASTDATA
* file to the directory. Eventually it may not be a bad idea to just
* quit if we can't read the file.
*
*/
int rastformat;
/*
*
* Although I originally had ideas about not using a RASTERLIST file, I now
* think it's probably a pretty good idea to use one. We could get around the
* missing size problems by linking raster files for unavailble sizes to ones
* we really have. That approach would cost more in downloading glyphs, but
* more we'd probably be able to place the glyphs a little better because
* we'd be able to set the character advance separately. Anyway it's really
* not all that clear which approach is better. I've allowed for use of a
* RASTERLIST file (routine rastlist()) but I've also decided that if it's
* not there we'll continue on with the program assuming we have every size
* that jobs ask for. If the job asks for a non-existent file it will die
* in routine getrastdata().
*
* The following data structures are used to keep track of any RASTLIST
* data we may have read. If maxrast is zero then there isn't any data
* and we'll assume, when we do the lookups, that all fonts can be printed
* in any size.
*
*/
int maxrast = 0; /* number of RASTERLIST font entries */
Sizedata sizedata[MAXFONTS]; /* available raster size data */
/*
*
* Standard things needed after we've read troff's font and device tables.
* The binary files are all built by makedev and will be looked for in the
* target printer's dev directory located in *fontdir. Actually that's not
* quite right. There are mapping problems, both for fonts and characters,
* that will exist if we try and use font files for a device that don't
* exactly map into the raster files that are being used. For example if
* we used the character code field in the normal APS-5 font tables when
* we print jobs generated for the APS-5 we'd be guaranteed to get garbage.
* To get around that problem I have the post-processor first look in
* *rastdir for the dev directory. If it's not there then we look in *fontdir.
*
*/
struct dev dev; /* DESC.out starts this way */
struct Font *fontbase[NFONT+1]; /* starts each FONT.out file */
short *pstab; /* typesetter knows these sizes */
int nsizes = 1; /* sizes in *pstab list */
int nfonts; /* number of font positions */
int smnt; /* index of first special font */
int nchtab; /* number of special character names */
char *chname; /* special character strings */
short *chtab; /* used to locate character names */
char *fitab[NFONT+1]; /* locates char info on each font */
char *widthtab[NFONT+1]; /* widtab would be a better name */
char *codetab[NFONT+1]; /* codes to get characters printed */
/*
*
* Variables that we use to keep track of troff's requests. All these
* guys are set from values in the input files.
*
*/
int size = 1; /* current size - internal value */
int font = 1; /* font position we're using now */
int hpos = 0; /* troff's current horizontal position */
int vpos = 0; /* same but vertically */
int lastw = 0; /* width of the last input character */
int lastc = 0; /* and its name (or index) */
/*
*
* We'll also want to keep track of some of the same things, but for the
* target printer.
*
*/
int lastsize = -1; /* last internal size we used */
int lastfont = -1; /* last font we told printer about */
int lastx = -1; /* printer's current position */
int lasty = -1;
/*
*
* The following structure is used to keep track of the fonts that are
* loaded in various positions. Both fields are filled in by routine t_fp()
* using values in the binary font files.
*
*/
struct {
char *name; /* name of the font loaded here */
int number; /* its internal number */
} fontname[NFONT+1];
/*
*
* A few variables that are really just used for drawing things. Although
* they're declared here most are only really used in draw.c. The pen
* width and the step sizes can be changed by options. The step sizes DX
* and DY control how far we move horizontally or vertically between
* adjacent dots when drawing curves. They'll have no effect if we're
* using Impress graphics commands for all graphics. Decreasing DX and DY
* improves pictures but increases the size and complexity of the output
* files. Because Impress complies and prints pages on the fly you may
* not be able to draw fairly simple figures if the step sizes are too
* small.
*
*/
int drawdot = '.'; /* draw with this character */
int drawsize = 1; /* shrink size by this factor */
int penwidth = 1; /* use this as the pen diameter */
int DX = 6; /* horiz step when using drawdot */
int DY = 6; /* same but for vertical step */
/*
*
* We may want to shift things around on the output page a little. In
* particular moving everything right on the output pages is normal because
* the left 3/8 inch or so of each page on an Imprint-10 isn't visible.
* All this stuff could be done more efficiently by defining a new
* coordinate system to match the requested offsets rather than doing
* the calculations each time. I've left things this way for now because
* that's the way we originally did stuff in di10.
*
* The xoff and yoff values are in inches while the xoffset and yoffset
* numbers are pixels. We'll set the pixel values after we're sure about
* the target printer's resolution. xoff and yoff can be changed by options.
* xfac and yfac are scaling factors used to convert coordinates in the
* input files to appropiate values in the target printers coordinate
* system. Their values are set in t_init() because we can only do it
* properly after we've gotten the printer's resolution (from options)
* and read the "x res" command in each input file.
*
*/
float xoff; /* shift right by this many inches */
float yoff; /* and down by this much */
int xoffset; /* pixel values = xoff * pres */
int yoffset; /* = yoff * pres */
float xfac = 1.0; /* scaling factor for x */
float yfac = 1.0; /* scaling factor for y */
/*
*
* A few miscellaneous variable declarations. I've added landscape mode
* to the post-processor. It's requested using the -l option. Might also
* be reasonable to add a new device control command to request landscape
* mode, although I haven't done it yet. None of this stuff will work with
* printer resident fonts.
*
*/
int mode = PORTRAIT; /* landscape or portrait mode */
int angle = ROT_0; /* ROT_270 for LNADSCAPE mode */
int output = 0; /* do we do output at all? */
int pageno = -1; /* output page number */
int copies = 1; /* ask IPR for this many */
float aspect = 1; /* default aspect ratio */
int cancenter = TRUE; /* try to improve char placement? */
int center = 0; /* for alphanumeric characters only */
/*
*
* We'll really need to deal with three possibly different resolutions
* when we're printing files. The first is the resolution used by troff in
* preparing the input file. Next is the resolution of the target printer.
* Imprint-10s are 240 and 8/300s are 300 dots per inch. Finially we'll need
* or at least want to know the resolution of the raster files we're using
* to print the file. Obviously we'll get the best results when all three
* numbers agree, but no matter what we should be able to do something
* reasonable with any set of numbers.
*
*/
int res; /* resolution assumed in input file */
int pres; /* resolution of the target printer */
int rres; /* raster file resolution */
/*
*
* The data about the different printers supported by the program is
* stored in prdata[]. It's initialized using PR_INIT which is defined
* in dimpress.h. The fields in structure Prdata are used to define the
* printer name, resolution, x and y offsets (in inches), and the string
* that should be used for *bitdir.
*
*/
Prdata prdata[] = PR_INIT; /* printer data */
int pr_num = PR_NUM; /* printer we're using - index in prdata[] */
/*
*
* Many of the printer dependent variables can be set by several different
* options. Most times we'll want to use the -T option, but there may be
* occasions when we want to override one or more of the default values.
* These variables keep track of whether we've tried to set values by other
* options.
*
*/
int setpenwidth = FALSE; /* changed by the -P option */
int setxoff = FALSE; /* -x option */
int setyoff = FALSE; /* -y option */
int setpres = FALSE; /* -r option */
/*
*
* A few variables that are really only used if we're doing accounting.
* Much of the accounting stuff has been designed for our own use at
* MHCC and may not suit your needs.
*
*/
char *acctfile = NULL; /* append accounting record to this file */
char *jacctfile = NULL; /* just a page count for this job */
int acctpages = 0; /* charge for this many pages */
char *username = NULL; /* guy whose running this program */
/*
*
* If we're emulating another device we'll want to use the following array to
* help map font names available on that device into PostScript fonts. It's
* initialized using FONTMAP (file dpost.h) and may be changed in routine
* getfontmap(). In particular if there's a file that matches the device name
* in directory *fontdir/devpost/fontmaps, getfontmap() will use it instead of
* the default - haven't implemented it and probably never will.
*
*/
Fontmap fontmap[100] = FONTMAP; /* just for device emulation */
/*
*
* Output and accounting FILE definitions. If you invoke this program with
* the -t option everything goes to stdout, otherwise it will be written
* to *tempfile and then passed along to Imagen's spooler using IPR.
*
*/
char *tempfile = NULL; /* output file name if no -t option used */
FILE *tf = NULL; /* and Impress output goes here */
FILE *fp_acct = stderr; /* accounting stuff written here */
extern int maxdots; /* defined and used in draw.c */
/*****************************************************************************/
main(agc, agv)
int agc;
char *agv[];
{
/*
*
* Post-processor that's used to translate troff's device independent
* output language into Impress (version 2.0 right now). A call to Imagen's
* spooling package, through IPR, is made in print_file() provided
* the output hasn't gone to stdout. Using the -t option or initializing
* tf to be stdout forces output to stdout. If there are any processing
* errors x_stat will be non-zero and done() will remove *tempfile before
* quitting.
*
*/
argc = agc; /* global so everyone can use them */
argv = agv;
prog_name = argv[0]; /* just used for error messages */
init_signals(); /* sets up interrupt handling */
options(); /* command line options */
initialize(); /* must be done after options */
rastsetup(); /* set all the raster file stuff up */
rastlist(); /* get availble font and size list */
resfonts(tf); /* setup for any resident fonts */
acct_file(); /* open accounting file - maybe */
arguments(); /* translate all the input files */
t_wrapup(); /* mark the end of job for Impress */
print_file(); /* print the file we just built */
done(); /* everything probably went OK */
} /* End of main */
/*****************************************************************************/
init_signals()
{
int done(); /* handles them if we're catching sigs */
/*
*
* Makes sure we handle any interrupts properly. It wasn't done right
* in di10.
*
*/
if ( signal(SIGINT, done) == SIG_IGN ) {
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
} else {
signal(SIGHUP, done);
signal(SIGQUIT, done);
} /* End else */
} /* End of init_signals */
/*****************************************************************************/
options()
{
int ch; /* option name returned from getopt */
char *names = "u:c:tx:y:r:a:o:p:LP:n:d:F:f:B:f:R:T:AJ:";
extern char *optarg; /* option argument set by getopt() */
extern int optind;
/*
*
* Processes the command line options. The original stuff stuff done in
* di10 has been changed a little. I've also used getopt() to scan the
* options.
*
* The most confusing options are -B and -R. The *bitdir string is the
* directory where we expect to find the raster file directories. They all
* start with "rast" and end with a device name. I've got things set up so
* that they're in /usr/lib/raster, but di10 looked for directory rasti10
* in *fontdir (/usr/lib/font/devi10). The -B option changes the value
* of *bitdir. If you're running DWB and want this program to replace di10
* call it using the option "-B /usr/lib/font/devi10". The -R option
* sets the value of string *rastdev. If that string isn't NULL then
* "/rast*rastdev" will be appended to the end of *bitdir to locate the
* raster file directory that we really want to use. By default rastdev is
* NULL so *realdev will be used in its place.
*
* The -c option doesn't work right now. If you want to implement it you'll
* probably just need to change the IPR system() call that's made in
* print_file().
*
*/
while ( (ch = getopt(argc, argv, names)) != EOF ) {
switch ( ch ) {
case 'u':
username = optarg;
break;
case 'c':
copies = atoi(optarg);
break;
case 't':
tf = stdout;
break;
case 'x':
xoff = atof(optarg);
setxoff = TRUE;
break;
case 'y':
yoff = atof(optarg);
setyoff = TRUE;
break;
case 'r':
pres = atoi(optarg);
setpres = TRUE;
break;
case 'a':
aspect = atof(optarg);
break;
case 'o':
out_list(optarg);
break;
case 'p': /* pixels of resolution */
if ( (DX = DY = atoi(optarg)) <= 0 )
DX = DY = 1;
break;
case 'L': /* landscape mode */
mode = LANDSCAPE;
break;
case 'P': /* pen diameter for drawing */
if ( (penwidth = atoi(optarg)) > 20 )
penwidth = 20;
else if ( penwidth < 1 ) penwidth = 1;
setpenwidth = TRUE;
break;
case 'n': /* a limit for drawing routines */
if ( (maxdots = atoi(optarg)) <= 0 )
maxdots = 32000;
break;
case 'd':
if ( (debug = atoi(optarg)) == 0 )
debug = 1;
tf = stdout;
break;
case 'F': /* font table directory */
fontdir = optarg;
break;
case 'B': /* rast* directories found here */
bitdir = optarg;
break;
case 'f': /* use this resident font file */
resfile = optarg;
break;
case 'R': /* use this guys raster files */
rastdev = optarg;
break;
case 'T': /* target printer */
for ( pr_num = 0; prdata[pr_num].prname != NULL; pr_num++ )
if ( strcmp(optarg, prdata[pr_num].prname) == 0 )
break;
if ( prdata[pr_num].prname == NULL )
error(FATAL, "don't know printer %s", optarg);
break;
/* These options were added for the MHCC */
case 'A':
x_stat |= DO_ACCT;
break;
case 'J':
jacctfile = optarg;
x_stat |= DO_ACCT;
break;
case '?':
error(FATAL, "");
break;
default:
error(FATAL, "don't know option %s", argv[1]);
break;
}
}
argc -= optind; /* get ready for non-options args */
argv += optind;
} /* End of options */
/*****************************************************************************/
initialize()
{
char *mktemp();
#ifdef V9
char *getlogin();
#endif
/*
*
* Much of this stuff can only be done properly after the command line
* options have been processed, so make sure it's called (from main())
* after options().
*
*/
#ifdef V9
if (username == NULL && (username = getlogin()) == NULL )
#endif
#ifdef SYSV
if ( (username = cuserid((char *) 0)) == NULL )
#endif
username = "???";
if (tf != stdout) {
tempfile = mktemp("/tmp/dimpXXXXX");
if ((tf = fopen(tempfile, "w")) == NULL)
error(FATAL, "can't open temporary file %s", tempfile);
} /* End if */
if ( realdev == NULL )
realdev = prdata[pr_num].prname;
if ( setpres == FALSE )
pres = prdata[pr_num].pres;
if ( setxoff == FALSE )
xoff = prdata[pr_num].xoff;
if ( setyoff == FALSE )
yoff = prdata[pr_num].yoff;
if ( setpenwidth == FALSE )
penwidth = prdata[pr_num].penwidth;
if ( bitdir == NULL )
bitdir = prdata[pr_num].bitdir;
if ( resfile == NULL )
resfile = prdata[pr_num].prname;
res = rres = pres; /* just to be safe */
xoffset = pres * xoff; /* set the pixel offsets */
yoffset = pres * yoff;
} /* End of initialize */
/*****************************************************************************/
rastsetup()
{
static char rastname[100]; /* rastdir string saved here */
char temp[100]; /* for pathnames and reads from *fp */
FILE *fp; /* RASTDATA and RASTLIST files */
int ch; /* just used to skip lines in *fp */
/*
*
* We'll need to know a bunch of stuff about the raster files before we can
* actually use them. First of all we need to figure out where they are.
* Strings *bitdir and either *rastdev or *realdev will be used to initialize
* *rastdir. Once we've got rastname set up we'll need to determine the
* format of the raster files and their resolution. All that stuff should
* be in file *rastdir/RASTDATA. If the file's not there or we can't read
* it we'll assume the files are written in the old format at a resolution
* of 240 dots per inch. I've done things this way because RASTDATA is new
* and won't be part of the of raster file directory unless you add it.
* This way nothing has to be done to the old raster file directory.
*
*/
sprintf(rastname, "%s/rast%s", bitdir, (rastdev == NULL) ? realdev : rastdev);
rastdir = rastname;
sprintf(temp, "%s/%s", rastdir, RASTDATA);
if ( (fp = fopen(temp, "r")) == NULL ) {
rastformat = OLD_FORMAT;
rres = 240;
return;
} /* End if */
while ( fscanf(fp, "%s", temp) != EOF )
if ( strcmp(temp, "format") == 0 ) {
fscanf(fp, "%s", temp);
if ( strcmp(temp, "old") == 0 )
rastformat = OLD_FORMAT;
else rastformat = RST_FORMAT;
} else if ( strcmp(temp, "resolution") == 0 )
fscanf(fp, "%d", &rres);
else while ( (ch = getc(fp)) != '\n' && ch != EOF ) ;
fclose(fp);
} /* End of rastsetup */
/*****************************************************************************/
rastlist()
{
int n; /* next size for current font */
int i; /* next size goes here */
char name[100]; /* pathname for RASTERLIST file */
FILE *fp;
/*
*
* If we're not using the old format raster files we'll want to read the
* list of available fonts and sizes in *rastdir. The file that's got all
* the info is called RASTLIST (defined in init.h). The format is exactly
* the same as Brian's original file. Under the old format all this stuff
* is done in routine initfontdata().
*
* For now if we can't open RASTERLIST and were not using the old format
* raster files we'll just return to the caller. That really just means
* we'll assume we can handle any font + size request that may come our
* way. If that's not the case we better make up a complete RASTERLIST file.
*
*/
if ( rastformat == OLD_FORMAT ) /* don't bother doing it here */
return;
sprintf(name, "%s/%s", rastdir, RASTLIST);
if ( (fp = fopen(name, "r")) == NULL )
return;
/* name should be no more than L_FNAME characters */
while ( fscanf(fp, "%10s", sizedata[maxrast].name) != EOF ) {
i = 0;
while ( fscanf(fp, "%d", &n) != EOF && n < 100 )
sizedata[maxrast].sizes[i++] = n;
sizedata[maxrast].sizes[i] = 999;
if ( ++maxrast >= MAXFONTS )
error(FATAL, "too many fonts in %s", name);
} /* End while */
fclose(fp);
} /* End of rastlist */
/*****************************************************************************/
arguments()
{
FILE *fp; /* next input file */
/*
*
* All the rest of the command line options are input files we want to
* translate. If we get here and there are no more arguments, or if '-' is
* in the list of file names, we'll process stdin.
*
*/
if (argc < 1)
conv(stdin);
else
while (argc > 0) {
if (strcmp(*argv, "-") == 0)
fp = stdin;
else if ((fp = fopen(*argv, "r")) == NULL)
error(FATAL, "can't open %s", *argv);
conv(fp);
fclose(fp);
argc--;
argv++;
}
} /* End of arguments */
/*****************************************************************************/
print_file()
{
char buf[BUFSIZ]; /* IPR command line built up here */
/*
*
* Finished with all the input files and everything the printer needs to
* know is in FILE *tf. We'll close the file because we're all done with
* it, and then call IPR if we haven't been writing to stdout.
*
*/
fclose(tf); /* everything's in the file */
if ( tf != stdout || debug ) {
sprintf(buf, "%s -Limpress -r -o '-Downer \"'\"%s\"'\"'\", jobheader on, pagecollation on, pagereversal on\" %s 0</dev/null 1>/dev/null 2>&1 &",
IPR, username, tempfile);
if ( debug )
fprintf(stderr, "executing %s\n", buf);
else system(buf);
} /* End if */
} /* End of print_file */
/*****************************************************************************/
acct_file()
{
/*
*
* If we want to do accounting *acctfile will be the name of the file where
* we put the accounting data. If for some reason we can't open the file
* we'll just quit. I've called the routine from main() before anything is
* written to the output file.
*
*/
if ( acctfile != NULL && *acctfile != '\0' ) {
if ( (fp_acct = fopen(acctfile, "a")) == NULL ) {
fp_acct = stderr;
x_stat |= NO_ACCTFILE;
error(FATAL, "can't open accounting file");
exit(x_stat);
}
if ( tf != stdout )
x_stat |= DO_ACCT;
}
} /* End of acct_file */
/*****************************************************************************/
account()
{
FILE *f; /* just the job's page count */
/*
*
* Writes an accounting record, usually to *fp_acct, for the current job.
* All this stuff is set up for our MHCC printers. In some cases we'll
* know most everything about the job (called with -J option) and all
* we'll do is write a page count to *jacctfile. In other cases we'll want
* a more complete record and all the stuff will go to *fp_acct. You'll
* undoubtedly want to change this stuff to suit your own needs.
*
*/
if ( x_stat & DO_ACCT ) {
if ( jacctfile == NULL || *jacctfile == '\0' ) {
fprintf(fp_acct, " user = %-10s", username);
fprintf(fp_acct, " paper = %-10d", acctpages * copies);
x_stat &= ~DO_ACCT;
fprintf(fp_acct, " exit_status = 0%-6o", x_stat);
fprintf(fp_acct, " type = t ");
if ( tf == stdout )
fprintf(fp_acct, " ??");
fprintf(fp_acct, "\n");
} else {
if ( (f = fopen(jacctfile, "a")) != NULL ) {
fprintf(f, "%d\n", acctpages);
fclose(f);
}
x_stat &= ~DO_ACCT;
} /* End else */
}
} /* End of account */
/*****************************************************************************/
done()
{
/*
*
* Finished with everything so we want to make sure accounting is handled
* properly and the right exit status is returned to the caller. We'll also
* delete the temporary file if x_stat != 0.
*
*/
account();
if ( tf != stdout && x_stat != 0 )
unlink(tempfile);
exit(x_stat);
} /* End of done */
/*****************************************************************************/
conv(fp)
register FILE *fp;
{
register int c, k;
int m, n, i, n1, m1;
char str[100];
/*
*
* Controls the translation of troff's device independent output language
* to Impress. Some of the commands, like slant and height, are no-ops
* on Imagen's bitmap printers even though routines are called to do the
* processing.
*
*/
lineno = 1; /* line in current file */
x_stat |= FILE_STARTED; /* we'll clear it when done with *fp */
while ((c = getc(fp)) != EOF) {
switch (c) {
case '\n': /* just count this line */
lineno++;
break;
case ' ': /* when input is text */
case 0: /* occasional noise creeps in */
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
/* two motion digits plus a character */
hmot((c-'0')*10 + getc(fp)-'0');
put1(getc(fp));
break;
case 'c': /* single ascii character */
put1(getc(fp));
break;
case 'C': /* special character */
fscanf(fp, "%s", str);
put1s(str);
break;
case 'N': /* character at position n */
fscanf(fp, "%d", &m);
oput(m);
break;
case 'D': /* drawing function */
lineno++;
switch ((c=getc(fp))) {
case 'p': /* draw a path */
while (fscanf(fp, "%d %d", &n, &m) == 2)
drawline(n, m);
break;
case 'l': /* draw a line */
fscanf(fp, "%d %d %c", &n, &m, &n1);
drawline(n, m);
break;
case 'c': /* circle */
fscanf(fp, "%d", &n);
drawcirc(n);
break;
case 'e': /* ellipse */
fscanf(fp, "%d %d", &m, &n);
drawellip(m, n);
break;
case 'a': /* arc */
fscanf(fp, "%d %d %d %d", &n, &m, &n1, &m1);
drawarc(n, m, n1, m1);
break;
case 'q': /* spline */
drawspline(fp, 1);
break;
case '~': /* wiggly line */
drawspline(fp, 2);
break;
default:
error(FATAL, "unknown drawing function %c", c);
break;
}
break;
case 's': /* use this point size */
fscanf(fp, "%d", &n); /* ignore fractional sizes */
setsize(t_size(n));
break;
case 'f': /* use font mounted here */
fscanf(fp, "%s", str);
setfont(t_font(str));
break;
case 'H': /* absolute horizontal motion */
/*
*
* The simple scan I've commented out didn't handle negative numbers right
* and believe it or not we did get jobs that asked for negative absolute
* positions. Even though negative absolute coordinates probably are a
* mistake it makes more sense to handle the numbers properly.
*
while ((c = getc(fp)) == ' ')
;
k = 0;
do {
k = 10 * k + c - '0';
} while (isdigit(c = getc(fp)));
ungetc(c, fp);
hgoto(k);
*
*/
fscanf(fp, "%d", &n);
hgoto(n);
break;
case 'h': /* relative horizontal motion */
/*
*
* Again the same potential problem with negative numbers exists here. In
* fact it makes a lot more sense to expect negative relative motions even
* though I never did see them. Anyway just to be safe I've made the same
* change - take it out if you want.
*
while ((c = getc(fp)) == ' ')
;
k = 0;
do {
k = 10 * k + c - '0';
} while (isdigit(c = getc(fp)));
ungetc(c, fp);
hmot(k);
*
*/
fscanf(fp, "%d", &n);
hmot(n);
break;
case 'w': /* word space */
break;
case 'V': /* absolute vertical position */
fscanf(fp, "%d", &n);
vgoto(n);
break;
case 'v': /* relative vertical motion */
fscanf(fp, "%d", &n);
vmot(n);
break;
case 'p': /* new page */
fscanf(fp, "%d", &n);
t_page(n);
break;
case 'n': /* end of line */
while ( (c = getc(fp)) != '\n' && c != EOF ) ;
t_newline();
lineno++;
break;
case '#': /* comment */
while ( (c = getc(fp)) != '\n' && c != EOF ) ;
lineno++;
break;
case 'x': /* device control function */
devcntrl(fp);
break;
default:
error(!FATAL, "unknown input character %o %c", c, c);
done();
}
}
x_stat &= ~FILE_STARTED;
} /* End of conv */
/*****************************************************************************/
devcntrl(fp)
FILE *fp; /* current input file */
{
char str[20], str1[50], buf[50];
int c, n, x, y;
/*
*
* Called from conv() to process the rest of a device control function.
* There's a whole family of them and they all begin with the string
* "x ". The rest of the command consists of the function name followed
* by zero or more arguments that depend on the particular command. We've
* already read the "x" from the input file, that's why the routine was
* called. The whole rest of the input line is assumed to be part of the
* device control command.
*
*/
fscanf(fp, "%s", str); /* get the control function name */
switch ( str[0] ) { /* only the first character counts now */
case 'i': /* initialize */
fileinit();
t_init(0);
break;
case 'T': /* device name */
fscanf(fp, "%s", devname);
break;
case 't': /* trailer */
t_trailer();
break;
case 'p': /* pause -- can restart */
t_reset('p');
break;
case 's': /* stop */
t_reset('s');
break;
case 'r': /* resolution assumed when prepared */
fscanf(fp, "%d", &res);
break;
case 'f': /* load font in a position */
fscanf(fp, "%d %s", &n, str);
fgets(buf, sizeof buf, fp); /* in case there's a filename */
ungetc('\n', fp); /* fgets goes too far */
str1[0] = 0; /* in case there's nothing to come in */
sscanf(buf, "%s", str1);
loadfont(n, str, str1);
break;
/* these don't belong here... */
case 'H': /* char height */
fscanf(fp, "%d", &n);
t_charht(n);
break;
case 'S': /* slant */
fscanf(fp, "%d", &n);
t_slant(n);
break;
case 'I':
case 'B':
x = hpos * xfac + xoffset + .5;
y = vpos * yfac + yoffset + .5;
/* force 32x32 alignment, imagen 3.2 software does this
** anyway, but this should fix others
*/
putc(ASETAV, tf); putint(y&~0x1f, tf);
putc(ASETAH, tf); putint(x&~0x1f, tf);
if (str[0] == 'I') {
fscanf(fp, "%d %s", &n, buf);
iglyphpage(tf, buf, n, x&0x1f, y&0x1f);
} else if (str[0] == 'B') {
fscanf(fp, "%d %s", &n, buf);
glyphpage(tf, buf, n, x&0x1f, y&0x1f);
}
/* position back where it belongs */
putc(ASETAV, tf); putint(y, tf); lasty = y;
putc(ASETAH, tf); putint(x, tf); lastx = x;
break;
case 'X':
fscanf(fp, "%s", str); /* line style */
break;
}
while ( (c = getc(fp)) != '\n' && c != EOF ) ;
lineno++;
} /* End of devcntrl */
/*****************************************************************************/
fileinit()
{
int i, fin;
char *filebase;
char temp[100];
/*
*
* Called from t_init(), which in turn is called from devcntrl(), whenever we get
* an "x init" command. There are a few lines of code here that set things up for
* emulating another device.
*
*/
sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname);
if ( (fin = open(temp, 0)) < 0 )
error(FATAL, "can't open tables for %s", temp);
read(fin, &dev, sizeof(struct dev));
nfonts = dev.nfonts;
if ( strcmp(devname, realdev) != 0 ) { /* device emulation */
close(fin);
strcpy(devname, realdev);
sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname);
if ( (fin = open(temp, 0)) < 0 )
error(FATAL, "can't open tables for %s", temp);
read(fin, &dev, sizeof(struct dev));
} /* End if */
nsizes = dev.nsizes;
nchtab = dev.nchtab;
if ( (filebase = malloc(dev.filesize)) == NULL )
error(FATAL, "no memory for description file");
read(fin, filebase, dev.filesize); /* all at once */
pstab = (short *) filebase;
chtab = pstab + nsizes + 1;
chname = (char *) (chtab + dev.nchtab);
for ( i = 1; i <= nfonts; i++ ) {
fontbase[i] = NULL;
widthtab[i] = codetab[i] = fitab[i] = NULL;
} /* End for */
close(fin);
} /* End of fileinit */
/*****************************************************************************/
fontprint(i)
int i; /* font's index in fontbase[] */
{
int j, n;
char *p;
/*
*
* Just a debugging routine that dumps most of the important information about
* the font that's mounted in position i.
*
*/
fprintf(tf, "font %d:\n", i);
p = (char *) fontbase[i];
n = fontbase[i]->nwfont & BMASK;
/* name should be no more than L_FNAME characters long */
fprintf(tf, "base=0%o, nchars=%d, spec=%d, name=%.10s, widtab=0%o, fitab=0%o\n",
p, n, fontbase[i]->specfont, fontbase[i]->namefont, widthtab[i], fitab[i]);
fprintf(tf, "widths:\n");
for ( j = 0; j <= n; j++ ) {
fprintf(tf, " %2d", widthtab[i][j] & BMASK);
if ( j % 20 == 19 ) putc('\n', tf);
} /* End for */
fprintf(tf, "\ncodetab:\n");
for ( j = 0; j <= n; j++ ) {
fprintf(tf, " %2d", codetab[i][j] & BMASK);
if ( j % 20 == 19 ) putc('\n', tf);
} /* End for */
fprintf(tf, "\nfitab:\n");
for ( j = 0; j <= dev.nchtab + 128-32; j++ ) {
fprintf(tf, " %2d", fitab[i][j] & BMASK);
if ( j % 20 == 19 ) putc('\n', tf);
} /* End for */
putc('\n', tf);
} /* End of fontprint */
/*****************************************************************************/
loadfont(n, s, s1)
int n;
char *s, *s1;
{
char temp[80];
int fin, nw;
/*
*
* Called to to load font info for font *s on position n using the binary tables
* located in directory *s1 (if it's not NULL or the empty string).
*
*/
if ( n < 0 || n > NFONT ) /* make sure it's a legal position */
error(FATAL, "illegal fp command %d %s", n, s);
/*
*
* If the font's already loaded on position n there's nothing to do.
*
*/
if ( fontbase[n] != NULL && strncmp(s, fontbase[n]->namefont, L_FNAME) == 0 )
return;
/*
*
* If *s1 isn't NULL or the NULL string that's what we'll use for the font
* directory, otherwise use *fontdir.
*
*/
if ( s1 == NULL || s1[0] == '\0' )
sprintf(temp, "%s/dev%s/%.10s.out", fontdir, devname, s);
else sprintf(temp, "%s/%.10s.out", s1, s);
if ( (fin = open(temp, 0)) < 0 ) {
sprintf(temp, "%s/dev%s/%.10s.out", fontdir, devname, mapfont(s));
if ( (fin = open(temp, 0)) < 0 )
error(FATAL, "can't open font table %s", temp);
} /* End if */
if ( fontbase[n] != NULL ) /* something's already there */
free(fontbase[n]); /* so release the memory first */
fontbase[n] = (struct Font *) malloc(3*255 + dev.nchtab + (128-32) + sizeof(struct Font));
if ( fontbase[n] == NULL )
error(FATAL, "Out of space in loadfont %s", s);
read(fin, fontbase[n], 3*255 + nchtab+128-32 + sizeof(struct Font));
close(fin);
if ( smnt == 0 && fontbase[n]->specfont == 1 )
smnt = n;
nw = fontbase[n]->nwfont & BMASK;
widthtab[n] = (char *) fontbase[n] + sizeof(struct Font);
codetab[n] = (char *) widthtab[n] + 2 * nw;
fitab[n] = (char *) widthtab[n] + 3 * nw;
t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
if ( debug == ON )
fontprint(n);
} /* End of loadfont */
/*****************************************************************************/
char *mapfont(name)
char *name; /* name of the font troff wants */
{
int i; /* loop index for fontmap[] */
/*
*
* Only called from loadfont() when we haven't been able to open the font file
* that troff asked for. We take the font name and map it into an appropriate
* substitute. If the initial lookup fails we do a simple mapping that should
* be good enough most of the time.
*
* This stuff should only be needed when we're emulating another printer like
* the APS-5.
*
*/
for ( i = 0; fontmap[i].name != NULL && i < L_FNAME; i++ )
if ( strncmp(name, fontmap[i].name, L_FNAME) == 0 )
return(fontmap[i].use);
switch ( *++name ) {
case 'I':
case 'B':
return(name);
case 'X':
return("BI");
default:
return("R");
} /* End switch */
} /* End of mapfont */
/*****************************************************************************/
convint(c)
unsigned char c;
{
/*
*
* Converts a character to a proper 2's complement integer. Really just used
* on 3b's when we're reading raster tables in the old format. There's
* really no need to make this a separate routine - at least I don't
* think there is. Should just redefine CONVINT() macro so it does this
* stuff.
*
*/
return((c & 0200) ? ((256 - c) * -1) : c);
} /* End of convint */
/*****************************************************************************/
t_init(reinit)
int reinit;
{
int i;
FILE *tmpfile();
/*
*
* Called to initialize the printer and associated variables. reinit will
* be zero when the "x init" command was found in the output file, while
* it will be non-zero when the routine is called to set things up for a
* new page.
*
*/
if (! reinit) {
for (i = 0; i < nchtab; i++)
if (strcmp(&chname[chtab[i]], "l.") == 0)
break;
if (i < nchtab) {
drawdot = i + 128;
drawsize = 1;
} else {
drawdot = '.';
drawsize = 2; /* half size */
}
xfac = (float) pres / res * aspect;
yfac = (float) pres / res;
putc(ASETPEN, tf);
putc(penwidth, tf);
if ( mode == LANDSCAPE ) {
putc(ASETHV, tf);
putc(0107, tf);
angle = ROT_270;
} /* End if */
}
hpos = vpos = 0;
setsize(t_size(10)); /* start somewhere */
} /* End of t_init */
/*****************************************************************************/
t_page(pg)
{
register int i, j, n;
register unsigned char *p;
/*
*
* Get the printer and everything else ready for a new page. If the -o
* option has been used only selected pages will be printed. If output
* is ON when this routine is called we'll write the endpage Impress
* command to the output file. If we're supposed to be doing output for
* page pg we'll write the APAGE command out, and that will cause the
* horizontal and vertical positions (in Impress) to be set to zero. hpos
* and vpos are initialized in routine t_init(), although I really don't
* see any reason why we couldn't just skip the call and do it here.
*
*/
if ( debug == ON )
fprintf(stderr, "t_page %d, output=%d\n", pg, output);
pageno = pg;
if ( output == ON ) /* doing output for last page */
putc(AENDP, tf);
if ( (output = in_olist(pg)) == ON ) { /* print this page */
putc(APAGE, tf);
acctpages++;
}
lastx = lasty = -1;
t_init(1); /* setup for this page */
} /* End of t_page */
/*****************************************************************************/
t_newline()
{
/*
*
* Read an "n a b" command in the input file and are ready to start a new
* line. There really isn't much else this routine can do besides set the
* horizontal position to zero. Anyway troff takes care of any needed
* positioning before it starts printing text.
*
*/
hpos = 0;
} /* End of t_newline */
/*****************************************************************************/
t_size(n)
int n; /* convert this point size */
{
int i;
/*
*
* Converts a point size into an internal size that can be used as an
* index into the pstab[] array. Actually the internal size is defined as
* one plus the index of the least upper bound of n in pstab[] or nsizes
* if n is larger than all the listed sizes.
*
*/
if (n <= pstab[0])
return(1);
else if (n >= pstab[nsizes-1])
return(nsizes);
for (i = 0; n > pstab[i]; i++) ;
return(i+1);
} /* End of t_size */
/*****************************************************************************/
t_charht(n)
int n; /* use this as the character height */
{
/*
*
* Although it can be done on some typesetters, like the APS-5, it's ignored
* on Imagen's bitmap printers like the Imprint-10 and the 8/300. It would
* be absurd to keep any extra raster files around just so we could implement
* this command, and right now there's no Impress command to do it to
* downloaded glyphs.
*
*/
} /* End of t_charht */
/*****************************************************************************/
t_slant(n)
int n; /* slant characters this many degrees */
{
/*
*
* As with troff's height command, there's no simple way to slant characters
* on Imagen's bitmap printers and it's really not worth any effort to try
* and make it work.
*
*/
} /* End of t_slant */
/*****************************************************************************/
t_font(s)
char *s;
{
int n;
/*
*
* Just converts the string *s into an integer and checks to make sure the
* number is a legal font position. If it's not we'll print an error message
* and then quit. di10 handled bad requests a little differently. Instead
* of treating mistakes as FATAL errors it would return 1 as the font
* number.
*
*/
if ( (n = atoi(s)) < 0 || n > nfonts )
error(FATAL, "illegal font position %d", n);
return(n);
} /* End of t_font */
/*****************************************************************************/
t_reset(c)
int c; /* pause or restart */
{
/*
*
* Called from devcntrl() when we've found an "x stop" or "x pause" command.
* There's really nothing we need to do for Imagen's bitmap printers, and
* leaving the final cleanup (ie. AEOF code etc.) to someone else means
* we should be able to cat a bunch of troff output files together and
* have them all printed properly.
*
*/
} /* End of t_reset */
/*****************************************************************************/
t_wrapup()
{
/*
*
* We're finished with all the input files and all that's left to do is
* end the last page we were working on and then mark the end of the Impress
* file.
*
*/
putc(AENDP, tf);
putc(AEOF, tf);
} /* End of t_wrapup */
/*****************************************************************************/
t_trailer()
{
/*
*
* Called from devcntrl() when an "x trailer" command is found. There's
* nothing we need to do here for Imagen's printers.
*
*/
} /* End of t_trailer */
/*****************************************************************************/
hgoto(n)
int n; /* where we want to be */
{
/*
*
* Want to be at this absolute horizontal position next - usually will
* get these motion commands right before printing a character.
*
*/
hpos = n;
} /* End of hgoto */
/*****************************************************************************/
hmot(n)
int n; /* move this far from where we are */
{
/*
*
* Handles relative horizontal motion. troff's current positon as recorded
* in hpos is changed by n units.
*
*/
hpos += n;
} /* End of hmot */
/*****************************************************************************/
vgoto(n)
int n; /* new vertical position */
{
/*
*
* Moves vertically in troff's coordinate system to absolute position n.
*
*/
vpos = n;
} /* End of vgoto */
/*****************************************************************************/
vmot(n)
int n; /* move this far vertically */
{
/*
*
* Handles relative vertical motion of n units in troff's coordinate system.
*
*/
vpos += n;
} /* End of vmot */
/*****************************************************************************/
put1s(s)
register char *s;
{
static int i = 0; /* last one we found - usually */
/*
*
* Does whatever is necessary to have special character *s printed. If we're
* doing output on this page we'll look the character up using chname[] and
* chtab[]. The first array contains all the special character names
* separated by '\0' that are mentioned in the typesetter's DESC file, while
* chname[i] points to the start of character i in chname[]. Both arrays
* come from the DESC.out file for printer *devname which is found in
* *fontdir (wherever that might be).
*
*/
if ( output == OFF )
return;
if ( debug )
printf("%s", s);
if (strcmp(s, &chname[chtab[i]]) != 0)
for (i = 0; i < nchtab; i++)
if (strcmp(&chname[chtab[i]], s) == 0)
break;
if (i < nchtab)
put1(i + 128);
else
i = 0;
} /* End of put1s */
/*****************************************************************************/
put1(c)
register int c; /* print this character */
{
char *pw;
register char *p;
register int i, j, k;
int ofont, code;
/*
*
* Arranges to have character c printed. If c < 128 it's a simple ASCII character,
* otherwise it's a special character. We subtract 32 from c because non-graphic
* ASCII characters aren't included in the tables.
*
*/
lastc = c; /* charlib() may need the real name */
c -= 32;
if ( c <= 0 ) {
if ( debug == ON )
fprintf(tf, "non-exist 0%o\n", lastc);
return;
} /* End if */
k = ofont = font;
i = fitab[font][c] & BMASK;
if ( i != 0 ) { /* it's on this font */
p = codetab[font];
pw = widthtab[font];
} else if ( smnt > 0 ) { /* on special (we hope) */
for ( k=smnt, j=0; j <= nfonts; j++, k = (k+1) % (nfonts+1) ) {
if ( k == 0 ) continue;
if ( (i = fitab[k][c] & BMASK) != 0 ) {
p = codetab[k];
pw = widthtab[k];
setfont(k);
break;
} /* End if */
} /* End for */
} /* End else */
if ( i == 0 || (code = p[i] & BMASK) == 0 || k > nfonts ) {
if ( debug == ON )
fprintf(tf, "not found 0%o\n", lastc);
if ( font != ofont ) setfont(ofont);
return;
} /* End if */
lastw = ((pw[i] & BMASK) * pstab[size-1] + dev.unitwidth/2) / dev.unitwidth;
if ( debug == ON ) {
if ( isprint(lastc) )
fprintf(tf, "%c %d\n", lastc, code);
else fprintf(tf, "%03o %d\n", lastc, code);
} else oput(code);
if ( font != ofont )
setfont(ofont);
} /* End of put1 */
/*****************************************************************************/
setsize(n)
int n; /* new internal size */
{
/*
*
* We want to use internal size n for now, where n is an index into *pstab
* where we can find the closest available approximation to the requested
* point size.
*
*/
size = n;
} /* End of setsize */
/*****************************************************************************/
t_fp(n, s, si)
int n; /* font position to update */
char *s; /* it now contains this font */
char *si; /* and this is its internal number */
{
/*
*
* Called when we've loaded font *s in position n. The font position info
* is recorded in fontname[].
*
*/
fontname[n].name = s;
fontname[n].number = atoi(si);
if ( n == lastfont ) lastfont = -1; /* force getfontdata() call */
} /* End of t_fp */
/*****************************************************************************/
setfont(n)
int n; /* this will be the current font */
{
/*
*
* Job now wants to use the font loaded in position n. The variable font
* keeps track of which one we're currently using. If the requested positon
* is out of range we'll just quit.
*
*/
if ( output == OFF )
return;
if (n < 0 || n > NFONT)
error(FATAL, "illegal font %d", n);
font = n;
} /* End of setfont */
/*****************************************************************************/
oput(c)
int c; /* want to print this character */
{
int x, y; /* current scaled position */
int member; /* glyph number for c in current family */
/*
*
* Arranges to print the character whose code is c in the current font.
* The old and new raster file formats are supported.
*
*/
if ( output == OFF )
return;
if ( rastformat == OLD_FORMAT ) {
xychar(c, fontname[font].name, pstab[size-1], lastw, tf);
return;
} /* End if */
if ( font != lastfont || size != lastsize ) {
if ( isresident(fontname[font].name) == FALSE )
getrastdata(fontname[font].name, mapsize(fontname[font].name, pstab[size-1]));
else getresdata(fontname[font].name, mapsize(fontname[font].name, pstab[size-1]), tf);
lastfont = font;
lastsize = size;
} /* End if */
member = download(c, lastw, angle, tf);
x = hpos * xfac + xoffset + .5;
y = vpos * yfac + yoffset + .5;
if ( y != lasty ) {
putc(ASETAV, tf);
putint(y, tf);
lasty = y;
} /* End if */
if ( ABS(x - lastx) > SLOP ) {
putc(ASETAH, tf);
putint(x, tf);
lastx = x + fam->advance[member];
} else lastx += fam->advance[member];
putc(member, tf);
} /* End of oput */
/*****************************************************************************/
mapsize(name, ps)
char *name; /* name of the font */
int ps; /* point size troff wants to use */
{
int i, j;
/*
* Uses the data that's been filled in from RASTLIST to map point size
* ps font font *name into the best size available in our raster tables.
* If no RASTLIST file was used rastsize will be zero and we'll just
* assume that any size that's aske for is available.
*/
if ( maxrast == 0 ) /* don't have any size data */
return(ps);
for ( i = 0; i < maxrast; i++ )
if ( strncmp(name, sizedata[i].name, L_FNAME) == 0 )
break;
if ( i >= maxrast ) /* didn't find the font */
error(FATAL, "missing raster list data for font %s", name);
for ( j = 1, ps = (ps * pres) / rres; ps >= sizedata[i].sizes[j]; j++ ) ;
return(sizedata[i].sizes[--j]);
} /* End of mapsize */
/*****************************************************************************/