|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T a
Length: 42689 (0xa6c1) Types: TextFile Names: »aix.tex«
└─⟦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«
\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}