-- 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.