DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T q

⟦fc8ad3938⟧ TextFile

    Length: 16621 (0x40ed)
    Types: TextFile
    Names: »qmsfonts.c«

Derivation

└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
    └─⟦this⟧ »./DVIware/obsolete/mitdrivers/dvi2qms/qmsfonts.c« 

TextFile

/* qmsfonts.c: font module for dvi printing on qms printers
 * Copyright 1985 Massachusetts Institute of Technology
 * Some portions were written by Scott Simpson, TRW
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/dir.h>
#include "util.h"
#include "fonts.h"
#include "findfile.h"

#define MAXDVIFONTS  256	/* Maximum number of DVI fonts allowed */
#define MAXQMSFONTS  256	/* Maximum number of QMS fonts allowed */
#define QMSMAXBLOCKS 386	/* Stated on qms status page */
#define MAXCHARS     128	/* Max chars per QMS font */
#define MAXFNTDIR     16	/* Max number of dirs to look for fonts */
#define MAXFNTNAMLEN  32	/* Maximum number of chars in a font name */
#define USEROTPXL      1	/* Write and read rotated pxl files */

#define DELETEFONT "^DF%05.5d%c^G"
#define DEFINEFONT "^(^DF%05.5d%c%c%4.4s%03.3dT"
#define ADDTOFONT  "^(^DFI%05.5d%c%c%4.4s%03.3dT"
#define DEFINECHAR ",%c%c%03.3d%03.3d%03.3d%c%03.3d%c%03.3d"
#define ENDDEF     "^G^)"
#define SELECTFONT "^IS%05.5d"

unsigned char *malloc();
char *strcat();
char *strcpy();
char *strncpy();
char *strncmp();
char *strcmp();

long numerator,denominator,half_denominator,jobmag;
char job_orientation,printer_orientation;

int      freeblocks = QMSMAXBLOCKS;   /* free space on printer */
char     *hex = "0123456789ABCDEF";   
FILE     *qms;                        /* output device */
char *filter_name;                    /* the name of the calling prog */
char *fntdirvec[MAXFNTDIR];
int fntdirveclen;

#define QC_LOADED    0x0001	/* Char has been loaded in the printer */
#define QC_NOGLYPH   0x0002	/* Glyph is still in pxl file */
#define QC_ROTATED   0x0004	/* Glyph has been rotated */
#define QC_NEEDED    0x0008	/* This char is needed on this page */

struct qmschar {
  short qc_info,qc_qmswidth;
  short qc_height,qc_width;
  short qc_xoffset,qc_yoffset;
  long  qc_texwidth,qc_pxlwidth;
  union {long l; unsigned char *p} qc_glyph;
};

#define QF_LOADED    0x0001	/* Font has been loaded into printer */
#define QF_RELOAD    0x0002	/* We have to load more needed chars */
#define QF_FILE      0x0004	/* Font hasn't been loaded from the file */

struct qmsfont {
  short          qf_info;
  short          qf_qmsnumber;
  short          qf_maxheight;
  long           qf_mag;
  long           qf_words_used;
  long           qf_words_needed;
  long           qf_timestamp;
  char           qf_qmsname[4];
  long           qf_pxl_checksum;
  long           qf_pxl_mag_val;
  long           qf_pxl_design_size;
  long           qf_s;
  char           qf_name[MAXFNTNAMLEN];
  char           qf_filename[MAXNAMLEN];
  struct qmschar qf_char[MAXCHARS]; 
} *qmsfonts[MAXQMSFONTS];

int nqmsfonts;
struct qmsfont *curfnt; /* ptr to current and last font */
long timestamp;			/* Timestamp for stamping qms fonts */

/* The dvifont struct provides a (possible) many-to-one mapping
 * because several DVI fonts can map to the same QMS font during font
 * substitution.
 */
struct dvifont {
  unsigned long   df_num;	/* DVI font number */
  struct qmsfont  *df_qmsfont;	/* Font which contains */
} dvifonts[MAXDVIFONTS];
int ndvifonts;

long max(a,b)
     long a,b;
{
  return((a>b)? a:b);
}

long min(a,b)
     long a,b;
{
  return((a<b)? a:b);
}

/* called at the beginning of the driver program */
f_init(printer,pgmnam,dirvec,dirveclen,num,den,mag,options)
FILE *printer;
char *pgmnam,*dirvec[];
int dirveclen;
long num,den,mag;
unsigned long options;
{
  int i;
  
  numerator = num;
  denominator = den;
  half_denominator = denominator / 2;
  jobmag = mag;
  fntdirveclen = min(MAXFNTDIR,dirveclen);
  for (i = 0; i < fntdirveclen; i++) fntdirvec[i] = dirvec[i];
  ndvifonts = 0;
  nqmsfonts = 0;
  timestamp = 0;
  qms = printer;
  filter_name = pgmnam;
  if (options & F_INIT_LANDSCAPE) job_orientation = 'L';
  else job_orientation = 'P';
  if (options & F_INIT_QMS800) printer_orientation = 'P';
  else printer_orientation = 'L';
}

/* Called at the end of the driver program. */
f_term()
{
}

struct qmsfont *
find_qmsfont(area,name,texmag,s)
     char *area,*name;
     long texmag,s;
{
  char fname[MAXNAMLEN],nname[128];
  int i,nmag;
  int mag = (texmag * 3 + 1) / 2;
  struct qmsfont *fnt;

  /* try to find a font file */
  if (!findfile(fntdirvec,fntdirveclen,area,name,mag,fname,nname,&nmag))
    croak("no font %s.%d",name,texmag);
  
  /* make a new qms font */
  if (nqmsfonts >= MAXQMSFONTS) croak("too many qms fonts");
  if (!(qmsfonts[nqmsfonts++] = fnt =
	(struct qmsfont *) malloc(sizeof(struct qmsfont)))) 
    croak("malloc %d",sizeof(struct qmsfont));
  fnt->qf_mag = nmag;
  fnt->qf_timestamp = 0;
  fnt->qf_words_needed = 400;
  fnt->qf_words_used = 0;
  fnt->qf_qmsnumber = nqmsfonts + 1000;
  sprintf(fnt->qf_qmsname,"%04.4d",fnt->qf_qmsnumber);
  fnt->qf_maxheight = 0;
  fnt->qf_s = s;
  strcpy(fnt->qf_name,nname);
  strcpy(fnt->qf_filename,fname);
  fnt->qf_info = QF_FILE;
  return(fnt);
}

getfontfromfile(fnt)
     struct qmsfont *fnt;
{
  char fname[MAXNAMLEN];
  FILE *f;
  int i;

  sprintf(fname,"%sr",fnt->qf_filename);
  if (USEROTPXL && job_orientation != printer_orientation) {
    if (!access(fname,4)) readpxlfile(fnt,fname,1);
    else {
      readpxlfile(fnt,fnt->qf_filename,0);
      if (f = fopen(fname,"w")) {
	fclose(f);
	for (i = 0; i < MAXCHARS; i++) rotate(&(fnt->qf_char[i]),fnt);
	writepxlfile(fnt,fname);
      }
    }
  } else readpxlfile(fnt,fnt->qf_filename,0);
  fnt->qf_info &= ~QF_FILE;
}

writepxlfile(fnt,fname)
     struct qmsfont *fnt;
     char *fname;
{
  FILE *f;
  long glyphaddrs[MAXCHARS],pxl_dir_ptr;

  if (!(f = fopen(fname,"w"))) croak("can't open %s to write",fname);
  put4(1001,f);
  writeglyphs(fnt,f,glyphaddrs);
  pxl_dir_ptr = ftell(f) / 4;
  writepxldir(fnt,f,glyphaddrs);
  put4(fnt->qf_pxl_checksum,f);
  put4(fnt->qf_pxl_mag_val,f);
  put4(fnt->qf_pxl_design_size,f);
  put4(pxl_dir_ptr,f);
  put4(1001,f);
  fclose(f);
}

writepxldir(fnt,f,glyphaddrs)
     struct qmsfont *fnt;
     FILE *f;
     long glyphaddrs[];
{
  int i;
  struct qmschar *c;

  for (i = 0; i < MAXCHARS; i++) {
    c = &(fnt->qf_char[i]);
    put2(c->qc_width,f);
    put2(c->qc_height,f);
    put2(c->qc_xoffset,f);
    put2(c->qc_yoffset,f);
    put4(glyphaddrs[i],f);
    put4(c->qc_pxlwidth,f);
  }
}

writeglyphs(fnt,f,glyphaddrs)
     struct qmsfont *fnt;
     FILE *f;
     long glyphaddrs[];
{
  register int j;
  int i,fbw,bw,row;
  struct qmschar *c;
  register unsigned char *p;

  for (i = 0; i < MAXCHARS; i++) {
    c = &(fnt->qf_char[i]);
    if (c->qc_glyph.p) {
      glyphaddrs[i] = ftell(f) / 4;
      /* Write out this glyph to the PXL file */
      p = c->qc_glyph.p;
      bw = (c->qc_width + 7) / 8;
      fbw = ((c->qc_width + 31) / 32) * 4;
      for (row = 0; row < c->qc_height; row++) {
	for (j = 0; j < bw; j++) putc(*p++,f);
	for (j = bw; j < fbw; j++) putc(0,f);
      }
    } else glyphaddrs[i] = 0;
  }
}

int char_words_needed(c)
     struct qmschar *c;
{
  if (c->qc_info & QC_ROTATED)
    return(((c->qc_width + 15) / 16) * c->qc_height);
  else
    return(((c->qc_height + 15) / 16) * c->qc_width);
}

int font_blocks_used(fnt)
     struct qmsfont *fnt;
{
  return((fnt->qf_words_used + 511) / 512);
}

int font_blocks_needed(fnt)
     struct qmsfont *fnt;
{
  return((fnt->qf_words_needed + fnt->qf_words_used + 511) / 512
	 - font_blocks_used(fnt));
}

/* Define a font.
 * Can be called more than once for the same font.
 */
f_define_font(num,options,area,name,texmag,s,tfmchecksum)
char *area,*name;
unsigned long num,options,texmag,s,tfmchecksum;
{
  int i;

  /* check to see if font is already defined */
  for(i = 0; i < ndvifonts ; i++) if (dvifonts[i].df_num == num) return;

  /* Does this make too many fonts defined? */
  if (ndvifonts >= MAXDVIFONTS) croak("too many dvi fonts");
  dvifonts[ndvifonts].df_num = num;
  dvifonts[ndvifonts++].df_qmsfont = find_qmsfont(area,name,texmag,s);
}

struct qmsfont *
find_dvi_font(fontnum)
     unsigned long fontnum;
{
  register int i;

  /* scan through the dvi font list. */
  for(i = 0; i < ndvifonts ; i++)
    if (dvifonts[i].df_num == fontnum) {
      dvifonts[i].df_qmsfont->qf_timestamp = timestamp++;
      return(dvifonts[i].df_qmsfont);
    }
  croak("no dvi font %d defined",fontnum);
}

/* Set a font as the current font.
 */
f_use_font(fontnum,font_space)
unsigned long fontnum;
long *font_space;
{
  curfnt = find_dvi_font(fontnum);
  if (curfnt->qf_info & QF_FILE) getfontfromfile(curfnt);
  /* Make sure that it's loaded in the printer */
  if (!(curfnt->qf_info & QF_LOADED)
      || (curfnt->qf_info & QF_RELOAD))
    download_font(curfnt);
  /* Start using it */
  fprintf(qms,SELECTFONT,curfnt->qf_qmsnumber);
  *font_space = curfnt->qf_s / 6;
}

/* Hints as to what fonts are to be used.
 * This is called once per page to give fonts module hints as what fonts
 * and characters in those fonts are going to be used on this page.
 */
f_newpage(fontvec,charvec,veclen)
     unsigned long fontvec[];
     unsigned long charvec[][4];
     int veclen;
{
  struct qmschar *c;
  register int i,j;
  struct qmsfont *f;

  for (i = 0; i < veclen; i++) {
    f = find_dvi_font(fontvec[i]);
    if (f->qf_info & QF_FILE) getfontfromfile(f);
    if (!(f->qf_info & QF_LOADED)) {
      f->qf_words_used = 0;
      f->qf_words_needed = 400;
    }
    for (j = 0; j < MAXCHARS; j++) 
      if (charvec[i][j/32] & (1 << (j % 32))) {
	c = &(f->qf_char[j]);
	c->qc_info |= QC_NEEDED;
	if (!(c->qc_info & QC_LOADED)) {
	  f->qf_info |= QF_RELOAD;
	  f->qf_words_needed += char_words_needed(c);
	}
      } else f->qf_char[j].qc_info &= ~QC_NEEDED;
  }
}

clear(p,n)
     char *p;
     int n;
{
  while (n-- > 0) *p++ = 0;
}

rotate(c,fnt)
     struct qmschar *c;
     struct qmsfont *fnt;
{
  unsigned char *oldglyph = c->qc_glyph.p;
  unsigned int width = (unsigned int)c->qc_width;
  unsigned int  height = (unsigned int)c->qc_height;
  int newbyteswide = (c->qc_height + 7) / 8;
  int oldbyteswide = (c->qc_width + 7) / 8;
  unsigned char *newglyph,*putbyte;
  int column;
  int row = -1;			/* Start row at 0 when incremented */
  int mask;
  int i, j;
  int times;
  int extractbyte;

  if (!(c->qc_info & QC_NOGLYPH)) {
    if (!(newglyph = malloc(newbyteswide * width)))
      croak("malloc %d",newbyteswide * width);
    clear(newglyph, newbyteswide * width);

    for (i = 0; i < oldbyteswide * height; i++) {
      extractbyte = *(oldglyph + i);
      if (i % oldbyteswide == 0) row++;
      times = (i + 1) % oldbyteswide ? 8 : (width + 7) % 8 + 1;
      for (j = 0, mask = 0x80; j < times; j++, mask >>= 1) {
	column = (((i % oldbyteswide) == 0) && (j == 0)) ? 0 : (column + 1);
	if (mask & extractbyte) {
	  putbyte = newglyph + column * newbyteswide +
	    (int)((height - (row + 1)) / 8);
	  *putbyte |= 1 << 7 - ((height + 7) - row) % 8;
	}
      }
    }
    free(oldglyph);
    c->qc_glyph.p = newglyph;
  }
  c->qc_info |= QC_ROTATED;
  i = c->qc_width;
  c->qc_width = c->qc_height;
  c->qc_height = i;
  i = c->qc_xoffset;
  c->qc_xoffset = c->qc_width - c->qc_yoffset - fnt->qf_maxheight;
  c->qc_yoffset = i;
}

/* Load a font into the qms.
 */
download_font(fnt)
     struct qmsfont *fnt;
{
  register int i;

  if (font_blocks_needed(fnt) > freeblocks)
    qmsfree(font_blocks_needed(fnt));
  freeblocks -= font_blocks_needed(fnt);
  fnt->qf_words_used += fnt->qf_words_needed;
  fnt->qf_words_needed = 0;
  if (fnt->qf_info & QF_LOADED) {
    fprintf(qms,
	    ADDTOFONT,
	    fnt->qf_qmsnumber,job_orientation,
	    1,fnt->qf_qmsname,fnt->qf_maxheight);
  } else {
    fprintf(qms,
	    DEFINEFONT,
	    fnt->qf_qmsnumber,job_orientation,
	    1,fnt->qf_qmsname,fnt->qf_maxheight);
  }
  for (i = 0; i < MAXCHARS; i++)
    if ((fnt->qf_char[i].qc_info & QC_NEEDED)
	&& !(fnt->qf_char[i].qc_info & QC_LOADED))
	  load_char(i,fnt);
  fprintf(qms,ENDDEF);
  fnt->qf_info |= QF_LOADED;
  fnt->qf_info &= ~QF_RELOAD;
}

load_char(ch,fnt)
     unsigned long ch;
     struct qmsfont *fnt;
{
  register unsigned char *bp;
  register int bytes;
  struct qmschar *c = &(fnt->qf_char[ch]);
  int row,bw,bo;

  if (job_orientation != printer_orientation
      && !(c->qc_info & QC_ROTATED)) rotate(c,fnt);
  bp = c->qc_glyph.p;
  fprintf(qms,DEFINECHAR,hex[(ch >> 4) & 017],hex[ch & 017],
	  c->qc_qmswidth,c->qc_height,c->qc_width,
	  (c->qc_yoffset < 0) ? '+' : '-',abs(c->qc_yoffset),
	  (c->qc_xoffset < 0) ? '+' : '-',abs(c->qc_xoffset));
  bw = (c->qc_width + 7) / 8;
  bo = ((c->qc_width + 15) / 16) * 2;
  for (row = 0; row < c->qc_height; row++) {
    for (bytes = 0; bytes < bw; bytes++) putc(*bp++,qms);
    if (bw != bo) putc(0,qms);
  }
  c->qc_info |= QC_LOADED;
}

int readpxlfile(fnt,fname,rotated)
     struct qmsfont *fnt;
     char *fname;
     int rotated;
{
  long pxl_id,pxl_dir_ptr;
  FILE *f;

  if (!(f = fopen(fname,"r"))) croak("no pxl file %s",fname);
  if ((pxl_id = sget4(f)) != 1001)
    croak("%d bad initial pxl ID; %s doesn't look like a pxl file",
	  pxl_id, fnt->qf_filename);

  /* Read the last 5 longs from the pxl file */
  (void) fseek(f, (long)(-5*4), 2);
  fnt->qf_pxl_checksum = sget4(f);
  fnt->qf_pxl_mag_val = sget4(f);
  fnt->qf_pxl_design_size = sget4(f);
  pxl_dir_ptr = sget4(f);
  if ((pxl_id = sget4(f)) != 1001)
    croak("%d bad final pxl ID; %s doesn't look like a pxl file",
	  pxl_id, fnt->qf_filename);
  if (pxl_dir_ptr != ftell(f) / 4 - 517) 
    croak("%s pxl dir ptr is %x, should be %x",
	  fnt->qf_filename, pxl_dir_ptr, ftell(f) / 4 - 517);
  debug("pxl: checksum %d mag %d designsize %d dir %x\n",
	fnt->qf_pxl_checksum,fnt->qf_pxl_mag_val,
	fnt->qf_pxl_design_size,pxl_dir_ptr);

  /* Read the directory */
  (void) fseek(f, pxl_dir_ptr * 4, 0);
  getpxldir(fnt,f,rotated);
  debug("     %s max_height=%d\n",fnt->qf_filename,fnt->qf_maxheight);

  /* Read in all the glyphs */
  getglyphs(fnt,f);

  (void) fclose(f);
}

getpxldir(fnt,f,rotated)
     struct qmsfont *fnt;
     FILE *f;
     int rotated;
{
  int i;
  struct qmschar *c;
  double ds = ((double) fnt->qf_s) / ((double) (1 << 20));

  fnt->qf_maxheight = 0;
  for (i = 0; i < MAXCHARS; i++) {
    c = &(fnt->qf_char[i]);
    c->qc_width = sget2(f);
    c->qc_height = sget2(f);
    c->qc_xoffset = sget2(f);
    c->qc_yoffset = sget2(f);
    c->qc_glyph.l = get4(f);
    c->qc_pxlwidth = sget4(f);
    c->qc_texwidth = (long) (((double) c->qc_pxlwidth) * ds);
    c->qc_qmswidth = 
      (c->qc_texwidth * numerator + half_denominator) / denominator;
    if (rotated) {
      c->qc_info = QC_NOGLYPH | QC_ROTATED;
      fnt->qf_maxheight = max(fnt->qf_maxheight,c->qc_width);
    } else {
      c->qc_info = QC_NOGLYPH;
      fnt->qf_maxheight = max(fnt->qf_maxheight,c->qc_height);
    }
  }
}

getglyphs(fnt,f)
     struct qmsfont *fnt;
     FILE *f;
{
  register int j,row;
  register unsigned char *p;
  int i,fbw,bw;
  struct qmschar *c;

  for (i = 0; i < MAXCHARS; i++) {
    c = &(fnt->qf_char[i]);
    if (c->qc_glyph.l) {
      (void) fseek(f, c->qc_glyph.l * 4, 0);
      fbw = ((c->qc_width + 31) / 32) * 4;
      bw = (c->qc_width + 7) / 8;
      if (!(p = malloc(bw * c->qc_height)))
	croak("malloc %d",bw * c->qc_height);
      c->qc_glyph.p = p;
      for (row = 0; row < c->qc_height; row++) {
	for (j = 0; j < bw; j++) *p++ = getc(f);
	for (j = bw; j < fbw; j++) (void) getc(f);
      }
      c->qc_info &= ~QC_NOGLYPH;
    }
  }
}

/* Make sure that the font info for this character is loaded.
 * Characters are incrementally loaded into the printer.
 * This procedure is called for every character so it must be fast.
 */
f_use_char(ch,texwidth,devwidth)
unsigned long ch;
long *texwidth,*devwidth;
{
  register struct qmschar *c = &(curfnt->qf_char[ch]);

  *texwidth = c->qc_texwidth;
  *devwidth = c->qc_qmswidth;
}


/* free blocks by deleting font(s) using LRU strategy */
int qmsfree(blocks)
     int blocks;
{
  int i,oldtime;
  struct qmsfont *oldfont;  

  while (blocks > freeblocks) {
    oldfont = NULL;
    oldtime = timestamp;
    for (i = 0; i < nqmsfonts; i++)
      if ((qmsfonts[i]->qf_info & QF_LOADED)
	  && (qmsfonts[i]->qf_timestamp < oldtime)) {
	oldfont = qmsfonts[i];
	oldtime = oldfont->qf_timestamp;
      }
    if (!oldfont) croak("qmsfree bug");
    fprintf(qms,DELETEFONT,oldfont->qf_qmsnumber,job_orientation);
    freeblocks += font_blocks_used(oldfont);
    oldfont->qf_info &= ~QF_LOADED;
    oldfont->qf_words_needed = 400;
    oldfont->qf_words_used = 0;
    for (i = 0; i < MAXCHARS; i++) {
      oldfont->qf_char[i].qc_info &= ~QC_LOADED;
      if (oldfont->qf_char[i].qc_info & QC_NEEDED)
	oldfont->qf_words_needed += char_words_needed(&(oldfont->qf_char[i]));
    }
  }
}