#define VERSION "3.1"
#ifndef lint
static char sccsid[] = "@(#)dvi2ps.c	3.1\t11/16/89";
#endif lint


/*
 * AUTHOR(s)
 *     Mark Senn wrote the early versions of this program for the
 *     BBN BitGraph.  Stephan Bechtolsheim, Bob Brown, Richard
 *     Furuta, James Schaad and Robert Wells improved it.  Norm
 *     Hutchinson ported the program to the Sun.  Neal Holtz ported
 *     it to the Apollo, and from there to producing PostScript
 *     output. Scott Jones added intelligent font substitution.
 *     Howard Trickey made it read GF files instead of PXL ones.
 *     Les Carr added the capacity for use of LaserWriter builtin fonts.
 *     Larry Denenberg added support for TeX-XeT's extensions.
 *
 *     Van Jacobson adapted the GF code to read PK files in addition 
 *     to PXL ones, add support for Trevor Darrell's psfig & 
 *     laserwriter font support (an enhanced version of LA Carr's work) 
 *     and added user-selectable font flushing intervals. JingBai Wang
 *     redid the special routines to reimplement "psfile", added "pspage"
 *     and "ps-string", and the ability to include Macintosh postscript.
 *     He also added an on-line help facility, and arbitrary scaling of
 *     all fonts to improve substitution. Kevin Coombes merged as many 
 *     versions as he could find.
 */

/* Basic method:
 * Two passes are made over each page in the DVI file.  The first pass
 * simply outputs the bitmaps for all characters on that page that haven't
 * been sent before.  The second pass outputs all the character setting
 * and positioning commands.  This allows us to bracket the setting portion
 * with PostScript save's and restore's, thus reclaiming considerable
 * virtual memory after each page.
 *
 * All coordinates are output in the PostScript system (TeX origin),
 * and in integer units of rasters (300/inch) -- except for character
 * widths, which are sent as floating point numbers.
 *
 * Several pages of PostScript support code must be sent to the LaserWriter
 * before this stuff goes.  It is automatically included unless the
 * -h option is given.
 *
 * The variable "state" determines what we are doing with dvi instructions as
 * we read them from the main input file.  The possible values are:
 *   SKIPPING      Ignoring everthing; used on pages that the user doesn't want
 *   CHARFINDING   Loading characters; used on the first pass over each page
 *   TYPESETTING   Typesetting normally
 *
 * Here is a summary of all the ways that "state" can change:
 *    We start in state SKIPPING.
 *    If a BOP determines that the page should be output, it changes from
 *	SKIPPING to CHARFINDING.
 *    An EOP will change from CHARFINDING to TYPESETTING and go back to
 *	start the second pass.  It also changes TYPESETTING to SKIPPING
 *	and goes off to the next page.
 */


/**********************************************************************/
/***********************  external definitions  ***********************/
/**********************************************************************/

#include <stdio.h>
#include <ctype.h>
#include <sys/param.h>
#include <signal.h>
#include <strings.h>
#include "site.h"
#include "struct.h"
#include "defs.h"
#include "commands.h"

#define SKIPPING	0
#define CHARFINDING	1
#define TYPESETTING	2
#define DRIFT 		2	/* maximum drift in pixels	*/
#define UNDEFPOS -314159728
#define SET	TRUE		/* used to distinguish SETs from PUTs */

extern bool  InPageList();	/* defined in pagelist.c	*/
extern void  DoSpecial();	/* defined in special.c		*/
extern void  Initialize();	/* defined in decode.c		*/
extern void  Preliminaries();	/* defined in prelim.c		*/

/* defined in auxiliary.c */
extern void  AbortRun(), Fatal(), Progress(), Warning();
extern void  CopyFile(), GetBytes(), PutInt(), PutOct();
extern int   NoSignExtend(), PixRound(), RuleRound(), SignExtend();

/* defined in fontfiles.c */
extern float ActualFactor();
extern void  EmitBits(), LoadAChar(), ReadFontDef(), SkipFontDef();

#ifdef BUILTIN
extern void SetPSFont(), InitPSFont();
extern int  FirstChar(), MoreChar();
#endif BUILTIN
#ifdef apollo
extern char *logname();
#endif apollo

/**********************************************************************/
/*************************  Global Procedures  ************************/
/**********************************************************************/
/* Note:  Procedures are declared here in the order in which they appear.
 * The names are unique in the first 6 characters for portability. */

void	MainLoop();

void	AllDone();
void    ClearOutput();
bool    HasBeenRead();
void	MoveDown();
void	MoveOver();
void	MoveRight();
void    PopAll();
void    PushAll();
void	SetChar();
void	SetFntNum();
void    SetPosn();
void	SetRule();
void    SetString();


/**********************************************************************/
/*************************  Global Variables  *************************/
/**********************************************************************/

/* file name stuff */
FILE *dvifp  = NULL;		/* DVI file pointer			*/
FILE *outfp = NULL;		/* output file				*/
FILE *G_logfp;			/* log file pointer			*/
long  ppagep;			/* previous page pointer		*/
bool  C_logcreate = TRUE;	/* are warning messages going to file?	 */
char  G_Logname[STRSIZE];       /* name of log file, if created		*/
bool  G_FullPage = FALSE;	/* Has a full page special been found?	*/
char  G_FullName[STRSIZE];	/* Name of file with full page special	*/
#ifdef CREOPT
bool  C_create = FALSE;		/* create an output file ?		*/
char  G_outfname[STRSIZE];	/* name of output file			*/
#endif CREOPT

/* pagination stuff */
int   G_pagecount = 0;		/* number of pages processed	 	*/
int   G_temporary = TEMPORARY; 	/* font/char has been read from file    */
int   G_permanent = PERMANENT;	/* font/char has been sent to printer	*/
#ifdef BUDGET
int   budget = BUDGET;		/* estimated available VM		*/
int   startbudget = BUDGET;	/* estimated starting value of VM	*/
bool  G_flushflag = FALSE;	/* should we flush fonts and start over */
#endif BUDGET

/* status stuff */
int   state;			/* what are we doing?			*/
int   G_exitcode = 0;		/* number of errors encountered		*/
int   waiting = 0;		/* how many strings to show ?		*/

/* command-line stuff */
bool  C_reverse = TRUE;		/* process DVI pages in reverse order?	*/
bool  C_preload = TRUE;	        /* preload the font descriptions?	*/

/* font stuff */
font_entry  *fontptr;		/* current font				*/
font_entry  *prevfont=NULL;	/* font of previous character		*/
font_entry  *headfont=NULL;	/* head of lists of all fonts		*/

/* measurement stuff */
int   hconv, vconv;		/* converts DVI units to pixels		*/
int   h, v;			/* current position in DVI units	*/
int   w, x;			/* horizontal spacing parameters	*/
int   y, z;			/* vertical spacing parameters		*/
int   hh, vv;			/* current h and v on device		*/
int   hhh = UNDEFPOS;		/* rounded h, v on device,		*/
int   vvv = UNDEFPOS;		/*   used to control drift		*/
int   num;			/* numerator specified in preamble	*/
int   den;			/* denominator specified in preamble	*/
int   mag;			/* magnification specified in preamble	*/
stack_entry  stack[STACKSIZE];	/* stack for push, pop and reflection	*/
stack_entry *sp;		/* pointer to top of stack		*/

char  n[STRSIZE];		/* temporary command parameter		*/

#ifdef STATS
bool  C_stats = FALSE;		/* are we reporting stats?		*/
int   Snbpxl = 0;		/* number of bytes of pixel data	*/
int   Sonbpx = 0;		/* "optimal" number of bytes of data	*/
int   Sndc = 0;			/* number of different chars typeset	*/
int   Stnc = 0;			/* total number of characters typeset	*/
int   Snbpx0, Sndc0, Stnc0;	/* for incremental changes per page	*/
#endif STATS


/**********************************************************************/
/*******************************  main  *******************************/
/**********************************************************************/
main(argc, argv)
int argc;
char *argv[];
{
    Initialize(argc, argv);
    Preliminaries();
    MainLoop();
}


/**********************************************************************/
/*****************************  MainLoop  *****************************/
/**********************************************************************/
void
MainLoop()
{
   register int command;	/* current command			*/
   int count0;			/* first counter on each page		*/
   long cpagep;			/* current page pointer			*/
   register int k, val, val2;	/* temporaries				*/

   state = SKIPPING;

   while (TRUE) {

      command = NoSignExtend(dvifp, 1);

      /* handle a common case very quickly */
      if ((state == SKIPPING) &&
	(command >= SETC_000) && (command <= SETC_127))
	   continue;

      switch (command) {

	case SET1: case SET2: case SET3: case SET4:
	    val = NoSignExtend(dvifp, command-SET1+1);
	    SetChar(val, SET);
	    break;

	case PUT1: case PUT2: case PUT3: case PUT4:
	    val = NoSignExtend(dvifp,command-PUT1+1);
	    SetChar(val, !SET);
	    break;

	case SET_RULE:
	    val = NoSignExtend(dvifp, 4);
	    val2 = NoSignExtend(dvifp, 4);
	    SetRule(val, val2, SET);
	    break;

	case PUT_RULE:
	    val = NoSignExtend(dvifp, 4);
	    val2 = NoSignExtend(dvifp, 4);
	    SetRule(val, val2, !SET);
	    break;

	case NOP:
	    break;

	case BOP:
	    cpagep = ftell(dvifp) - 1;
	    count0 = NoSignExtend(dvifp, 4);
	    GetBytes(dvifp, n, 36);		/* skip over count1--count9 */
	    ppagep = NoSignExtend(dvifp, 4);
	    h = v = w = x = y = z = 0;		/* initialize the stack */
	    hh = vv = 0;
	    hhh = vvv = UNDEFPOS;
	    sp = stack - 1;
	    fontptr = NULL;
	    prevfont = NULL;
#ifdef BUILTIN
	    InitPSFont();
#endif /* BUILTIN */

	    if (state == SKIPPING) {
	        if (InPageList(count0)) {
		   state = CHARFINDING;
		   ++G_pagecount;
		   EMIT(outfp, "%d @bop0\n", count0);
		   Progress("[%d", count0);
		   if (G_flushflag == TRUE) {
#ifdef STATS
			Progress("...Flushing fonts...page %d]\n",G_pagecount);
#endif STATS
			EMITS("@flushfonts\n");
			budget = startbudget;
			++G_temporary;
			++G_permanent;
		   }
#ifdef STATS
		   if (C_stats) { Sndc0 = Sndc; Stnc0 = Stnc; Snbpx0 = Snbpxl; }
#endif STATS
		}
/* else if not skipping and reading in reverse, use ppagep to jump there */
	    } else if (state == TYPESETTING) {
		EMIT(outfp, "%d @bop1\n", count0);
		waiting = 0;
	    } else
		Fatal("Invalid state at start of page");
	    break;

	case EOP:
	    if (state == CHARFINDING) {
		state = TYPESETTING;
		(void) fseek(dvifp,cpagep,0);
	    }
	    else {
		  if (state != SKIPPING) {
			if (waiting > 0) ClearOutput();
			EMITS("@eop\n");
			Progress("]%c", (G_pagecount % 10) ? ' ' : '\n');
			state = SKIPPING;
			if (G_FullPage == TRUE && *G_FullName != '\0') {
				EMITS("@beginfullpage\n");
				CopyFile(G_FullName);
				EMITS("@endfullpage\n");
				G_FullPage = FALSE;
			}
#ifdef STATS
			if (C_stats)
			    Progress(
				" - %d total ch, %d diff ch, %d pxl bytes]\n",
				Stnc-Stnc0, Sndc-Sndc0, Snbpxl-Snbpx0);
#endif STATS
		  }
		  if (C_reverse && (ppagep >  0)) 
			(void) fseek(dvifp, ppagep, 0);
		  if (C_reverse && (ppagep <= 0)) AllDone();
	    }
	    break;

	case PUSH:
	    if (state >= TYPESETTING) PushAll();
	    break;

	case POP:
	    if (state >= TYPESETTING) PopAll();
	    break;

	case RIGHT1: case RIGHT2: case RIGHT3: case RIGHT4:
	    val = SignExtend(dvifp,command-RIGHT1+1);
	    MoveOver(val);
	    break;

	case W0:
	    MoveOver(w);
	    break;

	case W1: case W2: case W3: case W4:
	    w = SignExtend(dvifp,command-W1+1);
	    MoveOver(w);
	    break;

	case X0:
	    MoveOver(x);
	    break;

	case X1: case X2: case X3: case X4:
	    x = SignExtend(dvifp,command-X1+1);
	    MoveOver(x);
	    break;

	case DOWN1: case DOWN2: case DOWN3: case DOWN4:
	    val = SignExtend(dvifp,command-DOWN1+1);
	    MoveDown(val);
	    break;

	case Y0:
	    MoveDown(y);
	    break;

	case Y1: case Y2: case Y3: case Y4:
	    y = SignExtend(dvifp,command-Y1+1);
	    MoveDown(y);
	    break;

	case Z0:
	    MoveDown(z);
	    break;

	case Z1: case Z2: case Z3: case Z4:
	    z = SignExtend(dvifp,command-Z1+1);
	    MoveDown(z);
	    break;

	case FNT1: case FNT2: case FNT3: case FNT4:
	    k = NoSignExtend(dvifp,command-FNT1+1);
	    if (state > SKIPPING) 
		SetFntNum(k);
	    break;

	case XXX1: case XXX2: case XXX3: case XXX4:
	    DoSpecial(dvifp, command);
	    break;

	case FNT_DEF1: case FNT_DEF2: case FNT_DEF3: case FNT_DEF4:
	    k = NoSignExtend(dvifp, command-FNT_DEF1+1);
	    if (C_preload || HasBeenRead(k) || (state == SKIPPING))
		SkipFontDef();
	    else
		ReadFontDef(k);
	    break;

	case PRE:
	    Fatal("PRE occurs within file");
	    break;

	case POST:
	    AllDone();
	    break;

	case POST_POST:
 	    Fatal("POST_POST with no preceding POST");
	    break;

	default:
	    if (command >= FONT_00 && command <= FONT_63)
		  SetFntNum(command - FONT_00);
	    else if (command >= SETC_000 && command <= SETC_127)
		  SetString(command);
	    else  Fatal("%d is an undefined command", command);
	    break;

      }		/* end of "switch (command) ..."	*/
   }	   /* end of "while (TRUE) ..."	*/
}	/* end of procedure MainLoop */


/**********************************************************************/
/****************************** AllDone  ******************************/
/**********************************************************************/
void
AllDone()
{
#ifdef STATS
    register font_entry *p;

    if (C_stats) {
	Progress("Total chars   diff chars   pxl bytes\n" );
	Progress("      #   %%        #   %%       #   %%\n" );
	Progress("------- ---   ------ ---   ----- ---\n" );
	for( p=headfont; p!=NULL; p=p->next ) {
		Progress("%7d%4d", p->ncts, (100*p->ncts + Stnc/2)/Stnc );
		Progress("%9d%4d", p->ncdl, (100*p->ncdl + Sndc/2)/Sndc );
		Progress("%8d%4d", p->nbpxl, (100*p->nbpxl + Snbpxl/2)/Snbpxl );
		Progress("  %s\n", p->psname );
		}
	Progress("\nTotal number of characters typeset: %d\n", Stnc);
	Progress("Number of different characters downloaded: %d\n", Sndc);
	Progress("Number of bytes of pxl data downloaded: %d\n", Snbpxl);
	Progress("Optimal # of bytes of pxl data: %d\n", Sonbpx);
	}
#endif STATS

    EMITS("@end\n");
    Progress("\n");

#ifdef CREOPT
    if( C_create ) {
	(void) fclose(outfp);
	Progress("Output written on \"%s\"\n", G_outfname );
	}
#endif CREOPT

   if (C_logcreate == TRUE && G_logfp != NULL && G_logfp != stderr)  {
	(void) fclose(G_logfp);
	(void) fprintf(stderr, "Log file \"%s\" created.\n",G_Logname);
    }
    AbortRun(G_exitcode);
}


/**********************************************************************/
/***************************  ClearOutput  ****************************/
/**********************************************************************/
void
ClearOutput()
{
    if (waiting == 0) return;
    if (waiting == 1) EMITS(" s\n");
    if (waiting > 1)  EMITS(" ks \n");
    waiting = 0;
}


/**********************************************************************/
/***************************  HasBeenRead  ****************************/
/**********************************************************************/
bool
HasBeenRead(k)
register int k;
{
    register font_entry *fep;

    fep = headfont;
    while ((fep != NULL) && (fep->k != k))
	fep = fep->next;
    return( fep != NULL );
}


/**********************************************************************/
/****************************  MoveDown  ******************************/
/**********************************************************************/
void
MoveDown(a)
int a;
{
    int vtemp;

    if (state < TYPESETTING) return;
    vtemp = PixRound (v += a, vconv);
    if (fontptr && abs(a) < 5*fontptr->font_space) {
	vv += PixRound(a, vconv);
	if (vtemp > vv+DRIFT) vv = vtemp-DRIFT;
	else if (vtemp < vv-DRIFT) vv = vtemp+DRIFT;
    }
    else vv = vtemp;
}


/**********************************************************************/
/****************************  MoveOver  ******************************/
/**********************************************************************/
void
MoveOver(b)
int b;
{
    int htemp;

    if (state < TYPESETTING) return;
    htemp = PixRound (h += b, hconv);
    if (fontptr && b < fontptr->font_space && b > -4*fontptr->font_space) {
	hh += PixRound(b, hconv);
	if (htemp > hh+DRIFT) hh = htemp-DRIFT;
	else if (htemp < hh-DRIFT) hh = htemp+DRIFT;
    }
    else hh = htemp;
}


/**********************************************************************/
/****************************  MoveRight  ******************************/
/**********************************************************************/
void
MoveRight(b)
int b;
{
    int htemp;

    htemp = PixRound (h += b, hconv);
    if (htemp > hh+DRIFT) hh = htemp-DRIFT;
    else if (htemp < hh-DRIFT) hh = htemp+DRIFT;
}


/**********************************************************************/
/******************************  PopAll  ******************************/
/**********************************************************************/
void
PopAll()
{
    if (sp < stack) Fatal("stack underflow");
    h = sp->h;  v = sp->v;  w = sp->w;  x = sp->x;  y = sp->y;  z = sp->z;
    hh = sp->hh; vv = sp->vv;
#ifdef BUILTIN
    vvv = UNDEFPOS;	/* a hack for builtin font rounding errors */
#endif BUILTIN
    sp--;
}


/**********************************************************************/
/*****************************  PushAll  ******************************/
/**********************************************************************/
void PushAll()
{
    sp++;
    if (sp >= stack + STACKSIZE) Fatal("stack overflow");
    sp->h = h;  sp->v = v;  sp->w = w;  sp->x = x;  sp->y = y;  sp->z = z;
    sp->hh = hh; sp->vv = vv;
}


/**********************************************************************/
/*****************************  SetChar  ******************************/
/**********************************************************************/
void
SetChar(c, setting)
int c;
bool setting;
{
    register char_entry *cep;		/* temporary */
    float fscale;		/* scaling factor for substituted fonts */

    if (state == SKIPPING) return;
    if (fontptr == NULL)
	Fatal("internal - unexpected null font in SetChar()\n");

    cep = &(fontptr->ch[c]);
#ifdef BUILTIN
    if(fontptr->dic_pack == TRUE) SetPSFont(fontptr, c);
#endif /* BUILTIN */
    if (cep->where.isloaded < G_permanent)
	LoadAChar(c, cep);
    if (state == CHARFINDING) return;

    if (IsBuiltIn(fontptr->n)) fscale = 1.0;
    else fscale = fontptr->ps_scale;

    SetPosn(hh,vv);

    if (fontptr->font_file_id != NO_FILE) { 	/* Ignore missing fonts */
#ifdef BUDGET
	if (cep->where.isloaded == G_temporary) { /* and missing characters */
	    if (cep->where.address.pixptr != NULL) {
		EMITS(" save\n");
		EmitBits(c, cep, " @pc restore");
	    }
	} else {
#endif BUDGET
	    if (waiting++ == 0) EMITS("m ");
	    if ((waiting % 6) == 0) EMITC('\n');
#ifdef BUILTIN
	    c = cep->pschar;
#endif BUILTIN
	    EMITC('('); EMITO(c); EMITS(") ");
	    hhh += (int) (fscale * cep->dx);
#ifdef BUDGET
	}
#endif BUDGET
    }
    if (setting == (state == TYPESETTING)) {
	hh += (int) (fscale * cep->dx);
	MoveRight(cep->tfmw);
    }
#ifdef STATS
    Stnc += 1;
    fontptr->ncts += 1;
#endif STATS
}


/**********************************************************************/
/****************************  SetFntNum  *****************************/
/**********************************************************************/
/*  Specify the font to be used in printing future characters */
void
SetFntNum(k)
int k;
{
   if (state == SKIPPING) return;
   fontptr = headfont;
   while ((fontptr != NULL) && (fontptr->k != k))
      fontptr = fontptr->next;
   if (fontptr == NULL)
      Fatal("font %d undefined", k);
   if ((fontptr->font_file_id != NO_FILE) && (state >= TYPESETTING)) {
	ClearOutput();
	if (fontptr->dic_pack == FALSE && fontptr->defined >= G_permanent)
	    EMIT(outfp,"%s @sf\n", fontptr->psname);
    }
}


/**********************************************************************/
/*****************************  SetPosn  ******************************/
/**********************************************************************/
/* output a positioning command */
void
SetPosn(xx, yy)
int xx, yy;
{
	if (yy == vvv) {  /*  relative movement if just moving horizontally */
	    if ( xx != hhh ) {
		EMITN(xx-hhh);
		if (waiting == 0) EMITS("r ");
		}
	    else if (waiting > 0) EMITS("0 ");
	    }
	else {
	    ClearOutput();
	    EMITN(xx);
	    EMITN(yy);
	    EMITS("p ");
	    }
	    hhh = xx;
	    vvv = yy;
}


/**********************************************************************/
/*****************************  SetRule  ******************************/
/**********************************************************************/
/* draw a rule */
void
SetRule(a, b, setting)
int a, b;
bool setting;
{
    int q;

    if (state < TYPESETTING) return;
    if ((a > 0) && (b > 0)) {
	ClearOutput();
	SetPosn(hh,vv);		   	 	/* lower left corner */
	EMITN(q = RuleRound(b, hconv));		/* width */
	EMITN(RuleRound(a,vconv));		/* height */
	EMITS("ru\n");
	}
    if (setting == (state == TYPESETTING)) { hh += q; MoveRight(b); }
}


/**********************************************************************/
/*****************************  SetString  ****************************/
/**********************************************************************/
#define MAXSTRING 256
char chars[MAXSTRING];

void
SetString(firstch)
int firstch;
{
    char *char0;			/*  First character to set */
    char *charn;			/*  Just past last character to set */
    register char *charp;
    register int c = firstch;
    register char_entry *ptr;
    float fscale;
    int  h1, hh1;
    bool special = FALSE;	/* TRUE if we can't load the last character */
#ifdef BUILTIN
    int psf;
#endif /* BUILTIN */

    if (state == SKIPPING) return;      /* Shouldn't really happen */
    if (fontptr == NULL)
	Fatal("internal - null font pointer - SetString()\n");
#ifdef BUILTIN
    if (fontptr->dic_pack == TRUE) psf = FirstChar(fontptr, firstch);
    else psf = 0;
#endif /* BUILTIN */

    char0 = chars;			/* Read entire string of chars. */
    for (charn = chars; c >= SETC_000 && c <= SETC_127; ) {
#ifdef BUILTIN
	if (psf && psf != MoreChar(fontptr, c)) break;
#endif /* BUILTIN */
	*charn++ = c;
	ptr = &(fontptr->ch[c]);
	if (ptr->where.isloaded < G_permanent) LoadAChar(c, ptr);
	if (state >= TYPESETTING && ptr->where.isloaded == G_temporary)
	    { --charn; special = TRUE; break; }
	c = NoSignExtend(dvifp, 1);
    }
    if (special == FALSE)
	(void) fseek(dvifp, (long) -1, 1);	/* backup one character */

    if (state == CHARFINDING) return;
    if (IsBuiltIn(fontptr->n)) fscale = 1.0;
    else fscale = fontptr->ps_scale;

    if (charn != char0 && fontptr->font_file_id != NO_FILE) {
	charp = char0;
	while (charp < charn) {
	    SetPosn(hh,vv);
	    if (waiting++ == 0) EMITS("m ");
	    if ((waiting % 6) == 0) EMITC('\n');
	    EMITC('(');
	    h1 = h;
	    while (charp < charn) {
		ptr = &(fontptr->ch[*charp]);
		c = *charp;
#ifdef BUILTIN
		if (fontptr->dic_pack == TRUE) c = ptr->pschar;
#endif /* BUILTIN */
		h1 += ptr->tfmw;
		hh += (int) (fscale * ptr->dx);
	        if (c < ' ' || c >= 0177)
		    EMITO(c);
	        else if (c == '(' || c == ')' || c == '\\') {
		    EMITC('\\');
		    EMITC(c);
	        } else
		    EMITC(c);
		++charp;
		hh1 = PixRound(h1, hconv) - hh;
		if (abs(hh1) > DRIFT) break;
	    }
	    EMITS(") ");
	    hhh = hh;
	    MoveRight(h1-h);
	}
    }
    if (special == TRUE) { ClearOutput(); SetChar(*charn, SET); }

#ifdef STATS
    Stnc += charn - char0;
    fontptr->ncts += charn - char0;
#endif STATS
}
