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 a

⟦40639a8f9⟧ TextFile

    Length: 42689 (0xa6c1)
    Types: TextFile
    Names: »aix.tex«

Derivation

└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦c319c2751⟧ »unix3.0/TeX3.0.tar.Z« 
        └─⟦036c765ac⟧ 
            └─⟦this⟧ »TeX3.0/aix/aix.tex« 
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦63303ae94⟧ »unix3.14/TeX3.14.tar.Z« 
        └─⟦c58930e5c⟧ 
            └─⟦this⟧ »TeX3.14/aix/aix.tex« 

TextFile

\documentstyle{article}
\author{Greg Baran}
\title{Porting \TeX\ to the IBM RT Running AIX}


\font\reggrk=grreg10
\def\texx2{\TeX x2}
\def\unix{ {\sc UNIX} }


\begin{document}
\maketitle
\section{Overview}
It may do some good to 
review a port of
\TeX\ to IBM RTs running AIX.
Apart from bug reports of most interest
to the authors of software, it may help
other people attacking the port
avoid trouble and
overly optimistic expectations.
The biggest puzzles encountered were
in {\em tangle}, X11, and \texx2.
The 
contributions of most general interest
from this work are to report the set of parameters
that make the
\TeX\ distribution work on the RT, to report bugs
in IBM's X11 port, to correct a few
problems in \texx2, and to contribute a
semi-automated translation of
{\em pktogf} in WEB to C.
\section{Acquiring the \TeX\ Distribution}
When MSRI began running the Distributed Services
single-system image software, it quickly
became clear that the original IBM \TeX\ port
to AIX 2.2.1 would not work.
The reason is that mapped files were used to
access everything - fonts, input, style
sheets, etc.
Unfortunately, mapped files under AIX are
supported only
on a local disk, not across the network.
Since users may log onto any workstation
and thereby obtain access to their
own files over the network.
This means that if there are $N$ workstations,
the user's files would be remotely
mounted on $N-1$ of them.
We discovered this on 7 March 89.

We tried to cover up the fact the \TeX\ didn't
really work in our environment using
some shell scripts written for the occasion.
The scripts copied the needed files
to the local disk.
This solution was clumsy, expensive, and unreliable.
We learned of other porting efforts of \TeX
to the RTs, but these were for 4.3, not AIX.
Therefore, we decided to obtain the
standard \unix\ distribution
tape from Elisabeth at the University of Washington
and do the port ourselves.
It arrived on March 20th.

Attempts to read in the tape, created at UW on
a Sun 2 in QIC-24 format, failed.
The RT tape controller thought there was an end of file
somewhere in the middle of the tape.
Luckily, I have a Sun 3/50 at home.
I copied the \TeX\ tape to disk, then wrote it
out again to another cartridge tape in QIC-11 format.
This scheme also failed in the same
way as the original tape.
Ultimately, I wrote two tapes
and copied the distribution
onto the RTs in pieces.
By about 27 March 89, I could begin really
porting the \TeX\ distribution.
\section{\TeX\ and MF Port}
The first step was to print out all of the
relevant {\em READMEs} and read them.
I followed the directions for porting
\TeX, and thought I made good choices
for the {\em site.h} file.

Only {\em tangle} didn't work.
It bombed while evaluating a macro
saying that a value was too big
in statement 3151 of the tex.web file.
\begin{verbatim}
3148: @d penalty_node=12 {|type| of a penalty node}
3149: @d inf_penalty=inf_bad
      {``infinite'' penalty value}
3150: @d eject_penalty=-inf_penalty
      {``negatively infinite'' penalty value}
3151: @d penalty(#) == mem[#+1].int
      {the added cost of breaking a list here}
\end{verbatim}
So I spent quite a long time trying to puzzle
out what could be wrong about the interpretation
of statement 3151 by {\em tangle}.
I looked at numerical macro interpretation,
at array addressing, at the union declarations
for {\em mem}, etc.
Nothing was wrong.

It turned out that {\em tangle} lied.
The bug was really in line 3150.
The code for changing the sign of an integer
stored the sign in a {\em char} variable,
which is {\em unsigned} on the RT.
So when the sign was flipped, the
sign variable became 0xff, which
when used to multiply the original value
of {\em inf\_penalty}, became 255 times
that value.
The repair I made was to declare
type {\em schar} to be a short,
not a char.
Probably it could be declared to
be of type {\em signed char} and
thereby save space.
I haven't tried that.

So eventually, all of \TeX\ and Metafont
were built and passed trip and trap,
respectively.
This was verified for both the ``-g''
option and the ``-O'' option.
\TeX\ was ported on about 4 April.
It took that long mostly because
it was hard to figure out how
{\em tangle} worked.
I didn't know what it was supposed to do
beforehand.

I used the Advanced C compiler ({\em bl8cc})
to compile some of \TeX, but it
was extremely slow and very greedy
for disk space and CPU time.
Therefore, it was abandoned.
\section{\texx2\ Port}
On 5 April I started to port the X11
window-based previewer written by
Dirk Grunwald at the University of Illinois.
The version of his previewer on the distribution
tape was hopelessly out of date,
so we FTPed a new copy from UI.

Our link to LBL at the moment is over the
phone at 9600 baud.
We tried to use kermit to transfer the
compressed file, but the result
was chaos.
So I copied the source for compress
to the Sun at LBL, compiled it,
uncompressed the .Z file,
and tried to copy the resulting
tar file using kermit.
No luck.
Good old ``tape header error'',
and the IBM version doesn't support
skipping ahead over bad headers.
This left no choice but to
un-tar the file on the LBL machine,
make a {\em cpio} archive using
the ascii-compatibility mode,
and transfer that.
Finally the source was obtained in this way.

The first problem was that there are
no makefile, just Imakefiles.
Unfortunately, the {\em ximake}
utility didn't make it onto the
AIX distribution for some reason.
So I hacked a makefile from the Imakefile
by hand.
The top level makefile changes were:

\hrule
\begin{verbatim}
7,8c7,8
< FONTDESC	=/usr/local/lib/tex/fontdesc
< TEXFONTS=.:/usr/lpp/tex/fonts
---
> FONTDESC	=/usr/local/lib/tex82/fontdesc
> TEXFONTS=.:/usr/local/lib/tex82/fonts
24c24
< XIMAKE		=echo "No XIMAKE"
---
> XIMAKE		=ximake
28c28
< CC	=/bin/cc
---
> CC	=gcc -traditional
48c48
< 	cd texx2; $(XIMAKE); $(MAKE) $(MFLAGS) texx2
---
> 	cd texx2; $(XIMAKE); $(MAKE) $(MFLAGS) texx2 mftobdf
\end{verbatim}
\hrule
\vskip 0.2in
The texx2 makefile looks like:
\begin{verbatim}

        TEXFONTS=.:/usr/local/lib/tex/fonts
        DEFINES = -DDEFAULT_TFM_PATH=\"$(TEXFONTS)\"

          SRCS1 = texx2.c t2-widgets.c \
                  texx2-file.c texx2-error.c dvi-simple.c \
                  texx2-page.c texx2-font.c texx2-mark.c \
                  DviPage.c DviPage2.c
          OBJS1 = texx2.o t2-widgets.o \
                  texx2-file.o texx2-error.o dvi-simple.o \
                  texx2-page.o texx2-font.o texx2-mark.o \
                  DviPage.o DviPage2.o
          SRCS2 = mftobdf.c
          OBJS2 = mftobdf.o
       PROGRAMS = mftobdf texx2
       INCLUDES = -I../h -I/msri/XWindows/X11/Xamples/Xaw

DEFINES         = -Nn5000 -Nd6000 -DBSD_INCLUDES -DAIX
CFLAGS=-g ${DEFINES} ${INCLUDES}

SYS_LIBRARIES = ../lib/libXaw.a /usr/lib/libXt.a \
	../lib/libXmu.a /usr/lib/libX11.a

texx2:	$(OBJS1) ../lib/lib.a
	cc -o texx2 ${OBJS1} ${LDFLAGS} \
	../lib/lib.a -lm ${SYS_LIBRARIES}

# InstallProgram(texx2, $(BINDIR))
# InstallManPage(texx2, $(MANDIR))

mftobdf:	$(OBJS2) ../lib/lib.a
	cc -o mftobdf ${OBJS2} ${LDFLAGS} ../lib/lib.a -lm ${SYS_LIBRARIES}

# InstallProgram(mftobdf, $(BINDIR) )
\end{verbatim}
\hrule
\vskip 0.2in
Note the definition of ``DEFINES'', specifically for the RT
compiler.

The next problem lay in X11 headers.
The standard AIX 2.2.1 distribution includes
only the Xlib headers.
The Xaw and Xmu headers are on the distribution
floppies, but they are hidden away in
the Xamples directory.
I got these out and tried to compile
\texx2\ again.
In addition, the headers
{\em Label.h} and {\em List.h}
are not to be found in the IBM distribution
at all.
They were found on the machine {\bf scam}
at Berkeley, but are not compatible
with the IBM version of X.

Therefore, some more arbitrary hacking was
called for.
Rather than recounting the history, let's
dive into the actual changes.
Here are the output lines from {\em diff}
for the files which were changed in texx2:

In all of the following, the ``$<$'' file
is the original file, while the ``$>$'' file
is the new file version.

In DviPage.c, there were 
several classes of changes.
One was optional, the rest were not.
Line 50 is changed to reflect the new name
IBM gave a toolbox Boolean type.
The ``GRUNWALD'' ifdef removes initilization
of a couple of structure elements not
supported in the IBM version of X.
The XTBUG code after line 227 makes up
for an X initialization bug.
Lines 294 and 295 didn't need to be
changed since the bug was caused by the
Xaw library, but an error check there
doesn't hurt.

Defining MAX\_DVI\_STRING to be 1 rather than 64
un-optimizes string drawing, but it makes
the ligatures of the babel/greek fonts
work.
If full strings with natural spacing
are put out, the escapement of IBM's
X gets all fouled up, and some characters
are missing, and some words get misplaced.
Putting out one character at a time
gives the best shot at correct output.

Finally, for DviPage.c, the common code
for DrawString was moved to a separate
function, rather than appearing essentially
unchanged in three places.
This was gratuitous, but was done in self
defense while debugging the DrawString problems.
\hrule
{ \footnotesize
\begin{verbatim}
********************* DviPage.c ********************
50c50
<     {XtNreverseVideo,  XtCReverseVideo, XtRBool, sizeof(Bool),
---
>     {XtNreverseVideo,  XtCReverseVideo, XtRBoolean, sizeof(Bool),
129a130
> #ifdef GRUNWALD
131a133
> #endif GRUNWALD
227a232,250
> #define XTBUG 1
> #ifdef XTBUG
> 	/* Add these assignments to make up for bug in Xt resource management */
> {
> 	extern XFontStruct *XLoadQueryFont();
> 
>   w -> dviPage.font = XLoadQueryFont( XtDisplay ( w ), "Rom10.500" );
> 	if( w->dviPage.font ) {
> #endif
> 	} else {
> 		printf( "NO FONT Rom10.500!\n" );
> 		exit( 1 );
> 	}
> }
>   w -> dviPage.background = 1;
>   w -> dviPage.foreground = 0;
>   w -> dviPage.reverseVideo = False;
>   w -> dviPage.useBackingStore = False;
> 
287a311
> 
294,295d317
<   XtFree( w -> dviPage.dviStack );
<   w -> dviPage.dviStack = 0;
296a319,325
>   if(  w->dviPage.dviStack ) {
>   	XtFree( w -> dviPage.dviStack );
>   	w -> dviPage.dviStack = 0;
>   } else {
>         exit( 1 );
>   } 
> 
425a455,469
> /* following are used to reduce the number of XDrawStrings we do */
> 
> #ifdef UNDEF
> #define MAX_DVI_STRING 64
> #endif
> #define MAX_DVI_STRING 1
 
> static char dviString[ MAX_DVI_STRING ];
> static int dviStringLength;
> 
> static int startHH, startVV;
> static int endHH, endVV;
> static LocalDviStack *dviStack;
> static LocalDviStack *dviStackP;	/* current stack item */
> 
445c489
< /* following are used to reduce the number of XDrawStrings we do */
---
>   dviStack = page -> dviStack;
447,455d490
< #define MAX_DVI_STRING 64
<   char dviString[ MAX_DVI_STRING ];
<   int dviStringLength;
<   int startHH, startVV;
<   int endHH, endVV;
< 
<   LocalDviStack *dviStack = page -> dviStack;
<   LocalDviStack *dviStackP;	/* current stack item */
< 
460,461d494
<   assert( dviStack != 0 );
< 
493,516c526,527
< 
< 	  if ( dviStringLength > 0 ) {
< 	    i32 atHH = fastFromSP(widget, startHH);
< 	    i32 atVV = fastFromSP(widget, startVV);
< 	    Bool doit = True;
< 
< 	    if ( widget -> dviPage.haveBackingStore ) {
< 	      i32 width = fastFromSP(widget, endHH);
< 	      i32 height = fastFromSP(widget, endVV);
< 	      
< 	      doit =
< 		XRectInRegion( widget -> dviPage.updateRegion, atHH, atVV,
< 			      width, height) != RectangleOut;
< 	    }
< 
< 	    if (doit) {
< 	      XDrawString( XtDisplay( widget ), XtWindow( widget ),
< 			  page -> globalGC, atHH, atVV,
< 			  dviString, dviStringLength );
< 	    }
< 	  }
< 	  dviStringLength = 0;
< 	  startHH = dviStackP -> h;
< 	  startVV = dviStackP -> v ;
---
> 	  if ( dviStringLength > 0 )
> 		DrawString( widget );
518a530,533
> 	if( dviStringLength == 0 ) {
>     		startHH = dviStackP -> h;
>     		startVV = dviStackP -> v ;
> 	}
636d650
< 
708,728c722
< 	    i32 atHH = fastFromSP(widget, startHH);
< 	    i32 atVV = fastFromSP(widget, startVV);
< 	    Bool doit = True;
< 
< 	    if ( widget -> dviPage.haveBackingStore ) {
< 	      i32 width = fastFromSP(widget, endHH);
< 	      i32 height = fastFromSP(widget, endVV);
< 	      
< 	      doit =
< 		XRectInRegion( widget -> dviPage.updateRegion, atHH, atVV,
< 			      width, height) != RectangleOut;
< 	    }
< 
< 	    if (doit) {
< 	      XDrawString( XtDisplay( widget ), XtWindow( widget ),
< 			  page -> globalGC, atHH, atVV,
< 			  dviString, dviStringLength );
< 	    }
< 	    dviStringLength = 0;
< 	    startHH = dviStackP -> h;
< 	    startVV = dviStackP -> v ;
---
> 		DrawString( widget );
823,841c817
<     i32 atHH = fastFromSP(widget, startHH);
<     i32 atVV = fastFromSP(widget, startVV);
<     Bool doit = True;
<     
<     if ( widget -> dviPage.haveBackingStore ) {
<       i32 width = fastFromSP(widget, endHH);
<       i32 height = fastFromSP(widget, endVV);
<       
<       doit =
< 	XRectInRegion( widget -> dviPage.updateRegion, atHH, atVV,
< 		      width, height) != RectangleOut;
<     }
<     
<     if (doit) {
<       XDrawString( XtDisplay( widget ), XtWindow( widget ),
< 		  page -> globalGC, atHH, atVV,
< 		  dviString, dviStringLength );
<     }
<     dviStringLength = 0;
---
> 	DrawString( widget );
914a891,917
> }
> 
> static DrawString( widget )
> DviPageWidget widget;
> {
>     i32 atHH = fastFromSP(widget, startHH);
>     i32 atVV = fastFromSP(widget, startVV);
>     i32 width = fastFromSP(widget, endHH);
>     i32 height = fastFromSP(widget, endVV);
>     DviPagePart *page = &( widget -> dviPage); 
>     Bool doit = True;
>     
>     if ( widget -> dviPage.haveBackingStore ) {
>       
>       doit =
> 	XRectInRegion( widget -> dviPage.updateRegion, atHH, atVV,
> 		      width, height) != RectangleOut;
>     }
>     
>     if (doit) {
>       XDrawString( XtDisplay( widget ), XtWindow( widget ),
> 		  page -> globalGC, atHH, atVV,
> 		  dviString, dviStringLength );
>     }
>     dviStringLength = 0;
>     startHH = dviStackP -> h;
>     startVV = dviStackP -> v ;
\end{verbatim}
}
\hrule
\vskip 0.2in

There was only one change needed here,
to make {\em lint} happy.
The arguments were wrong.
It isn't clear to me when this code
is ever used.
\hrule
{ \footnotesize
\begin{verbatim}
********************* DviPage2.c ********************
264c264
<       dot_at(cx0, cy0);
---
>       dot_at(w, cx0, cy0);
\end{verbatim}
}
\hrule
\vskip 0.2in

A real bug in the original code
popped up here when previewing
256 character fonts.
There was an off-by-one loop
iteration in line 294.
The other change is a pedantic spelling correction.
\hrule
{ \footnotesize
\begin{verbatim}
********************* dvi-simple.c ********************
114d113
<   
294a294
> #ifdef XBUG
295a296,298
> #else
>       for (i = 0; i < nc; i++) {
> #endif
340a344
> 
386c390
< 	 *	Unlink the temporary file. This keeps tmp files from cluddering
---
> 	 *	Unlink the temporary file. This keeps tmp files from cluttering
485d488
< 
\end{verbatim}
}
\hrule
\vskip 0.2in

The output file under AIX will be missing its last
block unless you actually close it.
This is a bug in the original.
It should be closed.
\hrule
{ \footnotesize
\begin{verbatim}
********************* mftobdf.c ********************
599a600
> 	fclose( fontOut );
\end{verbatim}
}
\hrule
\vskip 0.2in

All of the ``RESIZEME'' ifdefs remove
attribute assignment in widgets for
resizing.
It is not a supported attribute in 
AIX X11.
The line 60-61 change satisfies lint.
{ \footnotesize
\begin{verbatim}
********************* t2-widgets.c ********************
53a54
> #ifdef RESIZEME
54a56
> #endif RESIZEME
60,61c62,63
<   BuildFileLevel(topPane);
<   BuildErrorBox(topPane);
---
>   BuildFileLevel();
>   BuildErrorBox();
72a75
> #ifdef RESIZEME
73a77
> #endif RESIZEME
81a86
> #ifdef RESIZEME
82a88
> #endif RESIZEME
88a95
> #ifdef RESIZEME
89a97
> #endif RESIZEME
95a104
> #ifdef RESIZEME
96a106
> #endif RESIZEME
102a113
> #ifdef RESIZEME
103a115
> #endif RESIZEME
110a123
> #ifdef RESIZEME
111a125
> #endif RESIZEME
117a132
> #ifdef RESIZEME
118a134
> #endif RESIZEME
125a142
> #ifdef RESIZEME
126a144
> #endif RESIZEME
132a151
> #ifdef RESIZEME
133a153
> #endif RESIZEME
139a160
> #ifdef RESIZEME
140a162
> #endif RESIZEME
148a171
> #ifdef RESIZEME
149a173
> #endif RESIZEME
156a181
> #ifdef RESIZEME
157a183
> #endif RESIZEME
162a189
> #ifdef RESIZEME
163a191
> #endif RESIZEME
\end{verbatim}
}
\hrule
\vskip 0.2in


It turns out that AIX supports vsprintf,
even though it is not a 4.2 system.
\hrule
{ \footnotesize
\begin{verbatim}
********************* texx2-error.c ********************
164a165,168
> 
> /* FOR RT */
>   (void) vsprintf(p, fmt, l);
> 
202a207,209
> 
> /* FOR RT */
>   (void) vsprintf(p, fmt, l);
\end{verbatim}
}
\hrule
\vskip 0.2in

More ``RESIZEME'' references.
See above.
\hrule
{ \footnotesize
\begin{verbatim}
********************* texx2-file.c ********************
153d152
<   
367a367
> #ifdef RESIZEME
368a369
> #endif RESIZEME
376a378
> #ifdef RESIZEME
377a380
> #endif RESIZEME
\end{verbatim}
}
\hrule
\vskip 0.2in

The changes here are to make up
for small inaccuracies in integer scaling
and file naming.
We essentially allow a request for
{\em foo.120pk}, say, match
120, 121, 122, or 123pk.
\hrule
{ \footnotesize
\begin{verbatim}
********************* texx2-font.c ********************
63a64
>       int slop;
65,66c66,69
<       sprintf(tmpStr,"%s.%d",
< 	      TheFontInfo[font].paf.paf_name, (int) suff);
---
>       /* Try to find something close ... */
>       for( slop=3; slop >= 0; --slop ) {
>       	sprintf(tmpStr,"%s.%d",
> 	      TheFontInfo[font].paf.paf_name, (int) suff + slop );
68,69c71,76
<       thisMag[ font ]
< 	= XLoadQueryFont( XtDisplay ( TopLevelWidget ), tmpStr );
---
>         thisMag[ font ]
> 	  = XLoadQueryFont( XtDisplay ( TopLevelWidget ), tmpStr );
> 
> 	if( thisMag[ font ] != 0 )
> 		break;
>       }
76d82
< 
\end{verbatim}
}
\hrule
\vskip 0.2in

Our print filters require an actual
{\em .dvi} file name extension.
This code adds it.
\hrule
{ \footnotesize
\begin{verbatim}
********************* texx2-mark.c ********************
92a93
>   char tmpfname[256];
107c108,109
<     fileToPrint = (char *) tmpnam( 0 );
---
>     sprintf( tmpfname, "%s.dvi", (char *) tmpnam( 0 ) );
>     fileToPrint = tmpfname;
\end{verbatim}
}
\hrule
\vskip 0.2in

A message saying ``EVENT''
whenever a character is typed at the keyboard
and the mouse is not in an input box
was eliminated from the code.
The intention of the assertion here was to
see if the pageno fell in an interval.
As originally written, the assert() had no effect.
Line 342 was changed so that if a 
dvi page window is tied to another
window and it is displaying pages
upstream from the original page,
you won't go off the end of the document
and crash and burn.
The rest of the changes are the familiar
``RESIZEME'' definitions.
\hrule
{ \footnotesize
\begin{verbatim}
********************* texx2-page.c ********************
29d28
< #ifdef UNDEF
31d29
< #endif
155c153
<   assert( pageno >= 0 || pageno < DviTotalPages );
---
>   assert( pageno >= 0 && pageno < DviTotalPages );
169c167
<   assert( pageno >= 0 || pageno < DviTotalPages );
---
>   assert( pageno >= 0 && pageno < DviTotalPages );
342c340
<   if (tp -> pageNumber >= DviTotalPages) {
---
>   if (tp -> pageNumber >= DviTotalPages - 1) {
580a579
> #ifdef RESIZEME
581a581
> #endif RESIZEME
588a589
> #ifdef RESIZEME
589a591
> #endif RESIZEME
595a598
> #ifdef RESIZEME
596a600
> #endif RESIZEME
605a610
> #ifdef RESIZEME
606a612
> #endif RESIZEME
616a623
> #ifdef RESIZEME
617a625
> #endif RESIZEME
626a635
> #ifdef RESIZEME
627a637
> #endif RESIZEME
636a647
> #ifdef RESIZEME
637a649
> #endif RESIZEME
647a660
> #ifdef RESIZEME
648a662
> #endif RESIZEME
657a672
> #ifdef RESIZEME
658a674
> #endif RESIZEME
667a684
> #ifdef RESIZEME
668a686
> #endif RESIZEME
677a696
> #ifdef RESIZEME
678a698
> #endif RESIZEME
688a709
> #ifdef RESIZEME
689a711
> #endif RESIZEME
703a726
> #ifdef RESIZEME
704a728
> #endif RESIZEME
713a738
> #ifdef RESIZEME
714a740
> #endif RESIZEME
723a750
> #ifdef RESIZEME
724a752
> #endif RESIZEME
742a771
> #ifdef RESIZEME
743a773
> #endif RESIZEME
\end{verbatim}
}
\hrule
\vskip 0.2in

The approach I took was to
let the natural design size be
considered 300.
Then scale at 100, 118, and 150
dots per inch.
Let {\bf Large} be 150
and {\bf Small} be 118.
You can get 100 by setting {\bf Mag}=333,
and 300 by setting {\bf Mag}=1000.

The more significant change is the following.
Suppose you say
\begin{verbatim}
texx2\ foo/bar/my.dvi.
\end{verbatim}
The current directory used to be set to
{\em \${PWD}/foo/bar} and
the file name was set to {\em foo/bar/my.dvi}.
The problem is that if you click
on {\bf Open}, the file is not found
since you're looking for
{\em \${PWD}/foo/bar/foo/bar/my.dvi}.
The following code removes the prefix
to the file name so a click on the {\bf Open}
button
followed by a click on the {\bf Page} button
works.
{ \footnotesize
\begin{verbatim}
********************* texx2.c ********************
19c19
<      Offset(printProgram), XtRString, "lpr -d"},
---
>      Offset(printProgram), XtRString, "dviprint"},
22c22
<      Offset(userMag), XtRString, "500"},
---
>      Offset(userMag), XtRString, "393"},
31c31
<      Offset(smallMag), XtRString, "333"},
---
>      Offset(smallMag), XtRString, "393"},
39c39
<   {"autoSize", XtCString, XtRBool, sizeof(Bool),
---
>   {"autoSize", XtCString, XtRBoolean, sizeof(Bool),
87,88d86
<     struct stat buf;
< 
91c89,102
<     setFileName( Argv[1] );
---
>     /*
>      * BUG - Leave the file name alone - peel off the
>      * directory prefix since setDirectory will compensate
>      */
>     {
> 	register char *p;
> 
> 	p = Argv[1];
> 	p += strlen(Argv[1]) - 1;
> 	while( p != Argv[1] && *p != '/' )
> 		--p;
> 	if( *p == '/' ) p++;
>     	setFileName( p );
>     }
\end{verbatim}
}
\hrule
\vskip 0.2in
\texx2\ was completely ported by 1 May 89.
\section{X Bugs}
One bug in the IBM distribution is that
third-party software depends on something
that is not usually installed,
the toolkits.
So the Xaw and Xmu libraries had to be brought
out into the open in order to
link \texx2.

There was a big bug, though, in
the Xaw library, in the {\em Viewport.c} file.
Here, in the {\em SetValues} function, a scrollbar
is created whenever the {\em forcebars} attribute is
enabled, and wasn't previously.
This is fine, except that the pointer to
the parent widget is retained in the
new widget.
Unfortunately, as written, the pointer to the
new widget points to the stack, not the
original widget.
As a consequence, things started acting strangely,
scrollbars didn't work, \texx2\ crashed.

To fix it, change the calls in {\em SetValues} in
{\em Viewport.c} from
\begin{verbatim}
CreateScrollbar( w, True );
...
CreateScrollbar( w, False );
\end{verbatim}
to
\begin{verbatim}
CreateScrollbar( current, True )
...
CreateScrollbar( current, False )
\end{verbatim}
since current points to the permanent
heap-allocated structure.
For the same reason, change the resize call to:
\begin{verbatim}
(*w->core.widget_class->core_class.resize)( current );
\end{verbatim}

There are two remaining bugs in the previewer
that I don't think I can fix without
getting IBM involved.
These are:
\begin{enumerate}
\item
The upper left-hand part of the preview window
sometimes has the first line obliterated.
It is as if a clipping region has encroached
on the window.
Sometimes the text can be made visible by
scrolling the top of the page
off and then scrolling it back on.
The redisplay function is being called several times
by the X server, and the first call makes
all the text visible, but succeeding calls
wipe it out.
This can't be the whole story, though,
since running \texx2\ under the debugger
and stopping after one redisplay call
still may have the beginning text missing.
\item
The other bug relates to special characters,
the ligatures in the classical greek fonts.
For example, the word
``{\reggrk stigma}'' comes out without the
``{\reggrk st}'' and with the
``{\reggrk igma}'' pushed over an extra few
letter spaces.
Not good.
To make this come out, I
caused DviPage to send out individual characters
to the X server.
Even so, some single characters will be invisible
under certain circumstances that I am unable
to characterize well.
\end{enumerate}
\section{Fonts}
The big problem with getting things to work
well under the IBM X windows is making fonts.
This requires generating a set of {\em RTX}
fonts starting from pk format fonts.

The technique used, apparently successfully,
by Dirk Grunwald, is to rescale pk fonts.
The intermediate format used is {\em bdf},
a format used in X.
Unfortunately, the bdf files created by
the {\em mftobdf} program caused the IBM {\em bdftortx}
program to crash horribly.

So the only possible path was to go back
to Metafont, and regenerate everything
at the desired magnifications.
\section{Appendix 1: C Version of PKTOGF}
This program was generated by
running tangle on {\em pktogf.web}
in mfware/CMFware,
then fixing up the ``defines'' file 
for each and every definition, one by one.
The convert program was:
% Save as convert.sh:
\begin{verbatim}
#!/bin/sh
# This script does all the work necessary
# to convert pktogf.p to a C program.
#

cat pktogf.defines pktogf.p \
        | ../../web2cdir/web2c  \
        | ../../web2cdir/fixwrites \
        | ../../web2cdir/splitup
\end{verbatim}

The word ``all'' above is a lie.
The result would not compile,
but not to worry, some arbitrary
hacking was sufficient to make cc happy.
If you want, I can send
anyone interested the defines file
so you can try it yourself.


\vskip 0.2in
\hrule
{ \footnotesize 
% Save as pktogf.c:
\begin{verbatim}
#include <stdio.h>

#define EXTERN extern
#define incr(a) (a++)
#define decr(a) (a--)
#define true (1)
#define false (0)

#define round(a) ((int)(a+0.5))
#define pkbyte() zpkbyte()
#define gfbyte(a) zgfbyte((integer)(a))
#define eof(z) feof(z)
#define readln(f) {register c; while ((c=getc(f))!='\n' && c!=EOF); }

  typedef int integer ;
  typedef char boolean ;
  typedef unsigned char ASCIIcode ; 
  typedef unsigned char eightbits ; 
  typedef FILE *bytefile ; 

  char comment[128];
  integer charpointer[256];
  ASCIIcode xord[128] ; 

  integer xchr[256] ; 
  integer sveresc[256]; 
  integer shoresc[256]; 
  integer stfmwidth[256]; 

  bytefile gffile ; 
  bytefile pkfile ; 
  integer pkloc ; 
  integer gfloc ; 

#define MAXCOUNTS 400
	integer rowcounts[MAXCOUNTS];

#define NAMELENGTH 81
  char pkname[NAMELENGTH], gfname[NAMELENGTH] ; 

  integer bitweight ; 
  integer tfmwidth ; 
  integer maxn, minn ; 
  integer maxm, minm ; 
  integer mmaxn, mminn ; 
  integer mmaxm, mminm ; 
  integer inputbyte;
  integer dynf, flagbyte;
  integer repeatcount;
  integer thischarptr;

	integer hppp, designsize, checksum;
	integer vppp, magnification, lasteoc;
	integer turnon, packetlength, car;
	integer endofpacket, horesc, veresc;
	integer cwidth, cheight, wordwidth;
	integer xoff, yoff;
	integer countdown, xtogo, ytogo;
	integer curn, count, firston;
	integer rcp, done;

extern integer zpkbyte();
extern integer signedbyte();
extern integer get16();
extern integer signed16();
extern integer get32();

extern integer chr();

#define gf16(a) zgf16((integer)(a))
#define gf24(a) zgf24((integer)(a))
#define gfquad(a) zgfquad((integer)(a))

integer getnyb();
boolean getbit();
integer pkpackednum();

initialize () {
    integer i  ; 
  (void) fprintf( stdout , "%s\n",
	 "This is PKtoGF, Version 1.0" ) ; 
  {register integer for_end; i = 0 ; for_end = 31 ; if ( i <= for_end) do 
    xchr [ i ] = '?' ; 
  while ( i++ < for_end ) ; } 
  xchr [ 32 ] = ' ' ; xchr [ 33 ] = '!' ; xchr [ 34 ] = '"' ; 
  xchr [ 35 ] = '#' ; xchr [ 36 ] = '$' ; xchr [ 37 ] = '%' ; 
  xchr [ 38 ] = '&' ; xchr [ 39 ] = '\'' ; xchr [ 40 ] = '(' ; 
  xchr [ 41 ] = ')' ; xchr [ 42 ] = '*' ; xchr [ 43 ] = '+' ; 
  xchr [ 44 ] = ',' ; xchr [ 45 ] = '-' ; xchr [ 46 ] = '.' ; 
  xchr [ 47 ] = '/' ; xchr [ 48 ] = '0' ; xchr [ 49 ] = '1' ; 
  xchr [ 50 ] = '2' ; xchr [ 51 ] = '3' ; xchr [ 52 ] = '4' ; 
  xchr [ 53 ] = '5' ; xchr [ 54 ] = '6' ; xchr [ 55 ] = '7' ; 
  xchr [ 56 ] = '8' ; xchr [ 57 ] = '9' ; xchr [ 58 ] = ':' ; 
  xchr [ 59 ] = ';' ; xchr [ 60 ] = '<' ; xchr [ 61 ] = '=' ; 
  xchr [ 62 ] = '>' ; xchr [ 63 ] = '?' ; xchr [ 64 ] = '@' ; 
  xchr [ 65 ] = 'A' ; xchr [ 66 ] = 'B' ; xchr [ 67 ] = 'C' ; 
  xchr [ 68 ] = 'D' ; xchr [ 69 ] = 'E' ; xchr [ 70 ] = 'F' ; 
  xchr [ 71 ] = 'G' ; xchr [ 72 ] = 'H' ; xchr [ 73 ] = 'I' ; 
  xchr [ 74 ] = 'J' ; xchr [ 75 ] = 'K' ; xchr [ 76 ] = 'L' ; 
  xchr [ 77 ] = 'M' ; xchr [ 78 ] = 'N' ; xchr [ 79 ] = 'O' ; 
  xchr [ 80 ] = 'P' ; xchr [ 81 ] = 'Q' ; xchr [ 82 ] = 'R' ; 
  xchr [ 83 ] = 'S' ; xchr [ 84 ] = 'T' ; xchr [ 85 ] = 'U' ; 
  xchr [ 86 ] = 'V' ; xchr [ 87 ] = 'W' ; xchr [ 88 ] = 'X' ; 
  xchr [ 89 ] = 'Y' ; xchr [ 90 ] = 'Z' ; xchr [ 91 ] = '[' ; 
  xchr [ 92 ] = '\\' ; xchr [ 93 ] = ']' ; xchr [ 94 ] = '^' ; 
  xchr [ 95 ] = '_' ; xchr [ 96 ] = '`' ; xchr [ 97 ] = 'a' ; 
  xchr [ 98 ] = 'b' ; xchr [ 99 ] = 'c' ; xchr [ 100 ] = 'd' ; 
  xchr [ 101 ] = 'e' ; xchr [ 102 ] = 'f' ; xchr [ 103 ] = 'g' ; 
  xchr [ 104 ] = 'h' ; xchr [ 105 ] = 'i' ; xchr [ 106 ] = 'j' ; 
  xchr [ 107 ] = 'k' ; xchr [ 108 ] = 'l' ; xchr [ 109 ] = 'm' ; 
  xchr [ 110 ] = 'n' ; xchr [ 111 ] = 'o' ; xchr [ 112 ] = 'p' ; 
  xchr [ 113 ] = 'q' ; xchr [ 114 ] = 'r' ; xchr [ 115 ] = 's' ; 
  xchr [ 116 ] = 't' ; xchr [ 117 ] = 'u' ; xchr [ 118 ] = 'v' ; 
  xchr [ 119 ] = 'w' ; xchr [ 120 ] = 'x' ; xchr [ 121 ] = 'y' ; 
  xchr [ 122 ] = 'z' ; xchr [ 123 ] = '{' ; xchr [ 124 ] = '|' ; 
  xchr [ 125 ] = '}' ; xchr [ 126 ] = '~' ; 

  {register integer for_end;
	i = 127 ;
	for_end = 255 ;
 	if ( i <= for_end) do
		xchr [ i ] = '?' ; while ( i++ < for_end ) ; } 
  {register integer for_end;
	i = 0 ;
	for_end = 127 ;
	if ( i <= for_end) do 
    		xord [ i ] = 32 ; while ( i++ < for_end ) ; } 

  {register integer for_end;
	i = 32 ;
	for_end = 126 ;
	if ( i <= for_end) do 
    		xord [ xchr [ i ] ] = i ; while ( i++ < for_end ) ; } 

  strcpy( comment, "PKtoGF 1.0 output" ); 
  mminm = 999999L ; 
  mminn = 999999L ; 
  mmaxm = -999999L ; 
  mmaxn = -999999L ; 
  {register integer for_end; i = 0 ; for_end = 255 ; if ( i <= for_end) do 
    charpointer [ i ] = -1 ; 
  while ( i++ < for_end ) ; } 
} 

jumpout () {
    exit( 1 );
} 

/*
 * GF, PK file IO
 */
zgfbyte ( i ) 
integer i ; 
{ 
	incr( gfloc );
  	putc( i, gffile );
} 

integer zpkbyte () {
	incr ( pkloc ) ; 
	return ( getc ( pkfile ) ) ; 
} 

opengffile () {
	gffile = fopen ( gfname , "w" ) ; 
	printf( "GF file: %s\n", gfname );
	if( gffile == NULL ) {
		printf( "%s cannot be created\n", gfname );
	}
    	gfloc = 0 ; 
} 

openpkfile () {
	printf( "PK file: %s\n", pkname );
	pkfile = fopen ( pkname , "r" ) ; 
	if (pkfile==NULL) {
      		printf("%s does not exist\n", pkname) ;
      		jumpout() ;
    	}
	pkloc = 0 ; 
} 

/* Simulate eoln function */
boolean eoln(f)
FILE *f;
{
    register int c;

    if (feof(f)) return(true);	/* Fulfill "weaker" requirement */
    c = getc(f);
    (void) ungetc(c, f);
    return(c == '\n');
}

integer signedbyte () {
    register integer Result; integer a  ; 
  a = pkbyte () ; 
  if ( a > 127 ) 
  a = a - 256 ; 
  Result = a ; 
  return(Result) ; 
} 
integer get16 () {
    register integer Result; integer a  ; 
  a = pkbyte () ; 
  Result = a * 256 + pkbyte () ; 
  return(Result) ; 
} 
integer signed16 () {
    register integer Result; integer a  ; 
  a = signedbyte () ; 
  Result = a * 256 + pkbyte () ; 
  return(Result) ; 
} 
integer get32 () {
    register integer Result; integer a  ; 
  a = get16 () ; 
  if ( a > 32767 ) 
  a = a - 65536L ; 
  Result = a * 65536L + get16 () ; 
  return(Result) ; 
} 
zgf16 ( i ) 
integer i ; 
{gfbyte ( i / 256 ) ; 
  gfbyte ( i % 256 ) ; 
} 
zgf24 ( i ) 
integer i ; 
{gfbyte ( i / 65536L ) ; 
  gf16 ( i % 65536L ) ; 
} 
zgfquad ( i ) 
integer i ; 
{if ( i >= 0 ) 
  {
    gfbyte ( i / 16777216L ) ; 
  } 
  else {
      
    i = ( i + 1073741824L ) + 1073741824L ; 
    gfbyte ( 128 + ( i / 16777216L ) ) ; 
  } 
  gf24 ( i % 16777216L ) ; 
} 
integer getnyb () {
    register integer Result; eightbits temp  ; 
  if ( bitweight == 0 ) 
  {
    inputbyte = pkbyte () ; 
    bitweight = 16 ; 
  } 
  temp = inputbyte / bitweight ; 
  inputbyte = inputbyte - temp * bitweight ; 
  bitweight = bitweight / 16 ; 
  Result = temp ; 
  return(Result) ; 
} 
boolean getbit () {
    register boolean Result; boolean temp  ; 
  bitweight = bitweight / 2 ; 
  if ( bitweight == 0 ) 
  {
    inputbyte = pkbyte () ; 
    bitweight = 128 ; 
  } 
  temp = inputbyte >= bitweight ; 
  if ( temp ) 
  inputbyte = inputbyte - bitweight ; 
  Result = temp ; 
  return(Result) ; 
} 
integer pkpackednum () {
    register integer Result; integer i, j; 
  i = getnyb () ; 
  if ( i == 0 ) 
  {
    do {
	j = getnyb () ; 
      i = i + 1 ; 
    } while ( ! ( j != 0 ) ) ; 
    while ( i > 0 ) {
	
      j = j * 16 + getnyb () ; 
      i = i - 1 ; 
    } 
    Result = j - 15 + ( 13 - dynf ) * 16 + dynf ; 
  } 
  else if ( i <= dynf ) 
  Result = i ; 
  else if ( i < 14 ) 
  Result = ( i - dynf - 1 ) * 16 + getnyb () + dynf + 1 ; 
  else {
      
    if ( i == 14 ) 
    repeatcount = pkpackednum () ; 
    else repeatcount = 1 ; 
    Result = pkpackednum () ; 
  } 
  return(Result) ; 
} 
skipspecials () {
    integer i, j, k  ; 
  thischarptr = gfloc ; 
  do {
      flagbyte = pkbyte () ; 
    if ( flagbyte >= 240 ) 
    switch ( flagbyte ) 
    {case 240 : 
    case 241 : 
    case 242 : 
    case 243 : 
      {
	i = 0 ; 
	gfbyte ( flagbyte - 1 ) ; 
	{register integer for_end; j = 240 ; for_end = flagbyte ; if ( j <= 
	for_end) do 
	  {
	    k = pkbyte () ; 
	    gfbyte ( k ) ; 
	    i = 256 * i + k ; 
	  } 
	while ( j++ < for_end ) ; } 
	{register integer for_end; j = 1 ; for_end = i ; if ( j <= for_end) 
	do 
	  gfbyte ( pkbyte () ) ; 
	while ( j++ < for_end ) ; } 
      } 
      break ; 
    case 244 : 
      {
	gfbyte ( 243 ) ; 
	gfquad ( get32 () ) ; 
      } 
      break ; 
    case 245 : 
      {
	; 
      } 
      break ; 
    case 246 : 
      {
	; 
      } 
      break ; 
    case 247 : 
    case 248 : 
    case 249 : 
    case 250 : 
    case 251 : 
    case 252 : 
    case 253 : 
    case 254 : 
    case 255 : 
      {
	(void) fprintf( stdout , "%c%s%ld%c\n",  ' ' ,
	"Unexpected " , (long)flagbyte , '!' ) ; 
	jumpout () ; 
      } 
      break ; 
    } 
  } while ( ! ( ( flagbyte < 240 ) || ( flagbyte == 245 ) ) ) ; 
} 

main( argc, argv )
int argc;
char **argv;
{
	register int i, j;
    
  	initialize () ; 

	if( argc == 3 ) {
		strcpy( pkname, argv[1] );
  		openpkfile () ; 
		strcpy( gfname, argv[2] );
 		opengffile () ; 
	} else {
		fprintf( stderr, "Usage: pktogf <pkfile> <gffile>\n" );
		jumpout();
	}

  if ( pkbyte () != 247 ) 
  {
    (void) fprintf( stdout , "%c%s\n",  ' ' ,
	"Bad pk file!  pre command missing." ) ; 
    jumpout () ; 
  } 
  gfbyte ( 247 ) ; 
  if ( pkbyte () != 89 ) 
  {
    (void) fprintf( stdout , "%c%s\n",  ' ' ,
	"Wrong version of packed file!." ) ; 
    jumpout () ; 
  } 
  gfbyte ( 131 ) ; 
  j = pkbyte () ; 
  {register integer for_end; i = 1 ; for_end = j ; if ( i <= for_end) do 
    hppp = pkbyte () ; 
  while ( i++ < for_end ) ; } 
  gfbyte ( 17 ) ; 
  {register integer for_end; i = 1 ; for_end = 17 ; if ( i <= for_end) do 
    gfbyte ( xord [ comment [ i ] ] ) ; 
  while ( i++ < for_end ) ; } 
  designsize = get32 () ; 
  checksum = get32 () ; 
  hppp = get32 () ; 
  vppp = get32 () ; 
  if ( hppp != vppp ) 
  (void) fprintf( stdout , "%s\n",
	 "Warning:  aspect ratio not 1:1!" ) ; 
  magnification = round ( hppp * 72.27 * 5 / ((double) 65536L ) ) ; 
  lasteoc = gfloc ; 
  skipspecials () ; 
  while ( flagbyte != 245 ) {
      
    dynf = flagbyte / 16 ; 
    flagbyte = flagbyte % 16 ; 
    turnon = flagbyte >= 8 ; 
    if ( turnon ) 
    flagbyte = flagbyte - 8 ; 
    if ( flagbyte == 7 ) 
    {
      packetlength = get32 () ; 
      car = get32 () ; 
      endofpacket = packetlength + pkloc ; 
      tfmwidth = get32 () ; 
      horesc = get32 () ; 
      veresc = get32 () ; 
      cwidth = get32 () ; 
      cheight = get32 () ; 
      wordwidth = ( cwidth + 31 ) / 32 ; 
      xoff = get32 () ; 
      yoff = get32 () ; 
    } 
    else if ( flagbyte > 3 ) 
    {
      packetlength = ( flagbyte - 4 ) * 65536L + get16 () ; 
      car = pkbyte () ; 
      endofpacket = packetlength + pkloc ; 
      i = pkbyte () ; 
      tfmwidth = i * 65536L + get16 () ; 
      horesc = get16 () * 65536L ; 
      veresc = 0 ; 
      cwidth = get16 () ; 
      cheight = get16 () ; 
      wordwidth = ( cwidth + 31 ) / 32 ; 
      xoff = signed16 () ; 
      yoff = signed16 () ; 
    } 
    else {
	
      packetlength = flagbyte * 256 + pkbyte () ; 
      car = pkbyte () ; 
      endofpacket = packetlength + pkloc ; 
      i = pkbyte () ; 
      tfmwidth = i * 65536L + get16 () ; 
      horesc = pkbyte () * 65536L ; 
      veresc = 0 ; 
      cwidth = pkbyte () ; 
      cheight = pkbyte () ; 
      wordwidth = ( cwidth + 31 ) / 32 ; 
      xoff = signedbyte () ; 
      yoff = signedbyte () ; 
    } 
    minm = - (integer) xoff ; 
    if ( minm < mminm ) 
    mminm = minm ; 
    maxm = cwidth + minm ; 
    if ( maxm > mmaxm ) 
    mmaxm = maxm ; 
    minn = yoff - cheight + 1 ; 
    if ( minn < mminn ) 
    mminn = minn ; 
    maxn = yoff ; 
    if ( maxn > mmaxn ) 
    mmaxn = maxn ; 
    {
      i = car % 256 ; 
      if ( ( charpointer [ i ] == -1 ) ) 
      {
	sveresc [ i ] = veresc ; 
	shoresc [ i ] = horesc ; 
	stfmwidth [ i ] = tfmwidth ; 
      } 
      else {
	  
	if ( ( sveresc [ i ] != veresc ) || ( shoresc [ i ] != horesc ) || ( 
	stfmwidth [ i ] != tfmwidth ) ) 
	(void) fprintf( stdout , "%s%ld%s\n",
	 "Two characters mod " , (long)i ,
        " have mismatched parameters" ) ; 
      } 
    } 
    {
      if ( ( charpointer [ car % 256 ] == -1 ) && ( car >= 0 ) && ( car < 256 
      ) && ( maxm >= 0 ) && ( maxm < 256 ) && ( maxn >= 0 ) && ( maxn < 256 ) 
      && ( maxm >= minm ) && ( maxn >= minn ) && ( maxm < minm + 256 ) && ( 
      maxn < minn + 256 ) ) 
      {
	charpointer [ car % 256 ] = thischarptr ; 
	gfbyte ( 68 ) ; 
	gfbyte ( car ) ; 
	gfbyte ( maxm - minm ) ; 
	gfbyte ( maxm ) ; 
	gfbyte ( maxn - minn ) ; 
	gfbyte ( maxn ) ; 
      } 
      else {
	  
	gfbyte ( 67 ) ; 
	gfquad ( car ) ; 
	gfquad ( charpointer [ car % 256 ] ) ; 
	charpointer [ car % 256 ] = thischarptr ; 
	gfquad ( minm ) ; 
	gfquad ( maxm ) ; 
	gfquad ( minn ) ; 
	gfquad ( maxn ) ; 
      } 
    } 
    if ( ( cwidth > 0 ) && ( cheight > 0 ) ) 
    {
      bitweight = 0 ; 
      countdown = cheight * cwidth - 1 ; 
      if ( dynf == 14 ) 
      turnon = getbit () ; 
      repeatcount = 0 ; 
      xtogo = cwidth ; 
      ytogo = cheight ; 
      curn = cheight ; 
      count = 0 ; 
      firston = turnon ; 
      turnon = ! turnon ; 
      rcp = 0 ; 
      while ( ytogo > 0 ) {
	  
	if ( count == 0 ) 
	{
	  turnon = ! turnon ; 
	  if ( dynf == 14 ) 
	  {
	    count = 1 ; 
	    done = false ; 
	    while ( ! done ) {
		
	      if ( countdown <= 0 ) 
	      done = true ; 
	      else if ( ( turnon == getbit () ) ) 
	      count = count + 1 ; 
	      else done = true ; 
	      countdown = countdown - 1 ; 
	    } 
	  } 
	  else count = pkpackednum () ; 
	} 
	if ( rcp == 0 ) 
	firston = turnon ; 
	while ( count >= xtogo ) {
	    
	  rowcounts [ rcp ] = xtogo ; 
	  count = count - xtogo ; 
	  {register integer for_end; i = 0 ; for_end = repeatcount ; if ( i 
	  <= for_end) do 
	    {
	      if ( ( rcp > 0 ) || firston ) 
	      {
		register integer max;
		j = 0 ; 
		max = rcp ; 
		if ( ! turnon ) 
		max = max - 1 ; 
		if ( curn - ytogo == 1 ) 
		{
		  if ( firston ) 
		  gfbyte ( 74 ) ; 
		  else if ( rowcounts [ 0 ] < 165 ) 
		  {
		    gfbyte ( 74 + rowcounts [ 0 ] ) ; 
		    j = j + 1 ; 
		  } 
		  else gfbyte ( 70 ) ; 
		} 
		else if ( curn > ytogo ) 
		{
		  if ( curn - ytogo < 257 ) 
		  {
		    gfbyte ( 71 ) ; 
		    gfbyte ( curn - ytogo - 1 ) ; 
		  } 
		  else {
		      
		    gfbyte ( 72 ) ; 
		    gf16 ( curn - ytogo - 1 ) ; 
		  } 
		  if ( firston ) 
		  gfbyte ( 0 ) ; 
		} 
		else if ( firston ) 
		gfbyte ( 0 ) ; 
		curn = ytogo ; 
		while ( j <= max ) {
		    
		  if ( rowcounts [ j ] < 64 ) 
		  gfbyte ( 0 + rowcounts [ j ] ) ; 
		  else if ( rowcounts [ j ] < 256 ) 
		  {
		    gfbyte ( 64 ) ; 
		    gfbyte ( rowcounts [ j ] ) ; 
		  } 
		  else {
		      
		    gfbyte ( 65 ) ; 
		    gf16 ( rowcounts [ j ] ) ; 
		  } 
		  j = j + 1 ; 
		} 
	      } 
	      ytogo = ytogo - 1 ; 
	    } 
	  while ( i++ < for_end ) ; } 
	  repeatcount = 0 ; 
	  xtogo = cwidth ; 
	  rcp = 0 ; 
	  if ( ( count > 0 ) ) 
	  firston = turnon ; 
	} 
	if ( count > 0 ) 
	{
	  rowcounts [ rcp ] = count ; 
	  if ( rcp == 0 ) 
	  firston = turnon ; 
	  rcp = rcp + 1 ; 
	  if ( rcp > MAXCOUNTS ) 
	  {
	    (void) fprintf( stdout , "%s\n",
		 "A character had too many run counts" ) ; 
	    jumpout () ; 
	  } 
	  xtogo = xtogo - count ; 
	  count = 0 ; 
	} 
      } 
    } 
    gfbyte ( 69 ) ; 
    lasteoc = gfloc ; 
    if ( endofpacket != pkloc ) 
    {
      (void) fprintf( stdout , "%c%s\n",  ' ' ,
      "Bad pk file!  Bad packet length." ) ; 
      jumpout () ; 
    } 
    skipspecials () ; 
  } 
  while ( ! eof ( pkfile ) ) i = pkbyte () ; 
  j = gfloc ; 
  gfbyte ( 248 ) ; 
  gfquad ( lasteoc ) ; 
  gfquad ( designsize ) ; 
  gfquad ( checksum ) ; 
  gfquad ( hppp ) ; 
  gfquad ( vppp ) ; 
  gfquad ( mminm ) ; 
  gfquad ( mmaxm ) ; 
  gfquad ( mminn ) ; 
  gfquad ( mmaxn ) ; 
  {register integer for_end; i = 0 ; for_end = 255 ; if ( i <= for_end) do 
    if ( charpointer [ i ] != -1 ) 
    {
      if ( ( sveresc [ i ] == 0 )
		&& ( shoresc [ i ] >= 0 )
		&& ( shoresc [ i ] < 16777216L )
		&& ( shoresc [ i ] % 65536L == 0 ) ) 
      {
	gfbyte ( 246 ) ; 
	gfbyte ( i ) ; 
	gfbyte ( shoresc [ i ] / 65536L ) ; 
      } 
      else {
	  
	gfbyte ( 245 ) ; 
	gfbyte ( i ) ; 
	gfquad ( shoresc [ i ] ) ; 
	gfquad ( sveresc [ i ] ) ; 
      } 
      gfquad ( stfmwidth [ i ] ) ; 
      gfquad ( charpointer [ i ] ) ; 
    } 
  while ( i++ < for_end ) ; } 
  gfbyte ( 249 ) ; 
  gfquad ( j ) ; 
  gfbyte ( 131 ) ; 
  {register integer for_end; i = 0 ; for_end = 3 ; if ( i <= for_end) do 
    gfbyte ( 223 ) ; 
  while ( i++ < for_end ) ; } 
  while ( gfloc % 4 != 0 ) gfbyte ( 223 ) ; 
  (void) fprintf( stdout , "%ld%s%ld%s\n",
  (long)pkloc , " bytes unpacked to " , (long)gfloc , " bytes." ) ; 

	return( 0 );
} 
\end{verbatim}
}
\end{document}