
/*#############################################################################
 # ============================>>  crereshp.c  <<=============================#
 ##############################################################################
 #           Download fonts resident to the HP Laserjet II printers           #
 #                           for fonts in .PK format                          #
 ##############################################################################
 # This program was written by                                                #
 #                                                                            #
 #                 Helmut Kopka                                               #
 #                 Max-Planck-Institut fuer Aeronomie                         #
 #                 D-3411 Katlenburg-Lindau                                   #
 #                 Tel. 05556-401451                                          #
 #                 FRG                                                        #
 #                                                                            #
 #----------------------------------------------------------------------------#
 #                    All rights reserved by H. Kopka                         #
 #----------------------------------------------------------------------------#
 #  You may copy the laserjet kit in whole or in part as long as you don't    #
 #  try to make money off it, or pretend that you wrote it.       H. Kopka    #
 #############################################################################*/



/******************************************************************************
 * 'crereshp' is intended as a companion to 'dvihp',  a driver for the HP     *
 * Laserjet II printer.   'crereshp' creates a file, which, when sent to the  *
 * laser printer, downloads any font that should be resident but not in the   *
 * firmware. It reads a file, called 'reshp.fnt',  which contains a list of   *
 * all of the fonts assumed resident. If a font needs downloading, it's       *
 * pk_font file is read, the packed characters are converted into their byte- *
 * aligned pixel patterns and those and the necessary commands to download    *
 * the font are sent to the file called 'inithp.fnt'.                         *
 * -------------------------------------------------------------------------- *
 * This program should only be run after the downloaded font information is   *
 * changed. On every power cycle or crash of the paser printer, the created   *
 * 'inithp.fnt' file should be sent to the printer before the first TeX job.  *
 ******************************************************************************/


#include <stdio.h>
#include "paths.h"
#include "common.h"
#include "hpcom.h"

#define BANNER "This is crereshp , C Version 3.14, Oct 18 1991\n"
/* The BANNER string should be changed whenever 'crereshp.c' gets modified */


/*==========================================================================*
 * The following definitions should be customized to your printer's memory  *
 *==========================================================================*/


#define LASMEM 4598784          /* Corresponds to max memory = 395 Kbytes    */
				/* usable from the base memory of 640 Kbytes */
				/* plus 4 Mbytes memory board extension.     */
			        /* Adjust this value to your local resources!*/

#define LASMIN 3025920          /* Minimum usuable memory should be strongly */
				/* >= max(250 KByte, .5*(full usable memory) */
                                /* The chosen value corresponds to 1.5 Mbytes*/
				/* available for permanent downloaded fonts  */
				/* with respect to the chosen LASMEM value.  */
			        /* Adjust this value to your local resources!*/


/*==========================================================================*
 * The following definitions could be customized to your choice             *
 *==========================================================================*/

#define MAXPKSIZE 12000         /* Large enough to load all pk-files up to   */
				/* magstep 8 and cminch to magstep 4         */

#define MAXPXLSIZE 20000        /* Large enough to maintain any character up */
				/* to magstep 8, except for cminch. For memo-*/
				/* ry effiency, permanent loading for magni- */
				/* fied cminch fonts should be avoided, if   */
				/* these fonts are not heavily used!         */

#define NAMELENGTH 50           /* Maximum length for path and file names    */



/*==========================================================================*
 * Don't modify the following definitions under no circumstances !!!!!      *
 *==========================================================================*/

#define BLACKBYTE '\377'
#define FALSE 0
#define FIX 1048576.0                  /* units of 2**-20 */
#define FMASK 7
#define SCALE 75780587.52              /* 72.27*2**20 */
#define TRUE 1
#define WHITEBYTE '\0'

/* HP-Laserjet PLUS Printer dependent macros */

#define CHAR_ID "\033*c%dE\033(s%dW"   /* specify char and download it */
#define CLEAN_PRINTER "\033E\033&k2G"  /* CR => CR; LF => CR+LF; FF = CR+FF */
#define FONT_ID "\033*c%dD\033)s64W"   /* specify font ID and download fd   */
#define INIT_PRINTER "\033E\033*c0F "  /* printer reset and delete all fonts*/
#define MAKE_FONT_PERM "\033*c5F"      /* make font permanent (last ID)     */


  
/* global files  */

  FILE *bitfile;
  FILE *pkfile;
  FILE *resfile;
  FILE *tempfile;

/* global variables in alphabetical order */

  char     answer[] = "yes";
  cdfmt    cd;                                   /* character descriptor  ## */
  int      c_black;    
  int      c_flag;
  int      c_height;
  int      c_hoffset;
  int      c_nyb;
  byte     c_pad[] = {'\0','\200','\300','\340','\360','\370','\374','\376'};
  int      c_pitch;
  int      c_voffset;
  int      c_width;
  int      dyn_f;
  byte    *endofchardata;
  fdfmt    fd;                                   /* font descriptor       ## */
  int      fonts_down;
  int      fontheight;
  char     fontname[16];
  int      fontnumber;
  int      fontsize;
  char     initname[NAMELENGTH];
  int      landscape;
  long     lasmem;
  long     lastmem;
  byte    *pkbase;
  long     pkbuffer[MAXPKSIZE];
  byte    *pkcharinfo();
  byte    *pkdir[256];
  char     pkname[NAMELENGTH];
  byte    *pk_ptr;
  byte     power[8];
  byte     pxlbuffer[MAXPXLSIZE];
  double   pxlconv;
  int      repeat_count;
  char     resname[NAMELENGTH];
  byte    *rotate_char();



/******************************************************************************
 ******************************************************************************
 * ===>> main()                                                               *
 ******************************************************************************/

main()
{ int memload;
  char  c;
  char  firmware;
  char  orientation[2];
  char  command[80];

  initialize();                              /* get things started properly */
  openresfile();
  opentempfile();
  openbitfile();
  fprintf(bitfile , INIT_PRINTER);
  while((c = getc(resfile)) != 'M')
  { ungetc(c,resfile);
    fscanf(resfile , "%s%d%d%s" , fontname,&fontsize,&fontnumber,orientation);
    printf ("%s %d %d %s", fontname,fontsize,fontnumber,orientation);
    fprintf(tempfile,"%s %d %d %s\n",fontname,fontsize,fontnumber,orientation);
    memload = TRUE;
    landscape = (orientation[0] == 'L');
    while ((firmware = putchar(getc(resfile))) >= ' ')
    { if(firmware == 'R') memload = FALSE;
      putc(firmware,tempfile);
    }
    if (memload)
    { if(lasmem >= LASMIN)
      { loadpkfile();
	makepkdir();
	downloadfont();
        printf("--- %d bytes of Laserjet+ memory occupied\n",
	        lastmem - lasmem);
	  lastmem = lasmem;
      }
      else
      { printf("\nNo more fonts from 'resident.fnt can be downloadede\n");
        printf("Remaining fonts on 'resident.fnt will be deleted\n");
        printf("Free Laserjet+ memory is %d bytes\n",lasmem);
        printf("Is this acceptable ? ");
        scanf("%s",answer);
        break;
      }
    }
  }
  fclose(resfile);
  if(answer[0] == 'y')
  { 
    fprintf(tempfile , "MEM %d\n" , lasmem);
    fprintf(bitfile , CLEAN_PRINTER);
    printf("Free Laserjet+ memory is %d bytes\n",lasmem);
    fclose(bitfile);
    fclose(tempfile);
    strcpy(command,"mv _tempfile ");
    strcat(command,resname);
    system(command);

  }
  else
  { printf("\n  !! Change 'resident.fnt' file and restart 'crereshp' !!\n");
    fclose(bitfile);
    fclose(tempfile);
    strcpy(command,"rm ");
    strcat(command,initname);
    system(command);
  }
}




/******************************************************************************
 * All of the procedures used in crereshp are listet in alphabetical rather   *
 * than in logical order, except for the 'error and die routines' which are   *
 * grouped together:   error(s) ,  stringerror(s,t)                           *
 * This routines are collected under the group name 'error and die' which is  *
 * found on its alphabetical place in the following list.                     *
 ******************************************************************************/




/******************************************************************************
 * ===>>  downloadfont()                                                      *
 ******************************************************************************/
downloadfont()
{ int i;

 /*---------------------------------------------------------------------------
  -        specify font ID = nextfontdown and set up fontdescriptor          -
  ---------------------------------------------------------------------------*/
  fprintf(bitfile , FONT_ID , fontnumber);
  printf("get_font_descriptor for %d\n", fontnumber);
  get_font_descriptor();
  printf("fonts_down\n");
  fonts_down++;
  fwrite((char *) &fd, sizeof(fd), 1, bitfile);
 /*---------------------------------------------------------------------------
  -                   download each character                                -
  ---------------------------------------------------------------------------*/
  for(i = 0 ; i < 256 ; i++) if(pkdir[i]) down_character(i);
  fprintf(bitfile, MAKE_FONT_PERM);                 /* Make font permanent */
  lasmem -= 64;
}


/*****************************************************************************
 * ===>> down_character(c)                                                   *
 * download character 'c', assuming that the corresponding font file is in   *
 * .PK format. Therfore 'pktopxl(c)" is called, which converts the pk-coded  *
 * character into the corresponding byte aligned pixel pattern, stored in    *
 * 'pkbuffer'. 'pktopxl(c)' also determines the global variables             *
 *     c_pitch, c_width, c_height, c_hoffset and c_voffset.                  *
 * For landscape mode the pixel pattern will be rotated and stored at the    *
 * end of the character pixel pattern at 'endofchardata' in pxlbuffer. The   *
 * appropriate pixel pattern then will be downloaded, i. e. put in 'bitfile',*
 * if possible, including the character descriptor preamble for the laserjet *
 * PLUS.                                                                     *
 *****************************************************************************/
down_character(c)
int c;
{ register int i;
  int length;
  int width_bytes;
  int width,height;
  byte *p;
   
  pktopxl(c);
  if(landscape)
  { p = rotate_char();
    width  = c_height;
    height = c_width;
    cd.left_offset = -c_voffset;
    cd.top_offset  = height - c_hoffset - 1;
    cd.orientation = '\1';
  }

  else
  { width  = c_width;
    height = c_height;
    width_bytes = (width + 7) / 8;
    cd.left_offset = - c_hoffset;
    cd.top_offset  = c_voffset;
    cd.orientation = '\0';
    p =  pxlbuffer;
  }
  width_bytes = (width + 7) / 8;
  length = height*width_bytes;

/*........................................................................
  .            Now download pixel pattern for c                          .
  ........................................................................*/
  cd.char_width  = width;
  cd.char_height = height;
  cd.delta_x = 4 * c_pitch; 
  lasmem -= (length + 16);
  fprintf(bitfile , CHAR_ID , c , length+16);
  fwrite((char *) &cd , sizeof(cd) , 1 , bitfile);
  for(i = 0 ; i < length ; i++) putc(*p++,bitfile);
}




/********************************************
 * error and die routines                   *
 * Prints error messages and exit crereshp  *
 ********************************************/

error(s)
char *s;
{ printf(s);
  printf("\n This was a fatal error.\n");
  exit();
}

stringerror(s,t)
char *s,*t;
{ printf(s,t);
  printf("\n This was a fatal error.\n");
  exit();
}



/*****************************************************************************
 * ===>> get_font_descriptor()                                               *
 * This routine determines the font descriptor. It ensures that any character*
 * of this font will fit within the boundaries of the font descriptror.      *
 *****************************************************************************/
get_font_descriptor()
{ int i;
  int max_width,max_offset,max_depth;
  int depth,xheight;
  byte *p;

  max_depth = max_width = max_offset = 0;
  for(i = 0 ; i < 256 ; i++)  
    if(pkdir[i])
    { pkcharinfo(i);
      if(c_voffset > max_offset) max_offset = c_voffset;
      if((depth = c_height - c_voffset) > max_depth) max_depth = depth;
      if(c_width > max_width) max_width = c_width;
    }

  pkcharinfo('x');   xheight = c_height;
/*-----------------------------------------------------------------------------
  -   Now determine font descriptor from max values above                     -
  ----------------------------------------------------------------------------*/
  fd.baseline    = max_offset;
  fd.cell_height = max_depth ? max_offset + max_depth : max_offset + 1;
  fd.cell_width  = max_width;
  fd.orientation = landscape ? 1 : 0;
  fd.height      = 4 * fontheight;
  fd.xheight     = 4 * xheight;
  fd.u_distance  = -max_depth;
  fd.text_height = 4 * fd.cell_height;
  fd.text_width  = 4 * fd.cell_width;
  fd.symbol_set  = fonts_down * 32 + 'X' - 64;
  i = 0;
  while(i <= 15 && (fd.name[i] = fontname[i])) i++;
}



/*********************************
 * ===>> initialize()            *
 * get all variable inititalized *
 *********************************/
initialize()
{ int i,j;
  printf(BANNER);

  lasmem = LASMEM;
  lastmem = LASMEM;
  pkbase = (byte *) pkbuffer;

  fd.size   = 64;
  fd.fmt    = 0;
  fd.type   = 2;
  fd.res1 = fd.res2 = fd.res3 = fd.res4 = fd.res5 = fd.res6 = 0;
  fd.spacing = 1;
  fd.pitch = 0;
  fd.wtype = 0;
  fd.style = 0;
  fd.stroke_weight = 0;
  fd.ltypeface = 3;
  fd.htypeface = 1;
  fd.u_height  = 3;
  fd.serif_style = 0;
  fd.ext_pitch = 0;
  fd.ext_height = 0;
  fd.cap_height = 0;

  cd.fmt   = 4;
  cd.cont  = 0;
  cd.size  = 14;
  cd.class = 1;
  cd.res   = 0;


  j = 1;
  for(i=0 ; i<8; i++)
  { power[i] = j;
    j <<= 1;
  }

  strcpy(resname,respath);
  strcat(resname,"hp.fnt");
  strcpy(initname,initpath);
  strcat(initname,"hp.fnt");
}



/******************************************************************************
 * ===>>  loadpkfile()                                                        *
 * Here is a procedure that reads the .PK file into 'pkbuffer'. Other than    *
 * insuring that the initial two bytes are 247 and 89 (the pk_pre command,    *
 * followed by the current .PK format identifier), it does no format checks.  *
 * If the corresponding .PK file doesn't fit into pkbuffer, crereshp will be  *
 * aborted. In this case MAXPKSIZE has to be increased by an appropriate      *
 * amount, and 'crereshp' has to be recompiled. At this state the choosen     *
 * value of MAXPKSIZE will serve all existing .PK files, but for future .PK   *
 * font files this maybe could happen.                                        *
 ******************************************************************************/
loadpkfile()
{ long *pkptr;
  byte *p;
  openpkfile();
  pkptr = pkbuffer;
  p = (byte *) pkptr; 
  *pkptr++ = getw(pkfile);
  if((getpkbyte(p) != pk_pre) || (getpkbyte(p) != 89))
    printf(" --- not loaded, PK File is bad\n");
  else
  { while(!feof(pkfile))
    { *pkptr++ = getw(pkfile);
      if(pkptr - pkbuffer >= MAXPKSIZE)
        error("dvihp memory size exceeded on load of pk file\n");
    }
  }
  fclose(pkfile);
}



/******************************************************************************
 * ===>> makepkdir()                                                          *
 * The coding scheme for the different characters in .PK files in general are *
 * not stored in ascending order of the ascii value of the character. Access  *
 * to an individual character would need a lot of searching within the pk-    *
 * buffer. So it is wise, to make a directory for all of the characters with- *
 * in the pkfont which holds a pointer to the flag byte of each character.    *
 * These pointers in the global pointer array '*pkdir[256]'.                  *
 ******************************************************************************/
 
makepkdir()
{ byte *p,*pc;
  int format,flag;
  int i;
  long ds,hppp,vppp;
  unsigned cc,pl;
  for(i=0 ; i<256 ; i++) pkdir[i] = NULL;
  p = pkbase + *(pkbase+2) + 3;
#ifndef MACROS
  ds = getpkquad(p);    p += 8;
  hppp = getpkquad(p);  p += 4;
  vppp = getpkquad(p);  p += 4;
#else
  ds = getpkquad(p);
  p +=4;
  hppp = getpkquad(p);
  vppp = getpkquad(p);
#endif
  pxlconv = ds / FIX * fontsize / SCALE ;
  fontheight = round(ds / FIX * vppp / 65536.0);
  while((flag = getpkbyte(p)) != pk_post)
  { if(flag < pk_cmd)
    { pc = p - 1;
      format = flag & FMASK;
      if(format < 4)               /* short format */
      { pl = getpkbyte(p);
	cc = getpkbyte(p);
        p += (format*256 + pl);
      }
      else if(format < 7)         /* extended short format */
#ifndef MACROS
      { pl = getpkpair(p);  p += 2;
	cc = getpkbyte(p);
        p += ((format-4)*65536 + pl);
      }
      else
      { pl = getpkquad(p);  p += 4;
	cc = getpkquad(p);  p += 4;
	p += pl;
      }
#else
      { pl = getpkpair(p);
	cc = getpkbyte(p);
        p += ((format-4)*65536 + pl);
      }
      else
      { pl = getpkquad(p);
	cc = getpkquad(p);
	p += pl;
      }
#endif
      if(cc < 256) pkdir[cc] = pc;
    }
    else
    { switch(flag)
      { case pk_xxx1:
	  pl = getpkbyte(p);
	  break;
#ifndef MACROS
	case pk_xxx2:
	  pl = getpkpair(p);  p += 2;
	  break;
	case pk_xxx3:
	  pl = getpktrio(p);  p += 3;
	  break;
	case pk_xxx4:
	  pl = getpkquad(p);  p += 4;
	  break;
#else
	case pk_xxx2:
	  pl = getpkpair(p);
	  break;
	case pk_xxx3:
	  pl = getpktrio(p);
	  break;
	case pk_xxx4:
	  pl = getpkquad(p);
	  break;
#endif
	case pk_yyy: 
	  pl = 4;
	  break;
	case pk_pre:
	  error("pk_pre within PK file\n");
	  break;
	default:
	  pl = 0;
	  break;
      } 
      p += pl;
    }
  }
}



/******************************************************************************
 * ===>> pkcharinfo(p)                                                        *
 * This routine determines the global variables                               *
 *    c_flag, dyn_f, c_pitch, c_width, c_height, c_hoffset and c_voffset      *
 * for the character c. It returns a pointer which points to the first run    *
 * count of the character in progress.                                        *
 ******************************************************************************/
byte *pkcharinfo(c)
int c;
{ int format;
  byte *p;
  int tfm;
  if(p = pkdir[c])
  { c_flag = getpkbyte(p);
    dyn_f = c_flag >> 4;
    format = c_flag & FMASK;
    if(format < 4)
    { p += 2;
            tfm = getpktrio(p);
#ifndef MACROS
      p += 4;
#else
      p++;
#endif
      c_width = getpkbyte(p);
      c_height = getpkbyte(p);
      c_hoffset = sigpkbyte(p);
      c_voffset = sigpkbyte(p);
    }
    else if(format < 7)
#ifndef MACROS
    { p += 3;
      tfm = getpktrio(p);        p += 5;
      c_width = getpkpair(p);    p += 2;
      c_height = getpkpair(p);   p += 2;
      c_hoffset = sigpkpair(p);  p += 2;
      c_voffset = sigpkpair(p);  p += 2;
    }
    else
    { p += 8;
      tfm = getpkquad(p);        p += 12;
      c_width = getpkquad(p);    p += 4;
      c_height = getpkquad(p);   p += 4;
      c_hoffset = sigpkquad(p);  p += 4;
      c_voffset = sigpkquad(p);  p += 4;
    }
#else
    { p += 3;
      tfm = getpktrio(p);    
      p += 2;
      c_width = getpkpair(p);
      c_height = getpkpair(p);
      c_hoffset = sigpkpair(p);
      c_voffset = sigpkpair(p);
    }
    else
    { p += 8;
      tfm = getpkquad(p); 
      p += 8;
      c_width = getpkquad(p);
      c_height = getpkquad(p);
      c_hoffset = sigpkquad(p);
      c_voffset = sigpkquad(p);
    }
#endif
    c_pitch = round(pxlconv*tfm);
    return(p);
  }
  else return(NULL);
}




/******************************************************************************
 * ===>> pk_num()                                                             *
 * This routine deliveres the final algorithm for decoding the run count,     *
 * assuming a procedure (macro) 'get_nyb()' is available to get the next      *
 * nybble from the 'pkbuffer'. It returns the next run_count as an integer,   *
 * and if the row needs to be repeated it returns additionally the repeat     *
 * value to the global variable 'repeat_count'. Since a repeat count can      *
 * occure only once within a row, namely after the first transition within a  *
 * row, it is the responsibility of the calling procedure to repeat such a    *
 * row and to reset 'repeat_count' to zero before calling the next run count  *
 * for the next row. - The global variable 'c_black' changes from 0 to -1 and *
 * back to 0 each time when 'pk_num' is called, indicating a run count for    *
 * black pixels by 'c_black = -1' or for white pixels by 'c_black = 0', resp. *
 * Note that this routine is recursive, but since a repeat count can never    *
 * directly follow another repeat count, it can only be recursive to one level*
 ******************************************************************************/
pk_num()
{ int i,j;
  c_black = ~c_black;
  if(!(i  = get_nyb()))
  { do i++; while(!(j = get_nyb()));
    while(i--) j = j*16 + get_nyb();
    return(j - 15 + (13 - dyn_f)*16 + dyn_f);
  }
  else if(i <= dyn_f) return(i);
  else if(i < 14) return((i - dyn_f - 1)*16 + get_nyb() + dyn_f + 1);
  else
  { if(repeat_count) error("Extra repeat count\n");
    if(i == 14) repeat_count = pk_num();
    else       {repeat_count = 1; c_black = ~c_black;}
    return(pk_num());
  }
}



/******************************************************************************
 * ===>> pktopxl(c)                                                           *
 * This routine converts a character coded in PK format into the appropriate  *
 * byte aligned pixel pattern. After calling 'pkcharinfo(c)', besides the     *
 * global variables                                                           * 
 *    dyn_f, c_flag, c_pitch, c_width, c_height, c_hoffset and c_voffset      *
 * a pointer to the first run_count is returned and stored in the global var  *
 * 'pk_ptr'. The produced pixel pattern is stored in the global array 'pxl-   *
 * buffer', and the global pointer 'endorchardata' points to the next free    *
 * byte in 'pxlbuffer'.                                                       *
 *----------------------------------------------------------------------------*
 * 'pktopxl' has two main branches: for those characters which ar coded into  *
 * run-repeat counts, indicated by a value of dyn_f < 14, the first branch is *
 * taken, wgile for bit mapped characters, indicated by dyn_f == 14, the      *
 * second branch is taken.                                                    *
 ******************************************************************************/
pktopxl(c)
int c;
{ byte *pxl, *row, *p;
  byte pxl_byte;
  int pad_bits, pad_comp;
  int pad_mask;
  int width_bytes;
  int nrows, length;
  int l,m,n;
  int run_count;

  pk_ptr = pkcharinfo(c);
  nrows = c_height;
  width_bytes = (c_width + 7) / 8;
  pad_bits = c_width % 8;
  pad_mask = c_pad[pad_bits];
  pxl = pxlbuffer;

  if(dyn_f < 14)
  {/*.................................................................
    .  convert run-repeat counts to byte aligned pixel pattern       .
    ..................................................................*/
    run_count = repeat_count = 0;
    c_nyb = 0;
    c_black = (c_flag & 0x8) ? 0 : ~0; 
    while(nrows)
    { if(repeat_count)
      { while(repeat_count)
        { repeat_count--;
       	  m = width_bytes;
          while(m--) *pxl++ = *row++;
          nrows--;
        }
      }
      else
      { if(!run_count) run_count = pk_num(); 
        if(run_count >= c_width)
	  while(run_count >= c_width)
	  { run_count -= c_width;
	    m = pad_bits ? width_bytes : width_bytes + 1;
	    while(--m) *pxl++ = c_black ? BLACKBYTE : WHITEBYTE;
	    if(pad_bits) *pxl++ = c_black ? pad_mask : WHITEBYTE;
	    nrows--;
	  }
        else
        { row = pxl;
	  m = pad_bits ? width_bytes : width_bytes + 1;
	  while(--m)
	  { if(run_count < 8)
	    { pxl_byte = c_black ? c_pad[run_count] : ~c_pad[run_count];
	      while((run_count += pk_num()) < 8)
	        if(c_black) pxl_byte &=  c_pad[run_count];
	        else        pxl_byte |= ~c_pad[run_count];
	      *pxl++ = pxl_byte;
	    }
	    else *pxl++ = c_black ? BLACKBYTE : WHITEBYTE;
	    run_count -= 8;
	  }
	  if(pad_bits)
	  { if(run_count < pad_bits)
	    { pxl_byte = c_black ? c_pad[run_count] : ~c_pad[run_count];
	      while((run_count += pk_num()) < pad_bits)
	        if(c_black) pxl_byte &=  c_pad[run_count];
	        else        pxl_byte |= ~c_pad[run_count];
	      *pxl++ = pxl_byte & pad_mask; 
	    }
	    else *pxl++ = c_black ? pad_mask : WHITEBYTE;
	  }
	  nrows--;
	  run_count -= pad_bits;
        }
      }
    }
  }
  else
  {/*.................................................................
    . convert bit mapped character into byte aligned pixel pattern   .
    ..................................................................*/
    p = pk_ptr;
    pad_comp = 8 - pad_bits;
    if(pad_bits)
    { m=0;
      while(nrows--)
      { l = width_bytes;
        while(--l) *pxl++ = m ? (*p++) << m | (*p >> n) & ~c_pad[n] : *p++;
        if(m) *pxl++ = m <= pad_comp ? (*p << m) & pad_mask 
	               : (*p++) << m | *p >> n & ~c_pad[n] & pad_mask;
        else  *pxl++ = *p & pad_mask;
        m = (m + c_width) % 8;
        if(!m) p++;
        else   n = 8 - m;
      }
    }
    else
    { length = width_bytes*c_height;
      while(length--) *pxl++ = *p++;
    }
  }
  endofchardata = pxl;
}



/*************************
 * file opening routines *
 *************************/

openbitfile()
{ bitfile = fopen(initname,"w");
}

openpkfile()
{ strcpy(pkname,fontpath);
#ifndef SINGLEPATH
  sprintf(pkname + strlen(pkname) ,"%d/" , fontsize);
#endif
  sprintf(fontname + strlen(fontname) ,".%dpk" , fontsize);
  strcat(pkname,fontname);
  if((pkfile = fopen(pkname,"r")) == NULL)
    stringerror ("PK file %s does not exist!\n",pkname);
}

openresfile()
{ if((resfile = fopen(resname,"r+")) == NULL)
    stringerror("Can't open %s!\n",resname);
}

opentempfile()
{ tempfile = fopen("_tempfile","w");
}


/*****************************************************************************
 * ===>> rotate_char()                                                       *
 * Rotate the pixel pattern, stored in pxlbuffer by 90 degrees for land-     *
 * scape printout mode. The rotated pixel pattern starts at the end of the   *
 * original pixel pattern in pxlbuffer. The pointer to the begin of the      *
 * rotated pattern is returned by rotate_char()                              *
 *****************************************************************************/
byte *rotate_char()
{ int lbit, tbit;
  int width, height, bytes, length;
  int mask;
  byte *pp, *lp, *tp;
  register int i,j;

  width  = c_height;
  height = c_width;
  bytes = (height + 7) / 8;
  length = height*((width + 7)/8);
  if(endofchardata - pxlbuffer + length >= MAXPXLSIZE)
       error("Out of memory while rotating character!\n");
  lp = endofchardata;
  for(i = 0 ; i < length ; i++) *lp++ = 0;
  lp = endofchardata - 1;
  tp = pxlbuffer - 1;
  tbit = 7 - (height -1) % 8;
  for(i = 0 ; i < height; i++)
  { if(tbit == 8)   { tbit = 0; tp--; }
    pp = tp + bytes;
    mask = power[tbit++];
    lp++;
    lbit = 8;
    for(j = 0 ; j < width ; j++)
    { if(!lbit--)   { lbit = 7; lp++; }
      if(*pp & mask) *lp |= power[lbit];
      pp += bytes;
    }
  }
  return(endofchardata);
}


