-- TexAlign.mesa -- Last changed by Doug Wyatt, September 23, 1980 3:39 PM DIRECTORY TexDefs: FROM "TexDefs", TexErrorDefs: FROM "TexErrorDefs", TexGlueDefs: FROM "TexGlueDefs", TexAlignDefs: FROM "TexAlignDefs", TexMainDefs: FROM "TexMainDefs", TexMemDefs: FROM "TexMemDefs", TexNodeDefs: FROM "TexNodeDefs", TexPackDefs: FROM "TexPackDefs", TexSynDefs: FROM "TexSynDefs", TexTableDefs: FROM "TexTableDefs", TexTokenDefs: FROM "TexTokenDefs"; TexAlign: PROGRAM IMPORTS TexErrorDefs,TexGlueDefs,TexMainDefs,TexMemDefs, TexNodeDefs,TexPackDefs,TexSynDefs,TexTableDefs,TexTokenDefs EXPORTS TexAlignDefs = BEGIN OPEN TexErrorDefs,TexMainDefs,TexPackDefs,TexTableDefs,TexNodeDefs, TexGlueDefs,TexSynDefs,TexTokenDefs,TexAlignDefs,TexDefs; alignmentInProgress: PUBLIC BOOLEAN←FALSE; MakeAlignRecord: PROCEDURE RETURNS [p: POINTER TO AlignRecord] = BEGIN p←TexMemDefs.AllocMem[SIZE[AlignRecord]]; p↑←[NIL,NIL,0,NIL,NIL]; END; FreeAlignRecord: PROCEDURE[p: POINTER TO AlignRecord] = BEGIN TexMemDefs.FreeMem[p,SIZE[AlignRecord]]; END; GetNonTabskipTok: PROCEDURE = BEGIN g: GluePtr←MakeGlue[]; AddGlueLink[g]; GetTok[]; DO -- get non-tabskip token WITH cc:curchar SELECT curcmd FROM assignglue => IF cc.glueparam=tabskip THEN BEGIN ScanGlue[g]; SetGlueParam[tabskip,g]; END; ENDCASE => EXIT; GetTok[]; ENDLOOP; DelGlueLink[g]; END; HAlign: PUBLIC PROCEDURE[vhead: VHeadPtr,math: BOOLEAN] = BEGIN Alignment[NIL,vhead,vlist,math]; END; VAlign: PUBLIC PROCEDURE[hhead: HHeadPtr] = BEGIN Alignment[hhead,NIL,hlist,FALSE]; END; Alignment: PROCEDURE[hhead: HHeadPtr, vhead: VHeadPtr, d: Direction, math: BOOLEAN] = BEGIN list: NodeListPtr; tempPtr,alignListPtr,alignRecPtr: POINTER TO AlignRecord; temp,len: Dimn; xpand, break: BOOLEAN; size: Dimn; lastBeforeAlign: NodePtr; prevPtr,tobesetPtr: NodePtr; carretseen: BOOLEAN; holdhead: TokenLEntry; q: TokenPtr; imbalance: INTEGER; -- first do the initalign code SELECT d FROM hlist => list←hhead.hlist; vlist => list←vhead.vlist; ENDCASE; size←DimnParam[hsize]; lastBeforeAlign←list.last; alignmentInProgress←TRUE; alignListPtr←alignRecPtr←MakeAlignRecord[]; [len,xpand,break]←ScanSpec[FALSE,size]; -- throw break away NewSaveLevel[aligncode]; -- guard against extra }'s DO BEGIN imbalance←0; AddGlueLink[alignRecPtr.tabglue←GlueParam[tabskip]]; IF curcmd=carret THEN EXIT; -- \cr sensed alignRecPtr←(alignRecPtr.link←MakeAlignRecord[]); q←@holdhead; holdhead←nilTokenLEntry; DO -- get U part GetNonTabskipTok[]; SELECT curcmd FROM tabmrk,carret => BEGIN BackError["Missing # inserted in alignment preamble"]; EXIT; END; macprm => EXIT; lbrace => imbalance←imbalance+1; rbrace => imbalance←imbalance-1; ENDCASE; StoreTok[@q,curtok]; ENDLOOP; alignRecPtr.UPart←holdhead.link; IF imbalance<0 THEN TexErrorDefs.Confusion; -- now start again q←@holdhead; holdhead←nilTokenLEntry; DO -- get V part GetNonTabskipTok[]; SELECT curcmd FROM tabmrk,carret => IF imbalance=0 THEN EXIT; macprm => BEGIN Error["Only one # allowed per tab"]; LOOP; END; lbrace => imbalance←imbalance+1; rbrace => imbalance←imbalance-1; ENDCASE; StoreTok[@q,curtok]; ENDLOOP; StoreTok[@q,[endv[]]]; alignRecPtr.VPart←holdhead.link; alignRecPtr.maxsofar←0; END; ENDLOOP; -- next process an arbitrary mixture of table rows and \noaligns DO ScanNonSpacer[]; SELECT curcmd FROM noalign => -- a \noalign BEGIN ScanLB[]; -- do skipspacers NewSaveLevel[noalignend]; IF d=vlist THEN VMode[vhead,TRUE] ELSE HMode[hhead,TRUE]; UnSave[noalignend]; END; rbrace => EXIT; -- end of alignment ENDCASE => -- a table row BEGIN rowPtr: NodeListPtr←InitNodeList[]; BackInput[]; -- curtok to be rescanned after the U part alignRecPtr←alignListPtr.link; -- "rewind" alignRecPtr carretseen←(curcmd=carret); -- catch an empty row WHILE NOT carretseen DO BEGIN unsetPtr: NodeListPtr←InitNodeList[]; totalFlex: FlexSums; flexPtr: FlexSumsPtr←@totalFlex; p: BoxNodePtr; IF alignRecPtr=NIL THEN BEGIN Error["Extra alignment tab"]; EXIT; END; NewSaveLevel[alignentry]; q←@holdhead; holdhead←nilTokenLEntry; imbalance←0; DO -- get a table entry GetTok[]; SELECT curcmd FROM lbrace => imbalance←imbalance+1; rbrace => IF imbalance=0 THEN BEGIN BackError["Missing \cr inserted"]; carretseen←TRUE; EXIT; END ELSE imbalance←imbalance-1; tabmrk => IF imbalance=0 THEN EXIT; carret => IF imbalance=0 THEN BEGIN carretseen←TRUE; EXIT; END; ENDCASE; StoreTok[@q,curtok]; ENDLOOP; InsVPart[alignRecPtr.VPart]; InsList[holdhead.link]; InsUPart[alignRecPtr.UPart]; IF d=vlist THEN BEGIN hh: HHead←[unsetPtr,sfOne]; HMode[@hh,TRUE]; -- claim: unsetPtr=hh.hlist END ELSE BEGIN vh: VHead←[unsetPtr,pflag]; VMode[@vh,TRUE]; -- claim: unsetPtr=vh.vlist END; IF curcmd#endv THEN TexErrorDefs.Confusion; UnSave[alignentry]; IF d=vlist THEN BEGIN insertsPtr: NodeListPtr←InitNodeList[]; p←HPackage[unsetPtr,0,TRUE,insertsPtr,flexPtr]; IF (temp←p.width)>alignRecPtr.maxsofar THEN alignRecPtr.maxsofar←temp; FreeNodeList[insertsPtr]; END ELSE BEGIN p←VPackage[unsetPtr,0,TRUE,FALSE,flexPtr]; IF (temp←p.height+p.depth)>alignRecPtr.maxsofar THEN alignRecPtr.maxsofar←temp; END; StoreNode[rowPtr,MakeUnsetNode[p,flexPtr]]; alignRecPtr←alignRecPtr.link; END; ENDLOOP; IF d=vlist THEN VAppend[vhead,HBox[rowPtr]] ELSE HAppend[hhead,VBox[rowPtr]]; END; ENDLOOP; UnSave[aligncode]; -- now do the endalign code prevPtr←tobesetPtr←lastBeforeAlign; WHILE tobesetPtr#NIL DO WITH cp:tobesetPtr SELECT FROM box => IF cp.head#NIL THEN BEGIN WITH unsetBox:cp.head SELECT FROM unset => BEGIN -- unsetBox contains an unset box; time to set it setRowPtr: NodeListPtr←InitNodeList[]; unsetRowPtr: UnsetNodePtr←@unsetBox; alignedBoxPtr,tempBoxPtr: BoxNodePtr; unsetListExhausted: BOOLEAN←FALSE; -- there is always one unset box IF cp.dir=d THEN TexErrorDefs.Confusion; alignRecPtr←alignListPtr; DO -- do a row StoreNode[setRowPtr,MakeGlueNode[alignRecPtr.tabglue]]; alignRecPtr←alignRecPtr.link; IF alignRecPtr=NIL THEN EXIT; IF unsetListExhausted THEN BEGIN tempBoxPtr←NullBox[]; IF d=vlist THEN tempBoxPtr.width←alignRecPtr.maxsofar ELSE tempBoxPtr.height←alignRecPtr.maxsofar; END ELSE BEGIN curboxPtr: BoxNodePtr←unsetRowPtr.box; delta: Dimn; l: Dimn; IF d=vlist THEN BEGIN l←curboxPtr.width; curboxPtr.width←alignRecPtr.maxsofar; END ELSE BEGIN l←curboxPtr.height+curboxPtr.depth; curboxPtr.height←alignRecPtr.maxsofar-curboxPtr.depth; END; IF (delta←alignRecPtr.maxsofar-l)#0 THEN curboxPtr.glueset←SetGlue[IF delta>0 THEN str ELSE shr, ABS[delta],@unsetRowPtr.totalStretch]; (tempBoxPtr←curboxPtr).link←NIL; cp.head←curboxPtr.link; unsetRowPtr.box←NIL; END; StoreNode[setRowPtr,tempBoxPtr]; IF unsetRowPtr.link=NIL THEN unsetListExhausted←TRUE ELSE WITH ur:unsetRowPtr.link SELECT FROM unset => unsetRowPtr←@ur; ENDCASE => TexErrorDefs.Confusion; ENDLOOP; IF d=vlist THEN alignedBoxPtr←HPack[setRowPtr,len,xpand] ELSE alignedBoxPtr←VPack[setRowPtr,len,xpand]; prevPtr.link←alignedBoxPtr; alignedBoxPtr.link←tobesetPtr.link; tobesetPtr.link←NIL; DsNode[tobesetPtr]; tobesetPtr←alignedBoxPtr; END; ENDCASE; END; ENDCASE; prevPtr←tobesetPtr; tobesetPtr←prevPtr.link; ENDLOOP; list.last←prevPtr; -- just to be sure alignRecPtr←alignListPtr; DO -- free the alignment records DelGlueLink[alignRecPtr.tabglue]; DsList[alignRecPtr.UPart]; DsList[alignRecPtr.VPart]; tempPtr←alignRecPtr.link; FreeAlignRecord[alignRecPtr]; IF tempPtr=NIL THEN EXIT ELSE alignRecPtr←tempPtr; ENDLOOP; IF math THEN -- insert dispskip glue before and after BEGIN r,s: GlueNodePtr; r←MakeGlueNode[GlueParam[dispskip]]; r.link←lastBeforeAlign.link; lastBeforeAlign.link←r; s←MakeGlueNode[GlueParam[dispskip]]; list.last←prevPtr.link←s; END; alignmentInProgress←FALSE; END; END.