LaTeXML-0.7.0/0000755002506700454610000000000011215766043012041 5ustar miller891divLaTeXML-0.7.0/t/0000755002506700454610000000000011215766043012304 5ustar miller891divLaTeXML-0.7.0/t/structure/0000755002506700454610000000000011215766043014344 5ustar miller891divLaTeXML-0.7.0/t/structure/itemize.dvi0000644002506700454610000000213011214255136016505 0ustar miller891div; TeX output 2007.12.04:0010y?>Nff cmbx121VLItemizeM !", cmsy10WK`y cmr10One,UUbutnot1MWTwo,UUbutnot2MWThree,UUbutnot3!č>2VLEnumerateJ81.WOneUU,butnot3J82.WTwoUU,butnot3J83.WThreeUU,butnot3!č>3VLDescription>"V cmbx10OneWLk,UUbutnot1>Tw9oXj,UUbutnot1>Three`,UUbutnot1!č>4VLNestedffEnumerateJ81.WOne[8(a)mOneZ(b)mTwo[(c)mThreeJ82.WTwo[8(a)mOneZ(b)mTwo[(c)mThreeJ83.WThree[8(a)mOneZ(b)mTwo[(c)mThree1*;y"V cmbx10Nff cmbx12 !", cmsy10K`y cmr10LaTeXML-0.7.0/t/structure/report.tex0000644002506700454610000000304411214255136016375 0ustar miller891div\documentclass{report} \begin{document} \chapter{First Chapter} \section{First Section} Begin first paragraph, \begin{equation} a + b, \end{equation} \begin{equation} c + d, \end{equation} \begin{figure} A Figure \caption{A Figure} \end{figure} \begin{table} A Figure \caption{A Figure} \end{table} \begin{enumerate} \item one \item two \begin{enumerate} \item one \item two \end{enumerate} \end{enumerate} \section{Second Section} Begin first paragraph, \begin{equation} a + b, \end{equation} \begin{equation} c + d, \end{equation} \begin{figure} A Figure \caption{A Figure} \end{figure} \begin{table} A Figure \caption{A Figure} \end{table} \begin{enumerate} \item one \item two \begin{enumerate} \item one \item two \end{enumerate} \end{enumerate} \chapter{Second Chapter} \section{First Section} Begin first paragraph, \begin{equation} a + b, \end{equation} \begin{equation} c + d, \end{equation} \begin{figure} A Figure \caption{A Figure} \end{figure} \begin{table} A Figure \caption{A Figure} \end{table} \begin{enumerate} \item one \item two \begin{enumerate} \item one \item two \end{enumerate} \end{enumerate} \section{Second Section} Begin first paragraph, \begin{equation} a + b, \end{equation} \begin{equation} c + d, \end{equation} \begin{figure} A Figure \caption{A Figure} \end{figure} \begin{table} A Figure \caption{A Figure} \end{table} \begin{enumerate} \item one \item two \begin{enumerate} \item one \item two \end{enumerate} \end{enumerate} \end{document} LaTeXML-0.7.0/t/structure/itemize.tex0000644002506700454610000000174411214255136016535 0ustar miller891div\documentclass{article} \begin{document} \section{Itemize} \begin{itemize} \item One\label{it:one}, but not \ref{en:one} \item Two\label{it:two}, but not \ref{en:two} \item Three\label{it:three}, but not \ref{en:three} \end{itemize} \section{Enumerate} \begin{enumerate} \item One \label{en:one}, but not \ref{de:one} \item Two \label{en:two}, but not \ref{de:two} \item Three \label{en:three}, but not \ref{de:three} \end{enumerate} \section{Description} \begin{description} \item[One] \label{de:one}, but not \ref{it:one} \item[Two] \label{de:two}, but not \ref{it:two} \item[Three] \label{de:three}, but not \ref{it:three} \end{description} \section{Nested Enumerate} \begin{enumerate} \item One \begin{enumerate} \item One \item Two \item Three \end{enumerate} \item Two \begin{enumerate} \item One \item Two \item Three \end{enumerate} \item Three \begin{enumerate} \item One \item Two \item Three \end{enumerate} \end{enumerate} \end{document} LaTeXML-0.7.0/t/structure/article.xml0000644002506700454610000001012411214255136016502 0ustar miller891div
First Section

Begin first paragraph,

+ a b
+ c d

A Figure

A Figure

A Figure

A Figure

one

two

one

two

Second Section

Begin first paragraph,

+ a b
+ c d

A Figure

A Figure

A Figure

A Figure

one

two

one

two

LaTeXML-0.7.0/t/structure/article.tex0000644002506700454610000000142611214255136016507 0ustar miller891div\documentclass{article} \begin{document} \section{First Section} Begin first paragraph, \begin{equation} a + b, \end{equation} \begin{equation} c + d, \end{equation} \begin{figure} A Figure \caption{A Figure} \end{figure} \begin{table} A Figure \caption{A Figure} \end{table} \begin{enumerate} \item one \item two \begin{enumerate} \item one \item two \end{enumerate} \end{enumerate} \section{Second Section} Begin first paragraph, \begin{equation} a + b, \end{equation} \begin{equation} c + d, \end{equation} \begin{figure} A Figure \caption{A Figure} \end{figure} \begin{table} A Figure \caption{A Figure} \end{table} \begin{enumerate} \item one \item two \begin{enumerate} \item one \item two \end{enumerate} \end{enumerate} \end{document} LaTeXML-0.7.0/t/structure/report.xml0000644002506700454610000002171111214255136016376 0ustar miller891div First Chapter
First Section

Begin first paragraph,

+ a b
+ c d

A Figure

A Figure

A Figure

A Figure

one

two

one

two

Second Section

Begin first paragraph,

+ a b
+ c d

A Figure

A Figure

A Figure

A Figure

one

two

one

two

Second Chapter
First Section

Begin first paragraph,

+ a b
+ c d

A Figure

A Figure

A Figure

A Figure

one

two

one

two

Second Section

Begin first paragraph,

+ a b
+ c d

A Figure

A Figure

A Figure

A Figure

one

two

one

two

LaTeXML-0.7.0/t/structure/authors.tex0000644002506700454610000000034611214255136016551 0ustar miller891div\documentclass{article} \title{Testing Authors\thanks{Whoppee!}} \author{Joe Blow\thanks{Somewhere}\and Fred Head\thanks{elsewhere}} \date{Today!} \begin{document} \maketitle \section{One}\label{sec:one} And so on. \end{document} LaTeXML-0.7.0/t/structure/sec.dvi0000644002506700454610000000130411214255136015613 0ustar miller891div; TeX output 2008.08.06:1424y?uODtGGcmr17TVesting7tSections XQ cmr12TVoSdary!+č>Nff cmbx121VLOne>K`y cmr10SectionUUOne.qAswewillseein !", cmsy10x1.!č>2VLTwo>AsUUseeninx1;SectionTwo.>3VLThree>Previously*,UUinx2.(>Hi!PFigureUU1:qAFigure >.1*;yNff cmbx12XQ cmr12DtGGcmr17 !", cmsy10K`y cmr101LaTeXML-0.7.0/t/structure/authors.xml0000644002506700454610000000124311214255136016546 0ustar miller891div Testing Authors<note class="thanks">Whoppee!</note> Joe Blow Somewhere Fred Head elsewhere Today!
One

And so on.

LaTeXML-0.7.0/t/structure/book.xml0000644002506700454610000002170711214255136016022 0ustar miller891div First Chapter
First Section

Begin first paragraph,

+ a b
+ c d

A Figure

A Figure

A Figure

A Figure

one

two

one

two

Second Section

Begin first paragraph,

+ a b
+ c d

A Figure

A Figure

A Figure

A Figure

one

two

one

two

Second Chapter
First Section

Begin first paragraph,

+ a b
+ c d

A Figure

A Figure

A Figure

A Figure

one

two

one

two

Second Section

Begin first paragraph,

+ a b
+ c d

A Figure

A Figure

A Figure

A Figure

one

two

one

two

LaTeXML-0.7.0/t/structure/para.dvi0000644002506700454610000000163411214255136015772 0ustar miller891div; TeX output 2008.08.06:1424y?>Nff cmbx121VLDisplayffMath>K`y cmr10BeginUU rstparagraph, 6 b> cmmi10a8+b;>continuingUUparagraph.MSingleUUlineparagraph.Ǥ6a8+b:MAnotherUUsinglelineparagraph.!č>2VLItemizations>BeginUU rstparagraph,M !", cmsy10WAMWB>continuingUUparagraph. MSingleUUlineparagraph.MWAMWBMAnotherUUsinglelineparagraph. MMultipleUUParawithinitemMWAWBMWC1*;yNff cmbx12 !", cmsy10 b> cmmi10K`y cmr10LaTeXML-0.7.0/t/structure/itemize.xml0000644002506700454610000001116211214255136016530 0ustar miller891div
Itemize

One, but not

Two, but not

Three, but not

Enumerate

One , but not

Two , but not

Three , but not

Description One

, but not

Two

, but not

Three

, but not

Nested Enumerate

One

One

Two

Three

Two

One

Two

Three

Three

One

Two

Three

LaTeXML-0.7.0/t/structure/sec.xml0000644002506700454610000000174311214255136015640 0ustar miller891div Testing Sections Today!
One

Section One. As we will see in §.

Two

As seen in §; Section Two.

Three

Previously, in §.

Hi!

A Figure

.

LaTeXML-0.7.0/t/structure/article.dvi0000644002506700454610000000216011214255136016465 0ustar miller891div; TeX output 2008.08.06:1507y?9>K`y cmr10AUUFigurePFigureUU1:qAFigure*9>AUUFigurenT*ableUU1:qAFigure>Nff cmbx121VLFirstffSection>BeginUU rstparagraph, 6 b> cmmi10a8+b;8(1);ܵc8+d;8(2)J81.WoneJ82.Wtwo[8(a)moneZ(b)mtwo!č>2VLSecondffSection>BeginUU rstparagraph, 6a8+b;8(3);ܵc8+d;8(4)J81.WoneJ82.Wtwo[8(a)moneZ(b)mtwouT9>AUUFigurePFigureUU2:qAFigure1*y?c9>AUUFigurenT*ableUU2:qAFigure2u;yNff cmbx12 b> cmmi10K`y cmr10LaTeXML-0.7.0/t/structure/book.dvi0000644002506700454610000000454411214255136016004 0ustar miller891div; TeX output 2007.12.03:1219s\ȍ88G/#Nq cmbx12Chapter 12#NH cmbx12First T{Chapter:#Nff cmbx121.1GcFirstffSection#K`y cmr10BeginUU rstparagraph, 6 b> cmmi10a8+b;gqò(1.1)|;ܵc8+d;gqò(1.2)/81.<onee/82.<twoe@8(a)Ronee?(b)Rtwo a#1.2GcSecondffSection#BeginUU rstparagraph,6a8+b;gqò(1.3)|;ܵc8+d;gqò(1.4)/81.<onee/82.<twoe@8(a)Ronee?(b)Rtwo89#AUUFigure1FigureUU1.1:qAFigureK1*s\ȍ8Y2p0J cmsl10CHAPTERUU1.FIRSTCHAPTER8GBc9YAUUFigure8T*ableUU1.1:qAFigure9YAUUFigure1FigureUU1.2:qAFigure9YAUUFigure8T*ableUU1.2:qAFigure`s\ȍ88G/#Chapter 22#Second T{Chapter:#2.1GcFirstffSection#BeginUU rstparagraph, 6a8+b;gqò(2.1)|;ܵc8+d;gqò(2.2)/81.<onee/82.<twoe@8(a)Ronee?(b)Rtwo a#2.2GcSecondffSection#BeginUU rstparagraph,6a8+b;gqò(2.3)|;ܵc8+d;gqò(2.4)/81.<onee/82.<twoe@8(a)Ronee?(b)Rtwo89#AUUFigure1FigureUU2.1:qAFigureK3s\ȍ8Y4qCHAPTERUU2.SECONDCHAPTER8GBc9YAUUFigure8T*ableUU2.1:qAFigure9YAUUFigure1FigureUU2.2:qAFigure9YAUUFigure8T*ableUU2.2:qAFigure{;s\p0J cmsl10Nff cmbx12NH cmbx12Nq cmbx12 b> cmmi10K`y cmr10LaTeXML-0.7.0/t/structure/sec.tex0000644002506700454610000000060511214255136015634 0ustar miller891div\documentclass{article} \title{Testing Sections} \date{Today!} \begin{document} \maketitle \section{One}\label{sec:one} Section One. As we will see in \S\ref{fig_three}. \section{Two}\label{sec:two} As seen in \S\ref{sec:one}; Section Two. \section{Three}\label{sec:three} Previously, in \S\ref{sec:two}. \begin{figure} Hi! \caption{A Figure\label{fig_three}}. \end{figure} \end{document} LaTeXML-0.7.0/t/structure/para.tex0000644002506700454610000000076711214255136016016 0ustar miller891div\documentclass{article} \begin{document} \section{Display Math} Begin first paragraph, \[ a + b, \] continuing paragraph. Single line paragraph. \[ a + b. \] Another single line paragraph. \section{Itemizations} Begin first paragraph, \begin{itemize} \item A \item B \end{itemize} continuing paragraph. Single line paragraph. \begin{itemize} \item A \item B \end{itemize} Another single line paragraph. Multiple Para within item \begin{itemize} \item A B \item C \end{itemize} \end{document} LaTeXML-0.7.0/t/structure/para.xml0000644002506700454610000000531111214255136016004 0ustar miller891div
Display Math

Begin first paragraph,

+ a b

continuing paragraph.

Single line paragraph.

+ a b

Another single line paragraph.

Itemizations

Begin first paragraph,

A

B

continuing paragraph.

Single line paragraph.

A

B

Another single line paragraph.

Multiple Para within item

A

B

C

LaTeXML-0.7.0/t/structure/authors.dvi0000644002506700454610000000147011214255136016532 0ustar miller891div; TeX output 2007.12.04:0006y?_DtGGcmr17TVesting7tAuthors!", cmsy10DXQ cmr12JoSeBlorw2K cmsy8y`RFVredHead2z TVoSdary!:ō>Nff cmbx121VLOne>K`y cmr10AndUUsoon.>Psffv @ -:q% cmsy6L|{Ycmr8WhoppNq cmbx12Chapter 12>NH cmbx12First T{Chapter:>Nff cmbx121.1bcFirstffSection>K`y cmr10BeginUU rstparagraph, 6 b> cmmi10a8+b;qò(1.1)|;ܵc8+d;qò(1.2)J81.WoneeJ82.Wtwoe[8(a)moneeZ(b)mtwo a>1.2bcSecondffSection>BeginUU rstparagraph,6a8+b;qò(1.3)|;ܵc8+d;qò(1.4)J81.WoneeJ82.Wtwoe[8(a)moneeZ(b)mtwo89>AUUFigure1FigureUU1.1:qAFigure1*y?Bc9>AUUFigure8T*ableUU1.1:qAFigure9>AUUFigure1FigureUU1.2:qAFigure9>AUUFigure8T*ableUU1.2:qAFigure2`y?/>Chapter 22>Second T{Chapter:>2.1bcFirstffSection>BeginUU rstparagraph, 6a8+b;qò(2.1)|;ܵc8+d;qò(2.2)J81.WoneeJ82.Wtwoe[8(a)moneeZ(b)mtwo a>2.2bcSecondffSection>BeginUU rstparagraph,6a8+b;qò(2.3)|;ܵc8+d;qò(2.4)J81.WoneeJ82.Wtwoe[8(a)moneeZ(b)mtwo89>AUUFigure1FigureUU2.1:qAFigure3yy?Bc9>AUUFigure8T*ableUU2.1:qAFigure9>AUUFigure1FigureUU2.2:qAFigure9>AUUFigure8T*ableUU2.2:qAFigure4C;yNff cmbx12NH cmbx12Nq cmbx12 b> cmmi10K`y cmr10\LaTeXML-0.7.0/t/structure/book.tex0000644002506700454610000000304211214255136016012 0ustar miller891div\documentclass{book} \begin{document} \chapter{First Chapter} \section{First Section} Begin first paragraph, \begin{equation} a + b, \end{equation} \begin{equation} c + d, \end{equation} \begin{figure} A Figure \caption{A Figure} \end{figure} \begin{table} A Figure \caption{A Figure} \end{table} \begin{enumerate} \item one \item two \begin{enumerate} \item one \item two \end{enumerate} \end{enumerate} \section{Second Section} Begin first paragraph, \begin{equation} a + b, \end{equation} \begin{equation} c + d, \end{equation} \begin{figure} A Figure \caption{A Figure} \end{figure} \begin{table} A Figure \caption{A Figure} \end{table} \begin{enumerate} \item one \item two \begin{enumerate} \item one \item two \end{enumerate} \end{enumerate} \chapter{Second Chapter} \section{First Section} Begin first paragraph, \begin{equation} a + b, \end{equation} \begin{equation} c + d, \end{equation} \begin{figure} A Figure \caption{A Figure} \end{figure} \begin{table} A Figure \caption{A Figure} \end{table} \begin{enumerate} \item one \item two \begin{enumerate} \item one \item two \end{enumerate} \end{enumerate} \section{Second Section} Begin first paragraph, \begin{equation} a + b, \end{equation} \begin{equation} c + d, \end{equation} \begin{figure} A Figure \caption{A Figure} \end{figure} \begin{table} A Figure \caption{A Figure} \end{table} \begin{enumerate} \item one \item two \begin{enumerate} \item one \item two \end{enumerate} \end{enumerate} \end{document} LaTeXML-0.7.0/t/parse/0000755002506700454610000000000011215766043013416 5ustar miller891divLaTeXML-0.7.0/t/parse/functions.dvi0000644002506700454610000000235411214255137016132 0ustar miller891div; TeX output 2008.08.06:1511y?>Nff cmbx121VLBasicffFfunctions #k b> cmmi10g[K`y cmr10(a)=g(b)ǵf(a)=g[ٲ(h(c)) h(c)=sin޵aٓRcmr72sinIf(a)!č>2VLTfrigonometricfffunctions ВsinބNa8+tanURbsinzeacosߵb !", cmsy106=sin6(acosb)pusinb;2"6=log\l2x2>3VLMissingffarguments 硍fg[hmfg[ha>4VLOps3erator-likefffunctions 硍FcGHtFcGHaf O!cmsy70Ȳ(a)=a2cf2(a)=g[ٟ 0ercmmi7b`(2)>5VLScripts 硍lna=logğqƴea=ln o+jb1*;yNff cmbx12 !", cmsy10 O!cmsy7 b> cmmi10 0ercmmi7K`y cmr10ٓRcmr7.LaTeXML-0.7.0/t/parse/terms.dvi0000644002506700454610000000175411214255137015257 0ustar miller891div; TeX output 2008.12.16:0924y?>Nff cmbx121VLBasicffmath ,0 b> cmmi10a8K`y cmr10+b+c !", cmsy10d+eea8+bcdeabc=deȟa8bc=de!č>2VLEvaluateffAt;gaj O!cmsy71B$abj 0ercmmi7aٓRcmr7=0scdjc=02e!č>3VLAbsoluteffvaluesKjajM.jjajjjaj1҇ja8+bj jja8jbjj!č>4VLFfailuresffw/oBacktracking DMjjaj8jbjj jjjaj8bjNjajbj11*;yNff cmbx12 !", cmsy10 O!cmsy7 b> cmmi10 0ercmmi7K`y cmr10ٓRcmr7.LaTeXML-0.7.0/t/parse/compose.xml0000644002506700454610000001230611214255137015603 0ustar miller891div
Compositions * f g x * * f g h x
Implicit lambdas? * y 2 f x * y y 2 f x * y 2 f x * f y 2 x
LaTeXML-0.7.0/t/parse/operators.tex0000644002506700454610000000131011214255137016145 0ustar miller891div\documentclass{article} \usepackage{latexml} \lxDeclare[role=ID]{$a$}% \lxDeclare[role=ID]{$b$}% \lxDeclare[role=ID]{$c$}% \lxDeclare[role=ID]{$d$}% \lxDeclare[role=ID]{$e$}% \lxDeclare[role=FUNCTION]{$f$}% \lxDeclare[role=FUNCTION]{$g$}% \lxDeclare[role=FUNCTION]{$h$}% \lxDeclare[role=OPERATOR]{$D$}% \lxDeclare[role=OPERATOR]{$G$}% \lxDeclare[role=OPERATOR]{$H$}% \begin{document} \section{Integration and Summation} \[ \sum_{a=0}^\infty f_a(c^a) \] \[ \sum_{a=0}^\infty \sum_{b=-a}^a f_a(c^a) g_b(c^b) \] \[ \sum_{a=0}^\infty \sum_{b=-a}^a \lim_{c\rightarrow 0} f_a(c^a) g_b(c^b) \] \section{Operators} \[ D a \] \[ D f \] \[ D f(a) \] \[ D G H f \] \[ D G H f (a) \] \[ D (a) (b) \] \end{document} LaTeXML-0.7.0/t/parse/operators.xml0000644002506700454610000002700311214255137016154 0ustar miller891div
Integration and Summation = a 0 f a c a = a 0 = b - a a f a c a g b c b = a 0 = b - a a lim c 0 f a c a g b c b
Operators D a D f D f a D G H f D G H f a D a b
LaTeXML-0.7.0/t/parse/parens.xml0000644002506700454610000004253711214255137015437 0ustar miller891div
Basic math - + a b c + a - b c
Intervals a b a b a b a b
Cases = a b c d c d + a c d b
Atop + a b c d + a b c d
Delimiters a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b a b + a b c d / a b c d
LaTeXML-0.7.0/t/parse/relations.tex0000644002506700454610000000130311214255137016131 0ustar miller891div\documentclass{article} \usepackage{latexml} \usepackage{amsmath} \lxDeclare[role=ID]{$a$}% \lxDeclare[role=ID]{$b$}% \lxDeclare[role=ID]{$c$}% \lxDeclare[role=ID]{$d$}% \lxDeclare[role=ID]{$e$}% \begin{document} \section{Grouping in multi-relations} \[ a=b=c=d=e \] \[ a=b,c=d \] \[ a=b,c,d,e \] \[ a=b,c,d=e \] \[ a=b>c\le d=e \] \paragraph{But period is somewhat different!} \[ a=b,c.d=e \] \[ a=b.c,d=e \] \section{Arrows as meta-relation} \[ a=b \rightarrow c\le d=e \] \[ a=b,c \rightarrow d=e \] \[ a=b \leftrightarrow c\le d=e \] \[ a=b,c \leftrightarrow d=e \] \section{Other Meta relations} \[ a (< e) \] \[ a; (< e) \] \[ a = b + c + d (< e) \] \[ a = b + c + d \mod e \] \end{document} LaTeXML-0.7.0/t/parse/parens.dvi0000644002506700454610000000555411214255137015417 0ustar miller891div; TeX output 2008.08.06:1511y?>Nff cmbx121VLBasicffmath ό*K`y cmr10(( b> cmmi10a8+b) !", cmsy10c)ό*(a8+(bc))!č>2VLIntervalsߙ(a;b)'[a;b)'(a;b][a;b]!č>3VLCasesda b_^u cmex10в=^dGc GdۉS^dǵc d9^#Ƣ(a8+^dTc TdƟ^"_+b)#s>4VLAtop ի1a8+<$pb 卑lc ,+d \da8+^<$ʵb 卑1c:?^=+d#ˍ>5VLDelimitersQ`<$hahwfeI0 (֍CbW˟`\Q`h<$hahwfeI0 (֍CbW˟`i1*y?Q`h<$hahwfeI0 (֍CbW˟`i\`n<$hahwfeI0 (֍CbW˟`o`n<$hahwfeI0 (֍CbW˟`oa`j<$hahwfeI0 (֍CbW˟`ka`l<$hahwfeI0 (֍CbW˟`mß`D<$hahwfeI0 (֍CbW˟`Eß`D<$hahwfeI0 (֍CbW˟`E\R R R <$hahwfeI0 (֍CbW˫ W W R R R <$hahwfeI0 (֍CbW˫ W W    <$hahwfeI0 (֍CbW˫ W W    <$hahwfeI0 (֍CbW˫ W W x??<$hahwfeI0 (֍CbW˫?W?Wy~ww<$hahwfeI0 (֍CbW˫wWwWoPxoP?oPy<$M/aM/wfeI0 (֍Cbɒ~ɒwɒ +0a8+^<$ b wfeS۟ (֍cs"^,+d<$ސaސ՟wfeI0 (֍Cb`.<$wҵcwfe4r (֍d22;yNff cmbx12 !", cmsy10 b> cmmi10K`y cmr10u cmex10 LaTeXML-0.7.0/t/parse/qm.tex0000644002506700454610000000112011214255137014543 0ustar miller891div\documentclass{article} \title{Less Than, Greater Than, Bars and Quantum Mechanics} \begin{document} \section{Relations} Relations: $ a < b < c $ Relations: $ > a $ Relations: $ a > $ \section{Quantum Mechanics Notations} Expectation: $ $ Bra: $$ Braket $$ Also $$ \section{Absolute Values} abs $|a|$ norm $||a||$ expr $|a|-|b|$ nested $||a|-|b||$ non-nested $a|a|+b|b|+c|c|$ \section{Mixtures that look like QM} abs and rel: $a
Basic Functions = g a g b = f a g h c = h c sin a 2 sin f a
Trigonometric functions + sin a tan b sin a cos b sin a cos b sin 2 π log 2 x 2
Missing arguments f g h f g h a
Operator-like functions F G H F G H a = f a a 2 = f 2 a g b 2
Scripts ln a = log e a = ln + b
LaTeXML-0.7.0/t/parse/sets.xml0000644002506700454610000000536511214255137015123 0ustar miller891div a a a b a a b a a b = c 0 LaTeXML-0.7.0/t/parse/relations.dvi0000644002506700454610000000212011214255137016111 0ustar miller891div; TeX output 2008.08.06:1511y?>Nff cmbx121VLGroupingffinmulti-relationsP b> cmmi10aK`y cmr10=b=c=d=eca=b;c=dHa=b;c;d;ea=b;c;d=ePa=b>c !", cmsy10d=e6>"V cmbx10ButTpQeriodissomewhatdi eren9t!ͬ-a=b;c:d=eͬ-a=b:c;d=e!č>2VLArrowsffasmeta-relationߵa=b!cd=eHa=b;c!d=ea=b$cd=eHa=b;c$d=e!č>3VLOtherffMetarelations\a(<e)#۵a;(<e)a=b8+c+d(<e)zpa=b8+c+d moGd e1*;y"V cmbx10Nff cmbx12 !", cmsy10 b> cmmi10K`y cmr10LaTeXML-0.7.0/t/parse/operators.dvi0000644002506700454610000000216011214255137016133 0ustar miller891div; TeX output 2008.08.06:1511y?>Nff cmbx121VLIntegrationffandSummation W O!cmsy71 0u cmex10X  0ercmmi7aٓRcmr7=09 b> cmmi10fapK`y cmr10(ca)(11 tX a=0%a зxX :b=a'fap(ca)gbD(cb)%`Uu1 X a=0+a X 7ɴb=a lim- c!0Sfap(ca)gbD(cb)'π>2VLOps3eratorsDGa cmmi10 0ercmmi7K`y cmr10ٓRcmr7u cmex10LaTeXML-0.7.0/t/parse/terms.tex0000644002506700454610000000121011214255137015260 0ustar miller891div\documentclass{article} \usepackage{latexml} \begin{document} \lxDeclare[role=ID]{$a$}% \lxDeclare[role=ID]{$b$}% \lxDeclare[role=ID]{$c$}% \lxDeclare[role=ID]{$d$}% \lxDeclare[role=ID]{$e$}% \section{Basic math} \[ a + b + c - d + e \] \[ a + b c - d e \] \[ a b c / d e \] \[ a \times b \times c / d \times e \] \section{Evaluate At} \[ a |_\infty \] \[ a b |_{a=0} c d |_{c=0} e \] \section{Absolute values} \[ |a| \] \[ ||a|| \] \[ |a |_\infty \] \[ |a + b| \] \[ |a - |b|| \] \section{Failures w/o Backtracking} \[ ||a| - |b|| \] \[ ||a|-b| \] \[ |a | b |_\infty \] % This one's too weird %\[ |a b |_\infty c | \] \end{document} LaTeXML-0.7.0/t/parse/relations.xml0000644002506700454610000003225311214255137016141 0ustar miller891div
Grouping in multi-relations a = b = c = d = e = a b = c d = a b c d e = a b c = d e a = b > c d = e But period is somewhat different! = a b c = d e = a b = c d e
Arrows as meta-relation a = b c d = e = a b c d = e = a b c d = e = a b c = d e
Other Meta relations a < e a < e = a + b c d < e = a mod + b c d e
LaTeXML-0.7.0/t/parse/compose.tex0000644002506700454610000000110511214255137015576 0ustar miller891div\documentclass{article} \usepackage{latexml} \lxDeclare[role=COMPOSEOP,meaning=compose]{$*$} \lxDeclare[role=FUNCTION]{$f$} \lxDeclare[role=FUNCTION]{$g$} \lxDeclare[role=FUNCTION]{$h$} \lxDeclare[role=ID]{$x$} \lxDeclare[role=ID]{$y$} \begin{document} \section{Compositions} % Straightforward \[ (f*g)(x) \] % Is nesting right? \[ (f*g*h)(x) \] \section{Implicit lambdas?} \[ (y^2 * f)(x) \] \[ (y y^2 * f)(x) \] \[ (y^2 * f)(x) \] \[ (f * y^2)(x) \] % \section{Dubious forms, probably should fail parsing} % \[ y y^2 * f x \] % \[ f * y^2 x \] % \[ f * y^2 (x) \] \end{document} LaTeXML-0.7.0/t/parse/sets.dvi0000644002506700454610000000075411214255137015102 0ustar miller891div; TeX output 2008.08.06:1511y?g !", cmsy10f b> cmmi10agffaK`y cmr10:a2bg֑~faja2bgx faja2bg 0ercmmi7cٓRcmr7=01*;y !", cmsy10 b> cmmi10 0ercmmi7K`y cmr10ٓRcmr7ZLaTeXML-0.7.0/t/parse/qm.dvi0000644002506700454610000000251411214255137014535 0ustar miller891div; TeX output 2008.12.17:0917y?>Nff cmbx121VLRelations>K`y cmr10Relations:q b> cmmi10aaMRelations:qǵa>!č>2VLQuantumffMechanicsNotations>ExpGectation:qǵ<a>MBra:qǵ<a !", cmsy10jMBra:qǵ<a;b;cjMBra:qǵ<=0jMKet:qǸjb>MBraketUU<ajb>MAlsoUU<ajfjb>!č>3VLAbsoluteffVfalues>absUUjajMnormUUjjajjMexprUUjaj8jbjMnestedUUjjaj8jbjjMnon-nestedUUajaj8+bjbj+cjcj!č>4VLMixturesffthatlos3oklikeQM>absUUandrel:qǵa cmmi10 0ercmmi7K`y cmr10ٓRcmr7u cmex10LaTeXML-0.7.0/t/parse/terms.xml0000644002506700454610000002532211214255137015272 0ustar miller891div
Basic math + - + a b c d e - + a b c d e / a b c d e × / × a b c d e
Evaluate At a a b = a 0 c d = c 0 e
Absolute values a a a + a b - a b
Failures w/o Backtracking - a b - a b a b
LaTeXML-0.7.0/t/parse/qm.xml0000644002506700454610000002107711214255137014560 0ustar miller891div Less Than, Greater Than, Bars and Quantum Mechanics
Relations

Relations: a<b<c

Relations: >a

Relations: >a

Quantum Mechanics Notations

Expectation: a

Bra: a

Bra: abc

Bra: =ϕ0

Ket: b

Braket ab

Also afb

Absolute Values

abs a

norm a

expr -ab

nested -ab

non-nested +aabbcc

Mixtures that look like QM

abs and rel: <acc

worse <amin±z-z21/12

LaTeXML-0.7.0/t/parse/functions.tex0000644002506700454610000000165111214255137016147 0ustar miller891div\documentclass{article} \usepackage{latexml} \lxDeclare[role=ID]{$a$}% \lxDeclare[role=ID]{$b$}% \lxDeclare[role=ID]{$c$}% \lxDeclare[role=ID]{$d$}% \lxDeclare[role=ID]{$e$}% \lxDeclare[role=FUNCTION]{$f$}% \lxDeclare[role=FUNCTION]{$g$}% \lxDeclare[role=FUNCTION]{$h$}% \lxDeclare[role=OPFUNCTION]{$F$}% \lxDeclare[role=OPFUNCTION]{$G$}% \lxDeclare[role=OPFUNCTION]{$H$}% \begin{document} \section{Basic Functions} \[ g(a) = g(b) \] \[ f(a) = g(h(c)) \] \[ h(c) = \sin a^2 \] \[ \sin f(a) \] \section{Trigonometric functions} \[ \sin a + \tan b \] \[ \sin a \cos b \neq \sin(a\cos b)\] % Parses wrong ? but how to clarify? \[ \sin 2\pi \neq \log 2x^2 \] \section{Missing arguments} % Presumably these are products \[ f g h \] \[ f g h a \] \section{Operator-like functions} % But these are applied! \[ F G H \] \[ F G H a \] \[ f'(a) = a^2 \] \[ f^2(a) = g^b(2) \] \section{Scripts} \[ \ln a = \log_e a = \ln_{+} b\] \end{document} LaTeXML-0.7.0/t/parse/compose.dvi0000644002506700454610000000132011214255137015557 0ustar miller891div; TeX output 2008.12.15:1147y?>Nff cmbx121VLComps3ositions ՗K`y cmr10( b> cmmi10fLo !", cmsy108g[ٲ)(x)3(fLo8gh)(x)!č>2VLImplicitfflambs3das?HK(y[ٟٓRcmr72,8f)(x)Ц(y[y2,8f)(x)HK(y[ٟ2,8f)(x)HK(fLo8y[ٟ2L)(x)1*;yNff cmbx12 !", cmsy10 b> cmmi10K`y cmr10ٓRcmr7;LaTeXML-0.7.0/t/parse/parens.tex0000644002506700454610000000270611214255137015431 0ustar miller891div\documentclass{article} \usepackage{latexml} \begin{document} \lxDeclare[role=ID]{$a$}% \lxDeclare[role=ID]{$b$}% \lxDeclare[role=ID]{$c$}% \lxDeclare[role=ID]{$d$}% \lxDeclare[role=ID]{$e$}% \section{Basic math} \[ ((a + b) - c) \] \[ (a + (b - c)) \] \section{Intervals} \[ (a,b) \] \[ [a,b) \] \[ (a,b] \] \[ [a,b] \] \section{Cases} \[ \left.\begin{array}{l} a \\ b \end{array}\right\} = \left\{\begin{array}{l} c\\ d\end{array}\right. \] \[ \left(\begin{array}{l} c\\ d\end{array}\right) \] \[ (a + \left(\begin{array}{l} c\\ d\end{array}\right) + b) \] \section{Atop} \[ a + { b \atop c } + d \] \[ a + \left[ b \atop c \right] + d \] \section{Delimiters} \[ \left( {a \over b} \right) \] \[ \left[ {a \over b} \right] \] \[ \left\lbrack {a \over b} \right\rbrack \] \[ \left\{ {a \over b} \right\} \] \[ \left\lbrace {a \over b} \right\rbrace \] \[ \left\lfloor {a \over b} \right\rfloor \] \[ \left\lceil {a \over b} \right\rceil \] \[ \left< {a \over b} \right> \] \[ \left\langle {a \over b} \right\rangle \] \[ \left| {a \over b} \right| \] \[ \left\vert {a \over b} \right\vert \] \[ \left\| {a \over b} \right\| \] \[ \left\Vert {a \over b} \right\Vert \] \[ \left\uparrow {a \over b} \right\downarrow \] \[ \left\Uparrow {a \over b} \right\Downarrow \] \[ \left\updownarrow {a \over b} \right\Updownarrow \] \def\foo{\langle} \def\bar{\rangle} \[ a + \left\foo {b \over c} \right\bar + d \] \[ {a \over b} \left/ {c \over d} \right. \] \end{document} LaTeXML-0.7.0/t/math/0000755002506700454610000000000011215766043013235 5ustar miller891divLaTeXML-0.7.0/t/math/simplemath.xml0000644002506700454610000001042711214255135016120 0ustar miller891div Testing Simple Math Parsing

Inline math +ab.

+ a b 123 + a b f 123 f D f + a b f 1 + a b f a
Restricted + a x b x 123
LaTeXML-0.7.0/t/math/testscripts.tex0000644002506700454610000000015211214255135016336 0ustar miller891div\documentclass{article} \begin{document} $$ f_a, f^a, f_a^a, f^a_a $$ $ {}_a$, ${}^a $ \end{document} LaTeXML-0.7.0/t/math/choose.dvi0000644002506700454610000000161411214255135015215 0ustar miller891div; TeX output 2007.12.03:1218y?>Nff cmbx121VLTfestingffChos3ose>K`y cmr10bGeepUUhello,BEEP*.beep. M1.q b> cmmi10a8+bM2.qǟbu cmex10  0ercmmi7a⾍ p4b ]b hM3.qǵa8+b Նb⾍7c ab/O+dM4.qǵa8+b Նb⾍7c ab/O+dM5.qǵa8+b Նb⾍7c ab/O+dM6.qǟb aٓRcmr7+b⾍ /c+dbb1*;yNff cmbx12 b> cmmi10 0ercmmi7K`y cmr10ٓRcmr7u cmex10LaTeXML-0.7.0/t/math/simplemath.dvi0000644002506700454610000000123411214255135016076 0ustar miller891div; TeX output 2007.12.04:1057y?MK`y cmr10InlineUUmath b> cmmi10a8+b. 4a8+b+1232a8+b+f(123) Ҧ{f 0ercmmi7D@f(a8+b)0fٓRcmr71|s(a8+b)V\q^fa!č>Nff cmbx121VLRestricted~a(x)8+b(x)+1231*;yNff cmbx12 b> cmmi10 0ercmmi7K`y cmr10ٓRcmr7 LaTeXML-0.7.0/t/math/testover.dvi0000644002506700454610000000116011214255135015604 0ustar miller891div; TeX output 2008.08.06:1423y?>Nff cmbx121VLTfestingffOver <$& b> cmmi10abcTwfeY (֍defС޽a<$*bc33wfe s (֍de Bf ޽a<$*bc33wfe s (֍de Bf޽a<$*bc33wfe s (֍de Bf޽a<$*bc33wfe s (֍de BfK`y cmr101*;yNff cmbx12 b> cmmi10K`y cmr10LaTeXML-0.7.0/t/math/testover.tex0000644002506700454610000000053611214255135015630 0ustar miller891div\documentclass{article} \def\beginfoo{\bgroup} \def\endfoo{\egroup} \begin{document} \section{Testing Over} \[ a b c \over d e f \] \[ a {b c \over d e} f \] \[ a {b c \over d e\egroup f \] \[ a \bgroup b c \over d e\egroup f \] \[ a \beginfoo b c \over d e\endfoo f \] % This one is ambiguous! % \[ a { b c \over d \over e} f \] \end{document} LaTeXML-0.7.0/t/math/testscripts.dvi0000644002506700454610000000065411214255135016327 0ustar miller891div; TeX output 2008.12.15:1143y? t b> cmmi10f 0ercmmi7ap;fa;faa;faaMaQpK`y cmr10,UU^a1*;y b> cmmi10 0ercmmi7K`y cmr10CLaTeXML-0.7.0/t/math/simplemath.latexml0000644002506700454610000000125411214255135016764 0ustar miller891divuse LaTeXML::Package; DefMathRewrite(scope=>'label:sec:restricted', match=>'a',attributes=>{role=>'FUNCTION'}); DefMathRewrite(scope=>'label:sec:restricted', match=>'b',attributes=>{role=>'FUNCTION'}); DefMathRewrite(match=>'a', attributes=>{role=>'ID'}); DefMathRewrite(match=>'b', attributes=>{role=>'ID'}); DefMathRewrite(match=>'\hat{f}', attributes=>{role=>'ID'}); DefMathRewrite(match=>'f_D)', attributes=>{role=>'DIFFOP'}); DefMathRewrite(match=>'f_\WildCardA', attributes=>{role=>'ID'}); DefMathRewrite(match=>'f', attributes=>{role=>'FUNCTION'}); DefMathRewrite(match=>'D', attributes=>{role=>'ID'}); DefMathRewrite(match=>'x', attributes=>{role=>'ID'}); LaTeXML-0.7.0/t/math/array.dvi0000644002506700454610000000064411214255135015055 0ustar miller891div; TeX output 2008.08.06:1423y?MK`y cmr10AnUUArrayqǍdD b> cmmi10ae bc ؿgcdؕTef*A/aDb c`dUT>Done.1*;y b> cmmi10K`y cmr10RLaTeXML-0.7.0/t/math/choose.tex0000644002506700454610000000143211214255135015231 0ustar miller891div\documentclass{article} \begin{document} \let\foo={ \let\bar=} \section{Testing Choose} \def\beep{beep} \beep\foo\def\beep{BEEP} hello, \beep. \bar\beep. 1. $ a + b $ 2. $ a \choose b $ 3. $ a + {b \choose c} + d$ % Should also work with these 4. $ a + \bgroup b \choose c \egroup + d$ % And even our own tokens \let to {} 5. $ a + \foo b \choose c \bar + d$ %% Interesting behaviour! \begingroup ..\endgroup do NOT create boxes! 6. $ a + \begingroup b \choose c \endgroup + d$ %$ a + { b \choose c \egroup + d$ %$ a + \bgroup b \choose c } + d$ % Aha, TeX doesn't like this (says Ambiguous) %$ a + \frac{b \choose c}{d \choose e} + f$ %\def\open{\bgroup}\def\close{\bgroup} % It doesn't like this either; it want's a real } %$ a + \open b \choose c \close + d$ \end{document} LaTeXML-0.7.0/t/math/testover.xml0000644002506700454610000001252211214255135015626 0ustar miller891div
Testing Over a b c d e f a b c d e f a b c d e f a b c d e f a b c d e f
LaTeXML-0.7.0/t/math/choose.xml0000644002506700454610000000563511214255135015242 0ustar miller891div
Testing Choose

beep hello, BEEP. beep.

1. +ab

2. ab

3. +abcd

4. +abcd

5. +abcd

6. +ab+cd

LaTeXML-0.7.0/t/math/array.tex0000644002506700454610000000027611214255135015074 0ustar miller891div\documentclass{article} \begin{document} An Array \[ \begin{array}{ccc} a & b & c \\ c & & d \\ \\ e & f \\ \end{array} \] \[ \matrix{a & b \cr c & d} \] Done. \end{document} LaTeXML-0.7.0/t/math/testscripts.xml0000644002506700454610000000414211214255135016341 0ustar miller891div f a f a f a a f a a

a, a

LaTeXML-0.7.0/t/math/array.xml0000644002506700454610000000500611214255135015070 0ustar miller891div

An Array

a b c c d e f a b c d

Done.

LaTeXML-0.7.0/t/math/simplemath.tex0000644002506700454610000000041211214255135016111 0ustar miller891div\documentclass{article} \title{Testing Simple Math Parsing} \begin{document} Inline math $a + b$. $$ a + b + 123$$ $$ a + b + f(123)$$ $$ f_D f(a+b)$$ $$ f_1(a+b)$$ $$ \hat{f} a $$ \section{Restricted}\label{sec:restricted} $$ a(x) + b(x) + 123$$ \end{document} LaTeXML-0.7.0/t/alignment/0000755002506700454610000000000011215766043014262 5ustar miller891divLaTeXML-0.7.0/t/alignment/tabtab.xml0000644002506700454610000000212411214255140016226 0ustar miller891div aa bb c d e f aa bb c d e f LaTeXML-0.7.0/t/alignment/plainmath.dvi0000644002506700454610000000222011214255140016725 0ustar miller891div; TeX output 2008.04.07:22263ڍ& b> cmmi10a_b }cd'bu cmex10ۚavbۚcNd -b ך^ұa_b }cd^䍒ѱsK`y cmr10(x)=\(㍍ +1#Gwhatever  !", cmsy101#Gx<0 0x ̷y+8i+g+y 0ercmmi7n ̷z#&x8+y+zpy+8i+g+ynpq&x ̷y+8i+g+ynC (x) ̷z$x ̷y+8i+g+yn(x) ̷z`1*;3Gu cmex10 !", cmsy10 0ercmmi7 b> cmmi10K`y cmr10LaTeXML-0.7.0/t/alignment/plainmath.xml0000644002506700454610000002733411214255140016760 0ustar miller891div a b c d a b c d a b c d = s x + 1 whatever - 1 < x 0 0 x + y i y n z + x y z + y i y n q x + y i y n x z x + y i y n x z LaTeXML-0.7.0/t/alignment/tabularstar.dvi0000644002506700454610000000037011214255140017300 0ustar miller891div; TeX output 2007.12.03:1223y?SK`y cmr10adb Scdd1*;yK`y cmr10LaTeXML-0.7.0/t/alignment/tabularstar.xml0000644002506700454610000000076511214255140017326 0ustar miller891div a b c d LaTeXML-0.7.0/t/alignment/halign.dvi0000644002506700454610000000062411214255140016220 0ustar miller891div; TeX output 2007.12.03:1223y?HK`y cmr10[u1]a1[v1]{[u2]a2[v2][u3]a3[v3] Ha1{[u2]a2[v2][u3]a3[v3]Ha1[u2]a2[v2][u3]a3[v3]Ha1)[u2]a2[v2]a3Ha2}na3Ha31*;yK`y cmr10VLaTeXML-0.7.0/t/alignment/longtable.dvi0000644002506700454610000000162411214255140016726 0ustar miller891div; TeX output 2008.08.06:1827y?Q$ӍK`y cmr10T*ableUU1:qTheISOGRK3entityUUsetX+bs"V cmbx10En9tityUnicoQdeTNameIHUnicoQde\rff\rfffdbsalphaGREEKUUSMALLLETTERALPHAIH03B1 bsbGetaGREEKUUSMALLLETTERBET*AIH03B2bschiGREEKUUSMALLLETTERCHIIH03C7bsDeltaGREEKUUCAPIT*ALLETTERDELTAIH0394bsdeltaGREEKUUSMALLLETTERDEL*TAIH03B4bsepsiGREEKUUSMALLLETTEREPSILONIH03B5bsepsisGREEKUULUNA*TEEPSILONSYMBOLIH03F5\rff\rff1*;y "V cmbx10K`y cmr10ALaTeXML-0.7.0/t/alignment/mathmix.xml0000644002506700454610000001125011214255140016440 0ustar miller891div
Normal Use t m t m
Perverse Use m t t m t m, n
Very Perverse m m
LaTeXML-0.7.0/t/alignment/halignatt.dvi0000644002506700454610000000221411214255140016726 0ustar miller891div; TeX output 2007.12.03:1224y?H>flff`Ȥfd ffK`y cmr10A*T&TUUCommonStoGckb ffff`ȡ ff bY*ear(fl ff4PriceUٟ ffW#Dividendb ffff`ȡ ff fg1971(fl ff241{54Uٟ ff`3@$2.60b ffff`ȡ fffj2(fl ff241{54Uٟ ffe3A2.70b ffff`ȡ fffj3(fl ff246{55Uٟ ffe3A2.87b ffff`ȡ fffj4(fl ff240{53Uٟ ffe3A3.24b ffff`ȡ fffj5(fl ff245{52Uٟ ffe3A3.40b ffff`ȡ fffj6(fl ff251{59Uٟ ffj3B.95*b ffff`ȟ fd*UU( rstquarteronly)1*;yK`y cmr10NLaTeXML-0.7.0/t/alignment/halignatt.xml0000644002506700454610000000562711214255140016757 0ustar miller891div AT&T Common Stock Year Price Dividend 1971 41–54 $2.60 2 41–54 2.70 3 46–55 2.87 4 40–53 3.24 5 45–52 3.40 6 51–59 .95* * (first quarter only) LaTeXML-0.7.0/t/alignment/halignatt.tex0000644002506700454610000000142411214255140016746 0ustar miller891div\documentclass{article} \begin{document} % From TeX Book, p247 \vbox{\tabskip=0pt \offinterlineskip \def\tablerule{\noalign{\hrule}} %\halign to 5in{\strut#&\vrule#\tabskip=1em plus2em& \halign{\strut#&\vrule#\tabskip=1em plus2em& \hfil#& \vrule#& \hfil#\hfil& \vrule#& \hfil#& \vrule#\tabskip=0pt\cr\tablerule &&\multispan5\hfil AT\&T Common Stock\hfil&\cr\tablerule &&\omit\hidewidth Year\hidewidth&& \omit\hidewidth Price\hidewidth&& \omit\hidewidth Dividend\hidewidth&\cr\tablerule &&1971&&41--54&&\$2.60&\cr\tablerule && 2&&41--54&&2.70&\cr\tablerule && 3&&46--55&&2.87&\cr\tablerule && 4&&40--53&&3.24&\cr\tablerule && 5&&45--52&&3.40&\cr\tablerule && 6&&51--59&&.95\rlap*&\cr\tablerule \noalign{\smallskip} &\multispan7* (first quarter only)\hfil\cr}} \end{document} LaTeXML-0.7.0/t/alignment/mathmix.tex0000644002506700454610000000066211214255140016445 0ustar miller891div\documentclass{article} \begin{document} \section{Normal Use} \begin{tabular}{cc} t & $m$ \end{tabular} \[\begin{tabular}{cc} t & $m$ \end{tabular}\] \section{Perverse Use} \[ \begin{array}{cc} m & $t$ \end{array}\] \[ \begin{array}{cc} \mbox{t} & \mbox{$m$} \end{array}\] \[ \begin{array}{cc} \mbox{t} & \mbox{$m$, $n$} \end{array}\] \section{Very Perverse} \[ \begin{array}{cc} m & $\hbox{$m$}$ \end{array}\] \end{document} LaTeXML-0.7.0/t/alignment/plainmath.tex0000644002506700454610000000075611214255140016757 0ustar miller891div $$ \matrix{a & b \cr c & d} $$ $$ \bordermatrix{a & b \cr c & d} $$ $$ \pmatrix{a & b \cr c & d} $$ $$ s(x) = \cases{+1 & whatever\cr -1 & $x<0$ \cr 0} $$ $$ \eqalign{ x &\ll y+i + \cdots + y_n \cr &\leq z } $$ $$ \eqalign{ x + y + z &\ll y+i + \cdots + y_n \cr & \leq q } $$ $$ \eqalignno{ x &\ll y+i + \cdots + y_n & (x)\cr & \leq z } $$ $$ \leqalignno{ x &\ll y+i + \cdots + y_n & (x)\cr & \leq z } $$ \bye LaTeXML-0.7.0/t/alignment/supertabular.tex0000644002506700454610000000130011214255140017475 0ustar miller891div\documentclass{article} \usepackage{supertabular} \begin{document} \begin{table} \tablecaption{The ISOGRK3 entity set} \tablehead {\bfseries Entity&\bfseries Unicode Name&\bfseries Unicode\\ \hline} \tabletail {\hline \multicolumn{3}{r}{\emph{Continued on next page}}\\} \tablelasttail{\hline} \begin{supertabular}{lll} alpha & GREEK SMALL LETTER ALPHA & 03B1\\ beta & GREEK SMALL LETTER BETA & 03B2\\ chi & GREEK SMALL LETTER CHI & 03C7\\ Delta & GREEK CAPITAL LETTER DELTA & 0394\\ delta & GREEK SMALL LETTER DELTA & 03B4\\ epsi & GREEK SMALL LETTER EPSILON & 03B5\\ epsis & GREEK LUNATE EPSILON SYMBOL & 03F5\\ \end{supertabular} \end{table} \end{document} LaTeXML-0.7.0/t/alignment/morse.xml0000644002506700454610000001506411214255140016125 0ustar miller891div A .- B -... C -.-. D -.. E . F ..-. G --. H .... I .. J .--- K -.- L .-.. M -- N -. O --- P .--. Q --.- R .-. S ... T - U ..- V ...- W .-- X -..- Y -.-- Z --.. 1 .---- 2 ..--- 3 ...-- 4 ....- 5 ..... 6 -.... 7 --... 8 ---.. 9 ----. 0 ----- LaTeXML-0.7.0/t/alignment/eqnarray.tex0000644002506700454610000000131711214255140016616 0ustar miller891div\documentclass{article} \begin{document} \begin{eqnarray} x & = & 17y \label{e1}\\ y & > & a + b + c + d + e + f + g + h + i + j + \nonumber \\ & & k + l + m + n + o + p \label{e2} \\ \end{eqnarray} \begin{eqnarray} x & = & 17y \label{e3}\\ y & > & a + b + c + d + e + f + g + h + i + j + \nonumber \\ & & k + l + m + n + o + p \label{e4} \end{eqnarray} \begin{eqnarray*} x & \ll & y+i + \cdots + y_n \\ & \leq & z \end{eqnarray*} \begin{eqnarray*} y & > & a + b + c + d + e + f + g + h + i + j\\ & & \mbox{} + k + l + m + n + o + p \end{eqnarray*} \begin{eqnarray*} \lefteqn{w+x+y+z=}\\ & & a + b + c + d + e + f + g + h + i + j + \\ & & k + l + m + n + o + p \end{eqnarray*} \end{document} LaTeXML-0.7.0/t/alignment/tabtab.tex0000644002506700454610000000033011214255140016223 0ustar miller891div\documentclass{article} \begin{document} \begin{tabular}{lll} aa & bb & \begin{tabular}{rr} c & d \\ e & f \end{tabular} \\ aa & bb & \begin{tabular}{rr} c & d \\ e & f \end{tabular} \\ \end{tabular} \end{document} LaTeXML-0.7.0/t/alignment/tabtab.dvi0000644002506700454610000000054411214255140016214 0ustar miller891div; TeX output 2007.12.03:1223y?SK`y cmr10aaibbdzcBd zeBfSaaibbdzcBd zeBf1*;y K`y cmr10(LaTeXML-0.7.0/t/alignment/tabularstar.tex0000644002506700454610000000016411214255140017317 0ustar miller891div\documentclass{article} \begin{document} \begin{tabular*}{2in}[t]{lr} a & b\\ c & d\\ \end{tabular*} \end{document} LaTeXML-0.7.0/t/alignment/eqnarray.xml0000644002506700454610000006254211214255140016625 0ustar miller891div = x 17 y x = 17 y > y + a b c d e f g h i j k l m n o p y > + a b c d e f g h i j + + k l m n o p = x 17 y x = 17 y > y + a b c d e f g h i j k l m n o p y > + a b c d e f g h i j + + k l m n o p x + y i y n z x + y i y n z > y + a b c d e f g h i j k l m n o p y > + a b c d e f g h i j + k l m n o p = + w x y z + a b c d e f g h i j k l m n o p = + w x y z + a b c d e f g h i j + + k l m n o p LaTeXML-0.7.0/t/alignment/mathmix.dvi0000644002506700454610000000114411214255140016423 0ustar miller891div; TeX output 2008.08.06:1827y?>Nff cmbx121VLNormalffUsedDK`y cmr10tS b> cmmi10md*]t m!č>2VLPerverseffUse d*]mt d*]t mdײtfm,UUn!č>3VLVferyffPerverse 硍dܸImm1*;yNff cmbx12 b> cmmi10K`y cmr10LaTeXML-0.7.0/t/alignment/morse.tex0000644002506700454610000000140011214255140016112 0ustar miller891div\documentclass{article} \usepackage{array} \begin{document} \begin{tabular}{|l|>{\tt}l||l|>{\tt}l||l|>{\tt}l||l|>{\tt}l||l|>{\tt}l|}\hline A & .- & B & -... & C & -.-. & D & -.. & E & .\\ F & ..-. & G & --. & H & .... & I & .. & J & .---\\ K & -.- & L & .-.. & M & -- & N & -. & O & --- \\ P & .--. & Q & --.- & R & .-. & S & ... & T & - \\ U & ..- & V & ...- & W & .-- & X & -..- & Y & -.-- \\ Z & --.. & & & & & & & & \\\hline 1 & .---- & 2 & ..--- & 3 & ...-- & 4 & ....- & 5 & .....\\ 6 & -.... & 7 & --... & 8 & ---.. & 9 & ----. & 0 & ----- \\\hline \end{tabular} \end{document} LaTeXML-0.7.0/t/alignment/supertabular.dvi0000644002506700454610000000152411214255140017467 0ustar miller891div; TeX output 2008.08.06:1827y?'X-AmK`y cmr10T*ableUU1:qTheISOGRK3entityUUset?-D"V cmbx10En9tityoUnicoQdeTName+UnicoQde>fffdalpha1GREEKUUSMALLLETTERALPHA03B1 bGeta1GREEKUUSMALLLETTERBET*A03B2chi1GREEKUUSMALLLETTERCHI03C7Delta1GREEKUUCAPIT*ALLETTERDELTA0394delta1GREEKUUSMALLLETTERDEL*TA03B4epsi1GREEKUUSMALLLETTEREPSILON03B5epsis1GREEKUULUNA*TEEPSILONSYMBOL03F5ff1*;y"V cmbx10K`y cmr10LaTeXML-0.7.0/t/alignment/morse.dvi0000644002506700454610000000561411214255140016107 0ustar miller891div; TeX output 2007.12.03:1224y? ML͉ff2fd fffdK`y cmr10AG ff [u1]a1[v1] [u2]a2[v2] [u3]a3[v3] a1 [u2]a2[v2] [u3]a3[v3] a1 [u2]a2[v2] [u3]a3[v3] a1 [u2]a2[v2] a3 a2a3 a3 LaTeXML-0.7.0/t/alignment/tabular.dvi0000644002506700454610000000217411214255140016412 0ustar miller891div; TeX output 2007.12.03:1223y?2M˳4ff]fdͤ ff/ǟfdK`y cmr10GG&AUUHoGofedStock/ơ ffff]ff]͟ ff ff ff0[Price  ff*[ ff"ff4 ͤ ff͟fdY*ear ff ff)|low ff<$high? ffquComments ffff]ͤ fffd1971͡ ff ff- 97{<$245 Ο ff\(BadUUyear.*[ ffff]ͤfffd72͡ffff(245{<$245 Οff\(Lighttradingdueto \(aUUheavywinter.*[ffff]ͤfffd73͡ffff(245{<$2001͟ff\(No gnus wasvery \(goGodUUgnusthisyear.*[ffff]1*;y K`y cmr10?LaTeXML-0.7.0/t/alignment/supertabular.xml0000644002506700454610000000332011214255140017501 0ustar miller891div
The ISOGRK3 entity set
Entity Unicode Name Unicode
alpha GREEK SMALL LETTER ALPHA 03B1
beta GREEK SMALL LETTER BETA 03B2
chi GREEK SMALL LETTER CHI 03C7
Delta GREEK CAPITAL LETTER DELTA 0394
delta GREEK SMALL LETTER DELTA 03B4
epsi GREEK SMALL LETTER EPSILON 03B5
epsis GREEK LUNATE EPSILON SYMBOL 03F5
LaTeXML-0.7.0/t/alignment/tabular.xml0000644002506700454610000000361611214255140016432 0ustar miller891div GG&A Hoofed Stock Price Year low high Comments 1971 97– 245 Bad year. 72 245– 245 Light trading due to a heavy winter. 73 245– 2001 No gnus was very good gnus this year. LaTeXML-0.7.0/t/alignment/tabular.tex0000644002506700454610000000105011214255140016420 0ustar miller891div\documentclass{article} % Tabular example from LaTeX manual, p.205 \begin{document} \begin{tabular}{|r||r@{--}l|p{1.25in}|} \hline \multicolumn{4}{|c|}{GG\&A Hoofed Stock} \\ \hline\hline &\multicolumn{2}{c|}{Price}& \\ \cline{2-3} \multicolumn{1}{|c||}{Year} & \multicolumn{1}{r@{\,\vline\,}}{low} & high & \multicolumn{1}{c|}{Comments} \\ \hline 1971 & 97 & 245 & Bad year.\\ \hline 72 & 245 & 245 & Light trading due to a heavy winter. \\ \hline 73 & 245 & 2001 & No gnus was very good gnus this year. \\ \hline \end{tabular} \end{document} LaTeXML-0.7.0/t/alignment/eqnarray.dvi0000644002506700454610000000231411214255140016576 0ustar miller891div; TeX output 2008.08.06:1827y?B b> cmmi10xK`y cmr10=17y8(1)y>a8+b+c+d+e+fLo+g+h+i+jk+kw+8lk@+m+n+o+p8(2)8(3)Bxٲ=17y8(4)y>a8+b+c+d+e+fLo+g+h+i+jk+kw+8lk@+m+n+o+p8(5) xƪ) !", cmsy10ڪ*y+8i+g+y 0ercmmi7nƛڪ*z>y6>Ta8+b+c+d+e+fLo+g+h+i+j4+8kw+lk@+m+n+o+pw}ò+8x+y+z7=ڵa8+b+c+d+e+fLo+g+h+i+jk+ڵkw+8lk@+m+n+o+p1*;y !", cmsy10 b> cmmi10 0ercmmi7K`y cmr10OLaTeXML-0.7.0/t/alignment/longtable.tex0000644002506700454610000000133611214255140016744 0ustar miller891div\documentclass{article} \usepackage{longtable} \begin{document} \begin{longtable}{lll} \caption{The ISOGRK3 entity set}\\ \bfseries Entity&\bfseries Unicode Name&\bfseries Unicode\\ \hline \endfirsthead \bfseries Entity&\bfseries Unicode Name&\bfseries Unicode\\ \hline \endhead \hline \multicolumn{3}{r}{\emph{Continued on next page}}\\ \endfoot \hline \endlastfoot alpha & GREEK SMALL LETTER ALPHA & 03B1\\ beta & GREEK SMALL LETTER BETA & 03B2\\ chi & GREEK SMALL LETTER CHI & 03C7\\ Delta & GREEK CAPITAL LETTER DELTA & 0394\\ delta & GREEK SMALL LETTER DELTA & 03B4\\ epsi & GREEK SMALL LETTER EPSILON & 03B5\\ epsis & GREEK LUNATE EPSILON SYMBOL & 03F5\\ \end{longtable} \end{document} LaTeXML-0.7.0/t/alignment/halign.tex0000644002506700454610000000046011214255140016234 0ustar miller891div\documentclass{article} \begin{document} \tabskip=1em \halign{\hfil [u1]#[v1]\hfil&\hfil [u2]#[v2]\hfil&\hfil [u3]#[v3]\hfil\cr a1& a2& a3\cr \omit a1& a2& a3\cr \omit a1\span a2& a3\cr \omit a1\span a2\span\omit a3\cr \omit\span\omit a2 \span\omit a3\cr \omit\span\omit\span\omit a3\cr } \end{document} LaTeXML-0.7.0/t/alignment/longtable.xml0000644002506700454610000000356611214255140016753 0ustar miller891div
The ISOGRK3 entity set
Entity Unicode Name Unicode
alpha GREEK SMALL LETTER ALPHA 03B1
beta GREEK SMALL LETTER BETA 03B2
chi GREEK SMALL LETTER CHI 03C7
Delta GREEK CAPITAL LETTER DELTA 0394
delta GREEK SMALL LETTER DELTA 03B4
epsi GREEK SMALL LETTER EPSILON 03B5
epsis GREEK LUNATE EPSILON SYMBOL 03F5
LaTeXML-0.7.0/t/graphics/0000755002506700454610000000000011215766042014103 5ustar miller891divLaTeXML-0.7.0/t/graphics/mykeyval.sty.ltxml0000644002506700454610000000265711214255137017653 0ustar miller891divuse LaTeXML::Package; package LaTeXML::Package::Pool; RequirePackage('keyval'); #====================================================================== # Tests of various constructors using KeyVals. #====================================================================== DefKeyVal('foo','path','Semiverbatim'); # Testing simple use of keys; # attribute is just list of key-value pairs. DefConstructor('\KVsimple OptionalKeyVals:foo', ""); # Testing more complex use of keys; # individual attributes are obtained from specific keys. DefConstructor('\KVcomplex OptionalKeyVals:foo', ""); # Testing use in an environment. DefEnvironment('{KVenv} OptionalKeyVals:foo', "#body"); # Testing structured use of keys; map an XML structure to the keys (eg. for amsrefs) DefEnvironment('{KVstruct} OptionalKeyVals:foo', "" ."?&KeyVal(#1,width)(Width: &KeyVal(#1,width))" ."&" ."?&KeyVal(#1,height)(Height: &KeyVal(#1,height))" ."#body"); # Testing automatic conversion of keys to text DefConstructor('\KVauto RequiredKeyVals:foo',"#1"); #====================================================================== 1; LaTeXML-0.7.0/t/graphics/picture.xml0000644002506700454610000002575011214255137016306 0ustar miller891div
Basic

Math: =ab

Pictures Lines:

using integers, scaling with floats, LaTeXcounters, TeX counters. All should be the same.

Vectors: Boxes; A A A A

A B C D

A B C D

Circles: Curves: Repeats: a a a a a a a a a a a
LaTeXML-0.7.0/t/graphics/keyval.dvi0000644002506700454610000000222411214255137016077 0ustar miller891div; TeX output 2007.12.03:1232y?MK`y cmr10SimpleUUKVnooptions:qGraphics[] MSimpleUUKVwithoptions:qGraphics[]MComplexUUKVnooptions:qGraphics[]MComplexUUKVwithoptions:qGraphics[]MFilenamesUUGraphics[]MFilenamesUU"V cmbx10Graphics[]MKVEnvironmentnooptions:VBeginT*ext[]Insidetheenvironment./EndText>AfterUUtheenvironment.MKV$EnvironmentMwithoptions:BeginT*ext[]Insidetheenvironment.TEnd->T*extUUAftertheenvironment.MKVeEnvironmentewithestructurenooptions:YBeginT*ext[]Insidetheenviron->ment.qEndT*extUUAftertheenvironment.MKVEnvironment%with&structurewithoptions:hBeginT*ext[]Insidetheenvi->ronment.qEndT*extUUAftertheenvironment.MKVUUautomaticconversionUUtostructureT*ext[]1*;y"V cmbx10K`y cmr10?LaTeXML-0.7.0/t/graphics/keyval.tex0000644002506700454610000000163311214255137016120 0ustar miller891div\documentclass{article} \usepackage{mykeyval} \begin{document} Simple KV no options: \KVsimple Simple KV with options: \KVsimple[width=100, height=200] Complex KV no options: \KVcomplex Complex KV with options: \KVcomplex[width=100, height=200] Filenames \KVsimple[path=a_dir/~foo.bar] Filenames \textbf{\KVsimple[path=a_dir/~foo.bar]} KV Environment no options: \begin{KVenv} Inside the environment. \end{KVenv} After the environment. KV Environment with options: \begin{KVenv}[width=100, height=200] Inside the environment. \end{KVenv} After the environment. KV Environment with structure no options: \begin{KVstruct} Inside the environment. \end{KVstruct} After the environment. KV Environment with structure with options: \begin{KVstruct}[width=100, height=200] Inside the environment. \end{KVstruct} After the environment. KV automatic conversion to structure \KVauto{width=100, height=200} \end{document} LaTeXML-0.7.0/t/graphics/picture.tex0000644002506700454610000000405211214255137016276 0ustar miller891div\documentclass{article} %\usepackage{graphpap} \begin{document} \section{Basic} Math: $a=b$ \begin{picture}(100,100) \put(0,0){\line(1,0){100}} \end{picture} %\end{document} \section{Pictures} \paragraph{Lines:} using integers, scaling with floats, \LaTeX counters, TeX counters. All should be the same. \par \begin{picture}(100,100) \put(0,0){\line(1,0){100}} \put(0,0){\line(1,1){50}} \put(0,0){\line(0,1){100}} \end{picture} {\unitlength=100pt\relax \begin{picture}(1.0,1.0) \put(0,0){\line(1,0){1.0}} \put(0,0){\line(1,1){0.5}} \put(0,0){\line(0,1){1.0}} \end{picture} } \newcounter{foo} \setcounter{foo}{50} \begin{picture}(100,100) \put(0,0){\line(1,0){100}} %\put(0,0){\line(1,1){100}} \put(0,0){\line(1,1){\value{foo}}} \put(0,0){\line(0,1){100}} \end{picture} \newcount\ffoo\ffoo=50\relax \begin{picture}(100,100) \put(0,0){\line(1,0){100}} %\put(0,0){\line(1,1){100}} \put(0,0){\line(1,1){\ffoo}} \put(0,0){\line(0,1){100}} \end{picture} %\end{document} \paragraph{Vectors:} \begin{picture}(100,100)(-100,-100) \put(0,0){\vector(-1, 0){100}} \put(0,0){\vector(-1,-1){100}} \put(0,0){\vector( 0,-1){100}} \end{picture} \paragraph{Boxes;} \begin{picture}(100,100) \put(0,0){\bf A} \put(15,15){\framebox(15,15){A}} \put(30,30){\framebox(15,15){\bf A}} \put(45,45){\framebox(15,15){A}} \put(60,20){\frame{\shortstack{A\\B\\\bf C\\D}}} \put(75,20){\framebox(15,80){\shortstack{A\\\bf B\\C\\D}}} \end{picture} \paragraph{Circles:} \begin{picture}(100,100) \put(30,30){\circle{30}\vector(0,1){15}\circle*{5}} \put(70,70){\oval(60,30)} \end{picture} \vskip 1em \paragraph{Curves:} \begin{picture}(100,100) \qbezier(40,80)(80,120)(100,80) \qbezier[50](40,89)(80,129)(100,89) \end{picture} \paragraph{Repeats:} \begin{picture}(100,100) \multiput(0,0)(10,10){11}{a} \end{picture} \begin{picture}(100,100) \put(10,10){\circle{5}} \put(20,20){\framebox(10,10){\circle{5}}} \put(30,30){\framebox(10,10)[l]{\circle{5}}} \put(40,40){\framebox(10,10)[r]{\circle{5}}} \put(50,50){\framebox(10,10)[t]{\circle{5}}} \put(60,60){\framebox(10,10)[b]{\circle{5}}} \end{picture} \end{document} LaTeXML-0.7.0/t/graphics/mykeyval.sty0000644002506700454610000000033011214255137016476 0ustar miller891div\newcommand{\KVsimple}[1][]{Graphics[]} \newcommand{\KVcomplex}[1][]{Graphics[]} \newenvironment{KVenv}[1][]{BeginText[]}{EndText} \newenvironment{KVstruct}[1][]{BeginText[]}{EndText} \newcommand{\KVauto}[1]{Text[]} LaTeXML-0.7.0/t/graphics/keyval.xml0000644002506700454610000000313511214255137016117 0ustar miller891div

Simple KV no options:

Simple KV with options:

Complex KV no options:

Complex KV with options:

Filenames

Filenames

KV Environment no options: Inside the environment. After the environment.

KV Environment with options: Inside the environment. After the environment.

KV Environment with structure no options: &amp; Inside the environment. After the environment.

KV Environment with structure with options: Width: 100&amp;Height: 200 Inside the environment. After the environment.

KV automatic conversion to structure width=100, height=200

LaTeXML-0.7.0/t/graphics/picture.dvi0000644002506700454610000002606411214255137016267 0ustar miller891div; TeX output 2008.04.25:0856y?>Nff cmbx121VLBasicn>K`y cmr10Math:q b> cmmi10a=bUU32fdd!č>2VLPictures>"V cmbx10Lines: using integers,<scaling with oats,L5ffٓRcmr7A͉TU>'ExXcounters,T*eX counters.All >shouldUUbGethesame.eM32fddMO line10WakuL΄dfeUU32fddUUUUUUUUUU"#dfeM32fddMWakuL΄dfeUU32fddUUUUUUUUUU"#dfer6>V ectors: 32fddάdZPF<2(   mτdfen?1*y?>>Bo9xes; AfeʟfeꪍAfefefeʎ'feʟfe9'Afefefeʎ6feʟfeꪍAfefefeʎEǣfe $\n$\nfex捍gA TpB rCUTDN6$\nfefefe TfeʟPPfe.7x捍A rhB T㎲C9DPfefefeʎt>Circles:Ο33< lcircle10'ϟfe(6(t3311Ο͉fe3333mmΟ͉fe33@33fe @33fe r6>Curv9es:1ϟ32fdfe1 fdfe23Pfdfe2f„fdfe2hrfdfe26gfdfe2۟fdfe31fdfe3dWʄfdfe3pƄfdfe3ə@fdfe3"fdfe4.Ffdfe4`=fdfe4Ofdfe4ŗP fdfe4ϟ ҄fdfe5)柬̄fdfe5[fdfe5fdfe5fvfdfe5⟬8sfdfe6# Ƅfdfe6Ui[fdfe62fdfe6ş2fdfe6[Vfdfe7៫*(fdfe7M;fdfe7~&fdfe7jfdfe7:{ fdfe8oOfdfe8Cs%fdfe8t`fdfe8 fdfe8fdfe9c|$fdfe98Rnfdfe9hԟ)fdfe9fdfe9*Gfdfe9fdfe:+@Lfdfe:[^Ffdfe:韨6fdfe:;fdfe:}瑄fdfe;fdfe;LՄfdfe;|sZfdfe;Lfdfe;ܣ&fdfe< @fdfe<<̄fdferfdfe>EmPfdfe>t{-fdfe>y fdfe>gvfdfe?E܄fdfe?/͟fdfe?^nfdfe?7dfdfe?ԟCfdfe?a#nfdfe@_fdfe@F㒄fdfe@u[úfdfe@pfdfe@㟣hfdfeAffdfeA-ڟG̈́fdfeA[埣)fdfeA fdfeA˟ʄfdfeA妟MfdfeBfdfeB@՟„fdfeBny fdfeB\fdfeBɣ@fdfeBŸ$fdfeC$+bfdfeCQfdfeC~͟hfdfeC|fdfeCϟ҄fdfeD矡jfdfeD2gDfdfeD_矡LfdfeDϟ3ZfdfeDfdfeD ڄfdfeE疄fdfeE?gfdfeEkfdfeEfdfeEđGfdfeEnfdfeFMW_fdfeFI@NfdfeFuɟ)fdfeFfdfeF͔6fdfeF,fdfeG%dfdfeGQsjfdfeG|ӟ%fdfeG"fdfeGK{afdfeGfjfdfeH+R,fdfeHW>0fdfeH*vfdfeHcfdfeHضKfdfeIVfdfeI/,ݣfdfeIYϟ2fdfeI៞fdfeI㟞fdfeI՟fdfeJ~fdfeJ0qфfdfeJZş`fdfeJvPEfdfeJ?fdfeJڨ/8fdfeKXfdfeK/fdfeKYo^fdfeKDfdfeKބfdfeK/GfdfeLfdfeL+Ο߄fdfeLU͟|fdfeLfdfeLfdfeL՟fdfeLs2fdfeM&AffdfeMOߟZbfdfeMymN]fdfeMQBfdfeM˾6~fdfeM+>fdfeNh @fdfeNGfdfeNp3 kfdfeNO2fdfeN[;fdfeNW솄fdfeOCpfdfeO=>fdfeOeFNfdfeOǠfdfeOfdfeOGbfdfePҟyfdfeP/҄fdfePX mfdfePgfdfePfdfeP럜fdfePffdfeQ |fdfeQHwfdfeQpq~fdfeQjl'fdfeQCf^fdfeQWafdfeR\fdfeR6XfdfeR^OTfdfeRןPfdfeRLfdfeRIAfdfeRSF:fdfeS"BfdfeSIџ@4fdfeSp9=fdfeSO;fdfeSU9sfdfeSK7fdfeT 16fdfeT2C5„fdfeTY4FfdfeT3ЄfdfeTb3fdfeT3fdfeT|3fdfeU'3„fdfeU?4fdfeUeߟ5fdfeU#7fdfeUW7̄fdfeU׬9fdfeU;„fdfeV#Ÿ> fdfeVI?fdfeVoBτfdfeVEfdfeVYIWfdfeV LfdfeWPfdfeW+?T:fdfeWO蟜XfdfeWuY]TfdfeWaifdfeW ffdfeWLl fdfeX }q„fdfeX.vڄfdfeXSϟ}fdfeXxϟfdfeXHfdfeXŸFfdfeX拟fdfeY J#fdfeY/fdfeYTfdfeYy'JfdfeY҄fdfeY+ǜfdfeY剟ШfdfeZ ן fdfeZ.♄fdfeZQUjfdfeZur}fdfeZfdfeZ| xfdfeZiPfdfe[F jfdfe[(+Ƅfdfe[K۟6ofdfe[oBNfdfe[#Nofdfe[Z҄fdfe[2f~fdfe[sdfdfe\fdfe\CCfdfe\f~fdfe\fdfe\şfdfe\ϟ2fdfe\ɟfdfe]؄fdfe]6fdfe]YSfdfe]| @fdfe]6fdfe]N/sfdfe]ן?fdfe^GPfdfe^'`fdfe^Jqfdfe^lOvfdfe^>fdfe^Hfdfe^Ѹfdfe^󿟞fdfe_fdfe_7fdfe_Xa2fdfe_z'Ƅfdfe_ݟ*fdfe_>fdfe_Qfdfe`ffdfe` {ofdfe`Bafdfe`cfdfe`vfdfe`0Zfdfe`7怄fdfe`KfdfeaOrfdfea)C)]fdfeaJ'@fdfeai؟WfdfeanfdfeaNxfdfea񟠞fdfea섟"fdfeb ߟβfdfeb,Q竄fdfebLfdfebmcfdfebG4"fdfebyLfdfebmg8fdfeb~fdfec fdfec,pYfdfecLQѢfdfecj-fdfecfdfec_#Ԅfdfec@$fdfec鏟\fdfedןyfdfed'FfdfedFfdfedeWfdfed32fdfed% OfdfedC)pfdfedQHfdfeeOffdfee=fdfee>:fdfee[fdfeezcʄfdfeefdfee$bfdfee:Cʄfdfeeodfdfef۟fdfef07`fdfefN˄fdfefl„fdfef fdfef.vfdfefğOfdfef㿟rfdfeg"fdfeg3fdfeg;fdfegYfdfegwa$afdfegHfdfegmfdfegΧjfdfegfdfeh iHfdfeh&fdfehC럧&҄fdfeh_M'fdfeh|ϟsfdfehןfdfehϟRfdfehӷ箄fdfeh-Lfdfei 7,fdfei(_NfdfeiERMfdfeia韨fdfei} لfdfeifdfei埩)fdfei;Rfdfei|fdfej ΄fdfej%pӄfdfejAfdfej]%{fdfejyPfdfejd|+fdfejǟtfdfejˋpfdfej?fdfek㟫+.fdfekwVzfdfek8}fdfekS„fdfekoZIfdfek fdfek8fdfek#ffdfekɟ|fdfek۟΄fdfelݟ߄fdfel+ϟ!2fdfelFPDŽfdfel`fdfelzŸ4fdfelsߎfdfel*fdfelʥAfdfel㟟pfdfelfdfemoӥfdfem2fdfemL6&fdfemehfdfemŸ8fdfemџ$fdfemПRfdfemͿ32fdfe1ϟ32fdfe3d\ʄfdfe4џ Ąfdfe6+ fdfe8oOބfdfe9fdfe;fdferfdfe?Rd[fdfe@fffdfeBnxӄfdfeCfdfeE?tfdfeFştfdfeGfjfdfeIZ„fdfeJ?|fdfeLĘfdfeMOߟZ)fdfeN fdfeO2MfdfeQ |fdfeR^8SfdfeS;bfdfeTş3-fdfeU;tfdfeW+ TfdfeXS럓|fdfeYxПJfdfeZfdfe[3Zfdfe\ϟĒfdfe]S?fdfe^󿟕΄fdfe_fofdfea+rfdfeb Nׄfdfec 3fdfed%xDŽfdfedfRfdfeedhfdfefArfdfegҟjfdfehK~fdfeifdfejxǟŌfdfekSfdfel+ ҄fdfelޟфfdfemş32fdfe>RepQeats: aaa(a2a<aFaPaZadanafǍWd`fe ʟ fed fefefe ʎjfe ʟ fed fefefe ʎtfe ʟ fed fefefe ʎ~fe ʟ fed fefefe ʎfe ʟ fed fefefe ʎ2o;y"V cmbx10Nff cmbx12 b> cmmi10K`y cmr10ٓRcmr7< lcircle10O line10+pLaTeXML-0.7.0/t/expansion/0000755002506700454610000000000011215766043014310 5ustar miller891divLaTeXML-0.7.0/t/expansion/testif.dvi0000644002506700454610000000127411214255140016304 0ustar miller891div; TeX output 2007.12.03:1209y?MK`y cmr10T*estUULettersAandA(True):True. MT*estUULettersAandB(False):qFalse.MT*estAUUandB(True):qTrue.MT*estAUUandC(False):qFalse.MNestedUU(T*rueFalse)TrueFalse.qNested(FalseTrue)FalseTrue.MT*estUUlet (TrueFalse);TrueFalse.MT*estUUletelse(TrueFalse);TrueFalse.MifxUUdoGesNOTexpandconditionaltokens(fooF*alse):qfooFalse.1*;yK`y cmr10}LaTeXML-0.7.0/t/expansion/environments.dvi0000644002506700454610000000047011214255140017532 0ustar miller891div; TeX output 2007.12.03:1208y?WK`y cmr10AUUQuote!WMY WAUUQuote!W1WAUUQuote!WONEWAUUQuote!1*;yK`y cmr10LaTeXML-0.7.0/t/expansion/for.xml0000644002506700454610000000076411214255140015615 0ustar miller891div

×abc

LaTeXML-0.7.0/t/expansion/testchar.tex0000644002506700454610000000267711214255140016651 0ustar miller891div\documentclass{article} \def\eatone#1{} \def\eatnone#1{#1} \newcommand{\onearg}[1]{(onearg: #1)} \newcommand{\twoarg}[2]{(twoarg: #1 ; #2)} \newcommand{\twoargopt}[2][missing]{(twoargopt: #1 ; #2)} \def\textwoarg#1#2{(textwoarg: #1 ; #2)} \begin{document} \section{Testing} Testing raw tex macros: Expect inline math: xx\eatone$$a+b\eatone$$xx Expect display math: xx\eatnone$$a+b\eatnone$$xx Expect 2 empty maths: xx$ $a+b$ $xx Testing latex macros Expect (onearg: one) \onearg{one} Expect (twoarg: one two) \twoarg{one}{two} Expect (twoargopt: one ; two) \twoargopt[one]{two} Expect (twoargopt: missing ; two)\twoargopt{two} Testing whitespace: Expect (twoarg: a ; b) \twoarg {a} {b} Expect (textwoarg: a ; b) \textwoarg {a} {b} Expect (twoargopt: a ; b) \twoargopt [a] {b} \expandafter\def\expandafter\baz\eatone##1{(#1)} Expecting (beep) : \baz{beep} \expandafter\def\expandafter\bloop\expandafter{\baz{foo}} Expecting (foo) : \bloop %\expandafter\def\expandafter\blorp\expandafter{\textrm{foo}} %\blorp %\section{Error inside arg \stoopid undefined macro} \def\inside#1{[[#1]]} \def\outside{\inside{x}} \def\deftoo#1{{\def\inside##1{(#1(##1)#1)}\outside}} Expect [[x]] : \outside Expect (y(x)y) : \deftoo{y} Expect [[x]] : \outside \def\now#1{NOW #1} \def\later#1{LATER #1} \edef\expanded{\now{a} \later{b} \noexpand\later{c}} \def\later#1{MUCHLATER #1} Expect NOW a LATER b MUCHLATER c: \expanded \end{document} LaTeXML-0.7.0/t/expansion/env.tex0000644002506700454610000000021211214255140015603 0ustar miller891div\documentclass{article} % Test undefined environs \def\foo{Foo} \begin{document} before \begin{foo} inside \end{foo} after \end{document} LaTeXML-0.7.0/t/expansion/testif.xml0000644002506700454610000000150411214255140016316 0ustar miller891div

Test Letters A and A (True) : True .

Test Letters A and B (False) : False.

TestA and B (True) : True .

TestA and C (False) : False.

Nested (True False) True False. Nested (False True) False True .

Test let fi (True False); True False.

Test let else (True False); True False.

ifx does NOT expand conditional tokens (fooFalse): fooFalse.

LaTeXML-0.7.0/t/expansion/testexpand.tex0000644002506700454610000000065611214255140017206 0ustar miller891div\documentclass{article} \def\eatone#1{} \begin{document} \section{Testing} \expandafter\def\expandafter\baz\eatone##1{(#1)} Expecting (beep) : \baz{beep} \expandafter\def\expandafter\bloop\expandafter{\baz{foo}} Expecting (foo) : \bloop \def\bar{(Bar)} Expecting (Bar): \bar { \def\bar{BAR} Expecting (BAR): \bar } Expecting (Bar): \bar { \global\def\bar{BAR} Expecting (BAR): \bar } Expecting (BAR): \bar \end{document} LaTeXML-0.7.0/t/expansion/env.xml0000644002506700454610000000034611214255140015613 0ustar miller891div

before Foo inside after

LaTeXML-0.7.0/t/expansion/environments.tex0000644002506700454610000000057711214255140017560 0ustar miller891div\documentclass{article} \newenvironment{myquote}{\begin{quote} MY\\}{\end{quote}} \newenvironment{quote1}{\begin{quote} 1\\}{\end{quote}} \begin{document} \begin{quote} A Quote! \end{quote} \begin{myquote} A Quote! \end{myquote} \begin{quote1} A Quote! \end{quote1} \renewenvironment{quote1}{\begin{quote} ONE\\}{\end{quote}} \begin{quote1} A Quote! \end{quote1} \end{document} LaTeXML-0.7.0/t/expansion/for.tex0000644002506700454610000000055011214255140015606 0ustar miller891div\documentclass{article} \makeatletter % building associative functions. Using \def\disj{\assoc\vee}, % $\disj{a,b,c}$ evaluates to (a\vee b\vee c) % \bassoc, is a variant of assoc with brackets around \def\assoc#1#2{\let\@tmpop\relax\@for\@I:=#2\do{\@tmpop\@I\let\@tmpop#1}} \def\disj{\assoc\times} \makeatother \begin{document} $\disj{a,b,c}$ \end{document} LaTeXML-0.7.0/t/expansion/for.dvi0000644002506700454610000000050011214255140015563 0ustar miller891div; TeX output 2007.12.03:1208y?M b> cmmi10a8 !", cmsy10bcK`y cmr101*;y !", cmsy10 b> cmmi10K`y cmr10LaTeXML-0.7.0/t/expansion/testexpand.dvi0000644002506700454610000000103411214255140017157 0ustar miller891div; TeX output 2007.12.03:1209y?>Nff cmbx121VLTfesting>K`y cmr10ExpGectingUU(beep):q(beep) MExpGectingUU(foo):q(foo)MExpGectingUU(Bar):q(Bar)MExpGectingUU(BAR):BARMExpGectingUU(Bar):q(Bar)MExpGectingUU(BAR):BARMExpGectingUU(BAR):BAR1*;yNff cmbx12K`y cmr10LaTeXML-0.7.0/t/expansion/testchar.xml0000644002506700454610000000365611214255140016647 0ustar miller891div
Testing

Testing raw tex macros: Expect inline math: xx+abxx

Expect display math: xx

+ a b

xx

Expect 2 empty maths: xxa+bxx

Testing latex macros Expect (onearg: one) (onearg: one) Expect (twoarg: one two) (twoarg: one ; two) Expect (twoargopt: one ; two) (twoargopt: one ; two) Expect (twoargopt: missing ; two)(twoargopt: missing ; two)

Testing whitespace: Expect (twoarg: a ; b) (twoarg: a ; b) Expect (textwoarg: a ; b) (textwoarg: a ; b) Expect (twoargopt: a ; b) (twoargopt: a ; b)

Expecting (beep) : (beep)

Expecting (foo) : (foo)

Expect [[x]] : [[x]]Expect (y(x)y) : (y(x)y) Expect [[x]] : [[x]]

Expect NOW a LATER b MUCHLATER c: NOW a LATER b MUCHLATER c

LaTeXML-0.7.0/t/expansion/testchar.dvi0000644002506700454610000000253411214255140016623 0ustar miller891div; TeX output 2007.12.03:1208y?>Nff cmbx121VLTfesting>K`y cmr10T*estingUUrawtexmacros:qExpGectinlinemath:xx b> cmmi10a8+bxx MExpGectUUdisplaymath:qxxߙa8+b>xxMExpGectUU2emptymaths:qxxa+bxxMT*estinglatexmacrosExpGect(onearg:Āone)(onearg:one)Expect(twoarg:>onetwo)(twoarg:1one;%two)ExpGect(twoargopt:1one;%two)(twoargopt:1one;>two)UUExpGect(twoargopt:qmissingUU;two)(twoargopt:missingUU;two)MT*esting8whitespace:ExpGect(twoarg:a8;b)(twoarg:a8;b)ExpGect(textwoarg:>aUU;b)(textwoarg:qaUU;b)ExpGect(twoargopt:aUU;b)(twoargopt:aUU;b)MExpGectingUU(beep):q(beep)MExpGectingUU(foo):q(foo)MExpGectUU[[x]]:q[[x]]Expect(y(x)y):q(y(x)y)Expect[[x]]:q[[x]]MExpGectwNOWwaLA*TERbMUCHLA*TERwc:NOWaLA*TERbMUCH->LA*TERUUc1*;yNff cmbx12 b> cmmi10K`y cmr10LaTeXML-0.7.0/t/expansion/environments.xml0000644002506700454610000000067011214255140017552 0ustar miller891div A Quote! MY A Quote! 1 A Quote! ONE A Quote! LaTeXML-0.7.0/t/expansion/env.dvi0000644002506700454610000000037411214255140015576 0ustar miller891div; TeX output 2007.12.03:1208y?MK`y cmr10bGeforeUUF*ooinsideafter1*;yK`y cmr10LaTeXML-0.7.0/t/expansion/testif.tex0000644002506700454610000000204011214255140016312 0ustar miller891div\documentclass{article} \begin{document} \def\testA{foo} \def\testB{foo} \def\testC{bar} Test Letters A and A (True) : \ifx AA True \else False\fi. Test Letters A and B (False) : \ifx AB True \else False\fi. TestA and B (True) : \ifx\testA\testB True \else False\fi. TestA and C (False) : \ifx\testA\testC True \else False\fi. Nested (True False) \ifx\testA\testB True \ifx\testA\testC True \else False\fi \else False \ifx\testA\testC True \else False\fi\fi. Nested (False True) \ifx\testA\testC True \ifx\testA\testB True \else False\fi \else False \ifx\testA\testB True \else False\fi\fi. \let\endif\fi Test let fi (True False); \ifx\testA\testB True \ifx\testA\testC True \else False\endif \else False\ifx\testA\testC True \else False\endif\endif. \let\otherwise\else Test let else (True False); \ifx\testA\testB True \ifx\testA\testC True \otherwise False\endif \otherwise False\ifx\testA\testC True \otherwise False\endif\endif. ifx does NOT expand conditional tokens (fooFalse): \ifx\iftrue\testA True\else\testB False\fi. \end{document} LaTeXML-0.7.0/t/expansion/testexpand.xml0000644002506700454610000000136211214255140017201 0ustar miller891div
Testing

Expecting (beep) : (beep)

Expecting (foo) : (foo)

Expecting (Bar): (Bar)

Expecting (BAR): BAR

Expecting (Bar): (Bar)

Expecting (BAR): BAR

Expecting (BAR): BAR

LaTeXML-0.7.0/t/namespace/0000755002506700454610000000000011215766043014240 5ustar miller891divLaTeXML-0.7.0/t/namespace/ns4.dtd0000644002506700454610000000040411214255136015432 0ustar miller891div LaTeXML-0.7.0/t/namespace/ns5.dtd0000644002506700454610000000035411214255136015437 0ustar miller891div LaTeXML-0.7.0/t/namespace/ns1.latexml0000644002506700454610000000142311214255136016324 0ustar miller891divuse strict; use LaTeXML::Package; #====================================================================== # Namespace tests ns1.tex, ns2.tex, ns3.tex... # The TeX sources are identical #====================================================================== # Case 1: The DTD and code use no Namespaces. # The XML output should also have no namespaces. #====================================================================== DocType("song","-//NIST LaTeXML//LaTeXML Poem",'ns1.dtd'); Tag('song', autoOpen=>1, autoClose=>1); Tag('verse', autoOpen=>1, autoClose=>1); Tag('line', autoOpen=>1, autoClose=>1); DefConstructor('\bigskip',""); DefConstructor('\par',sub{ $_[0]->maybeCloseElement('line'); }); #********************************************************************** 1; LaTeXML-0.7.0/t/namespace/ns1.dvi0000644002506700454610000000056411214255136015445 0ustar miller891div; TeX output 2007.10.29:18103ڍ&K`y cmr10Twinkle,UUtwinklelittlestar, HowUUIwonderwhatyouare.UpUUabGovetheworldsohigh,LikeUUadiamondinthesky`1*;3GK`y cmr107LaTeXML-0.7.0/t/namespace/ns5.tex0000644002506700454610000000021011214255136015453 0ustar miller891divTwinkle, twinkle little star,\par How I wonder what you are.\bigskip Up above the world so high,\par Like a diamond in the sky\par \bye LaTeXML-0.7.0/t/namespace/ns2.dtd0000644002506700454610000000026111214255136015431 0ustar miller891div LaTeXML-0.7.0/t/namespace/ns4.xml0000644002506700454610000000075011214255136015463 0ustar miller891div Twinkle, twinkle little star, How I wonder what you are. Up above the world so high, Like a diamond in the sky LaTeXML-0.7.0/t/namespace/ns3.xml0000644002506700454610000000075011214255136015462 0ustar miller891div Twinkle, twinkle little star, How I wonder what you are. Up above the world so high, Like a diamond in the sky LaTeXML-0.7.0/t/namespace/ns3.latexml0000644002506700454610000000172111214255136016327 0ustar miller891divuse strict; use LaTeXML::Package; #====================================================================== # Namespace tests ns1.tex, ns2.tex, ns3.tex... # The TeX sources are identical #====================================================================== # Case 3: The DTD uses the prefix "example" for the namespace http://example.com/ # The XML output should use the same prefix. # The code will use the prefix "incode" for the same namespace #====================================================================== RegisterNamespace(incode=>"http://example.com/"); DocType("incode:song","-//NIST LaTeXML//LaTeXML Poem",'ns3.dtd'); Tag('incode:song', autoOpen=>1, autoClose=>1); Tag('incode:verse', autoOpen=>1, autoClose=>1); Tag('incode:line', autoOpen=>1, autoClose=>1); DefConstructor('\bigskip',""); DefConstructor('\par',sub{ $_[0]->maybeCloseElement('incode:line'); }); #********************************************************************** 1; LaTeXML-0.7.0/t/namespace/ns2.latexml0000644002506700454610000000206411214255136016327 0ustar miller891divuse strict; use LaTeXML::Package; #====================================================================== # Namespace tests ns1.tex, ns2.tex, ns3.tex... # The TeX sources are identical #====================================================================== # Case 2: The DTD uses no Namespaces prefixes. # However, the output is expected to be in the namespace http://example.com/ # but without prefixes (ie. all in default namespace), so that it can # be validated against the DTD. # The code will use the prefix "incode" for the same namespace #====================================================================== RegisterNamespace(incode=>"http://example.com/"); DocType("incode:song","-//NIST LaTeXML//LaTeXML Poem",'ns2.dtd'); Tag('incode:song', autoOpen=>1, autoClose=>1); Tag('incode:verse', autoOpen=>1, autoClose=>1); Tag('incode:line', autoOpen=>1, autoClose=>1); DefConstructor('\bigskip',""); DefConstructor('\par',sub{ $_[0]->maybeCloseElement('incode:line'); }); #********************************************************************** 1; LaTeXML-0.7.0/t/namespace/ns3.dvi0000644002506700454610000000056411214255136015447 0ustar miller891div; TeX output 2007.10.29:18103ڍ&K`y cmr10Twinkle,UUtwinklelittlestar, HowUUIwonderwhatyouare.UpUUabGovetheworldsohigh,LikeUUadiamondinthesky`1*;3GK`y cmr107LaTeXML-0.7.0/t/namespace/ns1.dtd0000644002506700454610000000023511214255136015431 0ustar miller891div LaTeXML-0.7.0/t/namespace/ns3.dtd0000644002506700454610000000034111214255136015431 0ustar miller891div LaTeXML-0.7.0/t/namespace/ns4.dvi0000644002506700454610000000056411214255136015450 0ustar miller891div; TeX output 2007.10.29:18103ڍ&K`y cmr10Twinkle,UUtwinklelittlestar, HowUUIwonderwhatyouare.UpUUabGovetheworldsohigh,LikeUUadiamondinthesky`1*;3GK`y cmr107LaTeXML-0.7.0/t/namespace/ns2.dvi0000644002506700454610000000056411214255136015446 0ustar miller891div; TeX output 2007.10.29:18103ڍ&K`y cmr10Twinkle,UUtwinklelittlestar, HowUUIwonderwhatyouare.UpUUabGovetheworldsohigh,LikeUUadiamondinthesky`1*;3GK`y cmr107LaTeXML-0.7.0/t/namespace/ns2.tex0000644002506700454610000000021111214255136015451 0ustar miller891divTwinkle, twinkle little star,\par How I wonder what you are.\bigskip Up above the world so high,\par Like a diamond in the sky\par \bye LaTeXML-0.7.0/t/namespace/ns1.tex0000644002506700454610000000021111214255136015450 0ustar miller891divTwinkle, twinkle little star,\par How I wonder what you are.\bigskip Up above the world so high,\par Like a diamond in the sky\par \bye LaTeXML-0.7.0/t/namespace/ns5.latexml0000644002506700454610000000200411214255136016324 0ustar miller891divuse strict; use LaTeXML::Package; #====================================================================== # Namespace tests ns1.tex, ns2.tex, ns3.tex... # The TeX sources are identical #====================================================================== # Case 5: The DTD uses the two namespaces, but only one prefix "inner" # The XML output should use the same prefixes. # The code will use the prefix similar but different namespace prefixes #====================================================================== RegisterNamespace(incode=>"http://inner.com/"); RegisterNamespace(outcode=>"http://outer.com/"); DocType("outcode:song","-//NIST LaTeXML//LaTeXML Poem",'ns5.dtd'); Tag('outcode:song', autoOpen=>1, autoClose=>1); Tag('outcode:verse', autoOpen=>1, autoClose=>1); Tag('incode:line', autoOpen=>1, autoClose=>1); DefConstructor('\bigskip',""); DefConstructor('\par',sub{ $_[0]->maybeCloseElement('incode:line'); }); #********************************************************************** 1; LaTeXML-0.7.0/t/namespace/ns3.tex0000644002506700454610000000021011214255136015451 0ustar miller891divTwinkle, twinkle little star,\par How I wonder what you are.\bigskip Up above the world so high,\par Like a diamond in the sky\par \bye LaTeXML-0.7.0/t/namespace/ns5.xml0000644002506700454610000000067611214255136015473 0ustar miller891div Twinkle, twinkle little star, How I wonder what you are. Up above the world so high, Like a diamond in the sky LaTeXML-0.7.0/t/namespace/ns4.tex0000644002506700454610000000021011214255136015452 0ustar miller891divTwinkle, twinkle little star,\par How I wonder what you are.\bigskip Up above the world so high,\par Like a diamond in the sky\par \bye LaTeXML-0.7.0/t/namespace/ns4.latexml0000644002506700454610000000177111214255136016335 0ustar miller891divuse strict; use LaTeXML::Package; #====================================================================== # Namespace tests ns1.tex, ns2.tex, ns3.tex... # The TeX sources are identical #====================================================================== # Case 4: The DTD uses the two prefixes "inner" and "outer" # The XML output should use the same prefixes. # The code will use the prefix similar but different namespace prefixes #====================================================================== RegisterNamespace(incode=>"http://inner.com/"); RegisterNamespace(outcode=>"http://outer.com/"); DocType("outcode:song","-//NIST LaTeXML//LaTeXML Poem",'ns4.dtd'); Tag('outcode:song', autoOpen=>1, autoClose=>1); Tag('outcode:verse', autoOpen=>1, autoClose=>1); Tag('incode:line', autoOpen=>1, autoClose=>1); DefConstructor('\bigskip',""); DefConstructor('\par',sub{ $_[0]->maybeCloseElement('incode:line'); }); #********************************************************************** 1; LaTeXML-0.7.0/t/namespace/ns5.dvi0000644002506700454610000000056411214255136015451 0ustar miller891div; TeX output 2007.10.29:18153ڍ&K`y cmr10Twinkle,UUtwinklelittlestar, HowUUIwonderwhatyouare.UpUUabGovetheworldsohigh,LikeUUadiamondinthesky`1*;3GK`y cmr107LaTeXML-0.7.0/t/namespace/ns1.xml0000644002506700454610000000052411214255136015457 0ustar miller891div Twinkle, twinkle little star, How I wonder what you are. Up above the world so high, Like a diamond in the sky LaTeXML-0.7.0/t/namespace/ns2.xml0000644002506700454610000000056011214255136015460 0ustar miller891div Twinkle, twinkle little star, How I wonder what you are. Up above the world so high, Like a diamond in the sky LaTeXML-0.7.0/t/ams/0000755002506700454610000000000011215766043013064 5ustar miller891divLaTeXML-0.7.0/t/ams/amsdisplay.tex0000644002506700454610000000123211214255137015746 0ustar miller891div\documentclass{article} \usepackage{amsmath} \begin{document} \begin{equation*} a=b \end{equation*} \begin{equation} a=b \end{equation} \begin{equation}\label{xx} \begin{split} a& =b+c-c\\ & \quad +e-f\\ & =g+h\\ & =i \end{split} \end{equation} \begin{multline} a+b+c+d+e+f\\ +i+j+k+l+m+n \end{multline} \begin{gather} a_1=b_1+c_1\\ a_2=b_2+c_2-d_2+e_2 \end{gather} \begin{align} a_1& =b_1+c_1\\ a_2& =b_2+c_2-d_2+e_2 \end{align} \begin{align} a_{11}& =b_{11}& a_{12}& =b_{12}\\ a_{21}& =b_{21}& a_{22}& =b_{22}+c_{22}\\ \end{align} \begin{flalign} a_{11}& =b_{11}& a_{12}& =b_{12}\\ a_{21}& =b_{21}& a_{22}& =b_{22}+c_{22}\\ \end{flalign} \end{document} LaTeXML-0.7.0/t/ams/cd.dvi0000644002506700454610000000344411214255137014157 0ustar miller891div; TeX output 2008.12.29:2308y?" b> cmmi10S^ O!cmsy7WZcmr5L !", cmsy10 8Tꍒ7 0ercmmi7j$kÍ>UM!ŵTu cmex10??y:6?:6?:6y8ٓRcmr7End'wܴPLuK`y cmr10(Sm 8Tc)=Ikffffffk(Z 8Tc)=J8(1);"qcov, (L)l*>UM!lnonǸ(K$)Cƍ>UM!jcf (K$)"c'ˍ>UM!INAcfQ_(L)|t?|t?|tyx?? =x =? =?Qr?Qr?Qryp'add(L)l*>UM!laddǸ(K$)Cƍ>UM!Ccov (K$)"c'ˍ>UM!EcnonU (L)8(2)1*;y !", cmsy10 O!cmsy7 b> cmmi10 0ercmmi7K`y cmr10ٓRcmr7Zcmr5u cmex10TLaTeXML-0.7.0/t/ams/matrix.dvi0000644002506700454610000000162011214255137015067 0ustar miller891div; TeX output 2008.08.06:1509y?d b> cmmi10aCb 0cY^u cmex10daCb 0cI^n^daCb 0cI^6^daCb 0cI^` ` ` ` daCb 0cI I I I ' ' ' ' daCb 0cI I I I nA8/3 0ercmmi7aLbcK`y cmr101*;y b> cmmi10 0ercmmi7K`y cmr10u cmex10LaTeXML-0.7.0/t/ams/cd.xml0000644002506700454610000002154111214255137014173 0ustar miller891div S W Λ T j T End P / S T I = / Z T J cov L non K cf K cf L add L add K cov K non L LaTeXML-0.7.0/t/ams/amsdisplay.xml0000644002506700454610000007535511214255137015767 0ustar miller891div = a b = a b a = - + - + b c c e f = + g h = i + a b c d e f i j k l m n = a 1 + b 1 c 1 = a 2 + - + b 2 c 2 d 2 e 2 = a 1 + b 1 c 1 a 1 = + b 1 c 1 = a 2 + - + b 2 c 2 d 2 e 2 a 2 = + - + b 2 c 2 d 2 e 2 = a 11 b 11 a 11 = b 11 = a 12 b 12 a 12 = b 12 = a 21 b 21 a 21 = b 21 = a 22 + b 22 c 22 a 22 = + b 22 c 22 = a 11 b 11 a 11 = b 11 = a 12 b 12 a 12 = b 12 = a 21 b 21 a 21 = b 21 = a 22 + b 22 c 22 a 22 = + b 22 c 22 LaTeXML-0.7.0/t/ams/matrix.tex0000644002506700454610000000066111214255137015111 0ustar miller891div\documentclass{article} \usepackage{amsmath} \begin{document} \[ \begin{matrix} a & b \\ c \\ \end{matrix} \] \[ \begin{pmatrix} a & b \\ c \\ \end{pmatrix} \] \[ \begin{bmatrix} a & b \\ c \\ \end{bmatrix} \] \[ \begin{Bmatrix} a & b \\ c \\ \end{Bmatrix} \] \[ \begin{vmatrix} a & b \\ c \\ \end{vmatrix} \] \[ \begin{Vmatrix} a & b \\ c \\ \end{Vmatrix} \] \[ \begin{smallmatrix} a & b \\ c \\ \end{smallmatrix} \] \end{document} LaTeXML-0.7.0/t/ams/amsdisplay.dvi0000644002506700454610000000315411214255137015735 0ustar miller891div; TeX output 2008.08.06:1509y? l b> cmmi10aK`y cmr10=b la=b8(1)*fd~a֎=b8+c !", cmsy10cIJ+8ef֎=g+8h֎=i8(2)4dHa8+b+c+d+e+f}+8i+jk+kw+lk@+m+n (3) caٓRcmr71C=b1S+8c18(4)fصa2C=b2S+8c2d2+e28(5)fصa1=b1S+8c18(6)fصa2=b2S+8c2d2+e28(7)ӵa11=b11a12Ȳ=b128(8)ӵa21=b21a22Ȳ=b22 Ʋ+8c228(9)8(10)>a11N.=b11?XMa12O{=b128(11)>a21N.=b21?XMa22O{=b22 Ʋ+8c228(12)8(13)1*;y !", cmsy10 b> cmmi10K`y cmr10ٓRcmr7LaTeXML-0.7.0/t/ams/cd.tex0000644002506700454610000000125211214255137014170 0ustar miller891div\documentclass{article} \usepackage{amsmath} \usepackage{amscd} \newcommand{\End}{\operatorname{End}} \newcommand{\cov}{\operatorname{cov}} \newcommand{\non}{\operatorname{non}} \newcommand{\add}{\operatorname{add}} \newcommand{\cf}{\operatorname{cf}} \begin{document} \begin{equation} \begin{CD} S^{{\mathcal{W}}_\Lambda}\otimes T @>j>> T\\ @VVV @VV{\End P}V\\ (S\otimes T)/I @= (Z\otimes T)/J \end{CD} \end{equation} \begin{equation} \begin{CD} \cov(\mathcal{L}) @>>> \non(\mathcal{K}) @>>> \cf(\mathcal{K}) @>>> \cf(\mathcal{L})\\ @VVV @AAA @AAA @VVV\\ \add(\mathcal{L}) @>>> \add(\mathcal{K}) @>>> \cov(\mathcal{K}) @>>> \non(\mathcal{L}) \end{CD} \end{equation} \end{document} LaTeXML-0.7.0/t/ams/matrix.xml0000644002506700454610000001260511214255137015112 0ustar miller891div a b c a b c a b c a b c a b c a b c a b c LaTeXML-0.7.0/t/90_latexmlpost.t0000644002506700454610000000325611214255140015351 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML Postprocessing #********************************************************************** use Test; BEGIN { plan tests => 1; } use LaTeXML::Post; use LaTeXML::Post::MathML; # For each test $name there should be $name.xml and $name-post.xml # (the latter from a previous `good' run of # latexmlpost --dest=$name-post.xml --pmml --noscan --nocrossref --keepXMath $name #). dotest('t/post/simplemath'); #********************************************************************** # Do the test # Process the TeX file $texfile and compare the result to $xmlfile. # Do I need to do some redirection, silencing, etc? # What about turning off comments? # A decent XML Diff utility would be nice... sub dotest{ my($name)=@_; my @procs = (LaTeXML::Post::MathML::Presentation->new(verbosity=>-1)); return ok(0,1,"Couldn't instanciate LaTeXML::Post") unless @procs; my($doc) = LaTeXML::Post::ProcessChain( LaTeXML::Post::Document->newFromFile("$name.xml",validate=>1), @procs); my $output = $doc->toString; return ok(0,1,"Couldn't process $name.xml") unless $doc; my @lines = split('\n',$output); # open(IN,"<:utf8","$name-post.xml") || return ok(0,1,"Couldn't read $name-post.xml"); open(IN,"<","$name-post.xml") || return ok(0,1,"Couldn't read $name-post.xml"); my($n,$new,$old)=(0,undef,undef); do { $old=; chomp($old) if $old; $new=shift(@lines); $n++; } while($new && $old && ($new eq $old)); close(IN); ok($new,$old,"Comparing xml at line $n for $name"); } #********************************************************************** 1; LaTeXML-0.7.0/t/80_complex.t0000644002506700454610000000044311214255140014436 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/complex"); LaTeXML-0.7.0/t/digestion/0000755002506700454610000000000011215766043014271 5ustar miller891divLaTeXML-0.7.0/t/digestion/primes.dvi0000644002506700454610000000062011214255137016266 0ustar miller891div; TeX output 2007.11.13:14353ڍ&K`y cmr10The$4 rst$3thirtyprimenumbGers$4are2,3,.5,.7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71, 73,UU79,83,89,97,101,103,107,109,and113.`1*;3GK`y cmr10QLaTeXML-0.7.0/t/digestion/testctr.tex0000644002506700454610000000641311214255137016503 0ustar miller891div\documentclass{article} \begin{document} \section{Testing Counters} \newcounter{foo} Counter Foo [0] = \thefoo. \stepcounter{foo} Increment Foo[1] = \thefoo. \setcounter{foo}{2} Set Foo to 2 = \thefoo. \addtocounter{foo}{10} Add 10 to Foo [12] = \thefoo. \addtocounter{foo}{\value{foo}} Double Foo [24] = \thefoo. \section{Testing RefStep} Define bar to be reset within foo. \newcounter{bar}[foo] Now (Foo,Bar)[24,0] is (\thefoo,\thebar) Refstep bar: \refstepcounter{bar} Now (Foo,Bar)[24,1] is (\thefoo,\thebar) Refstep foo: \refstepcounter{foo} Now (Foo,Bar)[25,0] is (\thefoo,\thebar) \section{Number formatting} \newcounter{fubar} \setcounter{fubar}{6} arabic[6] = \thefubar \renewcommand{\thefubar}{\roman{fubar}} roman [vi] = \thefubar \renewcommand{\thefubar}{\Roman{fubar}} Roman [VI] = \thefubar \renewcommand{\thefubar}{\alph{fubar}} alph [f] = \thefubar \renewcommand{\thefubar}{\Alph{fubar}} Alph [F] = \thefubar \renewcommand{\thefubar}{\fnsymbol{fubar}} fnsymbol [$\Vert$] = \thefubar How far will \TeX\ go? \renewcommand{\thefubar}{\roman{fubar}} \setcounter{fubar}{9999} Fubar is \thefubar \section{TeX Counters} \subsection{Integers} \countdef\two=2 \two=7\relax 7 = \the\two. 7 = \the\count2. \subsection{Dimensions} HFuzz is \the\hfuzz. \hfuzz=2pt Now HFuzz is \the\hfuzz. HFuzz is \the\hfuzz. \hfuzz=2ptNow HFuzz is \the\hfuzz. %HFuzz is \the\hfuzz. %\hfuzz=2Now HFuzz is \the\hfuzz. %Linethickness: \the\linethickness %\linethickness=2pt %Now Linethickness: \the\linethickness \dimen7= 1.23 pt\relax Dimen 1.23pt = \the\dimen7. Dimen 1.23pt = \the\dimen\two. Dimen 1.23pt = \the\dimen\count2. \two=65536\relax\multiply\two3\relax count 2: 3*65536 = \the\two. \dimen7= 1\count2\relax Now dimen: 3pt = \the\dimen7 \dimen7 = 1em\relax One em = \the\dimen7 \dimen7 = 1ex\relax One ex = \the\dimen7 \dimendef\dseven7 Dimen: one ex = \the\dseven \dseven1pt\relax Dimen: 1pt = \the\dseven Dimen: 1pt = \the\dimen7 \dseven'10pt\relax 8 points = \the\dimen7 \dseven"Fpt\relax 15 points = \the\dimen7 \subsection{Glue} \skip7 = 1pt plus 3pt\relax 1pt plus 3pt = \the\skip7 \skip7 = 1pt plus 3fil\relax 1pt plus 3fil = \the\skip7 \skip8 = 1pt plus 3fill\relax 1pt plus 3fill = \the\skip8 \advance\skip7\skip8 Skip: 2pt plus 3fill = \the\skip7 \skip8 = .1pt plus 3fill\relax 0.1 plus 3fill = \the\skip8 \subsection{Undefined?} Unknown count: 0 = \the\count128\relax Unknown dimen: 0pt = \the\dimen128\relax Unknown skip: 0pt = \the\skip128\relax \subsection{The} the count 0 : \the\count0 the two (countdef 2) : \the\two \def\foo{FOO} %the macro foo : \the\foo %the primitive def : \the\def \toks2={ab\foo cd} Tokens: abFOOcd = \the\toks2 Catcode: 11 = \the\catcode`\A Catcode: 12 = \the\catcode`\@ \subsection{New Count, etc} \newcount\foo \foo3\relax 3 = \the\foo \subsection{\LaTeX\ style} \newlength{\foolen} \setlength{\foolen}{1em} 1em = \the\foolen \addtolength{\foolen}{2em} 3em = \the\foolen \subsection{Macrology} \def\numthree{3} \count2=1\relax 1=\the\count2 \count2=2\numthree\relax [23=\the\count2] \count2=2\ifnum20<\count2 9\else 8\fi [29=\the\count2] \count2=2\ifnum\count2<20 8\else 9\fi [29=\the\count2] \makeatletter \count\tw@=\@M\relax [10000=\the\count\tw@] [\chardef\mydollar=36\relax \$a\$ = \mydollar a\mydollar] \makeatother \end{document} LaTeXML-0.7.0/t/digestion/testctr.dvi0000644002506700454610000000535011214255137016464 0ustar miller891div; TeX output 2008.02.25:1130y?>Nff cmbx121VLTfestingffCounters>K`y cmr10CounterUUF*oGo[0]=0. MIncrementUUF*oGo[1]=1.MSetUUF*oGoto2=2.MAddUU10toF*oGo[12]=12.MDoubleUUF*oGo[24]=24.!č>2VLTfestingffRefStep>De neUUbartobGeresetwithinfoo.Now(F*oo,Bar)[24,0]is(24,0)MRefstepUUbar:Now(F*oGo,Bar)[24,1]is(24,1)MRefstepUUfoGo:Now(F*oo,Bar)[25,0]is(25,0)!č>3VLNumbs3erffformatting>arabic[6]UU=6MromanUU[vi]=viMRomanUU[VI]=VIMalphUU[f]=fMAlphUU[F]=FMfnsymbGolUU[ !", cmsy10k]=kMHowUUfarwillTU>'ExXgo? UUF*ubarismmmmmmmmmcmxcix!č>4VLTfeXffCounters>N cmbx124.1\IntegersuT>7UU=7.M7UU=7.6>4.2\Dimensions>HF*uzzUUis0.1pt.qNowHFuzzis2.0pt.MHF*uzzUUis2.0pt.qNowHFuzzis2.0pt.MDimenUU1.23pt=1.23pt.MDimenUU1.23pt=1.23pt.MDimenUU1.23pt=1.23pt.McountUU2:q3*65536=196608.MNowUUdimen:q3pt=3.0ptMOneUUem=10.00002ptMOneUUex=4.30554ptMDimen:qoneUUex=4.30554ptMDimen:q1ptUU=1.0pt1'*y?MDimen:q1ptUU=1.0pt M8UUpGoints=8.0ptM15UUpGoints=15.0pt6>4.3\GlueuT>1ptUUplus3pt=1.0ptplus3.0ptM1ptUUplus3 l=1.0ptplus3.0 lM1ptUUplus3 ll=1.0ptplus3.0 llMSkip:q2ptUUplus3 ll=2.0ptplus3.0 llM0.1UUplus3 ll=0.1ptplus3.0 ll>4.4\Unde ned?uT>UnknownUUcount:q0=0MUnknownUUdimen:q0pt=0.0ptMUnknownUUskip:q0pt=0.0pt>4.5\TheuT>theUUcount0:q2MtheUUtwo(countdef2):q196608MT*okens:qabFOOcdUU=abFOOcdMCatcoGde:q11UU=11MCatcoGde:q12UU=12>4.6\NewCount,etcuT>3UU=3>4.7\LAl#2@cmbx8A~/TESXstyle>1emUU=10.00002pt3em=30.00005pt>4.8\Macrology>1=1 M[23=23]M[29=29]M[29=29]M[10000=10000]UU[$a$=$a$]2 ;y2@cmbx8N cmbx12Nff cmbx12 !", cmsy10K`y cmr10 SLaTeXML-0.7.0/t/digestion/def.dvi0000644002506700454610000000052011214255137015524 0ustar miller891div; TeX output 2007.12.03:1213y?MK`y cmr10NormalUUmacro:q"V cmbx10abcdone MF*unkyUUmacro:qǹaTbcdone1*;y"V cmbx10K`y cmr10LaTeXML-0.7.0/t/digestion/primes.tex0000644002506700454610000000147611214255137016316 0ustar miller891div % From the TeX Book, p. 218 \newif\ifprime \newif\ifunknown % boolean variables \newcount\n \newcount\p \newcount\d \newcount\a % integer variables \def\primes#1{2,~3% assume that #1 is at least 3 \n=#1 \advance\n by-2 % n more to go \p=5 % odd primes starting with p \loop\ifnum\n>0 \printifprime\advance\p by2 \repeat} \def\printp{, % we will invoke \printp if p is prime \ifnum\n=1 and~\fi % `and' precedes the last value \number\p \advance\n by -1 } \def\printifprime{\testprimality \ifprime\printp\fi} \def\testprimality{{\d=3 \global\primetrue \loop\trialdivision \ifunknown\advance\d by2 \repeat}} \def\trialdivision{\a=\p \divide\a by\d \ifnum\a>\d \unknowntrue\else\unknownfalse\fi \multiply\a by\d \ifnum\a=\p \global\primefalse\unknownfalse\fi } The first thirty prime numbers are \primes{30}. \bye LaTeXML-0.7.0/t/digestion/box.xml0000644002506700454610000001170111214255137015577 0ustar miller891div

Box 0 is horizontal

Box 1 is horizontal

Box 2 is vertical

Using…

Hello,Goodbye

Box 3 is horizontal

Box 4 is empty

+ a a + a

a

+ a

a a

+ a

a a

- a

a

- a

a

- a a - a a
LaTeXML-0.7.0/t/digestion/testctr.xml0000644002506700454610000001260411214255137016502 0ustar miller891div
Testing Counters

Counter Foo [0] = 0.

Increment Foo[1] = 1.

Set Foo to 2 = 2.

Add 10 to Foo [12] = 12.

Double Foo [24] = 24.

Testing RefStep

Define bar to be reset within foo. Now (Foo,Bar)[24,0] is (24,0)

Refstep bar: Now (Foo,Bar)[24,1] is (24,1)

Refstep foo: Now (Foo,Bar)[25,0] is (25,0)

Number formatting

arabic[6] = 6

roman [vi] = vi

Roman [VI] = VI

alph [f] = f

Alph [F] = F

fnsymbol [] = ∥

How far will TeX go? Fubar is mmmmmmmmmcmxcix

TeX Counters Integers

7 = 7.

7 = 7.

Dimensions

HFuzz is 0.1pt. Now HFuzz is 2pt.

HFuzz is 2pt. Now HFuzz is 2pt.

Dimen 1.23pt = 1.23pt.

Dimen 1.23pt = 1.23pt.

Dimen 1.23pt = 1.23pt.

count 2: 3*65536 = 196608.

Now dimen: 3pt = 3pt

One em = 10pt

One ex = 4.3pt

Dimen: one ex = 4.3pt

Dimen: 1pt = 1pt

Dimen: 1pt = 1pt

8 points = 8pt

15 points = 15pt

Glue

1pt plus 3pt = 1pt plus 3pt

1pt plus 3fil = 1pt plus 3fil

1pt plus 3fill = 1pt plus 3fill

Skip: 2pt plus 3fill = 2pt plus 3fill

0.1 plus 3fill = 0.1pt plus 3fill

Undefined?

Unknown count: 0 = 0

Unknown dimen: 0pt = 0pt

Unknown skip: 0pt = 0pt

The

the count 0 : 0

the two (countdef 2) : 196608

Tokens: abFOOcd = abFOOcd

Catcode: 11 = 11

Catcode: 12 = 12

New Count, etc

3 = 3

LaTeX style

1em = 10pt 3em = 30pt

Macrology

1=1

[23=23]

[29=29]

[29=29]

[10000=10000] [$a$ = $a$]

LaTeXML-0.7.0/t/digestion/primes.xml0000644002506700454610000000051011214255137016302 0ustar miller891div

The first thirty prime numbers are 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, and 113.

LaTeXML-0.7.0/t/digestion/box.dvi0000644002506700454610000000135411214255137015564 0ustar miller891div; TeX output 2008.08.06:1422y?MK`y cmr10BoxUU0ishorizontal MBoxUU1ishorizontalMBoxUU2isverticalǍMUsing...Hello,GoGodbyeMBoxUU3ishorizontalMBoxUU4isemptyǤ> b> cmmi10a8+a>a+aUN8>a8+a a>a8+a a>a8 !", cmsy10N8a>a8N8a N8>a8N8aN8>a8N8a1*;y !", cmsy10 b> cmmi10K`y cmr10LaTeXML-0.7.0/t/digestion/def.tex0000644002506700454610000000025211214255137015544 0ustar miller891div\documentclass{article} \def\foo#1{\textbf{#1}} \def\bar#1#{\textbf{#1}} \begin{document} Normal macro: \foo a b c {done} Funky macro: \bar a b c {done} \end{document} LaTeXML-0.7.0/t/digestion/def.xml0000644002506700454610000000053211214255137015545 0ustar miller891div

Normal macro: a b c done

Funky macro: a b c done

LaTeXML-0.7.0/t/digestion/box.tex0000644002506700454610000000115411214255137015600 0ustar miller891div\documentclass{article} \def\testbox#1{% \ifvoid#1 Box #1 is empty \else\ifhbox#1 Box #1 is horizontal \else\ifvbox#1 Box #1 is vertical \fi\fi\fi \par} \begin{document} \setbox0=\hbox{Goodbye} \testbox{0} \setbox1=\hbox{Hello} \testbox{1} \setbox2=\vbox{\box1,\box0} \testbox{2} Using... \box2 \setbox3=\hbox{} \testbox{3} \testbox{4} \[ a + \hbox{a}\] \[ a + \vbox{a}\] \[ a + \vbox{\hbox{a}\hbox{a}} \] \[ a + \vtop{\hbox{a}\hbox{a}} \] \[ a - \lower1ex\vtop{\hbox{a}} \] \[ a - \lower1ex\vbox{\hbox{a}} \] \[ a - \lower1ex\hbox{a} \] \def\mybox#1{\hbox{#1}} \[ a - \lower1ex\mybox{a} \] \end{document} LaTeXML-0.7.0/t/40_math.t0000644002506700454610000000044011214255140013711 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/math"); LaTeXML-0.7.0/t/theorem/0000755002506700454610000000000011215766043013747 5ustar miller891divLaTeXML-0.7.0/t/theorem/amstheorem.tex0000644002506700454610000002017211214255140016625 0ustar miller891div%%% ==================================================================== %%% @LaTeX-file{ %%% filename = "thmtest.tex", %%% version = "2.01", %%% date = "2004/08/02", %%% time = "14:18:27 EDT", %%% checksum = "26819 255 963 8277", %%% author = "American Mathematical Society", %%% copyright = "Copyright 1996, 2004 American Mathematical Society, %%% all rights reserved. Copying of this file is %%% authorized only if either: %%% (1) you make absolutely no changes to your copy, %%% including name; OR %%% (2) if you do make changes, you first rename it %%% to some other name.", %%% address = "American Mathematical Society, %%% Technical Support, %%% Publications Technical Group, %%% 201 Charles Street, %%% Providence, RI 02904, %%% USA", %%% telephone = "401-455-4080 or (in the USA and Canada) %%% 800-321-4AMS (321-4267)", %%% FAX = "401-331-3842", %%% email = "tech-support@ams.org (Internet)", %%% codetable = "ISO/ASCII", %%% supported = "yes", %%% keywords = "latex, amslatex, ams-latex, theorem, proof", %%% abstract = "This is part of the AMS-\LaTeX{} distribution. %%% It is a sample document illustrating the use of %%% the amsthm package.", %%% docstring = "The checksum field above contains a CRC-16 %%% checksum as the first value, followed by the %%% equivalent of the standard UNIX wc (word %%% count) utility output of lines, words, and %%% characters. This is produced by Robert %%% Solovay's checksum utility.", %%% } %%% ==================================================================== %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Option test file, will be created during the first LaTeX run; % this facility is not available when using an AMS document class. % Removed for LaTeXML testing %\begin{filecontents}{exercise.thm} %\def\th@exercise{% % \normalfont % body font % \thm@headpunct{:}% %} %\end{filecontents} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \documentclass{article} \title{Newtheorem and theoremstyle test} \author{Michael Downes\\updated by Barbara Beeton} % for LaTeXML testing \date{none} \usepackage{amsthm} \newtheorem{thm}{Theorem}[section] \newtheorem{cor}[thm]{Corollary} \newtheorem{prop}{Proposition} \newtheorem{lem}[thm]{Lemma} \theoremstyle{remark} \newtheorem*{rmk}{Remark} \theoremstyle{plain} \newtheorem*{Ahlfors}{Ahlfors' Lemma} \newtheoremstyle{note}% name {3pt}% Space above {3pt}% Space below {}% Body font {}% Indent amount (empty = no indent, \parindent = para indent) {\itshape}% Thm head font {:}% Punctuation after thm head {.5em}% Space after thm head: " " = normal interword space; % \newline = linebreak {}% Thm head spec (can be left empty, meaning `normal') \theoremstyle{note} \newtheorem{note}{Note} \newtheoremstyle{citing}% name {3pt}% Space above, empty = `usual value' {3pt}% Space below {\itshape}% Body font {}% Indent amount (empty = no indent, \parindent = para indent) {\bfseries}% Thm head font {.}% Punctuation after thm head {.5em}% Space after thm head: " " = normal interword space; % \newline = linebreak {\thmnote{#3}}% Thm head spec \theoremstyle{citing} \newtheorem*{varthm}{}% all text supplied in the note \newtheoremstyle{break}% name {9pt}% Space above, empty = `usual value' {9pt}% Space below {\itshape}% Body font {}% Indent amount (empty = no indent, \parindent = para indent) {\bfseries}% Thm head font {.}% Punctuation after thm head {\newline}% Space after thm head: \newline = linebreak {}% Thm head spec \theoremstyle{break} \newtheorem{bthm}{B-Theorem} \newtheorem{exer}{Exercise} \swapnumbers \theoremstyle{plain} \newtheorem{thmsw}{Theorem}[section] \newtheorem{corsw}[thmsw]{Corollary} \newtheorem{propsw}{Proposition} \newtheorem{lemsw}[thmsw]{Lemma} % Because the amsmath pkg is not used, we need to define a couple of % commands in more primitive terms. \let\lvert=|\let\rvert=| \newcommand{\Ric}{\mathop{\mathrm{Ric}}\nolimits} % Dispel annoying problem of slightly overlong lines: \addtolength{\textwidth}{8pt} \begin{document} \maketitle \section{Test of standard theorem styles} Ahlfors' Lemma gives the principal criterion for obtaining lower bounds on the Kobayashi metric. \begin{Ahlfors} Let $ds^2 = h(z)\lvert dz\rvert^2$ be a Hermitian pseudo-metric on $\mathbf{D}_r$, $h\in C^2(\mathbf{D}_r)$, with $\omega$ the associated $(1,1)$-form. If $\Ric\omega\geq\omega$ on $\mathbf{D}_r$, then $\omega\leq\omega_r$ on all of $\mathbf{D}_r$ (or equivalently, $ds^2\leq ds_r^2$). \end{Ahlfors} \begin{lem}[negatively curved families] Let $\{ds_1^2,\dots,ds_k^2\}$ be a negatively curved family of metrics on $\mathbf{D}_r$, with associated forms $\omega^1$, \dots, $\omega^k$. Then $\omega^i \leq\omega_r$ for all $i$. \end{lem} Then our main theorem: \begin{thm}\label{pigspan} Let $d_{\max}$ and $d_{\min}$ be the maximum, resp.\ minimum distance between any two adjacent vertices of a quadrilateral $Q$. Let $\sigma$ be the diagonal pigspan of a pig $P$ with four legs. Then $P$ is capable of standing on the corners of $Q$ iff \begin{equation}\label{sdq} \sigma\geq \sqrt{d_{\max}^2+d_{\min}^2}. \end{equation} \end{thm} \begin{cor} Admitting reflection and rotation, a three-legged pig $P$ is capable of standing on the corners of a triangle $T$ iff (\ref{sdq}) holds. \end{cor} \begin{rmk} As two-legged pigs generally fall over, the case of a polygon of order $2$ is uninteresting. \end{rmk} \section{Custom theorem styles} \begin{exer} Generalize Theorem~\ref{pigspan} to three and four dimensions. \end{exer} \begin{note} This is a test of the custom theorem style `note'. It is supposed to have variant fonts and other differences. \end{note} \begin{bthm} Test of the `linebreak' style of theorem heading. \end{bthm} This is a test of a citing theorem to cite a theorem from some other source. \begin{varthm}[Theorem 3.6 in \cite{thatone}] No hyperlinking available here yet \dots\ but that's not a bad idea for the future. \end{varthm} \section{The proof environment} \begin{proof} Here is a test of the proof environment. \end{proof} \begin{proof}[Proof of Theorem \ref{pigspan}] And another test. \end{proof} \begin{proof}[Proof \textup(necessity\textup)] And another. \end{proof} \begin{proof}[Proof \textup(sufficiency\textup)] And another, ending with a display: \[ 1+1=2\,. \qedhere \] \end{proof} \section{Test of number-swapping} This is a repeat of the first section but with numbers in theorem heads swapped to the left. Ahlfors' Lemma gives the principal criterion for obtaining lower bounds on the Kobayashi metric. \begin{Ahlfors} Let $ds^2 = h(z)\lvert dz\rvert^2$ be a Hermitian pseudo-metric on $\mathbf{D}_r$, $h\in C^2(\mathbf{D}_r)$, with $\omega$ the associated $(1,1)$-form. If $\Ric\omega\geq\omega$ on $\mathbf{D}_r$, then $\omega\leq\omega_r$ on all of $\mathbf{D}_r$ (or equivalently, $ds^2\leq ds_r^2$). \end{Ahlfors} \begin{lemsw}[negatively curved families] Let $\{ds_1^2,\dots,ds_k^2\}$ be a negatively curved family of metrics on $\mathbf{D}_r$, with associated forms $\omega^1$, \dots, $\omega^k$. Then $\omega^i \leq\omega_r$ for all $i$. \end{lemsw} Then our main theorem: \begin{thmsw} Let $d_{\max}$ and $d_{\min}$ be the maximum, resp.\ minimum distance between any two adjacent vertices of a quadrilateral $Q$. Let $\sigma$ be the diagonal pigspan of a pig $P$ with four legs. Then $P$ is capable of standing on the corners of $Q$ iff \begin{equation}\label{sdqsw} \sigma\geq \sqrt{d_{\max}^2+d_{\min}^2}. \end{equation} \end{thmsw} \begin{corsw} Admitting reflection and rotation, a three-legged pig $P$ is capable of standing on the corners of a triangle $T$ iff (\ref{sdqsw}) holds. \end{corsw} \begin{thebibliography}{99} \bibitem{thatone} Dummy entry. \end{thebibliography} \end{document} LaTeXML-0.7.0/t/theorem/latextheorem.dvi0000644002506700454610000000357411214255137017161 0ustar miller891div; TeX output 2008.08.06:1508y?DtGGcmr17LdKGXQ cmr12AT[-E;gX's7tNewtheoremlznone+č>Nff cmbx121VLTfestffofstandardtheoremstyles>"V cmbx10LemmaT1.1(negativ9elycurvedfamilies) 0': cmti10L}'et !", cmsy10f b> cmmi10ds^ٓRcmr72l1|s;:::;ds^2v 0ercmmi7k됸gbeanegatively >curve}'d/familyofmetrics/onDrm,Cwithassociated/forms![ٟ^1L,C...,C![ٟ^kGi.x!Then/![ٟ^iw=!r>foralli.MK`y cmr10ThenUUourmaintheorem:>TheoremT1.2L}'et[dmax'anddmin_bethemaximum,xresp.minimumdistancebe->twe}'en͊anytwoadjacent͋verticesofaquadrilateralQ.WwLet)dbethediagonalpigspan>ofapigPvwithfourle}'gs.ThenPisc}'apableofstandingonthec}'ornersofQi Ė"vu cmex10q vfe3 dr2\nmaxz+8d:2Nmin@j:8(1)u㍍>CorollaryT1.3ڔA}'dmittingqre ectionrandrotation,athree-leggedrpigPiscapable>ofstandingonthec}'ornersofatriangleTvi (1)holds.1*;y ': cmti10"V cmbx10Nff cmbx12XQ cmr12DtGGcmr17 !", cmsy10 b> cmmi10 0ercmmi7K`y cmr10ٓRcmr7u cmex10hLaTeXML-0.7.0/t/theorem/latextheorem.tex0000644002506700454610000000256611214255137017177 0ustar miller891div\documentclass{article} % Simplified extract of the tests of ams theorem. \title{\LaTeX's Newtheorem} \date{none} \newtheorem{thm}{Theorem}[section] \newtheorem{cor}[thm]{Corollary} \newtheorem{prop}{Proposition} \newtheorem{lem}[thm]{Lemma} % Because the amsmath pkg is not used, we need to define a couple of % commands in more primitive terms. \let\lvert=|\let\rvert=| \newcommand{\Ric}{\mathop{\mathrm{Ric}}\nolimits} % Dispel annoying problem of slightly overlong lines: \addtolength{\textwidth}{8pt} \begin{document} \maketitle \section{Test of standard theorem styles} \begin{lem}[negatively curved families] Let $\{ds_1^2,\dots,ds_k^2\}$ be a negatively curved family of metrics on $\mathbf{D}_r$, with associated forms $\omega^1$, \dots, $\omega^k$. Then $\omega^i \leq\omega_r$ for all $i$. \end{lem} Then our main theorem: \begin{thm}\label{pigspan} Let $d_{\max}$ and $d_{\min}$ be the maximum, resp.\ minimum distance between any two adjacent vertices of a quadrilateral $Q$. Let $\sigma$ be the diagonal pigspan of a pig $P$ with four legs. Then $P$ is capable of standing on the corners of $Q$ iff \begin{equation}\label{sdq} \sigma\geq \sqrt{d_{\max}^2+d_{\min}^2}. \end{equation} \end{thm} \begin{cor} Admitting reflection and rotation, a three-legged pig $P$ is capable of standing on the corners of a triangle $T$ iff (\ref{sdq}) holds. \end{cor} \end{document} LaTeXML-0.7.0/t/theorem/amstheorem.dvi0000644002506700454610000001377411214255140016621 0ustar miller891div; TeX output 2008.08.06:1507y?uLDtGGcmr17Newtheorem7tandtheoremstqyletestXQ cmr12MicrhaelDownesupSdatedbryBarbaraBeeton"]⍒lznone+č>Nff cmbx121VLTfestffofstandardtheoremstyles>K`y cmr10Ahlfors'LemmagivestheprincipalcriterionforobtaininglowerbGoundsonthe >KobayashiUUmetric.>"V cmbx10Ahlfors' Lemma.': cmti10L}'etE b> cmmi10ds^ٓRcmr72 J=׵h(zp) !", cmsy10jdzj^2 beEaHermitianFpseudo-metriconD 0ercmmi7rm,>hꙸ2ꚵC^23(Drm),fwith!Ytheasso}'ciated(1;1)-form.bIfRic~!Frꚵ!YonDrm,gthen!Fsꙵ!r>onallofDr(ore}'quivalently,ds^2Cds^2፴r|s).>Lemma81.1(negatively8curvedfamilies).L}'et8fds^2l1|s;:::;ds^2vk됸gbeanegativelycurved>familyQofQmetricsonDrm,^vwithasso}'ciatedQforms![ٟ^1L,^u...,^v![ٟ^kGi.RThenQ![ٟ^iw=!rforall>i.MThenUUourmaintheorem:>Theorem1.2.jL}'et2dmax6anddmin7bethe3maximum,Mresp.minimum3distance>b}'etweenanytwoadjac}'entverticesofaquadrilateralQ.Let bethediagonal>pigsp}'anhofgapigPIwithfourle}'gs.ThenPIisc}'apablehofstandingonthec}'orners>ofQi Ė"vu cmex10q vfe3 dr2\nmaxz+8d:2Nmin@j:8(1)u㍑>Corollary1.3.A}'dmittingQfre ectionQgandrotation,^aQgthree-leggedpigPiscapable>ofstandingonthec}'ornersofatriangleTvi (1)holds.>R}'emark.1Astwo-leggedpigsgenerallyfallover,LthecaseofapGolygonoforder2>isUUuninteresting.!č>2VLCustomfftheoremstyles>ExerciseT1.>Gener}'alizeTheorem1.2tothreeandfourdimensions.>Notef˲1:Thisi{isatestoftheizcustomtheoremstyle`note'.9ItissuppGosedtohave>vqariantUUfontsandotherdi erences.1*y?>B-TheoremT1. >T;estofthe`linebr}'eak'styleofthe}'oremheading.MThisUUisatestofacitingtheoremtociteatheoremfromsomeothersource.>Theorem3.6in[1].pNosChyp}'erlinkingavailablehereyet...butsCthat'snotabad>ide}'aforthefuture. _>3VLTheffpros3ofenvironment>Pr}'oof.]UIHereUUisatestoftheproGofenvironment. ffdffYffff1{>Pr}'oofofThe}'orem1.2.{AndUUanothertest.ffdffYffff>Pr}'oof{(necessity}).ȲAndUUanother.ffdffYffff>Pr}'oof{(suciency}).O)AndUUanother,endingwithadisplay:h18+1=2:ffdffYffff>4VLTfestffofnumbs3er-swapping>ThisiisiarepGeatofthe rstsectionbutwithnumbGersiintheoremheadsswappGed >toUUtheleft.MAhlfors'NLemmaNgivestheprincipalcriterionforobtaininglowerbGoundsNon>theUUKobayashimetric.퍑>Ahlfors' Lemma.L}'etEds^2 J=׵h(zp)jdzj^2 beEaHermitianFpseudo-metriconDrm,>hꙸ2ꚵC^23(Drm),fwith!Ytheasso}'ciated(1;1)-form.bIfRic~!Frꚵ!YonDrm,gthen!Fsꙵ!r>onallofDr(ore}'quivalently,ds^2Cds^2፴r|s).>4.18Lemma(negatively8curvedfamilies).L}'et8fds^2l1|s;:::;ds^2vk됸gbeanegativelycurved>familyQofQmetricsonDrm,^vwithasso}'ciatedQforms![ٟ^1L,^u...,^v![ٟ^kGi.RThenQ![ٟ^iw=!rforall>i.MThenUUourmaintheorem:썑>4.2Theorem.jL}'et2dmax6anddmin7bethe3maximum,Mresp.minimum3distance>b}'etweenanytwoadjac}'entverticesofaquadrilateralQ.Let bethediagonal>pigsp}'anhofgapigPIwithfourle}'gs.ThenPIisc}'apablehofstandingonthec}'orners>ofQi Ė"vq vfe3 dr2\nmaxz+8d:2Nmin@j:8(2);Ѝ>4.3Corollary .UA}'dmittingkZre ectionk[androtation,swathree-leggedk[pigPiscapable>ofstandingonthec}'ornersofatriangleTvi (2)holds. _>ReferencesC[1]R cmmi10 0ercmmi7K`y cmr10ٓRcmr7u cmex10LaTeXML-0.7.0/t/theorem/latextheorem.xml0000644002506700454610000001577711214255137017207 0ustar miller891div LaTeX's Newtheorem none
Test of standard theorem styles <text font="bold">Lemma 1.1 (negatively curved families).</text>

Let ds12dsk2 be a negatively curved family of metrics on Dr, with associated forms ω1, …, ωk. Then ωiωr for all i.

Then our main theorem:

<text font="bold">Theorem 1.2.</text>

Let dmax and dmin be the maximum, resp. minimum distance between any two adjacent vertices of a quadrilateral Q. Let σ be the diagonal pigspan of a pig P with four legs. Then P is capable of standing on the corners of Q iff

σ + d max 2 d min 2
<text font="bold">Corollary 1.3.</text>

Admitting reflection and rotation, a three-legged pig P is capable of standing on the corners of a triangle T iff () holds.

LaTeXML-0.7.0/t/theorem/amstheorem.xml0000644002506700454610000006662311215765773016663 0ustar miller891div Newtheorem and theoremstyle test Michael Downesupdated by Barbara Beeton none
Test of standard theorem styles

Ahlfors' Lemma gives the principal criterion for obtaining lower bounds on the Kobayashi metric.

<text font="bold">Ahlfors' Lemma.</text>

Let =ds2hz|dz|2 be a Hermitian pseudo-metric on Dr, hC2Dr, with ω the associated 11-form. If Ricωω on Dr, then ωωr on all of Dr (or equivalently, ds2dsr2).

<text font="bold">Lemma 1.1 (negatively curved families).</text>

Let ds12dsk2 be a negatively curved family of metrics on Dr, with associated forms ω1, …, ωk. Then ωiωr for all i.

Then our main theorem:

<text font="bold">Theorem 1.2.</text>

Let dmax and dmin be the maximum, resp. minimum distance between any two adjacent vertices of a quadrilateral Q. Let σ be the diagonal pigspan of a pig P with four legs. Then P is capable of standing on the corners of Q iff

σ + d max 2 d min 2
<text font="bold">Corollary 1.3.</text>

Admitting reflection and rotation, a three-legged pig P is capable of standing on the corners of a triangle T iff () holds.

<text font="italic">Remark.</text>

As two-legged pigs generally fall over, the case of a polygon of order 2 is uninteresting.

Custom theorem styles <text font="bold">Exercise 1.</text>

Generalize Theorem  to three and four dimensions.

<text font="italic">Note 1:</text>

This is a test of the custom theorem style `note'. It is supposed to have variant fonts and other differences.

<text font="bold">B-Theorem 1.</text>

Test of the `linebreak' style of theorem heading.

This is a test of a citing theorem to cite a theorem from some other source.

<text font="bold">Theorem 3.6 in <cite>[<bibref bibrefs="thatone" separator="," show="Number" yyseparator=","/>]</cite>.</text>

No hyperlinking available here yet … but that's not a bad idea for the future.

The proof environment <text font="italic">Proof.</text>

Here is a test of the proof environment. ∎

<text font="italic">Proof of Theorem <ref labelref="LABEL:pigspan"/>.</text>

And another test. ∎

<text font="italic">Proof </text>(<text font="italic">necessity</text>)<text font="italic">.</text>

And another. ∎

<text font="italic">Proof </text>(<text font="italic">sufficiency</text>)<text font="italic">.</text>

And another, ending with a display:

= + 1 1 2 .
Test of number-swapping

This is a repeat of the first section but with numbers in theorem heads swapped to the left.

Ahlfors' Lemma gives the principal criterion for obtaining lower bounds on the Kobayashi metric.

<text font="bold">Ahlfors' Lemma.</text>

Let =ds2hz|dz|2 be a Hermitian pseudo-metric on Dr, hC2Dr, with ω the associated 11-form. If Ricωω on Dr, then ωωr on all of Dr (or equivalently, ds2dsr2).

<text font="bold">4.1 Lemma (negatively curved families).</text>

Let ds12dsk2 be a negatively curved family of metrics on Dr, with associated forms ω1, …, ωk. Then ωiωr for all i.

Then our main theorem:

<text font="bold">4.2 Theorem.</text>

Let dmax and dmin be the maximum, resp. minimum distance between any two adjacent vertices of a quadrilateral Q. Let σ be the diagonal pigspan of a pig P with four legs. Then P is capable of standing on the corners of Q iff

σ + d max 2 d min 2
<text font="bold">4.3 Corollary.</text>

Admitting reflection and rotation, a three-legged pig P is capable of standing on the corners of a triangle T iff () holds.

References 1 Dummy entry.
LaTeXML-0.7.0/t/55_theorem.t0000644002506700454610000000044311214255140014434 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/theorem"); LaTeXML-0.7.0/t/10_expansion.t0000644002506700454610000000044511214255140014766 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/expansion"); LaTeXML-0.7.0/t/fonts/0000755002506700454610000000000011215766043013435 5ustar miller891divLaTeXML-0.7.0/t/fonts/fonts.tex0000644002506700454610000000467311214255136015315 0ustar miller891div\documentclass{article} %\usepackage{amsmath} %\def\boldsymbol#1{#1} %\usepackage{tmmath} \def\ltrs{Fff} \def\grk{\alpha \Gamma} \def\sym{[a + b \cup c]} \def\num{123} \begin{document} \begin{tabular}{lcccr} & Letters & Greek & Symbols & Numbers\\\hline Default\\ - & $\ltrs$ & $\grk$ & $\sym$ & $\num$ \\ \hline Families \\ mathrm & $\mathrm{\ltrs}$ & $\mathrm{\grk}$ & $\mathrm{\sym}$ & $\mathrm{\num}$ \\ mathsf & $\mathsf{\ltrs}$ & $\mathsf{\grk}$ & $\mathsf{\sym}$ & $\mathsf{\num}$ \\ mathtt & $\mathtt{\ltrs}$ & $\mathtt{\grk}$ & $\mathtt{\sym}$ & $\mathtt{\num}$ \\ mathcal & $\mathcal{\ltrs}$ & $\mathcal{\grk}$ & $\mathcal{\sym}$ & $\mathcal{\num}$ \\ \hline Series \\ mathbf & $\mathbf{\ltrs}$ & $\mathbf{\grk}$ & $\mathbf{\sym}$ & $\mathbf{\num}$ \\ \hline Shape \\ mathit & $\mathit{\ltrs}$ & $\mathit{\grk}$ & $\mathit{\sym}$ & $\mathit{\num}$ \\ %mathsl & $\mathsl{\ltrs}$ & $\mathsl{\grk}$ & $\mathsl{\sym}$ & $\mathsl{\num}$ \\ \hline OldStyle \\ rm & $\rm \ltrs$ & $\rm \grk$ & $\rm \sym$ & $\rm \num$ \\ bf & $\bf \ltrs$ & $\bf \grk$ & $\bf \sym$ & $\bf \num$ \\ it & $\it \ltrs$ & $\it \grk$ & $\it \sym$ & $\it \num$ \\ \hline Combinations\\ mathsf/mathit & $\mathsf{\mathit{\ltrs}}$ & $\mathsf{\mathit{\grk}}$ & $\mathsf{\mathit{\sym}}$ & $\mathsf{\mathit{\num}}$ \\ mathit/mathsf & $\mathit{\mathsf{\ltrs}}$ & $\mathit{\mathsf{\grk}}$ & $\mathit{\mathsf{\sym}}$ & $\mathit{\mathsf{\num}}$ \\ mathsf/it & $\mathsf{\it \ltrs}$ & $\mathsf{\it\grk}$ & $\mathsf{\it\sym}$ & $\mathsf{\it \num}$ \\ \hline Boldmath\\ - & {\boldmath $\ltrs$ } & {\boldmath $\grk$ } & {\boldmath $\sym$ } & {\boldmath $\num$} \\ mathrm & {\boldmath $\mathrm{\ltrs}$ } & {\boldmath $\mathrm{\grk}$ } & {\boldmath $\mathrm{\sym}$ } & {\boldmath $\mathrm{\num}$ }\\ mathsf & {\boldmath $\mathsf{\ltrs}$ } & {\boldmath $\mathsf{\grk}$ } & {\boldmath $\mathsf{\sym}$ } & {\boldmath $\mathsf{\num}$ }\\ mathtt & {\boldmath $\mathtt{\ltrs}$ } & {\boldmath $\mathtt{\grk}$ } & {\boldmath $\mathtt{\sym}$ } & {\boldmath $\mathtt{\num}$ }\\ mathcal & {\boldmath $\mathcal{\ltrs}$ } & {\boldmath $\mathcal{\grk}$ } & {\boldmath $\mathcal{\sym}$ } & {\boldmath $\mathcal{\num}$ }\\ mathit & {\boldmath $\mathit{\ltrs}$ } & {\boldmath $\mathit{\grk}$ } & {\boldmath $\mathit{\sym}$ } & {\boldmath $\mathit{\num}$ } \\ \end{tabular} {\rm roman {\it roman-italic}} {\sffamily sans {\slshape sans-slant}} \end{document} LaTeXML-0.7.0/t/fonts/textsymbols.tex0000644002506700454610000000316711214255136016556 0ustar miller891div\documentclass{article} \begin{document} \section{Text Symbols} \begin{tabular}{ll} \verb|\textdollar| & \textdollar \\ \verb|\textemdash| & \textemdash \\ \verb|\textendash| & \textendash \\ \verb|\textexclamdown| & \textexclamdown \\ \verb|\textquestiondown| & \textquestiondown \\ \verb|\textquotedblleft| & \textquotedblleft \\ \verb|\textquotedblright| & \textquotedblright \\ \verb|\textquoteleft| & \textquoteleft \\ \verb|\textquoteright| & \textquoteright \\ \verb|\textsterling| & \textsterling \\ \verb|\textasteriskcentered| & \textasteriskcentered \\ \verb|\textbackslash| & \textbackslash \\ \verb|\textbar| & \textbar \\ \verb|\textbraceleft| & \textbraceleft \\ \verb|\textbraceright| & \textbraceright \\ \verb|\textbullet| & \textbullet \\ \verb|\textdaggerdbl| & \textdaggerdbl \\ \verb|\textdagger| & \textdagger \\ \verb|\textparagraph| & \textparagraph \\ \verb|\textperiodcentered| & \textperiodcentered \\ \verb|\textsection| & \textsection \\ \verb|\textcircled{x}| & \textcircled{x}\\ \verb|\textless| & \textless \\ \verb|\textgreater| & \textgreater \\ \verb|\textcopyright| & \textcopyright \\ \verb|\textasciicircum| & \textasciicircum \\ \verb|\textasciitilde| & \textasciitilde \\ \verb|\textcompwordmark| & \textcompwordmark \\ \verb|\textunderscore| & \textunderscore \\ \verb|\textvisiblespace| & \textvisiblespace \\ \verb|\textellipsis| & \textellipsis \\ \verb|\textregistered| & \textregistered \\ \verb|\texttrademark| & \texttrademark \\ \verb|\textsuperscript{X}| & \textsuperscript{X} \\ \verb|\textordfeminine| & \textordfeminine \\ \verb|\textordmasculine| & \textordmasculine \\ \end{tabular} \end{document} LaTeXML-0.7.0/t/fonts/textsymbols.xml0000644002506700454610000001560111214255136016552 0ustar miller891div
Text Symbols \textdollar $ \textemdash\textendash\textexclamdown ¡ \textquestiondown ¿ \textquotedblleft\textquotedblright\textquoteleft\textquoteright\textsterling £ \textasteriskcentered * \textbackslash \ \textbar | \textbraceleft { \textbraceright } \textbullet\textdaggerdbl\textdagger\textparagraph\textperiodcentered\textsection § \textcircled{x} x⃝ \textless < \textgreater > \textcopyright © \textasciicircum \textasciitilde ~ \textcompwordmark \textunderscore _ \textvisiblespace\textellipsis\textregistered ® \texttrademark\textsuperscript{X} X \textordfeminine ª \textordmasculine º
LaTeXML-0.7.0/t/fonts/fonts.dvi0000644002506700454610000000521411214255136015267 0ustar miller891div; TeX output 2007.12.03:1214y?eb8K`y cmr10LettersGreekcSymbGols3JNumbGersMfffdDefault -W b> cmmi10Fcff z6[a8+b !", cmsy10[c]123ff覍F*amilies mathrm[ F z[a8+b[c]123mathsf[ m#R cmss10F I z[a8+b[c]123mathttY cmmi10K`y cmr10 VLaTeXML-0.7.0/t/fonts/fonts.xml0000644002506700454610000007755111214255136015322 0ustar miller891div Letters Greek Symbols Numbers Default - F f f α Γ + a b c 123 Families mathrm Fff α Γ + a b c 123 mathsf Fff α Γ + a b c 123 mathtt Fff α Γ + a b c 123 mathcal F f f α Γ + a b c 123 Series mathbf Fff α Γ + a b c 123 Shape mathit Fff α Γ + a b c 123 OldStyle rm Fff α Γ + a b c 123 bf Fff α Γ + a b c 123 it Fff α Γ + a b c 123 Combinations mathsf/mathit Fff α Γ + a b c 123 mathit/mathsf Fff α Γ + a b c 123 mathsf/it Fff α Γ + a b c 123 Boldmath - Fff αΓ +abc 123 mathrm Fff αΓ +abc 123 mathsf Fff αΓ +abc 123 mathtt Fff αΓ +abc 123 mathcal Fff αΓ +abc 123 mathit Fff αΓ +abc 123

roman roman-italic sans sans-slant

LaTeXML-0.7.0/t/fonts/textsymbols.dvi0000644002506700454610000000351411214255136016534 0ustar miller891div; TeX output 2007.12.03:1214y?>Nff cmbx121VLTfextffSymbs3ols7 ->DD\textquotedblleft?ò\D\textquotedblright?ò"D\textquoteleft?ò`D\textquoteright?ò'D\textsterling? P cmu10$D\textasteriskcentered? !", cmsy10D\textbackslash?ønD\textbar?øjD\textbraceleft?øfD\textbraceright?øgD\textbullet?øD\textdaggerdbl?øzD\textdagger?øyD\textparagraph?ø{D\textperiodcentered?øD\textsection?øxD\textcircled{x}5ײx?ø D\textless? b> cmmi10D\textcopyrightײc?ø D\textasciicircum?ò^D\textasciitilde?ò~D\textcompwordmarkD\textunderscore[ffD\textvisiblespace[Jff?ff?ÄJffD\textellipsis?ò...D\textregisteredXٓRcmr7R?ø &D\texttrademark?ß^TMD\textsuperscript{X}?ß^X D\textordfeminine?ß^aD\textordmasculine?ß^o1*;y  P cmu10 cmmi10K`y cmr10ٓRcmr7LaTeXML-0.7.0/t/tokenize/0000755002506700454610000000000011215766043014134 5ustar miller891divLaTeXML-0.7.0/t/tokenize/alltt.tex0000644002506700454610000000046211214255135015772 0ustar miller891div\documentclass{article} \usepackage{alltt} \begin{document} Spacing \begin{alltt} Word Word Word Word Word \end{alltt} OK Funny Characters \begin{alltt} a b $ c & d # e ^ f _ g % h ~ i \end{alltt} With math? \begin{alltt} a+b \begin{math}a+b\end{math} a+b \end{alltt} \end{document} LaTeXML-0.7.0/t/tokenize/comment.tex0000644002506700454610000000156711214255135016323 0ustar miller891div\documentclass{article} \usepackage{comment} \includecomment{Included} \excludecomment{Excluded} \specialcomment{BoldSpecial}{[\begingroup\bf}{\endgroup]} \begin{document} Before Comment. \begin{comment} Inside Comment. \end{comment} After Comment. Before Included. \begin{Included} Inside Included. \end{Included} After Included. Before Excluded. \begin{Excluded} Inside Excluded. \end{Excluded} After Excluded. Before BoldSpecial. \begin{BoldSpecial} Inside BoldSpecial. \end{BoldSpecial} After BoldSpecial. Before Included. \begin{Included} \bf Bold Inside Included. \end{Included} After Included, but still Bold. \end{document} % Following doesn't even work in LaTeX ?? Before Comment \comment Inside Comment \endcomment After Comment Before Included \Included Inside Included \endIncluded After Included Before Excluded \Excluded Inside Excluded \endExcluded After Excluded LaTeXML-0.7.0/t/tokenize/alltt.xml0000644002506700454610000000145411214255135015774 0ustar miller891div

Spacing Word Word Word Word Word OK

Funny Characters a b $ c & d # e ^ f _ g % h ~ i

With math? a+b +ab a+b

LaTeXML-0.7.0/t/tokenize/mathtokens.dvi0000644002506700454610000000073011214255135017007 0ustar miller891div; TeX output 2008.08.06:1416y? b> cmmi10abc !", cmsy106K`y cmr10=abGcO6=': cmti10ab}'c;:::"3:1415926オa8bc1*;y': cmti10 !", cmsy10 b> cmmi10K`y cmr10XLaTeXML-0.7.0/t/tokenize/percent.dvi0000644002506700454610000000054011214255135016271 0ustar miller891div; TeX output 2008.08.06:2113y?MK`y cmr10T*extUUNff cmbx121VLTfestingffVerbatim>K`y cmr10NormalUU"V cmbx10Boldstu .>AbNormal?{\bfNonBold}stuff.>xxx>yyyUUMoreNormalBoldstu .MSomeUUinline\verbverbatim.>MoreUUinline\verbverbatim.Mxx\verby .=y1*;yNff cmbx121VLTfextffLigatures>K`y cmr10LDots...,UUversusdots... MAUUrange:q1{10getsen-dash.Ininterjection|likethis|getsem-dash.MAUU\quote"likethis.!č>2VLTyps3ewriterffnon-Ligatures>gets?em-dash.MA?``quote''likethis.1*;y a b c abc abc π 3.1415 926 a b c LaTeXML-0.7.0/t/tokenize/mathtokens.tex0000644002506700454610000000026411214255135017027 0ustar miller891div\documentclass{article} \begin{document} \[ abc \not= \mathrm{abc} \not= \mathit{abc} \ldots\] \[ \pi \approx 3.1415\;926 \] \[ a \cdot b \cdot c \cdot\cdot\cdot \] \end{document} LaTeXML-0.7.0/t/tokenize/comment.xml0000644002506700454610000000127311214255135016315 0ustar miller891div

Before Comment. After Comment.

Before Included. Inside Included. After Included.

Before Excluded. After Excluded.

Before BoldSpecial. [Inside BoldSpecial. ]After BoldSpecial.

Before Included. Bold Inside Included. After Included, but still Bold.

LaTeXML-0.7.0/t/tokenize/url.xml0000644002506700454610000000464011214255135015456 0ustar miller891div
Basic URLS

Basic url: http://example.com/~user or http://example.com/~user.

And even: http://example.com/\~{}user or http://example.com/\~{}user.

Path url: /foo/bar/baz or /foo/bar/baz

Verbatimness C:\foo\bar\baz or C:\foo\bar\baz

Styles

Email: or .

Defined urls

Myself: myself%node@gateway.net or .

Bracketting

Fancy url: <url: http://example.com/~user> or <url: http://example.com/~user>.

LaTeXML-0.7.0/t/tokenize/percent.xml0000644002506700454610000000103011214255135016302 0ustar miller891div

Text http://foo/bar and http://foo/baz%bar done.

Verbatim a_b done.

LaTeXML-0.7.0/t/tokenize/url.dvi0000644002506700454610000000233011214255135015432 0ustar miller891div; TeX output 2008.02.25:1128y?>Nff cmbx121VLBasicffURLS>K`y cmr10BasicUUurl:q2VLStyles>Email:qm#R cmss10myself%noGde@gateway*.netUUormyself%node@gateway*.net.>3VLDe nedffurls>Myself:qǻmyself%node@gateway.netUUormyself%noGde@gateway*.net.>4VLBracketting>F*ancy8url:㎸hurl:?http://example.com/j@userirorhurl:http://example.com/ >jD@useri㏲.1*;ym#R cmss10
Text Ligatures

LDots…, versus dots …

A range: 1–10 gets en-dash. In interjection — like this — gets em-dash.

A “quote” like this.

Typewriter non-Ligatures

LDots…, versus dots ...

A range: 1--10 gets en-dash. In interjection --- like this --- gets em-dash.

A ``quote'' like this.

LaTeXML-0.7.0/t/tokenize/url.tex0000644002506700454610000000152011214255135015450 0ustar miller891div\documentclass{article} \usepackage{url} \begin{document} \section{Basic URLS} Basic url: \url{http://example.com/~user} or \url|http://example.com/~user|. And even: \url{http://example.com/\~{}user} or \url|http://example.com/\~{}user|. Path url: \path{/foo/bar/baz} or \path|/foo/bar/baz| Verbatimness \path{C:\foo\bar\baz} or \path|C:\foo\bar\baz| \section{Styles} \DeclareUrlCommand\email{\urlstyle{sf}} Email: \email{myself%node@gateway.net} or \email|myself%node@gateway.net|. \section{Defined urls} \urldef{\myselfa}\url{myself%node@gateway.net} \urldef{\myselfb}\email|myself%node@gateway.net| Myself: \myselfa\ or \myselfb. \section{Bracketting} \DeclareUrlCommand\fancyurl{\def\UrlLeft{}\urlstyle{tt}} Fancy url: \fancyurl{http://example.com/~user} or \fancyurl|http://example.com/~user|. \end{document} LaTeXML-0.7.0/t/tokenize/alltt.dvi0000644002506700454610000000100011214255135015741 0ustar miller891div; TeX output 2007.12.03:1205y?MK`y cmr10Spacing>Word>OKMF*unnyUUCharacters>a b?$c&d#e^f_g%h~iMWithUUmath?>a+b? b> cmmi10a8+ba+b1*;y cmmi10K`y cmr10LaTeXML-0.7.0/t/tokenize/comment.dvi0000644002506700454610000000113011214255135016267 0ustar miller891div; TeX output 2007.12.03:1205y?MK`y cmr10BeforeUUComment.qAfterComment. MBeforeUUIncluded.qInsideIncluded.AfterIncluded.MBeforeUUExcluded.qAfterExcluded.MBeforeUUBoldSpGecial.q["V cmbx10InsideTBoldSpQecial.p]AfterBoldSpecial.MBeforeIncluded.Bold|Inside{Included. DAfterIncluded,butstill>Bold.1*;y"V cmbx10K`y cmr10LaTeXML-0.7.0/t/tokenize/percent.tex0000644002506700454610000000025011214255135016305 0ustar miller891div\documentclass%{foo} {article} \usepackage{url} \begin{document} Text \url{http://foo/bar} and \url{http://foo/baz%bar} done. Verbatim \verb%a_b% done. \end{document} LaTeXML-0.7.0/t/tokenize/ligatures.tex0000644002506700454610000000063711214255135016655 0ustar miller891div\documentclass{article} \begin{document} \section{Text Ligatures} LDots\ldots, versus dots ... A range: 1--10 gets en-dash. In interjection --- like this --- gets em-dash. A ``quote'' like this. \section{Typewriter non-Ligatures} \texttt{LDots\ldots, versus dots ...} \texttt{A range: 1--10 gets en-dash.} \texttt{In interjection --- like this --- gets em-dash.} \texttt{A ``quote'' like this.} \end{document} LaTeXML-0.7.0/t/tokenize/verb.tex0000644002506700454610000000075111214255135015611 0ustar miller891div\documentclass{article} \begin{document} \section{Testing Verbatim} Normal {\bf Bold} stuff. \begin{verbatim} AbNormal {\bf NonBold} stuff. \end{verbatim} \begin{verbatim} xxx AbNormal {\bf NonBold} stuff. xxx \end{verbatim} yyy More Normal {\bf Bold} stuff. % NOT allowed %\section{Inline \verb|\verb| verbatim.} Some inline \verb|\verb| verbatim. % But this IS allowed! \hbox{More inline \verb|\verb| verbatim.} % and this: x\hbox to 2in {\bf x\verb|\verb|y.}y \end{document} LaTeXML-0.7.0/t/tokenize/verb.xml0000644002506700454610000000203711214255135015610 0ustar miller891div
Testing Verbatim

Normal Bold stuff.

AbNormal {\bf NonBold} stuff. xxx AbNormal {\bf NonBold} stuff. xxx

yyy More Normal Bold stuff.

Some inline \verb verbatim.

More inline \verb verbatim.

xx\verby.y

LaTeXML-0.7.0/t/grouping/0000755002506700454610000000000011215766043014136 5ustar miller891divLaTeXML-0.7.0/t/grouping/mathgroup.xml0000644002506700454610000000421111214255137016660 0ustar miller891div

Expect Original : Original

Expect a + Original: +aOriginal

Expect Original : Original

Expect InBox + Original: InBox + Original

Expect Original : Original

Expect a + InlineMath: +aInlineMath

Expect Original : Original

Expect a + DisplayMath :

+ a DisplayMath

Expect Original : Original

Expect a + InText + InlineMath: +aInTextInlineMath

Expect Original : Original

LaTeXML-0.7.0/t/grouping/scopemacro.dvi0000644002506700454610000000214011214255137016766 0ustar miller891div; TeX output 2008.08.06:1418y?>Nff cmbx121VLOne>K`y cmr10ExpGectUUSection1:Unknown.!č>2VLTwo>ExpGectUUUnknown:qUnknown. EquationUU1=Unknown8(1)>ExpGectUUUnknown:qUnknown.6>N cmbx122.1\TwoptoneuT>ExpGectUUSubsection2.1:qUnknown>2.2\Twop`ointtwo>ExpGectUUUnknown:qUnknown.>2.3\Twop`ointthree>ExpGectUULabelledsubsection:qUnknown>2.4\Twop`ointfour>ExpGectUUUnknown:qUnknown.!č>3VLThree>ExpGectUUSection3:Unknown.>3.1\Threep`ointone>ExpGectUUSection3:qUnknown.!č>4VLFfour>ExpGectUUUnknown:qUnknown.1*;yN cmbx12Nff cmbx12K`y cmr10LaTeXML-0.7.0/t/grouping/scopemacro.xml0000644002506700454610000000440011214255137017005 0ustar miller891div
One

Expect Section 1:Section 1.

Two

Expect Unknown: Unknown.

= Equation 1 Equation 1

Expect Unknown: Unknown.

Two pt one

Expect Subsection 2.1: Subsection 2.1

Two point two

Expect Unknown: Unknown.

Two point three

Expect Labelled subsection: Labelled subsection

Two point four

Expect Unknown: Unknown.

Three

Expect Section 3:Section 3.

Three point one

Expect Section 3: Section 3.

Four

Expect Unknown: Unknown.

LaTeXML-0.7.0/t/grouping/mathgroup.tex0000644002506700454610000000127511214255137016667 0ustar miller891div\documentclass{article} % Did you know? % Mathmode and things like \hbox actually corresponds to groups! \begin{document} \def\foo{Original} Expect Original : \foo Expect a + Original: $ a + \mbox{\foo}$ Expect Original : \foo Expect InBox + Original: \hbox{\def\foo{InBox}\foo} + \foo Expect Original : \foo Expect a + InlineMath: $ \def\foo{InlineMath} a + \hbox{\foo}$ Expect Original : \foo Expect a + DisplayMath : \[ \def\foo{DisplayMath} a + \hbox{\foo}\] Expect Original : \foo % Note that text mode inside mathmode groups a 2nd level! Expect a + InText + InlineMath: $ \def\foo{InlineMath} a + \hbox{\def\foo{InText}\foo} + \hbox {\foo}$ Expect Original : \foo \end{document} LaTeXML-0.7.0/t/grouping/mathgroup.dvi0000644002506700454610000000153011214255137016643 0ustar miller891div; TeX output 2008.08.06:1418y?MK`y cmr10ExpGectUUOriginal:qOriginal MExpGectUUa+Original:q b> cmmi10a8+OriginalMExpGectUUOriginal:qOriginalMExpGectUUInBox+Original:qInBox"!+OriginalMExpGectUUOriginal:qOriginalMExpGectUUa+InlineMath:qǵa8+InlineMathMExpGectUUOriginal:qOriginalMExpGectUUa+DisplayMath:ŗصa8+DisplayMathMExpGectUUOriginal:qOriginal MExpGectUUa+InT*ext+InlineMath:qǵa8+InText!n+InlineMathMExpGectUUOriginal:qOriginal1*;y b> cmmi10K`y cmr10LaTeXML-0.7.0/t/grouping/scopemacro.latexml0000644002506700454610000000046611214255137017663 0ustar miller891divuse LaTeXML::Package; DefMacro('\where',"Section 1", scope=>"section:1"); DefMacro('\where',"Subsection 2.1", scope=>"subsection:2.1"); DefMacro('\where',"Labelled subsection", scope=>"label:labelled"); DefMacro('\where',"Section 3", scope=>"section:3"); DefMacro('\where',"Equation 1", scope=>"equation:1"); LaTeXML-0.7.0/t/grouping/scopemacro.tex0000644002506700454610000000116411214255137017011 0ustar miller891div\documentclass{article} \def\where{Unknown} \begin{document} \section{One} Expect Section 1:\where. \section{Two} Expect Unknown: \where. \begin{equation} \mbox{Equation 1} = \mbox{\where} \end{equation} Expect Unknown: \where. \subsection{Two pt one} Expect Subsection 2.1: \where \subsection{Two point two} Expect Unknown: \where. \subsection{Two point three}\label{labelled} Expect Labelled subsection: \where \subsection{Two point four} Expect Unknown: \where. \section{Three} Expect Section 3:\where. \subsection{Three point one} Expect Section 3: \where. \section{Four} Expect Unknown: \where. \end{document} LaTeXML-0.7.0/t/50_structure.t0000644002506700454610000000044411214255140015025 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/structure"); LaTeXML-0.7.0/t/complex/0000755002506700454610000000000011215766043013753 5ustar miller891divLaTeXML-0.7.0/t/complex/xii.dtd0000644002506700454610000000047411214255140015234 0ustar miller891div LaTeXML-0.7.0/t/complex/xii.dvi0000644002506700454610000000725411214255140015246 0ustar miller891div; TeX output 2006.02.06:10013ڍ&K`y cmr10OnUUthe rstdayofChristmasmytruelovegavetome aUUpartridgeinapGeartree.{OnUUtheseconddayofChristmasmytruelovegavetometwoUUturtledovesandUUapartridgeinapGeartree.OnUUthethirddayofChristmasmytruelovegavetomethreeUUfrenchhenstwoUUturtledovesandUUapartridgeinapGeartree.|OnUUthefourthdayofChristmasmytruelovegavetomefourUUcallingbirdsthreeUUfrenchhenstwoUUturtledovesandUUapartridgeinapGeartree.OnUUthe fthdayofChristmasmytruelovegavetome veUUgoldringsfourUUcallingbirdsthreeUUfrenchhenstwoUUturtledovesandUUapartridgeinapGeartree.OnUUthesixthdayofChristmasmytruelovegavetomesixUUgeesealaying veUUgoldringsfourUUcallingbirdsthreeUUfrenchhenstwoUUturtledovesandUUapartridgeinapGeartree.OnUUtheseventhUUdayofChristmasmytruelovegavetomesevenUUswansaswimmingsixUUgeesealaying veUUgoldringsfourUUcallingbirdsthreeUUfrenchhenstwoUUturtledovesandUUapartridgeinapGeartree.|OnUUtheeighthdayofChristmasmytruelovegavetomeeightUUmaidsamilkingsevenUUswansaswimmingsixUUgeesealaying veUUgoldringsfourUUcallingbirdsthreeUUfrenchhenstwoUUturtledovesandUUapartridgeinapGeartree.OnUUtheninthdayofChristmasmytruelovegavetomenineUUladiesdancing`1*3ڍ&eightUUmaidsamilking sevenUUswansaswimmingsixUUgeesealaying veUUgoldringsfourUUcallingbirdsthreeUUfrenchhenstwoUUturtledovesandUUapartridgeinapGeartree.OnUUthetenthdayofChristmasmytruelovegavetometenUUlordsaleapingnineUUladiesdancingeightUUmaidsamilkingsevenUUswansaswimmingsixUUgeesealaying veUUgoldringsfourUUcallingbirdsthreeUUfrenchhenstwoUUturtledovesandUUapartridgeinapGeartree.OnUUtheeleventhUUdayofChristmasmytruelovegavetomeelevenUUpipGerspipingtenUUlordsaleapingnineUUladiesdancingeightUUmaidsamilkingsevenUUswansaswimmingsixUUgeesealaying veUUgoldringsfourUUcallingbirdsthreeUUfrenchhenstwoUUturtledovesandUUapartridgeinapGeartree.OnUUthetwelfthUUdayofChristmasmytruelovegavetometwelveUUdrummersdrummingelevenUUpipGerspipingtenUUlordsaleapingnineUUladiesdancingeightUUmaidsamilkingsevenUUswansaswimmingsixUUgeesealaying veUUgoldringsfourUUcallingbirdsthreeUUfrenchhenstwoUUturtledovesandUUapartridgeinapGeartree.`2;3GK`y cmr10nLaTeXML-0.7.0/t/complex/xii.tex0000644002506700454610000000140011214255140015247 0ustar miller891div \let~\catcode~`76~`A13~`F1~`j00~`P2jdefA71F~`7113jdefPALLF PA''FwPA;;FPAZZFLaLPA//71F71iPAHHFLPAzzFenPASSFthP;A$$FevP A@@FfPARR717273F737271P;ADDFRgniPAWW71FPATTFvePA**FstRsamP AGGFRruoPAqq71.72.F717271PAYY7172F727171PA??Fi*LmPA&&71jfi Fjfi71PAVVFjbigskipRPWGAUU71727374 75,76Fjpar71727375Djifx :76jelse&U76jfiPLAKK7172F71l7271PAXX71FVLnOSeL71SLRyadR@oL RrhC?yLRurtKFeLPFovPgaTLtReRomL;PABB71 72,73:Fjif.73.jelse B73:jfiXF71PU71 72,73:PWs;AMM71F71diPAJJFRdriPAQQFRsreLPAI I71Fo71dPA!!FRgiePBt'el@ lTLqdrYmu.Q.,Ke;vz vzLqpip.Q.,tz; ;Lql.IrsZ.eap,qn.i. i.eLlMaesLdRcna,;!;h htLqm.MRasZ.ilk,% s$;z zLqs'.ansZ.Ymi,/sx ;LYegseZRyal,@i;@ TLRlogdLrDsW,@;G LcYlaDLbJsW,SWXJW ree @rzchLhzsW,;WERcesInW qt.'oL.Rtrul;e doTsW,Wk;Rri@stW aHAHHFndZPpqar.tridgeLinZpe.LtYer.W,:jbye LaTeXML-0.7.0/t/complex/xii.latexml0000644002506700454610000000163511214255140016127 0ustar miller891div#********************************************************************** # LaTeXML Declaration for David Carlisle's xii.tex #********************************************************************** use strict; use LaTeXML::Package; # Don't need to respect source newlines AssignValue(PRESERVE_NEWLINES=>0); # We'll use a DTD for a (trivial) Song, containing verses with lines. DocType("song","-//NIST LaTeXML//LaTeXML Poem",'xii.dtd'); # There's no explicit \begin{document}, so let the poem automatically open. Tag('song', autoOpen=>1); # Make \bigskip initiate a , closeable when needed. Tag('verse', autoClose=>1); DefConstructor('\bigskip',""); # David ends each line with \par; redefine \par to close an auto-opened DefConstructor('\par',sub{ $_[0]->maybeCloseElement('line'); }); Tag('line', autoClose=>1, autoOpen=>1); #********************************************************************** 1; LaTeXML-0.7.0/t/complex/xii.xml0000644002506700454610000001014111214255140015251 0ustar miller891div On the first day of Christmas my true love gave to me a partridge in a pear tree. On the second day of Christmas my true love gave to me two turtle doves and a partridge in a pear tree. On the third day of Christmas my true love gave to me three french hens two turtle doves and a partridge in a pear tree. On the fourth day of Christmas my true love gave to me four calling birds three french hens two turtle doves and a partridge in a pear tree. On the fifth day of Christmas my true love gave to me five gold rings four calling birds three french hens two turtle doves and a partridge in a pear tree. On the sixth day of Christmas my true love gave to me six geese a laying five gold rings four calling birds three french hens two turtle doves and a partridge in a pear tree. On the seventh day of Christmas my true love gave to me seven swans a swimming six geese a laying five gold rings four calling birds three french hens two turtle doves and a partridge in a pear tree. On the eighth day of Christmas my true love gave to me eight maids a milking seven swans a swimming six geese a laying five gold rings four calling birds three french hens two turtle doves and a partridge in a pear tree. On the ninth day of Christmas my true love gave to me nine ladies dancing eight maids a milking seven swans a swimming six geese a laying five gold rings four calling birds three french hens two turtle doves and a partridge in a pear tree. On the tenth day of Christmas my true love gave to me ten lords a leaping nine ladies dancing eight maids a milking seven swans a swimming six geese a laying five gold rings four calling birds three french hens two turtle doves and a partridge in a pear tree. On the eleventh day of Christmas my true love gave to me eleven pipers piping ten lords a leaping nine ladies dancing eight maids a milking seven swans a swimming six geese a laying five gold rings four calling birds three french hens two turtle doves and a partridge in a pear tree. On the twelfth day of Christmas my true love gave to me twelve drummers drumming eleven pipers piping ten lords a leaping nine ladies dancing eight maids a milking seven swans a swimming six geese a laying five gold rings four calling birds three french hens two turtle doves and a partridge in a pear tree. LaTeXML-0.7.0/t/00_tokenize.t0000644002506700454610000000044311214255140014607 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/tokenize"); LaTeXML-0.7.0/t/post/0000755002506700454610000000000011215766043013271 5ustar miller891divLaTeXML-0.7.0/t/post/simplemath-post.xml0000644002506700454610000001530311214255137017137 0ustar miller891div Testing Simple Math Parsing

Inline math +aba+b.

+ a b 123 a + b + 123 + a b f 123 a + b + f 123 f D f + a b f D f a + b f 1 + a b f 1 a + b ^ f a f ^ a
Restricted + a x b x 123 a x + b x + 123
LaTeXML-0.7.0/t/post/simplemath.xml0000644002506700454610000001017111214255137016152 0ustar miller891div Testing Simple Math Parsing

Inline math +ab.

+ a b 123 + a b f 123 f D f + a b f 1 + a b ^ f a
Restricted + a x b x 123
LaTeXML-0.7.0/t/65_graphics.t0000644002506700454610000000044411214255140014573 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/graphics"); LaTeXML-0.7.0/t/53_alignment.t0000644002506700454610000000044411214255140014746 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/alignment"); LaTeXML-0.7.0/t/22_fonts.t0000644002506700454610000000044111214255140014112 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/fonts"); LaTeXML-0.7.0/t/20_digestion.t0000644002506700454610000000044511214255140014750 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/digestion"); LaTeXML-0.7.0/t/lib/0000755002506700454610000000000011215766043013052 5ustar miller891divLaTeXML-0.7.0/t/lib/TestLaTeXML.pm0000644002506700454610000000663211214255136015460 0ustar miller891divpackage TestLaTeXML; use strict; use base qw(Test::Builder Exporter); use Test::More; our @EXPORT = (qw(latexml_ok is_xmlcontent is_filecontent is_strings skip_all latexml_tests), @Test::More::EXPORT); # Note that this is a singlet; the same Builder is shared. my $Test=Test::Builder->new(); # Test the conversion of all *.tex files in the given directory (typically t/something) # Skip any that have no corresponding *.xml file. sub latexml_tests { my($directory)=@_; if(!opendir(DIR,$directory)){ # Can't read directory? Fail (assumed single) test. $Test->expected_tests(1+$Test->expected_tests); do_fail($directory,"Couldn't read directory $directory:$!"); } else { local $Test::Builder::Level = $Test::Builder::Level+1; my @tests = map("$directory/$_", grep(s/\.tex$//, readdir(DIR))); closedir(DIR); $Test->expected_tests(1+scalar(@tests)+$Test->expected_tests); eval { use_ok("LaTeXML"); }; # || skip_all("Couldn't load LaTeXML"); } foreach my $test (@tests){ if(-f "$test.xml"){ latexml_ok("$test.tex","$test.xml",$test); } else { $Test->skip("No file $test.xml"); } }}} sub do_fail { my($name,$diag)=@_; { local $Test::Builder::Level = $Test::Builder::Level+1; my $ok = $Test->ok(0,$name); $Test->diag($diag); return $ok; }} sub skip_all { my($reason)=@_; $Test->skip_all($reason); } # Would like to evolve a sensible XML comparison. # This is a start... # NOTE: This assumes you will have successfully loaded LaTeXML. sub latexml_ok { my($texpath,$xmlpath,$name)=@_; my($latexml,$dom,$domstring); eval{ $latexml = LaTeXML->new(preload=>[], searchpath=>[], includeComments=>0, # verbosity=>-2); }; verbosity=>-1); }; return do_fail($name,"Couldn't instanciate LaTeXML: ".@!) unless $latexml; eval { $dom = $latexml->convertFile($texpath); }; return do_fail($name,"Couldn't convert $texpath: ".@!) unless $dom; { local $Test::Builder::Level = $Test::Builder::Level+1; is_xmlcontent($latexml,$dom,$xmlpath,$name); }} sub is_xmlcontent { my($latexml,$xmldom,$path,$name)=@_; my($domstring); if(!defined $xmldom){ do_fail($name,"The XML DOM was undefined for $name"); } else { eval { $domstring = $xmldom->toString(1); }; return do_fail($name,"Couldn't convert dom to string: ".@!) unless $domstring; { local $Test::Builder::Level = $Test::Builder::Level+1; is_filecontent([split('\n',$domstring)],$path,$name); }}} sub is_filecontent { my($strings,$path,$name)=@_; # if(!open(IN,"<:utf8",$path)){ if(!open(IN,"<",$path)){ do_fail($name,"Could not open $path"); } else { my @lines; { local $\=undef; @lines = ; } close(IN); { local $Test::Builder::Level = $Test::Builder::Level+1; is_strings($strings,[@lines],$name); }}} sub is_strings { my($strings1,$strings2,$name)=@_; my $max = $#$strings1 > $#$strings2 ? $#$strings1 : $#$strings2; my $ok = 1; for(my $i = 0; $i < $max; $i++){ my $string1 = $$strings1[$i]; my $string2 = $$strings2[$i]; if(defined $string1){ chomp($string1); } else{ $ok = 0; $string1 = ""; } if(defined $string2){ chomp($string2); } else{ $ok = 0; $string2 = ""; } if(!$ok || ($string1 ne $string2)){ return do_fail($name, "Difference at line ".($i+1)." for $name\n" ." got : '$string1'\n" ." expected : '$string2'\n"); }} $Test->ok(1, $name); } 1; LaTeXML-0.7.0/t/52_namespace.t0000644002506700454610000000044511214255140014724 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/namespace"); LaTeXML-0.7.0/t/70_parse.t0000644002506700454610000000044011214255140014075 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/parse"); LaTeXML-0.7.0/t/12_grouping.t0000644002506700454610000000044411214255140014615 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/grouping"); LaTeXML-0.7.0/t/56_ams.t0000644002506700454610000000043711214255140013555 0ustar miller891div# -*- CPERL -*- #********************************************************************** # Test cases for LaTeXML #********************************************************************** #use Test::More; use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/ams"); LaTeXML-0.7.0/t/maketests0000755002506700454610000002615311214255140014227 0ustar miller891div#!/usr/bin/perl -w # /=====================================================================\ # # | maketests | # # | Test Maintenance tool | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # use strict; use FindBin; use lib "$FindBin::RealBin/../blib/lib"; use Getopt::Long qw(:config no_ignore_case); use Pod::Usage; use LaTeXML; use LaTeXML::Util::Pathname; use Algorithm::Diff; #====================================================================== my $identity = "maketests (LaTeXML version $LaTeXML::VERSION)"; my ($doxml,$dodvi,$docompare)=(); my ($verbosity,$help,$showversion)=(0); GetOptions("xml!" => \$doxml, "dvi!" => \$dodvi, "compare!"=>\$docompare, "quiet" => sub { $verbosity--; }, "verbose" => sub { $verbosity++; }, "VERSION" => \$showversion, "help" => \$help, ) or pod2usage(-message => $identity, -exitval=>1, -verbose=>0, -output=>\*STDERR); pod2usage(-message=>$identity, -exitval=>1, -verbose=>2, -output=>\*STDOUT) if $help; if($showversion){ print STDERR "$identity\n"; exit(1); } pod2usage(-message=>"$identity\nMissing test TeX file", -exitval=>1, -verbose=>0,-output=>\*STDERR) unless @ARGV; my $source = $ARGV[0]; #====================================================================== # hmm... could be even more helpful # copy xml to a backup and compare ? # or compare option # What about if $ARG is a directory? Do all tests in that directory? foreach my $src_file (@ARGV){ $src_file .= ".tex" unless $src_file =~ /\.tex$/; if(! -f $src_file){ die "There seems to be no test case $src_file"; } my($dir,$name,$ext)=pathname_split($src_file); my $xml_file = pathname_concat($dir,"$name.xml"); my $dvi_file = pathname_concat($dir,"$name.dvi"); my $src_time = pathname_timestamp($src_file); my $xml_time = pathname_timestamp($xml_file); my $dvi_time = pathname_timestamp($dvi_file); if($docompare){ compare_xml($dir,$name); } else { # Possibly remake xml if(defined $doxml ? $doxml : !(-f $xml_file) || ($src_time > $xml_time)){ gen_xml($dir,$name); } elsif(! defined $doxml){ print STDERR "Test case $xml_file seems uptodate\n"; } # Possibly remake dvi if( (defined $dodvi ? $dodvi : !(-f $xml_file) || ($src_time > $dvi_time))){ gen_dvi($dir,$name); } elsif(! defined $dodvi){ print STDERR "Test case $dvi_file seems uptodate\n"; } } } #====================================================================== # Question! # How should the comparison be done? # * Incorporate a diff algorithm? Probably yes # * What form of the XML should be diff'd ? # Primarily a question of whitespace, # but potentially also namespace, PI, comments ? # Forms: # - the literal straight output of latexml? # - a normalized form that puts one element per line? # Whatever form, it is most useful if it is the same form # as is used by "make test" itself! # Or should it??? # The normalized form is most sensible for comparison, # but the literal form is most expected(?) for test!! # (else, we're ignoring whitespace changes in test) sub compare_xml { my($dir,$name)=@_; #======================================== # Generate the XML from the current latexml my $latexml= LaTeXML->new(preload=>[], searchpath=>[], includeComments=>0); my $file = pathname_concat($dir,$name); my $newdom = $latexml->convertFile(pathname_concat($dir,$name)) or die "Failed to convert $file.tex: $!"; my $newlines = stringifyDom($newdom); #======================================== # Read in the expected xml. my $parser = XML::LibXML->new(); my $olddom = $parser->parse_file("$file.xml"); my $oldlines = stringifyDom($olddom); #======================================== # Do the comparison print "\n".("="x40)."\nCompare Expected $dir/$name to current output XML:\n"; my $diff = Algorithm::Diff->new($oldlines,$newlines); while( $diff->Next() ) { next if $diff->Same(); my $sep = ''; if( ! $diff->Items(2) ) { printf "Missing: %d,%dd%d\n", $diff->Get(qw( Min1 Max1 Max2 )); } elsif( ! $diff->Items(1) ) { printf "Added: %da%d,%d\n", $diff->Get(qw( Max1 Min2 Max2 )); } else { $sep = "---\n"; printf "Changed: %d,%dc%d,%d\n", $diff->Get(qw( Min1 Max1 Min2 Max2 )); } print "< $_\n" for $diff->Items(1); print $sep; print "> $_\n" for $diff->Items(2); } } sub stringifyDom { my($dom)=@_; my $string = $dom->toString(2); [grep(/\S/,split("\n",$string))]; } sub gen_xml { my($dir,$name)=@_; my $latexml= LaTeXML->new(preload=>[], searchpath=>[], includeComments=>0); my $file = pathname_concat($dir,$name); if(-f "$file.xml"){ rename("$file.xml", "$file.xml.bak"); } $latexml->convertAndWriteFile($file) or die "Failed to create $file.xml: $!" } sub gen_dvi { my($dir,$name)=@_; my $cwd = pathname_cwd(); chdir($dir) if $dir; # Get list of files currently in directory. opendir(DIR,".") or die "Cannot read directory $dir: $!"; my @files_before = readdir(DIR); closedir(DIR); my $program = 'tex'; open(IN,"$name.tex") or die "Cannot scanTeX file $name.tex: $!"; while(){ $program = 'latex' if /documentclass/; } close(IN); $ENV{TEXINPUTS} = "$FindBin::RealBin/../texmf/::".($ENV{TEXINPUTS}||''); system($program,$name) == 0 or die "Couldn't run $program $name: $!"; system($program,$name) == 0 or die "Couldn't run $program $name: $!"; # Now delete an new files except $name.dvi opendir(DIR,".") or die "Cannot read directory $dir: $!"; my @files_now = readdir(DIR); closedir(DIR); foreach my $f (@files_now){ if(($f ne "$name.dvi") && !grep($f eq $_, @files_before)){ unlink($f); }} chdir($cwd) if $dir; } #====================================================================== __END__ =pod =head1 NAME C - LaTeXML test maintenance tool =head1 SYNOPSIS Use make test from the build directory to run all tests. To compare the current latexml output for I against the expected output: maketests --compare set/case To regenerate the xml for a specific case, that is, to assert that the XML as it is currently generated is what should now be expected for that case, use maketests set/case For help and description of the test framework: maketests --help =head1 OVERVIEW LaTeXML includes a set of test cases for validating the compilation and installation, as well as for verifying the impact of changes to the system. Tests are conducted using the standard L module, by executing make test from the top level build directory. It reports whether all tests are completed successfully, or which tests failed to generate the expected XML, typically showing the first mismatching line. =head2 Test Suite Organization Tests are collected in sets in the C subdirectory of the LaTeXML build directory. Each set tests related functionality and is represented by its own subdirectory (eg. I), and a driver program (eg. I<44_someset.t>) in the C directory. The driver runs all the test cases in given set's directory. Each test case, say I, within a test set consists of 3 files: case.tex The source TeX file case.xml The expected XML output from latexml case.dvi The result of running latex; This file is only for understanding the effect of the TeX markup. [The driver program and all three files for each testcase should be under SVN control.] =head2 Testing The C command should be run whenever LaTeXML is modified to verify that unexpected changes to the generated XML have not been introduced. Given the nature of TeX and LaTeXML, such surprises can be frequent! When failed tests are discovered, the command maketest --compare set/case can be run to see the differences between the expected output and the currently generated output. If the new output is not correct, you must continue refining LaTeXML until all tests pass. However, if the new output is preferred for whatever reason, the command maketest set/case should be used to update the test. Whenever new functionality is added to LaTeXML, new test cases or even new sets of test cases should be added. See the documentation below for more details about these forms of C, and the documentation for L for more information about testing Perl modules. =head1 TESTING OPERATIONS =head2 Comparing XML Output When a test fails, it is often unclear exactly how the output has changed; C only reports the first differing line of XML. The command maketests --compare set/case ... will generate the new output compare it to the expected output in a diff-like manner. Multiple testcases can be given on the command line. Note that to aid in comprehension, the XML is reformatted to start and end each element on a new line. In contrast, the testing in C compares the literal XML without changing whitespace. Thus, changes that only affect whitespace will report a failed test from C, but C will report the output as identical! =head2 Updating a Test Case Occasionally, modifications to latexml or its binding files change the expectations about what the generated XML should look like; presumably the new version is better. Or sometimes, you wish to improve the test by making it more comprehensive. In such cases, the test case(s) will need to be updated by regenerating the expected xml, and the dvi if the tex changed. Simply run maketests set/case ... Multiple testcases can be given on the command line to be updated. To force regeneration of the dvi, use: maketests --dvi set/case ... Remember to commit any changed files. =head2 Adding a Test Case To add a new test case, I, to an existing test set, I, create the appropriate TeX file C that involves the markup to be tested. Then run maketests set/newcase ... to create the required I and I files. Multiple testcases can be added at once. Remember to add all three files to the SVN repository. =head2 Adding a Test Set To create a new set of tests, say I, create the directory I to contain the test cases and a driver program, I, (choose a number for I<##> to specifies when this test set will run in the sequence). The driver should look like: use FindBin; use lib "$FindBin::Bin/lib"; use TestLaTeXML; latexml_tests("t/newset"); Then add any desired testcases as described above. Remember to add the directory, driver and any tests to the SVN repository. =cut LaTeXML-0.7.0/lib/0000755002506700454610000000000011215766043012607 5ustar miller891divLaTeXML-0.7.0/lib/LaTeXML/0000755002506700454610000000000011215766043014015 5ustar miller891divLaTeXML-0.7.0/lib/LaTeXML/Package/0000755002506700454610000000000011215766043015350 5ustar miller891divLaTeXML-0.7.0/lib/LaTeXML/Package/pst-grad.sty.ltxml0000644002506700454610000000261411214255161020765 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | pst-grad.sty | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML | # # | | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; RequirePackage('pstricks'); ########################################################################### ## Additional key-value pairs ########################################################################### # NOTE: None of these are yet being carried into the XML, # and thus not converted usefully to SVG. # However, the current status allows them to be propogated to image generation. # Actually, none of these have to even be declared. # Allows fillstyle=gradient. # gradbegin= # gradend= # gradlines= # gradmidpoint= # gradangle= 1; LaTeXML-0.7.0/lib/LaTeXML/Package/natbib.sty.ltxml0000644002506700454610000004546011215766021020514 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | natbib | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; use LaTeXML::Util::KeyVal; #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # natbib # following natbib.pdf document # The basic support function for citation styles is in LaTeX.pool # Other formatting support is in Post::MakeBibliography #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #====================================================================== # 5. Package Options # The kind of braces around citations DeclareOption('round', sub { setCitationStyle(round=>1); }); DeclareOption('curly', sub { setCitationStyle(curly=>1); }); DeclareOption('square', sub { setCitationStyle(square=>1); }); DeclareOption('angle', sub { setCitationStyle(angle=>1); }); # The kind of separator between multiple citations DeclareOption('semicolon', sub { setCitationStyle(semicolon=>1); }); DeclareOption('colon', sub { setCitationStyle(semicolon=>1); }); # SIC! DeclareOption('comma', sub { setCitationStyle(comma=>1); }); # The kind of citation DeclareOption('authoryear',sub { setCitationStyle(authoryear=>1); }); DeclareOption('numbers', sub { setCitationStyle(numbers=>1); }); DeclareOption('super', sub { setCitationStyle(super=>1); }); # sorting options DeclareOption('sort', sub {}); DeclareOption('sort&compress',sub {}); DeclareOption('compress', sub {}); DeclareOption('longnamesfirst',sub {}); DeclareOption('sectionbib', sub {}); DeclareOption('nonamebreak',sub {}); # They _say_ round & semicolon but ... #ExecuteOptions('square','comma','authoryear'); ExecuteOptions('round','semicolon','authoryear'); ProcessOptions(); #====================================================================== # 2.3 Basic Citation Commands # Leverage the definitions in LaTeX.pool. # Note that LaTeX's \cite command is treated almost equivalent to \citet in authoryear mode, # but like \citep in numbers mode. DefMacro('\cite[] Semiverbatim', sub { my($gullet,$post,$keys)=@_; my($open,$close,$ns)=map(LookupValue($_),qw(CITE_OPEN CITE_CLOSE CITE_NOTE_SEPARATOR)); $post = undef unless $post && $post->unlist; if(LookupValue('CITE_STYLE') eq 'numbers'){ Invocation(T_CS('\@@cite'), Tokens($open, Invocation(T_CS('\@@bibref'),T_OTHER("Number"),$keys,undef,undef), ($post ? ($ns,T_SPACE,$post):()), $close)); } else { Invocation(T_CS('\@@cite'), Invocation(T_CS('\@@bibref'), T_OTHER("Authors Phrase1YearPhrase2"), $keys, Invocation(T_CS('\@@citephrase'),$open), Invocation(T_CS('\@@citephrase'), Tokens(($post ? ($ns,T_SPACE,$post):()), $close)))); } }); DefMacro('\citet OptionalMatch:* [][] Semiverbatim', sub { my($gullet,$star,$pre,$post,$keys)=@_; my($open,$close,$ns)=map(LookupValue($_),qw(CITE_OPEN CITE_CLOSE CITE_NOTE_SEPARATOR)); if(!$post){ ($pre,$post)=(undef,$pre); } $pre = undef unless $pre && $pre->unlist; $post = undef unless $post && $post->unlist; my $author = ($star ? "FullAuthors" : "Authors"); if(LookupValue('CITE_STYLE') eq 'numbers'){ Invocation(T_CS('\@@cite'), Tokens(($pre ? ($pre,T_SPACE):()), Invocation(T_CS('\@@bibref'), T_OTHER("$author Phrase1NumberPhrase2"), $keys, Invocation(T_CS('\@@citephrase'),$open), Invocation(T_CS('\@@citephrase'),$close))->unlist, ($post ? ($ns->unlist,T_SPACE,$post->unlist):()))); } else { Invocation(T_CS('\@@cite'), Invocation(T_CS('\@@bibref'), T_OTHER("$author Phrase1YearPhrase2"), $keys, Invocation(T_CS('\@@citephrase'), Tokens($open,($pre ? ($pre,T_SPACE):()))), Invocation(T_CS('\@@citephrase'), Tokens(($post ? ($ns,T_SPACE,$post):()),$close)))); } }); DefMacro('\citep OptionalMatch:* [][] Semiverbatim', sub { my($gullet,$star,$pre,$post,$keys)=@_; my($open,$close,$ns,$ay)=map(LookupValue($_),qw(CITE_OPEN CITE_CLOSE CITE_NOTE_SEPARATOR CITE_AY_SEPARATOR)); if(!$post){ ($pre,$post)=(undef,$pre); } $pre = undef unless $pre && $pre->unlist; $post = undef unless $post && $post->unlist; my $author = ($star ? "FullAuthors" : "Authors"); if(LookupValue('CITE_STYLE') eq 'numbers'){ Invocation(T_CS('\@@cite'), Tokens($open,($pre ? ($pre,T_SPACE):()), Invocation(T_CS('\@@bibref'),T_OTHER("Number"),$keys, undef,undef), ($post ? ($ns,T_SPACE,$post):()),$close)); } else { Invocation(T_CS('\@@cite'), Tokens($open->unlist,($pre ? ($pre,T_SPACE):()), Invocation(T_CS('\@@bibref'), T_OTHER("${author}Phrase1Year"), $keys, Invocation(T_CS('\@@citephrase'),$ay), undef), ($post ? ($ns,T_SPACE,$post):()),$close)); } }); #====================================================================== # 2.4 Extended Citation Commands DefMacro('\@@cite@noparens',sub { AssignValue(CITE_OPEN=>Tokens()); AssignValue(CITE_CLOSE=>Tokens()); }); # The next two are the same as \citet, \citep, but redefine open & close to empty. DefMacro('\citealt OptionalMatch:* [][] Semiverbatim', sub { my($gullet,$star,$pre,$post,$keys)=@_; (T_CS('\bgroup'),T_CS('\@@cite@noparens'), Invocation(T_CS('\citet'),$star,$pre,$post,$keys)->unlist, T_CS('\egroup')); }); DefMacro('\citealp OptionalMatch:* [][] Semiverbatim', sub { my($gullet,$star,$pre,$post,$keys)=@_; (T_CS('\bgroup'),T_CS('\@@cite@noparens'), Invocation(T_CS('\citep'),$star,$pre,$post,$keys)->unlist, T_CS('\egroup')); }); DefMacro('\citenum Semiverbatim', sub { my($gullet,$keys)=@_; Invocation(T_CS('\@@cite'), Invocation(T_CS('\@@bibref'),T_OTHER("Number"),$keys,undef,undef)); }); # Sorta right, but would like to avoid the nested ! # maybe can neutralize \@@cite? DefMacro('\citetext','\@@cite'); DefMacro('\citeauthor OptionalMatch:* Semiverbatim', sub { my($gullet,$star,$keys)=@_; my $author = ($star ? "FullAuthors" : "Authors"); Invocation(T_CS('\@@cite'), Invocation(T_CS('\@@bibref'),T_OTHER($author),$keys,undef,undef)); }); DefMacro('\citefullauthor Semiverbatim', sub { my($gullet,$star,$keys)=@_; Invocation(T_CS('\@@cite'), Invocation(T_CS('\@@bibref'),T_OTHER("FullAuthors"),$keys,undef,undef)); }); DefMacro('\citeyear Semiverbatim', sub { my($gullet,$keys)=@_; Invocation(T_CS('\@@cite'), Invocation(T_CS('\@@bibref'),T_OTHER("Year"),$keys,undef,undef)); }); DefMacro('\citeyearpar Semiverbatim', sub { my($gullet,$keys)=@_; my($open,$close)=map(LookupValue($_),qw(CITE_OPEN CITE_CLOSE)); Invocation(T_CS('\@@cite'), Tokens($open, Invocation(T_CS('\@@bibref'),T_OTHER("Year"),$keys,undef,undef), $close)); }); #====================================================================== # 2.5 Forcing Upper Cased Name # These are SUPPOSED to capitalize the first letter, .. but DefMacro('\Citet','\citet'); DefMacro('\Citep','\citep'); DefMacro('\Citealt','\citealt'); DefMacro('\Citealp','\citealp'); DefMacro('\Citeauthor','\citeauthor'); #====================================================================== # 2.6 Citation Aliasing # Citation aliasing is achieved with # \defcitealias{key}{text} # \citetalias{key} ==>> text # \citepalias{key} ==>> (text) # should end the defined key with \@extra@b@citeb ??? DefPrimitive('\defcitealias Semiverbatim {}', sub { my($gullet,$key,$text)=@_; DefMacroI(T_CS('\al@'.ToString($key)),undef,$text); }); # These use the above defined text to fill in the bibref # (which will still be a link to the bibitem!) DefMacro('\citetalias Semiverbatim', sub { my($gullet,$key)=@_; my($open,$close)=map(LookupValue($_),qw(CITE_OPEN CITE_CLOSE)); Invocation(T_CS('\@@cite'), Invocation(T_CS('\@@bibref'), T_OTHER("Phrase1"), $key, Invocation(T_CS('\@@citephrase'),T_CS('\al@'.ToString($key))))); }); DefMacro('\citepalias Semiverbatim', sub { my($gullet,$key)=@_; my($open,$close)=map(LookupValue($_),qw(CITE_OPEN CITE_CLOSE)); Invocation(T_CS('\@@cite'), Tokens($open, Invocation(T_CS('\@@bibref'), T_OTHER("Phrase1"), $key, Invocation(T_CS('\@@citephrase'),T_CS('\al@'.ToString($key)))), $close)); }); #====================================================================== # 2.9 Selecting Citation Punctuation DefKeyVal('natbib','authoryear','','true'); DefKeyVal('natbib','numbers','','true'); DefKeyVal('natbib','super','','true'); DefKeyVal('natbib','round','','true'); DefKeyVal('natbib','square','','true'); DefKeyVal('natbib','open',''); DefKeyVal('natbib','close',''); DefKeyVal('natbib','semicolon',''); DefKeyVal('natbib','comma',''); DefKeyVal('natbib','citesep',''); DefKeyVal('natbib','aysep',''); DefKeyVal('natbib','yysep',''); DefKeyVal('natbib','notesep',''); AssignValue(CITE_AY_SEPARATOR=>T_OTHER(',')); sub setCitationStyle { my(@pairs)=@_; while(@pairs){ my($key,$value)=(shift(@pairs),shift(@pairs)); $key = ToString(Digest($key)) if ref $key; if ($key eq 'authoryear'){ AssignValue(CITE_STYLE=>'authoryear'); } elsif($key eq 'numbers'){ AssignValue(CITE_STYLE=>'numbers'); } elsif($key eq 'super'){ AssignValue(CITE_STYLE=>'super'); } elsif($key eq 'round'){ AssignValue(CITE_OPEN=>T_OTHER('(')); AssignValue(CITE_CLOSE=>T_OTHER(')')); } elsif($key eq 'square'){ AssignValue(CITE_OPEN=>T_OTHER('[')); AssignValue(CITE_CLOSE=>T_OTHER(']')); } elsif($key eq 'curly'){ AssignValue(CITE_OPEN=>T_OTHER('{')); AssignValue(CITE_CLOSE=>T_OTHER('}')); } elsif($key eq 'angle'){ AssignValue(CITE_OPEN=>T_OTHER('<')); AssignValue(CITE_CLOSE=>T_OTHER('>')); } elsif($key eq 'open'){ AssignValue(CITE_OPEN=>$value); } elsif($key eq 'close'){ AssignValue(CITE_CLOSE=>$value); } elsif($key eq 'semicolon'){ AssignValue(CITE_SEPARATOR=>T_OTHER(';')); } elsif($key eq 'comma'){ AssignValue(CITE_SEPARATOR=>T_OTHER(',')); } elsif($key eq 'aysep'){ AssignValue(CITE_AY_SEPARATOR=>$value); } elsif($key eq 'yysep'){ AssignValue(CITE_YY_SEPARATOR=>$value); } elsif($key eq 'notesep'){ AssignValue(CITE_NOTE_SEPARATOR=>$value); } else { Warn(":unexpected:$key Unexpected $key=$value while setting Citation Style"); }} return; } DefPrimitive('\setcitestyle RequiredKeyVals:natbib', sub { setCitationStyle($_[1]->getPairs); }); DefPrimitive('\bibpunct[]{}{}{}{}{}{}', sub { my($stomach,$notesep,$open,$close,$sep,$style,$aysep,$yysep)=@_; $style = ToString(Digest($style)); AssignValue(CITE_OPEN=>$open); AssignValue(CITE_CLOSE=>$close); AssignValue(CITE_SEPARATOR=>$sep); AssignValue(CITE_STYLE=>($style eq 'n' ? 'numbers' : ($style eq 's' ? 'super' : 'authoryear'))); AssignValue(CITE_AY_SEPARATOR=>$aysep); AssignValue(CITE_YY_SEPARATOR=>$yysep); AssignValue(CITE_NOTE_SEPARATOR=>$notesep) if $notesep; return; }); # NOTE that if this appears at the end next to the bibliography.... it's TOO LATE! # The doc says it loads newbib.cfg, but I don't see that... # \citestyle{newbib} DefMacro('\bibstyle{}', sub { my $style = T_CS('\bibstyle@'.ToString($_[1])); (LookupDefinition($style) ? ($style) : (T_CS('\relax'))); }); # \AtBeginDocument{\global\let\bibstyle=\@gobble} Let(T_CS('\@citestyle'),T_CS('\bibstyle')); DefMacro('\citestyle{}','\@citestyle{#1}\let\bibstyle\@gobble'); DefMacro('\bibstyle@chicago', '\bibpunct{(}{)}{;}{a}{,}{,}'); DefMacro('\bibstyle@named', '\bibpunct{[}{]}{;}{a}{,}{,}'); DefMacro('\bibstyle@agu', '\bibpunct{[}{]}{;}{a}{,}{,~}'); #Amer. Geophys. Union DefMacro('\bibstyle@copernicus', '\bibpunct{(}{)}{;}{a}{,}{,}'); #Copernicus Publications Let(T_CS('\bibstyle@egu'),T_CS('\bibstyle@copernicus')); Let(T_CS('\bibstyle@egs'),T_CS('\bibstyle@copernicus')); DefMacro('\bibstyle@agsm', '\bibpunct{(}{)}{,}{a}{}{,}\gdef\harvardand{\&}'); DefMacro('\bibstyle@kluwer', '\bibpunct{(}{)}{,}{a}{}{,}\gdef\harvardand{\&}'); DefMacro('\bibstyle@dcu', '\bibpunct{(}{)}{;}{a}{;}{,}\gdef\harvardand{and}'); DefMacro('\bibstyle@aa', '\bibpunct{(}{)}{;}{a}{}{,}'); # Astronomy & Astrophysics DefMacro('\bibstyle@pass', '\bibpunct{(}{)}{;}{a}{,}{,}'); #Planet. & Space Sci DefMacro('\bibstyle@anngeo', '\bibpunct{(}{)}{;}{a}{,}{,}'); #Annales Geophysicae DefMacro('\bibstyle@nlinproc', '\bibpunct{(}{)}{;}{a}{,}{,}'); #Nonlin.Proc.Geophys. DefMacro('\bibstyle@cospar', '\bibpunct{/}{/}{,}{n}{}{}'); DefMacro('\bibstyle@esa', '\bibpunct{(Ref.~}{)}{,}{n}{}{}'); DefMacro('\bibstyle@nature', '\bibpunct{}{}{,}{s}{}{\textsuperscript{,}}'); DefMacro('\bibstyle@plain', '\bibpunct{[}{]}{,}{n}{}{,}'); Let(T_CS('\bibstyle@alpha'),T_CS('\bibstyle@plain')); Let(T_CS('\bibstyle@abbrv'),T_CS('\bibstyle@plain')); Let(T_CS('\bibstyle@unsrt'),T_CS('\bibstyle@plain')); DefMacro('\bibstyle@plainnat', '\bibpunct{[}{]}{,}{a}{,}{,}'); Let(T_CS('\bibstyle@abbrvnat'),T_CS('\bibstyle@plainnat')); Let(T_CS('\bibstyle@unsrtnat'),T_CS('\bibstyle@plainnat')); #====================================================================== # 2.12 Other Formatting Options # mostly ignored... DefMacro('\bibsection',''); DefMacro('\bibpreamble',''); DefMacro('\bibfont',''); DefMacro('\citenumfont',''); DefMacro('\bibnumfmt{}','#1'); DefRegister('\bibhang',Dimension(0)); DefRegister('\bibsep',Dimension(0)); #====================================================================== # 2.13 Automatic Indexing of Citations # Ignored, but could be done... # However, it is basically equivalent to backrefs which are # automatically handled in MakeBibliography, anyway... RawTeX('\newif\ifciteindex'); DefMacro('\citeindextrue',''); DefMacro('\citeindexfalse',''); DefMacro('\citeindextype',''); #====================================================================== # 2.17 Long Author List on First Citation # Ignored (for now...) DefMacro('\shortcites Semiverbatim',''); #====================================================================== # Less Documented # For manually formatted bibliographies, the following magical incantations # will be recognized to deliniate the author and year: # \bibitem[Jones et al.(1990)]{key}... # \bibitem[Jones et al.(1990)Jones, Baker, and Williams]{key}... # \bibitem[Jones et al., 1990]{key}... # \bibitem[\protect\citeauthoryear{Jones, Baker, and Williams}{Jones et al.}{1990}]{key}... # \bibitem[\protect\citeauthoryear{Jones et al.}{1990}]{key}... # \bibitem[\protect\astroncite{Jones et al.}{1990}]{key}... # \bibitem[\protect\citename{Jones et al., }1990]{key}... # \harvarditem[Jones et al.]{Jones, Baker, and Williams}{1990}{key}... ##DefMacro('\bibitem','\refstepcounter{enumiv}\@ifnextchar[{\@lbibitem}{\@lbibitem[\the@bibitem]}'); DefMacro('\bibitem','\refstepcounter{@bibitem}\@ifnextchar[{\@lbibitem}{\@lbibitem[\the@bibitem]}'); RawTeX(<<'EOTeX'); %%% \def\citeauthoryear#1#2#3(@)(@)\@nil#4{% \if\relax#3\relax \NAT@wrout{\the@bibitem}{#2}{#1}{}{#4}\else \NAT@wrout{\the@bibitem}{#3}{#2}{#1}{#4}\fi} \def\astroncite#1#2(@)(@)\@nil#3{% \NAT@wrout{\the@bibitem}{#2}{#1}{}{#3}} \def\citename#1#2(@)(@)\@nil#3{% \expandafter\NAT@apalk#1#2, \@nil{#3}} \newcommand\harvarditem[4][]{% \if\relax#1\relax\bibitem[#2(#3)]{#4}\else\bibitem[#1(#3)#2]{#4}\fi } %%%% \def\@lbibitem[#1]#2{% \@@lbibitem{#2}\NAT@ifcmd#1(@)(@)\@nil{#2}\newblock} \newcommand\NAT@ifcmd{\futurelet\NAT@temp\NAT@ifxcmd} \newcommand\NAT@ifxcmd{\ifx\NAT@temp\relax\else\expandafter\NAT@bare\fi} \def\NAT@bare#1(#2)#3(@)#4\@nil#5{% \if @#2% \expandafter\NAT@apalk#1, , \@nil{#5}\else \NAT@wrout{\the@bibitem}{#2}{#1}{#3}{#5}\fi} \def\NAT@apalk#1, #2, #3\@nil#4{% \if\relax#2\relax\NAT@wrout{#1}{}{}{}{#4}\else\NAT@wrout{\the@bibitem}{#2}{#1}{}{#4}\fi} %%%% EOTeX # By this time, \NAT@wrout should look like: # \NAT@wrout{number}{year}{authors}{fullauthors}{bibkey} # So, we'll do one extra step, and format the refnum form DefMacro('\NAT@wrout{}{}{}{} Semiverbatim', sub { my($gullet,$number,$year,$authors,$fullauthors,$key)=@_; my($style,$open,$close)=map(LookupValue($_),qw(CITE_STYLE CITE_OPEN CITE_CLOSE)); $style = 'number' unless $authors->unlist && $year->unlist; if($style eq 'number'){ Invocation(T_CS('\NAT@@wrout'),$number,$year,$authors,$fullauthors, Tokens($open,$number,$close), $key)->unlist; } else { Invocation(T_CS('\NAT@@wrout'),$number,$year,$authors,$fullauthors, Tokens($authors,T_SPACE,$open,$year,$close), $key)->unlist; }}); DefConstructor('\NAT@@wrout{}{}{}{}{} Semiverbatim', "?#1(#1)" ."?#2(#2)" ."?#3(#3)" ."?#4(#4)" ."?#5(#5)", # Allow plain & in here ??? bounded=>1, beforeDigest=>sub{ Let(T_ALIGN,T_CS('\&')); } ); # Similar to the one defined in LaTeX.pool, but the bibtag's have been setup above. DefConstructor('\@@lbibitem Semiverbatim', "", afterDigest=>sub { my $key = CleanBibKey($_[1]->getArg(1)); my $id = ToString(Expand(T_CS('\the@bibitem@ID'))); $_[1]->setProperties(key=>$key, id=>$id); }); #====================================================================== # These macros allow you to get the pieces used in the current style # but don't seem to be used in natbib, so redefining them does nothing. DefMacro('\citestarts',sub { LookupValue('CITE_OPEN')->unlist; }); DefMacro('\citeends', sub { LookupValue('CITE_CLOSE')->unlist; }); DefMacro('\betweenauthors', 'and'); DefMacro('\harvardleft', sub { LookupValue('CITE_OPEN')->unlist; }); DefMacro('\harvardright', sub { LookupValue('CITE_CLOSE')->unlist; }); DefMacro('\harvardyearleft', sub { LookupValue('CITE_OPEN')->unlist; }); DefMacro('\harvardyearright', sub { LookupValue('CITE_CLOSE')->unlist; }); DefMacro('\harvardand', 'and'); DefConstructor('\harvardurl Semiverbatim', "#1", properties=>sub { (href=>CleanURL(ToString($_[1]))); }); Let(T_CS('\citeN'),T_CS('\cite')); Let(T_CS('\shortcite'),T_CS('\cite')); Let(T_CS('\citeasnoun'),T_CS('\cite')); DefMacro('\natexlab{}', '#1'); # ???? 1; LaTeXML-0.7.0/lib/LaTeXML/Package/multido.sty.ltxml0000644002506700454610000000501211214255161020714 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | multido.sty | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML | # # | | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; ########################################################################### ## ########################################################################### DefMacro('\multido{}{Number}{}',sub { my($gullet,$variables,$repetitions,$actions)=@_; my @vars=(); my @expansion=(); $gullet->openMouth($variables,1); while(my $var = $gullet->readToken){ $var->getCSName =~ /^\\(d|n|i|r)/i; my $type = $1; Error(":unexpected:".ToString($var)." Wrong format for multido variable: ".ToString($var)) unless $type; $gullet->readKeyword("=") or Error(":expected:= Missing = in multido variables"); my($init,$step); if ($type eq 'd'){ $init = $gullet->readDimension; } elsif($type eq 'n'){ $init = $gullet->readNumber; } elsif($type eq 'i'){ $init = $gullet->readNumber; } elsif($type eq 'r'){ $init = $gullet->readFloat; } $gullet->readKeyword("+") or Error(":expected:+ Missing + in multido variables"); if ($type eq 'd'){ $step = $gullet->readDimension; } elsif($type eq 'n'){ $step = $gullet->readNumber; } elsif($type eq 'i'){ $step = $gullet->readNumber; } elsif($type eq 'r'){ $step = $gullet->readFloat; } push(@expansion,T_CS('\def'),$var,T_BEGIN,$init->revert,T_END); push(@vars,[$var,$init,$step]); last unless $gullet->readKeyword(","); } $gullet->closeMouth; # Now, accumulate $repetitions copies of $actions # with @vars set appropriately. my $n = $repetitions->valueOf; for(my $i=0; $i<$n; $i++){ push(@expansion, $actions->unlist); foreach my $entry (@vars){ $$entry[1] = $$entry[1]->add($$entry[2]); push(@expansion,T_CS('\def'),$$entry[0],T_BEGIN,$$entry[1]->revert,T_END); }} @expansion; }); 1; LaTeXML-0.7.0/lib/LaTeXML/Package/alltt.sty.ltxml0000644002506700454610000000271211214255161020363 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | alltt | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; #********************************************************************** DefEnvironment('{alltt}',"#body", font=>{family=>'typewriter', series=>'medium', shape=>'upright'}, beforeDigest=>sub{ map(AssignCatcode($_=>CC_OTHER), ' ', '$', '&', '#', '^', '_', '%', '~'); AssignValue(PRESERVE_NEWLINES=>1); # \@noligs: This SHOULD inhibit ligature substitution! (eg quotes, dots, etc!!!) # \frenchspacing\@vobeyspaces }); #********************************************************************** 1; LaTeXML-0.7.0/lib/LaTeXML/Package/charter.sty.ltxml0000644002506700454610000000166011214255161020674 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | charter | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; # Nothing to do here. 1; LaTeXML-0.7.0/lib/LaTeXML/Package/aas_support.sty.ltxml0000644002506700454610000005671211214255161021614 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | aas_support.sty.ltxml | # # | Support for various AAS styles/classes for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # / Thanks to the arXMLiv group for # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # AAS : American Astronomical Society # Derived from aasguide # I have the suspicion that AAS style is strongly related to RevTeX, # but I don't see it ever made explicit. #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #====================================================================== # 2.1.3 Editorial Information DefMacro('\received{}', '\@add@frontmatter{ltx:date}[role=received]{#1}'); DefMacro('\revised{}', '\@add@frontmatter{ltx:date}[role=revised]{#1}'); DefMacro('\accepted{}', '\@add@frontmatter{ltx:date}[role=accepted]{#1}'); # Could add more metadata.. DefMacro('\journalid{}{}',''); DefMacro('\articleid{}{}',''); DefMacro('\paperid{}',''); DefMacro('\msid{}',''); # Manuscript id. #\ccc{code} DefMacro('\ccc{}',''); # Ignorable? #\cpright{type}{year} Should be recorded somehow? # type is AAS, ASP, PD, none DefMacro('\cpright{}{}', '\@add@frontmatter{ltx:note}[class=copyright]{\copyright #2: #1}'); # Editorial additions? DefMacro('\journal{}',''); DefMacro('\volume{}',''); DefMacro('\issue{}',''); DefMacro('\SGMLbi{}','#1'); DefMacro('\SGMLbsc{}','#1'); DefMacro('\SGMLclc{}','#1'); DefMacro('\SGMLentity{}','#1'); # Actually should produce  !!! DefMacro('\SGML{}',''); #====================================================================== # 2.1.4 Short Comment DefMacro('\slugcomment{}','\@add@frontmatter{ltx:note}[class=slugcomment]{#1}'); #====================================================================== # 2.1.5 Running Heads DefMacro('\shorttitle{}', '\@add@frontmatter{ltx:toctitle}{#1}'); DefMacro('\shortauthors{}',''); # not useful? DefMacro('\lefthead', '\shorttitle'); # Obsolete form DefMacro('\righthead','\shortauthors'); # Obsolete form #====================================================================== # 2.2 Starting the Main Body # normal LaTeX #====================================================================== # 2.3 Title and Author Information DefMacro('\author{}', '\@add@frontmatter{ltx:creator}[role=author]{\@personname{#1}}'); DefConstructor('\@affiliation{}',"^ #1"); DefMacro('\affil{}','\@add@to@frontmatter{ltx:creator}{\@affiliation{#1}}'); DefConstructor('\@authoraddr{}',"^ #1"); DefMacro('\authoraddr{}','\@add@to@frontmatter{ltx:creator}{\@authoraddr{#1}}'); DefConstructor('\@email{}',"^ #1"); DefMacro('\email{}', '\@add@to@frontmatter{ltx:creator}{\@email{#1}}'); # Redefine to straight email address after document begin. AddToMacro(T_CS('\@startsection@hook'),TokenizeInternal('\let\email\@@email')); # Ideally, this would add a contact to whatever author was identified with the mark! # \altaffilmark{keynumber} # \altaffiltext{keynumber}{text} DefMacro('\altaffilmark{}',''); DefMacro('\altaffiltext{}{}',''); DefPrimitive('\and',undef); DefMacro('\authoremail','\email'); # Obsolete form #====================================================================== # 2.4 Abstract # normal LaTeX #====================================================================== # 2.5 Keywords DefMacro('\keywords{}', '\@add@frontmatter{ltx:keywords}{#1}'); Let(T_CS('\subjectheadings'),T_CS('\keywords')); #====================================================================== # 2.6 Comments to Editors # Perhaps this should actually disappear? # DefConstructor('\notetoeditor{}',"#1"); DefMacro('\notetoeditor{}',''); NewCounter('editornote'); DefMacroI('\theeditornote',undef,'E\arabic{editornote}'); #====================================================================== # 2.7 Sections # normal LaTeX # Except that they apparently allow subsubsubsections! Ugh! #====================================================================== # 2.8 Figure and Table Placement # These tell where the table/figure labeled with \label{key} ought to appear; # the assumption is the tables/figures are at the end of the document. # Best would be if we moved them to there the \placeXXX is! # \placetable{key} # \placefigure{key} # For now, we ignore them, however. DefMacro('\placetable{}',''); DefMacro('\placefigure{}',''); DefMacro('\placeplate{}',''); NewCounter('plate'); DefEnvironment('{plate}[]', "" . "#body" ."", properties=> sub { RefStepCounter('plate') }); DefEnvironment('{plate*}[]', "" . "#body" ."", properties=> sub { RefStepCounter('plate') }); #====================================================================== # 2.9 Acknowledgements # acts like \section{Acknowledgements}, rather than container. Tag("ltx:acknowledgements", autoClose=>1); DefConstructor('\acknowledgements', ""); Let(T_CS('\acknowledgments'),T_CS('\acknowledgements')); #====================================================================== # 2.10 Facilities # Ultimately, this would get some more explicit semantic markup, but.. # \facility{facilityID} DefConstructor('\facility{}',"#1"); #====================================================================== # 2.11 Appendices # almost normal LaTeX DefPrimitive('\appendix',sub{ NewCounter('section', 'document', idprefix=>'A',nested=>['subsection']); NewCounter('equation', 'section', idprefix=>'E'); DefMacro('\thesection', '\Alph{section}'); DefMacro('\theequation','\thesection\arabic{equation}'); Let(T_CS('\section'),T_CS('\appendix@section'),'global'); }); #====================================================================== # 2.12 Equations # mostly normal LaTeX # Basically, {mathletters} is a copy of AMSMath's {subequations}... Isn't it? DefEnvironment('{mathletters}', "#body", afterDigestBegin=>sub { my($stomach,$whatsit)=@_; my %eqn = RefStepCounter('equation'); AssignValue(SAVED_EQUATION_NUMBER=>LookupValue('\c@equation')); ResetCounter('equation'); DefMacro('\theequation',UnTeX($eqn{refnum}).'\alph{equation}'); DefMacro('\theequation@ID',UnTeX($eqn{id}).'.\@equation@ID'); }, afterDigest =>sub{ AssignValue('\c@equation',LookupValue('SAVED_EQUATION_NUMBER'),'global'); }); # \eqnum{text} specifies equation number inside an equation # Basically, AMSMath's \tag ? DefConstructor('\eqnum {}', '', afterDigest=>sub { AssignValue(EQUATIONROW_NUMBER=>ToString(Digest($_[1])), 'global'); }, mode=>'text'); #====================================================================== # 2.13 Citations and Bibliography DefMacro('\markcite{}',''); # apparently like \cite w/o text? #====================================================================== # 2.13.1 The thebibliography Environment # normal LaTeX #====================================================================== # 2.13.2 Specifying Bibliographic and Citation Information RequirePackage('natbib'); # \bibitem[author(year)]{key} bibdata... #====================================================================== # 2.13.3 The references Environment # Is this the right treatment? # Is the same true for RevTeX? DefConstructor('\references', "" . "#refname" . "", afterDigest=>sub { my $docid = ToString(Expand(T_CS('\thedocument@ID'))); ResetCounter('enumiv'); DefMacroI(T_CS('\thebibliography@ID'),undef,($docid ? "$docid.bib" : 'bib')); $_[1]->setProperty(id=>ToString(Expand(T_CS('\thebibliography@ID')))); $_[1]->setProperty(refname=>Digest(T_CS('\refname'))); # Fix for missing \bibitems! setupPseudoBibitem(); }); DefConstructor('\endreferences', ""); Let(T_CS('\reference'),T_CS('\bibitem')); #====================================================================== # 2.13.4 Abbreviations for Journal Names DefMacro('\aj','{AJ}'); # Astronomical Journal DefMacro('\araa','{ARA\&A}'); # Annual Review of Astron and Astrophys DefMacro('\apj','{ApJ}'); # Astrophysical Journal DefMacro('\apjl','{ApJ}'); # Astrophysical Journal, Letters DefMacro('\apjs','{ApJS}'); # Astrophysical Journal, Supplement DefMacro('\ao','{Appl.~Opt.}'); # Applied Optics DefMacro('\apss','{Ap\&SS}'); # Astrophysics and Space Science DefMacro('\aap','{A\&A}'); # Astronomy and Astrophysics DefMacro('\aapr','{A\&A~Rev.}'); # Astronomy and Astrophysics Reviews DefMacro('\aaps','{A\&AS}'); # Astronomy and Astrophysics, Supplement DefMacro('\azh','{AZh}'); # Astronomicheskii Zhurnal DefMacro('\baas','{BAAS}'); # Bulletin of the AAS DefMacro('\jrasc','{JRASC}'); # Journal of the RAS of Canada DefMacro('\memras','{MmRAS}'); # Memoirs of the RAS DefMacro('\mnras','{MNRAS}'); # Monthly Notices of the RAS DefMacro('\pra','{Phys.~Rev.~A}'); # Physical Review A: General Physics DefMacro('\prb','{Phys.~Rev.~B}'); # Physical Review B: Solid State DefMacro('\prc','{Phys.~Rev.~C}'); # Physical Review C DefMacro('\prd','{Phys.~Rev.~D}'); # Physical Review D DefMacro('\pre','{Phys.~Rev.~E}'); # Physical Review E DefMacro('\prl','{Phys.~Rev.~Lett.}'); # Physical Review Letters DefMacro('\pasp','{PASP}'); # Publications of the ASP DefMacro('\pasj','{PASJ}'); # Publications of the ASJ DefMacro('\qjras','{QJRAS}'); # Quarterly Journal of the RAS DefMacro('\skytel','{S\&T}'); # Sky and Telescope DefMacro('\solphys','{Sol.~Phys.}'); # Solar Physics DefMacro('\sovast','{Soviet~Ast.}'); # Soviet Astronomy DefMacro('\ssr','{Space~Sci.~Rev.}'); # Space Science Reviews DefMacro('\zap','{ZAp}'); # Zeitschrift fuer Astrophysik DefMacro('\nat','{Nature}'); # Nature DefMacro('\iaucirc','{IAU~Circ.}'); # IAU Cirulars DefMacro('\aplett','{Astrophys.~Lett.}'); # Astrophysics Letters DefMacro('\apspr','{Astrophys.~Space~Phys.~Res.}'); # Astrophysics Space Physics Research DefMacro('\bain','{Bull.~Astron.~Inst.~Netherlands}'); # Bulletin Astronomical Institute of the Netherlands DefMacro('\fcp','{Fund.~Cosmic~Phys.}'); # Fundamental Cosmic Physics DefMacro('\gca','{Geochim.~Cosmochim.~Acta}'); # Geochimica Cosmochimica Acta DefMacro('\grl','{Geophys.~Res.~Lett.}'); # Geophysics Research Letters DefMacro('\jcp','{J.~Chem.~Phys.}'); # Journal of Chemical Physics DefMacro('\jgr','{J.~Geophys.~Res.}'); # Journal of Geophysics Research DefMacro('\jqsrt','{J.~Quant.~Spec.~Radiat.~Transf.}'); # Journal of Quantitiative Spectroscopy and Radiative Trasfer DefMacro('\memsai','{Mem.~Soc.~Astron.~Italiana}'); # Mem. Societa Astronomica Italiana DefMacro('\nphysa','{Nucl.~Phys.~A}'); # Nuclear Physics A DefMacro('\physrep','{Phys.~Rep.}'); # Physics Reports DefMacro('\physscr','{Phys.~Scr}'); # Physica Scripta DefMacro('\planss','{Planet.~Space~Sci.}'); # Planetary Space Science DefMacro('\procspie','{Proc.~SPIE}'); # Proceedings of the SPIE Let(T_CS('\astap'),T_CS('\aap')); Let(T_CS('\apjlett'),T_CS('\apjl')); Let(T_CS('\apjsupp'),T_CS('\apjs')); Let(T_CS('\applopt'),T_CS('\ao')); #====================================================================== # 2.14.1 Electronic Art RequirePackage('graphicx'); # \begin{figure} # \figurenum{text} # \epsscale{num} # \plotone{epsfile} # \plottwo{epsfile}{epsfile} # \caption{text} # \end{figure} DefMacro('\figurenum{}','\def\thefigure{#1}'); # Note: This needs an UnRefStepCounter('figure'); # or at least, defer the refstep till late enough to skip if needed? DefMacro('\epsscale{}',''); DefMacro('\plotone Semiverbatim','\includegraphics[width=\textwidth]{#1}'); DefMacro('\plottwo Semiverbatim Semiverbatim', '\hbox{\includegraphics[width=\textwidth]{#1}\includegraphics[width=\textwidth]{#2}}'); # \plotfiddle{epsfile}{vsize}{rot}{hsf}{vsf}{htrans}{vtrans} # Ugh... DefMacro('\plotfiddle Semiverbatim {}{}{}{}{}{}','\includegraphics[width=#4pt,height=#5pt]{#1}'); #====================================================================== # 2.14.2 Figure Captions # For figures added externally; Used at end of file. # \figcaption[filename]{text\label{key}} # But sometimes used just like \caption! DefMacro('\@figcaption OptionalSemiverbatim {}','\begin{figure}[#1]#2\end{figure}'); DefMacro('\figcaption',sub { ( ((LookupValue('current_environment')||'') =~ 'figure') ? T_CS('\caption') : T_CS('\@figcaption')); }); #====================================================================== # 2.15 Tables DefMacro('\dummytable','\refstepcounter{table}'); #====================================================================== # 2.15.1 The deluxetable Environment # \begin{deluxetable}{cols} # preamble # \startdata # data # \enddata # \tablenotetext,\tablecomments,\tablerefs # \end{deluxetable} DefMacro('\deluxetable{}','\set@deluxetable@template{#1}\def\@deluxetable@header{}\begin{table}'); DefMacro('\set@deluxetable@template AlignmentTemplate',sub { AssignValue('@deluxetable@template',$_[1]); }); DefMacro('\startdata', '\@deluxetable@bindings\@@deluxetabular\@start@alignment\hline\hline\@deluxetable@header'); DefMacro('\enddata', '\hline\@finish@alignment\@end@deluxetabular'); DefPrimitive('\@deluxetable@bindings',sub { alignmentBindings(LookupValue('@deluxetable@template'),'text'); }); DefConstructor('\@@deluxetabular DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body); }, reversion=>'\begin{tabular}[#1]{#2}#3\end{tabular}', beforeDigest=>sub { $_[0]->bgroup; }, mode=>'text'); DefPrimitive('\@end@deluxetabular',sub{ $_[0]->egroup; }); DefMacro('\enddeluxetable','\end{table}'); #====================================================================== # 2.15.2 Preamble to the deluxetable DefMacro('\tabletypesize{}',''); # Ignorable DefMacro('\rotate',''); # Ignorable ? DefMacro('\tabletail{}',''); DefMacro('\tablewidth{Dimension}',''); # Ignorable? DefMacro('\platewidth{Dimension}',''); # Ignorable? DefMacro('\tablenum{}','\def\thetable{#1}'); # Note: This needs an UnRefStepCounter('table'); DefMacro('\platenum{}','\def\theplate{#1}'); DefMacro('\tablecolumns{Number}',''); # Ignorable ??? Let(T_CS('\tablecaption'),T_CS('\caption')); DefMacro('\tablehead{}','\def\@deluxetable@header{#1\\\\\hline}'); DefMacro('\colhead{}','#1'); # Mark the existing rows as being headers DefPrimitive('\@mark@tableheader',sub { my $alignment = LookupValue('Alignment'); foreach my $row ($alignment->rows){ map($$_{head}=1, $row->columns); } return; }); DefMacro('\nl', '\\\\'); # Obsolete form DefMacro('\nextline', '\\\\'); # Obsolete form DefMacro('\tablevspace','\\\\'); # Obsolete form DefMacro('\tablebreak', '\\\\'); # Obsolete form #====================================================================== # 2.15.3 Content of deluxetable DefMacro('\phn','\phantom{0}'); DefMacro('\phd','\phantom{.}'); DefMacro('\phs','\phantom{+}'); DefMacro('\phm{}','\phantom{string}'); DefMacro('\tablebreak',''); # Ignorable; we're not splitting tables. DefMacro('\nodata',''); # Ignorable DefMacro('\cutinhead{}','\hline\multicolumn{\@alignment@ncolumns}{c}{#1}\\\\\hline'); DefMacro('\sidehead{}','\hline\multicolumn{\@alignment@ncolumns}{l}{#1}\\\\\hline'); #====================================================================== # 2.15.4 The table Environment # normal LaTeX DefMacro('\tableline','\hline'); # NOTE: DOM should reattach the footnotetext to the footnotemark ? # Same problem in LaTeX.pool... # In general the mark & text _could_ come in either order... # so, it really has to be at end of processing (rewrite?) DefMacro('\tablenotemark{}',''); #DefConstructor('\tablenotemark{}',""); # ???? DefMacro('\tablenotetext{}{}','\@tablenotetext{$\mathrm{#1}$}{#2}'); DefConstructor('\@tablenotetext{}{}', "#2", mode=>'text'); DefMacro('\tablerefs{}', 'References. -- #1'); DefMacro('\tablecomments{}','Note. -- #1'); #====================================================================== # 2.17 Miscellaneous #====================================================================== # 2.17.1 Celestial Objects and Data Sets # Ultimately, this would get some more explicit semantic markup, but.. # \objectname[catalogid]{text} # \dataset[catalogid]{text} DefConstructor('\objectname OptionalSemiverbatim Semiverbatim', "#1 (catalog #2)"); Let(T_CS('\object'),T_CS('\objectname')); # ??? DefConstructor('\dataset OptionalSemiverbatim Semiverbatim', "#1 (catalog #2)"); #====================================================================== # 2.17.2 Ionic Species and Chemical Bonds # Note that semantics could be useful! # \ion{element}{level} DefMacro('\ion{}{}','{#1 \uppercase{\romannumeral #2}}'); # NOTE: These are almost totally wrong... DefConstructor('\sbond',"\x{2212}"); DefConstructor('\dbond',"="); DefConstructor('\tbond',"\x{2261}"); #====================================================================== # 2.17.3 Fractions # \case{1}{2} == textstyle fraction # AND, apparently allowed in text mode! DefMacro('\case{}{}','\ensuremath{\text@frac{#1}{#2}}'); DefConstructor('\text@frac{}{}', "" . "" . "#1#2" ."", beforeDigest=>\&beforeTFrac, afterDigest =>\&afterTFrac); Let(T_CS('\slantfrac'),T_CS('\case')); #====================================================================== # 2.17.4 Astronomical Symbols # See aassymbols document. # Table 1: Additional AASTeX symbols DefConstructor('\micron',UTF(0xB5)."m"); DefMacro('\Sun','\sun'); DefMacro('\Sol','\sun'); DefConstructor('\sun', "\x{2609}"); DefConstructor('\Mercury', "\x{263F}"); DefConstructor('\Venus', "\x{2640}"); DefMacro('\Earth','\earth'); DefMacro('\Terra','\earth'); DefConstructor('\earth', "\x{2295}"); DefConstructor('\Mars', "\x{2642}"); DefConstructor('\Jupiter', "\x{2643}"); DefConstructor('\Saturn', "\x{2644}"); DefConstructor('\Uranus', "\x{2645}"); DefConstructor('\Neptune', "\x{2646}"); DefConstructor('\Pluto', "\x{2647}"); DefConstructor('\Moon', "\x{263D}"); # Not sure if this is the right Moon? DefMacro('\Luna','\Moon'); DefConstructor('\Aries', "\x{2648}"); DefMacro('\VEq','\Aries'); # Vernal Equinox DefConstructor('\Taurus', "\x{2649}"); DefConstructor('\Gemini', "\x{264A}"); DefConstructor('\Cancer', "\x{264B}"); DefConstructor('\Leo', "\x{264C}"); DefConstructor('\Virgo', "\x{264D}"); DefConstructor('\Libra', "\x{264E}"); DefMacro('\AEq','\Libra'); # Autumnal Equinox DefConstructor('\Scorpius', "\x{264F}"); DefConstructor('\Sagittarius', "\x{2650}"); DefConstructor('\Capricornus', "\x{2651}"); DefConstructor('\Aquarius', "\x{2652}"); DefConstructor('\Pisces', "\x{2653}"); DefConstructor('\diameter',"\x{2300}"); DefConstructor('\sq',"\x{25A1}"); DefConstructor('\arcdeg',UTF(0xB0)); Let(T_CS('\degr'),T_CS('\arcdeg')); DefConstructor('\arcmin',"\x{2032}"); DefConstructor('\arcsec',"\x{2033}"); # Hmm, will this work? DefConstructor('\aas@@fstack{}', "" . "" . "." . "#1" ."", properties=>{scriptpos=>sub{ "mid".$_[0]->getBoxingLevel; }}, mode=>'math', bounded=>1); DefMacro('\aas@fstack{}','\ensuremath{\aas@@fstack{#1}}'); DefMacro('\fd','\aas@fstack{d}'); DefMacro('\fh','\aas@fstack{h}'); DefMacro('\fm','\aas@fstack{m}'); DefMacro('\fs','\aas@fstack{s}'); DefMacro('\fdg','\aas@fstack{\circ}'); DefMacro('\farcm','\aas@fstack{\prime}'); DefMacro('\farcs','\aas@fstack{\prime\prime}'); DefMacro('\fp','\aas@fstack{p}'); DefMacro('\onehalf','\ifmmode\case{1}{2}\else\text@onehalf\fi'); DefConstructor('\text@onehalf',UTF(0xBD)); DefMacro('\onethird','\ifmmode\case{1}{3}\else\text@onethird\fi'); DefConstructor('\text@onethird',"\x{2153}"); DefMacro('\twothirds','\ifmmode\case{2}{3}\else\text@twothirds\fi'); DefConstructor('\text@twothirds',"\x{2154}"); DefMacro('\onequarter','\ifmmode\case{1}{4}\else\text@onequarter\fi'); DefConstructor('\text@onequarter',UTF(0xBC)); DefMacro('\threequarters','\ifmmode\case{3}{4}\else\text@threequarters\fi'); DefConstructor('\text@threequarters',UTF(0xBE)); DefConstructor('\ubvr',"UBVR", bounded=>1, font=>{shape=>'italic'}); DefConstructor('\ub',"U\x{2000}B",bounded=>1, font=>{shape=>'italic'}); DefConstructor('\bv',"B\x{2000}V",bounded=>1, font=>{shape=>'italic'}); DefConstructor('\vr',"V\x{2000}R",bounded=>1, font=>{shape=>'italic'}); DefConstructor('\ur',"U\x{2000}R",bounded=>1, font=>{shape=>'italic'}); # Remaining tables standard LaTeX or amssymb RequirePackage('latexsym'); RequirePackage('amssymb'); # \lesssim,\gtrsim in amssymb Let(T_CS('\la'),T_CS('\lesssim')); Let(T_CS('\ga'),T_CS('\gtrsim')); #====================================================================== # 2.17.5 Hypertext Constructs # \anchor{href}{text} RequirePackage('url'); DefConstructor('\anchor Semiverbatim Semiverbatim', "#2", properties=>sub { (href=>CleanURL(LookupValue('BASE_URL').ToString($_[1]))); } ); # \url{text} DefConstructor('\url Semiverbatim', "#1", properties=>sub { (href=>CleanURL(LookupValue('BASE_URL').ToString($_[1]))); } ); # This should be in effect only after frontmatter # \email{address} DefConstructor('\@@email Semiverbatim', "#1", properties=>sub { (href=>CleanURL("mailto:".ToString($_[1]))); } ); # RequirePackage('verbatim'); #====================================================================== # 2.18 Concluding # normal LaTeX # Number equations within sections DefMacro('\eqsecnum', '\@addtoreset{equation}{section}' .'\def\theequation{\arabic{section}-\arabic{equation}}'); #====================================================================== # Random extra bits DefMacroI('\singlespace',undef,''); DefMacroI('\doublespace',undef,''); DefMacroI('\tighten', undef,''); DefMacroI('\tightenlines',undef,''); DefMacroI('\nohyphenation',undef,''); DefMacroI('\offhyphenation',undef,''); DefMacroI('\ptlandscape',undef,''); DefMacroI('\refpar',undef,''); DefMacroI('\traceoutput',undef,''); DefMacroI('\tracingplain',undef,''); #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1; LaTeXML-0.7.0/lib/LaTeXML/Package/amsmath.sty.ltxml0000644002506700454610000011220311215766021020675 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | amsmath | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # #********************************************************************** # See amsldoc # Currently only a random collection of things I need for DLMF chapters. # Eventually, go through the doc and implement it all. #********************************************************************** package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; no warnings 'redefine'; # TODO: # Interesting options for limits placement # And TESTING!!!!! # sub-packages: RequirePackage('amsbsy'); RequirePackage('amstext'); RequirePackage('amsopn'); # Optional packages # amscd # amsxtra DefMacroI('\AmSfont',undef,Tokens()); DefMacroI('\AmS',undef,"AmS"); #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Section 3: Displayed equations #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # General implementation comments: # Some of these environments are intended for breaking up single equations # into multiple lines, while others are for presenting several equations in a group. # [some environments may be more ambiguous] # In any case, there may be specific relative alignment expected between the lines. # # Our primary objective, in LaTeXML, is to get at the semantics of the document, # and secondarily, to preserve enough of the author's intent to generate # presentation MathML that has the originally desired appearance. # Thus, our first concern is to recognize the portions of the input which represent # individual equations. These sequences can then be passed to the math parser # and hopefully recognized. # # We'll try to leverage the equationgroup/equation/MathFork arrangement # to achieve the secondary objective. # Where this doesn't work out, we'll insert additional hint or punctuation tokens # that indicate the requested alignment points or linebreaks. # Currently hints are discarded before parsing. Let('\notag','\nonumber'); #DefPrimitive('\tag OptionalMatch:* {}', sub { # AssignValue(EQUATIONROW_NUMBER=>ToString(Digest($_[2])), 'global'); }); DefConstructor('\tag OptionalMatch:* {}', '', afterDigest=>sub { # AssignValue(EQUATIONROW_NUMBER=>ToString(Digest($_[2])), 'global'); }, AssignValue(EQUATIONROW_NUMBER=>ToString($_[2]), 'global'); }, mode=>'text'); DefMacro('\@ams@intertext{}', '\@alignment@newline\multicolumn{\@alignment@ncolumns}{l}{\@@ams@intertext{#1}}\nonumber\@alignment@newline'); DefConstructor('\@@ams@intertext{}', "#1", mode=>'text'); sub amsalignBindings { my($template)=@_; # my $alignment = LaTeXML::Util::Alignment->new(containerElement=>'ltx:equationgroup', # rowElement=>'ltx:equation', # colElement=>'_Capture_'); my $alignment = LaTeXML::Util::Alignment ->new(openContainer =>sub{ $_[0]->openElement('ltx:equationgroup',@_[1..$#_]); }, closeContainer=>sub{ $_[0]->closeElement('ltx:equationgroup'); }, openRow =>sub{ $_[0]->openElement('ltx:equation',@_[1..$#_]); }, closeRow =>sub{ $_[0]->closeElement('ltx:equation'); }, openColumn =>sub{ $_[0]->openElement('_Capture_',@_[1..$#_]); }, closeColumn =>sub{ $_[0]->closeElement('_Capture_'); }); AssignValue(Alignment=>$alignment); $alignment->setTemplate($template); Let(T_ALIGN, T_CS('\@alignment@align')); Let(T_CS("\\\\"), T_CS('\@alignment@newline')); Let(T_CS('\cr'), T_CS('\@alignment@cr')); # Let('\span', T_CS('\@alignment@span')); Let(T_CS('\@open@row'),T_CS('\@equationgroup@open@row')); Let(T_CS('\@close@row'),T_CS('\@equationgroup@close@row')); Let(T_CS('\intertext'),T_CS('\@ams@intertext')); return; } #====================================================================== # Section 3.1 introduction #====================================================================== # Section 3.2 Single equations # equation, equation* #====================================================================== # Section 3.3 Split equations without alignment # Multiline is for single equations, but split on multiple lines, using \\ to separate lines. # Justifies the 1st line left, last line right, and middle ones centered. # Very useful when you are trying to fit a long equation into a known space, # but preserving the alignment seems less useful in the vaguer XML context, # particularly since there's no real alignment of columns that convey symmetry. # So... For now, we'll just turn into a single equation, ignoring the line breaks. DefEnvironment('{multline}', "" . "" . "#body" . "" ."", mode=>'display_math', beforeDigest=>sub { Let(T_MATH,T_CS('\@math@alignment$')); }, properties=> sub { RefStepCounter('equation') }); DefEnvironment('{multline*}', "" . "" . "#body" . "" ."", beforeDigest=>sub { Let(T_MATH,T_CS('\@math@alignment$')); }, mode=>'display_math'); #====================================================================== # Section 3.4 Split equations with alignment # split is used within other math environments to provide line breaks and alignment. # Since it's already within math, the MathFork branching doesn't work here. # Should we use a math alignment stucture? # [in which case it isn't clear how to get the high-level presentation vs. semantic] # Or just turn the markup into XMHint's; effectively ignoring them. # The latter, for now. DefEnvironment('{split}', "#body", beforeDigest=>sub{ # Just dummy up these definitions; they shouldn't do much special now. DefConstructor("&",""); DefConstructor("\\\\","", reversion=>Tokens(T_CS("\\\\"),T_CR)); DefConstructor('\intertext{}', "#1", mode=>'text'); }); #====================================================================== # Section 3.5 Equation groups without alignment # NOTE: Does this need provision to deal with metadata? DefConstructor('\@@amsgather SkipSpaces DigestedBody', sub { my($document,$body,%props)=@_; processAMSGatherRows($document,constructAlignment($document,$body, class=>'gather')); }, beforeDigest=>sub { $_[0]->bgroup; }); DefPrimitive('\end@amsgather',sub{ $_[0]->egroup; }); # Set up single centered column. DefPrimitive('\@amsgather@bindings', sub { my $col = {before=>Tokens(T_CS('\hfil'),T_MATH,T_CS('\displaystyle')), after=>Tokens(T_MATH,T_CS('\hfil'))}; amsalignBindings(LaTeXML::AlignmentTemplate->new(columns=>[$col])); }); # Each equation row (except intertext) consists of pairs (LHS, =RHS); group accordingly. # Since each column is a single equation, we'll skip the MathFork stuff, # and just pull the math content up past the _Capture_ sub processAMSGatherRows { my($document,$equationgroup)=@_; foreach my $equation ($document->getChildElements($equationgroup)){ my @cells = $document->getChildElements($equation); my @cell1cont = $document->getChildElements($cells[0]); # Check if this equation is really an intertext if((scalar(@cells)==1) && (scalar(@cell1cont)==1) && ($document->getNodeQName($cell1cont[0]) eq 'ltx:block')){ $equation->replaceNode($cell1cont[0]); } # Replace equation with the block. elsif((scalar(@cells)==1) && (scalar(@cell1cont)==0)){ # Empty row? Remove it! $equationgroup->removeChild($equation); } else { equationgroupFlattenCols($document,$equation); }}} # Note that some people use align or gather inside equation, which seems to "work" # So, we'll treat align as aligned in such cases. DefMacro('\gather', '\ifmmode\let\endgather\endgathered\gathered\else' .'\@amsgather@bindings\@@amsgather\@equationgroup@number\@start@alignment\fi'); DefMacro('\endgather', '\@finish@alignment\end@amsgather'); DefMacro('\csname gather*\endcsname', '\ifmmode\expandafter\let\csname endgather*\endcsname\endgathered\gathered\else' .'\@amsgather@bindings\@@amsgather\@equationgroup@nonumber\@start@alignment\fi'); DefMacro('\csname endgather*\endcsname', '\@finish@alignment\end@amsgather'); #====================================================================== # Section 3.6 Equation groups with mutual alignment # This environment can contain multiple columns, but apparently the intension is # that each pair should constitute an equation: # lhs & = rhs & lhs & = rhs ... # where each lhs is right aligned, and rhs is left aligned. # We'll use the equationgroup/equation/MathFork mechanism # similar to eqnarray. DefConstructor('\@@amsalign SkipSpaces DigestedBody', sub { my($document,$body,%props)=@_; processAMSAlignRows($document,constructAlignment($document,$body, class=>'align')); }, beforeDigest=>sub { $_[0]->bgroup; }); DefPrimitive('\end@amsalign',sub{ $_[0]->egroup; }); # Set up repeated pairs of columns. DefPrimitive('\@amsalign@bindings', sub { my $col1 = {before=>Tokens(T_CS('\hfil'),T_MATH,T_CS('\displaystyle')), after=>Tokens(T_MATH)}; my $col2 = {before=>Tokens(T_MATH,T_CS('\displaystyle')), after=>Tokens(T_MATH,T_CS('\hfil'))}; amsalignBindings(LaTeXML::AlignmentTemplate->new(repeated=>[$col1,$col2])); }); # Each equation row (except intertext) consists of pairs (LHS, =RHS); group accordingly. sub processAMSAlignRows { my($document,$equationgroup)=@_; foreach my $equation ($document->getChildElements($equationgroup)){ my @cells = $document->getChildElements($equation); shift(@cells) if $document->getNodeQName($cells[0]) eq 'ltx:metadata'; my @cell1cont = $document->getChildElements($cells[0]); # Check if this equation is really an intertext if((scalar(@cells)==1) && (scalar(@cell1cont)==1) && ($document->getNodeQName($cell1cont[0]) eq 'ltx:block')){ $equation->replaceNode($cell1cont[0]); } # Replace equation with the block. elsif((scalar(@cells)==1) && (scalar(@cell1cont)==0)){ # Empty row? Remove it! $equationgroup->removeChild($equation); } else { equationgroupJoinCols($document,2,$equation); }}} # Note that some people use align or gather inside equation, which seems to "work" # So, we'll treat align as aligned in such cases. DefMacro('\align', '\ifmmode\let\endalign\endaligned\aligned\else' .'\@amsalign@bindings\@@amsalign\@equationgroup@number\@start@alignment\fi'); DefMacro('\endalign', '\@finish@alignment\end@amsalign'); DefMacro('\csname align*\endcsname', '\ifmmode\expandafter\let\csname endalign*\endcsname\endaligned\aligned\else' .'\@amsalign@bindings\@@amsalign\@equationgroup@nonumber\@start@alignment\fi'); DefMacro('\csname endalign*\endcsname', '\@finish@alignment\end@amsalign'); # flalign typesets in the full column width (seems perverse to me). # So, for the time being, it's treated exactly like align. DefMacro('\flalign', '\ifmmode\let\endfalign\endaligned\aligned\else' .'\@amsalign@bindings\@@amsalign\@equationgroup@number\@start@alignment\fi'); DefMacro('\endflalign', '\@finish@alignment\end@amsalign'); DefMacro('\csname flalign*\endcsname', '\ifmmode\expandafter\let\csname endfalign*\endcsname\endaligned\aligned\else' .'\@amsalign@bindings\@@amsalign\@equationgroup@nonumber\@start@alignment\fi'); DefMacro('\csname endflalign*\endcsname', '\@finish@alignment\end@amsalign'); # alignat doesn't stretch the columns out as much (?) # and takes the number of column pairs (which we don't need?) # We'll ignore these distinctions for now. DefMacro('\alignat{}', '\ifmmode\let\endalignat\endalignedat\alignedat{#1}\else' .'\@amsalign@bindings\@@amsalign\@equationgroup@number\@start@alignment\fi'); DefMacro('\endalignat', '\@finish@alignment\end@amsalign'); DefMacro('\csname alignat*\endcsname{}', '\ifmmode\expandafter\let\csname endalignat*\endcsname\endalignedat\alignedat{#1}\else' .'\@amsalign@bindings\@@amsalign\@equationgroup@nonumber\@start@alignment\fi'); DefMacro('\csname endalignat*\endcsname', '\@finish@alignment\end@amsalign'); DefMacro('\xalignat{}', '\ifmmode\let\endalignat\endalignedat\alignedat{#1}\else' .'\@amsalign@bindings\@@amsalign\@equationgroup@number\@start@alignment\fi'); DefMacro('\endxalignat', '\@finish@alignment\end@amsalign'); DefMacro('\csname xalignat*\endcsname{}', '\ifmmode\expandafter\let\csname endalignat*\endcsname\endalignedat\alignedat{#1}\else' .'\@amsalign@bindings\@@amsalign\@equationgroup@nonumber\@start@alignment\fi'); DefMacro('\csname endxalignat*\endcsname', '\@finish@alignment\end@amsalign'); DefMacro('\xxalignat{}', '\ifmmode\let\endalignat\endalignedat\alignedat{#1}\else' .'\@amsalign@bindings\@@amsalign\@equationgroup@number\@start@alignment\fi'); DefMacro('\endxxalignat', '\@finish@alignment\end@amsalign'); #====================================================================== # Section 3.7. Alignmnet building blocks # gathered, aligned alignedat # These are intended to be used within math environments, but do they have the same # `semanitic' intent as far as separating equations? # aligned/alignedat perhaps do, since the alignment doesn't make much sense otherwise # [except for a single column, but then split should be used] # gathered could make sense as arranging a single subexpression into multiple lines within # a larger expression. # On the other hand, we'll already be inside of a math environment, so delineating # these potentially separate equations will be awkward anyway! # So, we just leave Hint markers for & and \\ # Hmm... DefMacro('\@noop@newline', sub { my($gullet)=@_; readNewlineArgs($gullet); # ignore (T_CS('\@noop@newline@marker')); }); DefConstructor('\@noop@newline@marker', "?#isMath()(\n)", properties=>{isSpace=>1}, reversion=>"\\\\"); DefEnvironment('{gathered}[]', "" . "#body" ."", beforeDigest=>sub{ Let(T_CS('\\\\'),T_CS('\@noop@newline')); }); DefMacro('\aligned[]', '\@@amsaligned\@start@alignment'); DefMacro('\endaligned', '\@finish@alignment\@end@amsaligned'); DefMacro('\alignedat{}[]','\@@amsaligned\@start@alignment'); DefMacro('\endalignedat', '\@finish@alignment\@end@amsaligned'); # NOTE: If this is the only child of an equation, it would seem better # to rewrite the thing into an equationgroup/equation/MathFork construct! # Besides, the MathML alignment (at least in firefox), pretty much sucks. DefPrimitive('\@end@amsaligned',sub{ $_[0]->egroup; }); DefConstructor('\@@amsaligned DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'aligned'}); }, beforeDigest=>sub { $_[0]->bgroup; my $col1 = {before=>Tokens(T_CS('\hfil'), T_CS('\displaystyle'))}; my $col2 = {before=>Tokens(T_CS('\displaystyle')), after=>Tokens(T_CS('\hfil'))}; my $template = LaTeXML::AlignmentTemplate->new(repeated=>[$col1,$col2]); alignmentBindings($template); }, reversion=>'\begin{aligned}#1\end{aligned}'); DefMacro('\cases', '\@@cases\@start@alignment'); DefMacro('\endcases', '\@finish@alignment\@end@cases'); DefPrimitive('\@end@cases',sub{ $_[0]->egroup; }); DefConstructor('\@@cases DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{meaning=>'cases',open=>'{'}); }, beforeDigest=>sub { $_[0]->bgroup; alignmentBindings('ll'); }, reversion=>'\begin{cases}#1\end{cases}'); #====================================================================== # Section 3.8 Adjusting tag placement DefMacro('\raisetag{Dimension}',''); # Ignorable #====================================================================== # Section 3.9 Vertical spacing and page breaks in multiline display DefMacro('\displaybreak[]',''); # Ignorable #====================================================================== # Section 3.10 Interrupting a display # default when not used inside an appropriate alignment. DefConstructor('\intertext{}', "#1", mode=>'text'); #====================================================================== # Section 3.11 Equation numbering # Section 3.11.1 Numbering hierarchy DefPrimitive('\numberwithin[]{}{}',sub { my($ignore,$format,$counter,$within)=@_; $format = ($format ? ToString($format) : '\arabic'); $counter = ToString($counter); $within = ToString($within); NewCounter($counter,$within); DefMacroI("\\the$counter",undef, "\\csname the$within\\endcsname.$format\{$counter\}", scope=>'global'); }); # Section 3.11.2 Cross references to equation numbers DefConstructor('\eqref Semiverbatim', "()", properties=>sub { (label=>CleanLabel($_[1])); }); # Section 3.11.3 Subordinate numbering sequences. DefEnvironment('{subequations}',"#body", afterDigestBegin=>sub { my($stomach,$whatsit)=@_; my %eqn = RefStepCounter('equation'); AssignValue(SAVED_EQUATION_NUMBER=>LookupValue('\c@equation')); $whatsit->setProperties(%eqn); ResetCounter('equation'); DefMacro('\theequation',UnTeX($eqn{refnum}).'\alph{equation}'); DefMacro('\theequation@ID',UnTeX($eqn{id}).'.\@equation@ID'); }, afterDigest =>sub{ AssignValue('\c@equation',LookupValue('SAVED_EQUATION_NUMBER'),'global'); }); #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Section 4: Miscellaneous mathematical features #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #====================================================================== # Section 4.1 Matrices DefMacro('\matrix', '\@@matrix\@start@alignment'); DefMacro('\endmatrix', '\@finish@alignment\@end@matrix'); DefPrimitive('\@end@matrix',sub{ $_[0]->egroup; }); DefConstructor('\@@matrix DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix'}); }, beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); }, reversion=>'\begin{matrix}#1\end{matrix}'); DefMacro('\pmatrix', '\@@pmatrix\@start@alignment'); DefMacro('\endpmatrix', '\@finish@alignment\@end@pmatrix'); DefPrimitive('\@end@pmatrix',sub{ $_[0]->egroup; }); DefConstructor('\@@pmatrix DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix', open=>'(',close=>')'}); }, beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); }, reversion=>'\begin{pmatrix}#1\end{pmatrix}'); DefMacro('\bmatrix', '\@@bmatrix\@start@alignment'); DefMacro('\endbmatrix', '\@finish@alignment\@end@bmatrix'); DefPrimitive('\@end@bmatrix',sub{ $_[0]->egroup; }); DefConstructor('\@@bmatrix DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix', open=>'[',close=>']'}); }, beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); }, reversion=>'\begin{bmatrix}#1\end{bmatrix}'); DefMacro('\Bmatrix', '\@@Bmatrix\@start@alignment'); DefMacro('\endBmatrix', '\@finish@alignment\@end@Bmatrix'); DefPrimitive('\@end@Bmatrix',sub{ $_[0]->egroup; }); DefConstructor('\@@Bmatrix DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix', open=>'{',close=>'}'}); }, beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); }, reversion=>'\begin{Bmatrix}#1\end{Bmatrix}'); DefMacro('\vmatrix', '\@@vmatrix\@start@alignment'); DefMacro('\endvmatrix', '\@finish@alignment\@end@vmatrix'); DefPrimitive('\@end@vmatrix',sub{ $_[0]->egroup; }); DefConstructor('\@@vmatrix DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix', open=>'|',close=>'|'}); }, beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); }, reversion=>'\begin{vmatrix}#1\end{vmatrix}'); DefMacro('\Vmatrix', '\@@Vmatrix\@start@alignment'); DefMacro('\endVmatrix', '\@finish@alignment\@end@Vmatrix'); DefPrimitive('\@end@Vmatrix',sub{ $_[0]->egroup; }); DefConstructor('\@@Vmatrix DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix', open=>"\x{2225}", close=>"\x{2225}"});}, beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); }, reversion=>'\begin{Vmatrix}#1\end{Vmatrix}'); DefMacro('\smallmatrix', '\@hidden{\scriptsize}\@@smallmatrix\@start@alignment'); DefMacro('\endsmallmatrix', '\@finish@alignment\@end@smallmatrix'); DefPrimitive('\@end@smallmatrix',sub{ $_[0]->egroup; }); DefConstructor('\@@smallmatrix DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix'}); }, beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); }, reversion=>'\begin{smallmatrix}#1\end{smallmatrix}'); #====================================================================== # Section 4.2 Math spacing commands # \, == \thinspace # \: == \medspace # \; == \thickspace # \quad # \qquad # \! == \negthinspace # \negmedspace # \negthickspace # I think only these are new DefConstructor('\medspace',"?#isMath()(\x{2005})"); # FOUR-PER-EM SPACE DefConstructor('\negthinspace',"?#isMath()()"); DefConstructor('\negmedspace',"?#isMath()()"); DefConstructor('\negthickspace',"?#isMath()()"); DefConstructor('\mspace{MuDimension}',""); #====================================================================== # Section 4.3 Dots # Nice idea, but not sure what I really should do about it. # In principle, a processor has access to the context.... DefMacroI('\dotsc',undef,'\ldots'); # Dots with commas DefMacroI('\dotsb',undef,'\cdots'); # Dots with binary operators/relations DefMacroI('\dotsm',undef,'\cdots'); # multiplication dots DefMacroI('\dotsi',undef,'\cdots'); # Dots with integrals DefMacroI('\dotso',undef,'\ldots'); # other dots (??) # Not really clear when these get set to something other than \relax, in amsfonts.sty DefMacroI('\DOTSB',undef,Tokens()); DefMacroI('\DOTSI',undef,Tokens()); DefMacroI('\DOTSX',undef,Tokens()); Let(T_CS('\hdots'),T_CS('\ldots')); # \hdotsfor ??? #====================================================================== # Section 4.4 Nonbreaking dashes # \nobreakdash DefMacro('\nobreakdash',''); # Ignorable #====================================================================== # Section 4.5 Accents in math DefMath('\dddot{}', "\x{02D9}\x{02D9}\x{02D9}", operator_role=>'OVERACCENT'); # DOT ABOVE DefMath('\ddddot{}',"\x{02D9}\x{02D9}\x{02D9}\x{02D9}", operator_role=>'OVERACCENT'); # DOT ABOVE # In amsxtra # \sphat \sptilde #====================================================================== # Section 4.6 Roots # It would be nice to carry this info through to mathml, but ignore for now. DefMacro('\leftroot{}',''); DefMacro('\uproot{}',''); #====================================================================== # Section 4.7 Boxed formulas DefConstructor('\boxed{}', "#1"); DefMath('\implies', "\x{27F9}", role=>'ARROW', meaning=>'implies'); DefMath('\impliedby',"\x{27F8}", role=>'ARROW', meaning=>'implied-by'); #====================================================================== # Section 4.8 Over and under arrows # Should be in LaTeX (& TeX): \overrightarrow, \overleftarrow DefMath('\underrightarrow{}', "\x{2192}", operator_role=>'UNDERACCENT'); DefMath('\underleftarrow{}', "\x{2190}", operator_role=>'UNDERACCENT'); DefMath('\overleftrightarrow{}', "\x{2194}", operator_role=>'OVERACCENT'); DefMath('\underleftrightarrow{}',"\x{2194}", operator_role=>'UNDERACCENT'); #====================================================================== # Section 4.9 Extensible arrows # \xleftarrow, \xrightarrow DefConstructor('\xleftarrow[]{}', "" . "" . "#2" . "\x{2190}" . "?#1(#1)" .""); DefConstructor('\xrightarrow[]{}', "" . "" . "#2" . "\x{2192}" . "?#1(#1)" .""); #====================================================================== # Section 4.10 Affixing symbols to other symbols DefConstructor('\overset{}{}', "" . "#1" . "#2" .""); DefConstructor('\underset{}{}', "" . "#1" . "#2" .""); #====================================================================== # Section 4.11 Fractions and related commands # Section 4.11.1 The \frac, \dfrac, and \tfrac commands DefConstructor('\tfrac{}{}', "" . "" . "#1#2" ."", beforeDigest=>\&beforeTFrac, afterDigest =>\&afterTFrac); DefConstructor('\dfrac{}{}', "" . "" . "#1#2" ."", beforeDigest=>\&beforeDFrac, afterDigest =>\&afterDFrac); DefConstructor('\ifrac{}{}', "" . "" . "#1#2" ."", beforeDigest=>\&beforeFrac, afterDigest =>\&afterFrac); # Section 4.11.2 The \binom, \dbinom, and \tbinom commands DefConstructor('\binom{}{}', "" . "" . "#1#2" ."", beforeDigest=>\&beforeFrac, afterDigest =>\&afterFrac); DefConstructor('\tbinom{}{}', "" . "" . "#1#2" ."", beforeDigest=>\&beforeTFrac, afterDigest =>\&afterTFrac); DefConstructor('\dbinom{}{}', "" . "" . "#1#2" ."", beforeDigest=>\&beforeDFrac, afterDigest =>\&afterDFrac); # Section 4.11.3 The \genfrac command DefConstructor('\genfrac{}{}{Dimension}{}{}{}', "" . "" . "#5" . "#6" ."", afterDigest=>sub{ my($stomach,$whatsit)=@_; my $open = ToString($whatsit->getArg(1)); my $close = ToString($whatsit->getArg(2)); if(my $entry = LaTeXML::Package::Pool::lookup_delimiter($open)){ $open = $$entry{char}; } if(my $entry = LaTeXML::Package::Pool::lookup_delimiter($close)){ $close = $$entry{char}; } $whatsit->setProperties(open=>$open, close=>$close, style=>LookupValue('mathstyle')); }); #====================================================================== # Section 4.12 Continued fractions # I think \cfracstyle my own invention? (I know I've redefined \cfrac in DLMFmath) # XMDual doesn't seem quite appropriate, since the args (denominators) get # divided up so oddly in the inline case. # I've left it to a special case in conversion to pmml. DefConstructor('\cfrac{}{}', "" . "" . "#1" . "#2" ."", properties=>sub{ (style=>LookupValue('CFRACSTYLE')); }); AssignValue(CFRACSTYLE=>'display'); # This should get incorporated into any \cfrac's that are constructed in scope. DefConstructor('\cfracstyle{}','', afterDigest=>sub{ my $style = ToString($_[1]->getArg(1)); $style = ($style eq 'd' ? 'display' : ($style eq 'i' ? 'inline' : $style)); AssignValue(CFRACSTYLE=>$style); }); #====================================================================== # Section 4.13 Smash options DefConstructor('\smash[]{}',"#2"); # well, what? #====================================================================== # Section 4.14 Delimiters # Section 4.14.1 Delimiter sizes # Redefinitions(?) of \bigl, \bigr, \Bigl,\Bigr, \biggl, \biggr, \Biggl, \Biggr # Section 4.14.2 Vertical bar notations DefMath('\lvert','|', role=>'OPEN'); DefMath('\lVert',"\x{2225}", role=>'OPEN'); # PARALLEL TO DefMath('\rvert','|', role=>'CLOSE'); DefMath('\rVert',"\x{2225}", role=>'CLOSE'); # PARALLEL TO #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Section 5 Operator names #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #====================================================================== # Section 5.1 Defining new operator names # See package amsopn (included by default) #====================================================================== # Section 5.2 \mod and it's relatives # \bmod, \pmod which are already in LaTeX DefMath('\mod', 'mod', role=>'MODIFIEROP', meaning=>'modulo'); DefMath('\pod{}', '(#1)', role=>'MODIFIER', meaning=>'modulo'); # Well, sorta postfix.. #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Section 6 The \text command #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # See package amstext, included by default. #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Section 7 Integrals and sums #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #====================================================================== # Section 7.1 Multiline subscripts and superscripts # \substack, \begin{subarray} # These make the combining operator be list, but often formulae would be better DefConstructor('\substack{}', "" . "" . "#1" ."", bounded=>1, beforeDigest=>sub{ DefConstructor("\\\\ OptionalMatch:* [Dimension]", "", reversion=>Tokens(T_CS("\\\\"),T_CR)); }); DefEnvironment('{subarray}[]', "" . "" . "#body" ."", beforeDigest=>sub{ DefConstructor("\\\\ OptionalMatch:* [Dimension]", "", reversion=>Tokens(T_CS("\\\\"),T_CR)); }); #====================================================================== # Section 7.2 the \sideset command # This is intended to be a modifier for \sum or \prod # NOTE that there can be at most one subscript in each of the pre & post, ditto for superscript. # Thus, our representation is: sideset(presub,presup,postsub,postsup,object) # Note, also, that this is quite ugly, but since it is a rather peculiar special case.... ? # try by nesting... DefConstructor('\sideset{}{}{}', sub { my($document,$pre,$post,$base,%props)=@_; my @scripts = (undef,undef,undef,undef); my $node = $document->insertElement('ltx:XMArg',$base); my $ch = $document->getFirstChildElement($node); my ($opx,$ignore) = ($ch && $ch->getAttribute('scriptpos')||'post') =~ /^(pre|mid|post)?(\d+)?$/; my $level = $props{level}||0; my $x = 'pre'; foreach my $group ($pre,$post){ # Best order? foreach my $script ($group->unlist){ my $y; if((ref $script eq 'LaTeXML::Whatsit') && (( ($script->getDefinition eq $STATE->lookupMeaning(T_CS('\@@FLOATINGSUPERSCRIPT'))) && ($y='SUPER')) || (($script->getDefinition eq $STATE->lookupMeaning(T_CS('\@@FLOATINGSUBSCRIPT'))) && ($y='SUB')))){ my $new = $document->openElement('ltx:XMApp'); $document->insertElement('ltx:XMTok',undef, role=>$y.'SCRIPTOP',scriptpos=>"$x$level"); $new->appendChild($node); $document->insertElement('ltx:XMWrap',$script->getArg(1)); $document->closeElement('ltx:XMApp'); $node = $new; } else { warn("Non sub/superscript in \\sideset: ".Stringify($script)); }} $x = 'post'; } $document->setAttribute($node,scriptpos=>$opx) if $opx; }); #====================================================================== # Section 7.3 Placement of subscripts and limits # \limits and \nolimits; already in TeX #====================================================================== # Section 7.4 Multiple integral signs DefMath('\iint', "\x{222C}", meaning=>'double-integral', role=>'INTOP'); # DOUBLE INTEGRAL DefMath('\iiint',"\x{222D}", meaning=>'triple-integral', role=>'INTOP'); # TRIPLE INTEGRAL DefMath('\iiiint',"\x{2A0C}", meaning=>'quadruple-integral', role=>'INTOP'); DefMath('\idotsint',"\x{222B}\x{22EF}\x{222B}", meaning=>'multiple-integral', role=>'INTOP'); DefMacro('\MultiIntegral{}',sub { my($gullet,$n)=@_; $n = ToString($n); (($n==0 ? T_CS('\idotsint'):($n==1?T_CS('\int'):($n==2?T_CS('\iint'):($n==3?T_CS('\iiint'):T_CS('\iiiint'))))));}); #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Section 8 Commutative diagrams #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Separately in amscd # CD environment # with commands @>.., @<<<, @VVV, @AAA to give right, left, down, up arrows... #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Section 9 Using math fonts #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #====================================================================== # Section 9.1 Introduction # See amsfonts, euscript #====================================================================== # Section 9.2 Recommended use of math font commands #====================================================================== # Section 9.3 Bold math symbols # See package amsbsy (included by default) #====================================================================== # Section 9.4 Italic Greek letters # I think this is sufficient: DefMath('\varGamma', "\x{0393}",font=>{shape=>'italic'}); DefMath('\varSigma', "\x{03A3}",font=>{shape=>'italic'}); DefMath('\varDelta', "\x{0394}",font=>{shape=>'italic'}); DefMath('\varUpsilon', "\x{03A5}",font=>{shape=>'italic'}); DefMath('\varTheta', "\x{0398}",font=>{shape=>'italic'}); DefMath('\varPhi', "\x{03A6}",font=>{shape=>'italic'}); DefMath('\varLambda', "\x{039B}",font=>{shape=>'italic'}); DefMath('\varPsi', "\x{03A8}",font=>{shape=>'italic'}); DefMath('\varXi', "\x{039E}",font=>{shape=>'italic'}); DefMath('\varOmega', "\x{03A9}",font=>{shape=>'italic'}); DefMath('\varPi', "\x{03A0}",font=>{shape=>'italic'}); #====================================================================== # And some random other weird naming Let('\Hat', '\hat'); Let('\Check', '\check'); Let('\Tilde', '\tilde'); Let('\Acute', '\acute'); Let('\Grave', '\grave'); Let('\Dot', '\dot'); Let('\Ddot', '\ddot'); Let('\Breve', '\breve'); Let('\Bar', '\bar'); Let('\Vec', '\vec'); # And where does this go? DefPrimitive('\allowdisplaybreaks[]', undef); #====================================================================== DefMacroI('\mintagsep',undef,Tokens()); DefMacroI('\minalignsep',undef,"10pt"); DefRegister('\multlinegap'=>Glue('10pt')); DefRegister('\multlinetaggap'=>Glue('10pt')); DefMacro('\primfrac{}',Tokens()); # \shoveleft, \shoveright should do something about eqn number placement? DefMacro('\shoveleft{}','#1'); DefMacro('\shoveright{}','#1'); #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1; LaTeXML-0.7.0/lib/LaTeXML/Package/lscape.sty.ltxml0000644002506700454610000000231511214255161020511 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | lscape | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; #********************************************************************** # Conceivably could be useful to add "pagination markers" # (empty elements that are normally ignored) at beginning and end DefEnvironment('{landscape}',"#body"); #********************************************************************** 1; LaTeXML-0.7.0/lib/LaTeXML/Package/amscd.sty.ltxml0000644002506700454610000001111211214255161020324 0ustar miller891div# -*- CPERL -*- # /=======================================================\ # # | amscd - Implementation for LaTeXML | # # | | # # |=======================================================| # # | Part of LaTeXML : http://dlmf.nist.gov/LaTeXML/ | # # | Copyright (c) 2006 arXMLiv group | # # | Released under the GNU Public License | # # \=======================================================/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Note that the amscd authors themselves point out that amcsd is limited, # only covering array-like commutative diagrams, and they suggest # diagram, xypic or kuvio as alternatives. # # However, it is just that simplicity that mkes it possible to represent # the commutative diagram in straight latexml math, w/o resorting to # the more general svg(-like) problems. #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DefMacro('\CD', '\@@CD\@start@alignment'); DefMacro('\endCD', '\@finish@alignment\@end@CD'); DefPrimitive('\@end@CD',sub{ $_[0]->egroup; }); DefConstructor('\@@CD DigestedBody', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix'}); }, beforeDigest=>sub { $_[0]->bgroup; alignmentBindings(MatrixTemplate()); AssignCatcode('math:@'=>1); Let(T_CS('@'),T_CS('\cd@')); }, reversion=>'\begin{matrix}#1\end{matrix}'); DefMacro('\cd@ Token',sub { my($gullet,$token)=@_; (T_CS('@'.ToString($token))); }); DefMacroI(T_CS('@>'),LaTeXML::Parameters::parseParameters('Until:> Until:>','@>..>..>'), '&\cd@stack{\rightarrowfill@}{#1}{#2}&'); DefMacroI(T_CS('@)'),LaTeXML::Parameters::parseParameters('Until:) Until:)','@)..)..)'), '&\cd@stack{\rightarrowfill@}{#1}{#2}&'); DefMacroI(T_CS('@<'),LaTeXML::Parameters::parseParameters('Until:< Until:<','@<..<..<'), '&\cd@stack{\leftarrowfill@}{#1}{#2}&'); DefMacroI(T_CS('@('),LaTeXML::Parameters::parseParameters('Until:( Until:(','@(..(..('), '&\cd@stack{\leftarrowfill@}{#1}{#2}&'); DefMacroI(T_CS('@A'),LaTeXML::Parameters::parseParameters('Until:A Until:A','@A..A..A'), '\cd@adjacent{\Big\uparrow}{#1}{#2}&&'); DefMacroI(T_CS('@V'),LaTeXML::Parameters::parseParameters('Until:V Until:V','@V..V..V'), '\cd@adjacent{\Big\downarrow}{#1}{#2}&&'); DefMacroI(T_CS('@='),undef, '&\wideequals@&'); DefMacroI(T_CS('@|'),undef, '\Big\Vert&&'); DefMacroI(T_CS('@\vert'),undef, '\Big\Vert&&'); DefMacroI(T_CS('@.'),undef, '&&'); DefRegister('\minaw@'=>Dimension('11.111pt')); # deal with under, over & underover! DefConstructor('\cd@stack{}{}{}', sub { my($document,$op,$over,$under,%props)=@_; my $scriptpos = $props{scriptpos}; if($under->unlist){ $document->openElement('ltx:XMApp'); # Role? $document->insertElement('ltx:XMTok',undef,role=>'SUBSCRIPTOP', scriptpos=>$scriptpos); if($over->unlist){ $document->openElement('ltx:XMApp'); # Role? $document->insertElement('ltx:XMTok',undef,role=>'SUPERSCRIPTOP', scriptpos=>$scriptpos); $document->insertElement('ltx:XMWrap',$op); $document->insertElement('ltx:XMWrap',$over); $document->closeElement('ltx:XMApp'); } else { $document->insertElement('ltx:XMWrap',$op); } $document->insertElement('ltx:XMWrap',$under); $document->closeElement('ltx:XMApp'); } elsif($over->unlist){ $document->openElement('ltx:XMApp'); # Role? $document->insertElement('ltx:XMTok',undef,role=>'SUPERSCRIPTOP', scriptpos=>$scriptpos); $document->insertElement('ltx:XMWrap',$op); $document->insertElement('ltx:XMWrap',$over); $document->closeElement('ltx:XMApp'); } else { $document->insertElement('ltx:XMWrap',$op); }}, properties=>{scriptpos=>sub{ "mid".$_[0]->getBoxingLevel; }}); # \cd@adj{}{}{} # Temporary... # Later deal with vertically centering the side things, parser issues... DefMacro('\cd@adjacent{}{}{}','{#2}{#1}{#3}'); # This isn't really having the desired effect when transformed to MathML and # displayed in Firefox.... have I got it right; has Firefox??? DefMath('\leftarrowfill@', "\x{2190}", role=>'ARROW', style=>'stretchy'); # , size=>'Bigg'); DefMath('\rightarrowfill@', "\x{2192}", role=>'ARROW', style=>'stretchy'); # , size=>'Bigg'); DefMath('\wideequals@', "=", role=>'ARROW', style=>'stretchy'); # , size=>'Bigg'); #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1; LaTeXML-0.7.0/lib/LaTeXML/Package/dcolumn.sty.ltxml0000644002506700454610000000426511214255161020711 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | dcolumn | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # use LaTeXML::Package; use strict; RequirePackage('array'); sub absorbedString { my($tokens)=@_; my $capdocument = LaTeXML::Document->new($STATE->getModel); my $capture = $capdocument->openElement('_Capture_', font=>LaTeXML::Font->new()); $capdocument->absorb(Digest($tokens)); my @nodes= $capdocument->findnodes("//ltx:XMath/*",$capture); $nodes[0]->textContent; } DefMacro('\DC@{}{}{}',sub { my($gullet,$delim,$todelim,$ndec)=@_; $delim=ToString($delim); if($delim ne ToString($todelim)){ AssignCatcode('math:$delim'=>1); DefMacroI(T_CS($delim),undef,'\ROLE{PERIOD}{'.join('',map(ToString($_),$todelim->revert)).'}'); } if(LookupValue('IN_MATH') || $gullet->ifNext(T_MATH)){ # Not really good enough, but... (); } else { Let('\DC@end',T_MATH); (T_MATH); }}); # NOTE: We should be making arrangements for this funny thing to still # be considered a number! DefMacro('\DC@end',''); DefColumnType('D{}{}{}',sub { my($gullet,$delim,$todelim,$ndec)=@_; my $alignment =absorbedString(Tokens(T_CS('\ensuremath'),T_BEGIN,$todelim,T_END)); $LaTeXML::BUILD_TEMPLATE->addColumn(before=>Tokens(T_CS('\DC@'), T_BEGIN,$delim->unlist,T_END, T_BEGIN,$todelim->unlist,T_END, T_BEGIN,$ndec->unlist,T_END), align=>'char:'.$alignment, after=>Tokens(T_CS('\DC@end'))); return; }); 1; LaTeXML-0.7.0/lib/LaTeXML/Package/TeX.pool.ltxml0000644002506700454610000052273511215766021020114 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | TeX | # # | Core TeX Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; use Unicode::Normalize; use LaTeXML::Util::Alignment; use LaTeXML::Util::KeyVal; use LaTeXML::Util::Pathname; no warnings 'redefine'; RegisterNamespace(ltx=>"http://dlmf.nist.gov/LaTeXML"); DefMacroI("\\\@empty",undef,Tokens()); # Base ID prefixes everything. if(my $docid = LookupValue('DOCUMENTID')){ DefMacroI('\thedocument@ID',undef,$docid); } else { Let(T_CS('\thedocument@ID'),T_CS('\@empty')); } NewCounter('@XMARG','document',idprefix=>'XM'); #********************************************************************** # CORE TeX; Built-in commands. #********************************************************************** #====================================================================== # Define parsers for standard parameter types. # Skip any spaces, but don't contribute an argument. DefParameterType('SkipSpaces', sub{$_[0]->skipSpaces; }, novalue=>1); # Read the next token DefParameterType('Token', sub{$_[0]->readToken; }); # Read the next token, after expanding any expandable ones. DefParameterType('XToken', sub{$_[0]->readXToken; }); # Read a number DefParameterType('Number', sub{$_[0]->readNumber; }); # Read a dimension DefParameterType('Dimension', sub{$_[0]->readDimension; }); # Read a Glue (aka skip) DefParameterType('Glue', sub{$_[0]->readGlue; }); # Read a MuDimension (math) DefParameterType('MuDimension',sub{$_[0]->readMuDimension; }); # Read a MuGlue (math) DefParameterType('MuGlue', sub{$_[0]->readMuGlue; }); # Read until the next (balanced) open brace { # used for the last TeX-style delimited argument DefParameterType('UntilBrace', sub{ my($gullet)=@_; my $value=$gullet->readUntil(T_BEGIN); $gullet->unread(T_BEGIN); $value; }); DefParameterType('XUntil', sub { my($gullet,$until)=@_; ($until) = $until->unlist; # Make sure it's a single token!!! my ($token,@tokens)=(); while($token = $gullet->readXToken()){ if($token->equals($until)){ last; } elsif($token->getCatcode == CC_BEGIN){ push(@tokens,$token,$gullet->readBalanced->unlist,T_END); } elsif(my $defn = LookupDefinition($token)){ push(@tokens,Invocation($token,$defn->readArguments($gullet))); } else { push(@tokens,$token); }} Tokens(@tokens); }); # Read a matching keyword, eg. Match:= DefParameterType('Match', sub{shift->readMatch(@_); }); # Read a keyword; eg. Keyword:to # (like Match, but ignores catcodes) DefParameterType('Keyword', sub{shift->readKeyword(@_); }); # Read balanced material (?) DefParameterType('Balanced', sub{$_[0]->readBalanced; }); # Read a Semiverbatim argument; ie w/ most catcodes neutralized. DefParameterType('Semiverbatim',sub{ $_[0]->readArg; }, semiverbatim=>1, reversion=>sub { (T_BEGIN,$_[0]->revert,T_END); }); # Read a LaTeX-style optional argument (ie. in []), but the contents read as Semiverbatim. DefParameterType('OptionalSemiverbatim',sub{ $_[0]->readOptional; }, semiverbatim=>1, optional=>1, reversion=>sub { ($_[0] ? (T_OTHER('['),$_[0]->revert,T_OTHER(']')) : ()); }); # Read an argument that will not be digested. DefParameterType('Undigested', sub { $_[0]->readArg; }, undigested=>1, reversion=>sub { (T_BEGIN,$_[0]->revert,T_END); }); # Read a LaTeX-style optional argument (ie. in []), but it will not be digested. DefParameterType('OptionalUndigested', sub { $_[0]->readOptional; }, undigested=>1, optional=>1, reversion=>sub { ($_[0] ? (T_OTHER('['),$_[0]->revert,T_OTHER(']')):()); }); # Read a keyword value (KeyVals), that will not be digested. DefParameterType('UndigestedKey', sub { $_[0]->readArg; }, undigested=>1); # Read a token as used when defining it, ie. it may be enclosed in braces. DefParameterType('DefToken', sub { my($gullet)=@_; my $token = $gullet->readToken; while($token->equals(T_BEGIN)){ my @toks = grep(!$_->equals(T_SPACE),$gullet->readBalanced->unlist); $token = shift(@toks); $gullet->unread(@toks); } $token; }); # Read a variable, ie. a token (after expansion) that is a writable register. DefParameterType('Variable', sub { my($gullet)=@_; my $token = $gullet->readXToken; my $defn = $token && LookupDefinition($token); if((defined $defn) && $defn->isRegister && !$defn->isReadonly){ [$defn,$defn->readArguments($gullet)]; } else { Error(":expected: A was supposed to be here, got".Stringify($token)); undef; }}); DefParameterType('TeXFileName', sub { my($gullet)=@_; my($token,$cc,@tokens)=(); while(($token = $gullet->readXToken()) && (($cc=$token->getCatcode) != CC_SPACE) &&($cc!=CC_EOL)&&($cc!=CC_COMMENT)&&($cc!=CC_CS)){ push(@tokens,$token); } $gullet->unread($token); Tokens(@tokens); }); # This reads a Box as needed by \raise, \lower, \moveleft, \moveright. # Hopefully there are no issues with the box being digested # as part of the reader??? DefParameterType('MoveableBox', sub{ my($gullet)=@_; $gullet->skipSpaces; my ($box,@stuff) = $STATE->getStomach->invokeToken($gullet->readXToken); Error(":expected: A was supposed to be here, got ".Stringify($box)) unless $box && $box->isa('LaTeXML::Whatsit') && ($box->getDefinition->getCSName =~ /^(\\hbox|\\vbox||\\vtop)$/); $box; }); # Read a parenthesis delimited argument. # Note that this does NOT balance () within the argument. DefParameterType('BalancedParen', sub { my ($gullet) = @_; my $tok = $gullet->readXToken; if (ref $tok && ToString($tok) eq '(') { $gullet->readUntil(T_OTHER(')')); } else { $gullet->unread($tok) if ref $tok; undef; }}, reversion=> sub { (T_OTHER('('), $_[0]->revert, T_OTHER(')')); }); # Read a digested argument. # The usual parameter (generally written as {}) gets # tokenized and digested in separate stages (like TeX), # and so it is tokenized w/o recognizing any special macros within (eg. \url). # This parameter gets digested until the (required) opening { is balanced. # It is useful when the content would usually need to have been \protect'd # in order to correctly deal with catcodes. DefParameterType('Digested', sub { my($gullet)=@_; $gullet->skipSpaces; my $ismath = $STATE->lookupValue('IN_MATH'); my $token = $gullet->readXToken; my @list=(); if($token->equals(T_BEGIN)){ Digest($token); @list = $STATE->getStomach->digestNextBody(); pop(@list); } else { @list = $STATE->getStomach->invokeToken($token); } # In most (all?) cases, we're really looking for a single Whatsit here... @list = grep(ref $_ ne 'LaTeXML::Comment', @list); (scalar(@list) == 1 ? $list[0] : ($ismath ? LaTeXML::MathList->new(@list) : LaTeXML::List->new(@list))); }, undigested=>1, # since _already_ digested. reversion=>sub { (T_BEGIN,$_[0]->revert,T_END); }); # A variation: Digest until we encounter a given token! DefParameterType('DigestUntil', sub { my($gullet,$until)=@_; $gullet->skipSpaces; my $ismath = $STATE->lookupValue('IN_MATH'); my @list = $STATE->getStomach->digestNextBody($until); @list = grep(ref $_ ne 'LaTeXML::Comment', @list); (scalar(@list) == 1 ? $list[0] : ($ismath ? LaTeXML::MathList->new(@list) : LaTeXML::List->new(@list))); }, undigested=>1, # since _already_ digested. reversion=>sub { (T_BEGIN,$_[0]->revert,T_END); }); # Reads until the current group has ended. # This is useful for environment-like constructs, # particularly alignments (which may or may not be actual environments), # but which need special treatment of some of their content # as the expansion is carried out. DefParameterType('DigestedBody', sub { my($gullet)=@_; my $ismath = $STATE->lookupValue('IN_MATH'); my @list = $STATE->getStomach->digestNextBody(); # In most (all?) cases, we're really looking for a single Whatsit here... @list = grep(ref $_ ne 'LaTeXML::Comment', @list); (scalar(@list) == 1 ? $list[0] : ($ismath ? LaTeXML::MathList->new(@list) : LaTeXML::List->new(@list))); }, undigested=>1); # In addition to the standard TeX Dimension, there are various LaTeX constructs # (particularly, the LaTeX picture environment, and the various pstricks packages) # that take a different sort of length. They differ in two ways. # (1) They do not accept a comma as decimal separator # (they generally use it to separate coordinates), and # (2) They accept a plain float which is scaled against a Dimension register. # Actually, there are two subcases: # (a) picture accepts a float, which is scaled against \unitlength # (b) pstricks accepts a float, and optionally a unit, # If the unit is omitted, it is relative to \psxunit or \psyunit. # How to capture these ? ## DefParameterType('Length', sub { ## my($gullet,$unit)=@_; #********************************************************************** # Expandable Primitives # See The TeXBook, Ch. 20, Definitions (also called Macros) pp. 212--215 #********************************************************************** #====================================================================== # Conditionals # Expand enough to determine true/false, then maybe skip # record a flag somewhere so that \else or \fi is recognized # (otherwise, they should signal an error) # Skipping for conditionals # 0 : skip to \fi # -1 : skip to \else, if any, or \fi # n : skip to n-th \or, if any, or \else, if any, or \fi. sub skipConditionalBody { my($gullet,$nskips)=@_; my $level=1; my $n_ors = 0; while(my $t= $gullet->readToken){ if(defined(my $defn = LookupDefinition($t))){ if($defn->isExpandable && $defn->isConditional){ $level++; } elsif(Equals($t,T_CS('\fi')) && (!--$level)){ fiHandler($gullet); return; } elsif($level > 1){ # Ignore nested \else,\or } elsif(Equals($t,T_CS('\or')) && (++$n_ors == $nskips)){ return; } elsif(Equals($t,T_CS('\else')) && $nskips){ return; }}} Fatal(":expected:\\fi Missing \\fi or \\else, conditional fell off end"); } # NOTE: See Definition setting current_if_level before conditionals! sub ifHandler { my($gullet,$boolean)=@_; AssignValue(if_level=>LookupValue('current_if_level'), 'global'); skipConditionalBody($gullet,-1) unless $boolean; return; } sub elseHandler { my($gullet)=@_; my ($curr,$level) = (LookupValue('current_if_level'),LookupValue('if_level')); if(!$curr){ Error(":unexpected:\\else Didn't expect an \\else since we seem not to be in an \\if"); return; } elsif($curr > $level){ (T_CS('\relax'),T_CS('\else')); } else { skipConditionalBody($gullet,0); return; }} sub fiHandler { my($gullet)=@_; my ($curr,$level) = (LookupValue('current_if_level'),LookupValue('if_level')); if(!$curr){ Error(":unexpected:\\fi Didn't expect an \\fi here since we seem not to be in an \\fi"); return; } elsif($curr > $level){ (T_CS('\relax'),T_CS('\fi')); } else { AssignValue(current_if_level=>$curr-1, 'global'); AssignValue(if_level=>$curr-1, 'global'); return; }} #====================================================================== # Should complain if we aren't actually evaluating an \if DefMacroI('\else',undef, \&elseHandler); DefMacroI('\or', undef, \&elseHandler); DefMacroI('\fi', undef, \&fiHandler); sub compare { my($a,$rel,$b)=@_; if ($rel->equals(T_OTHER('<')) || $rel->equals(T_CS('\@@<'))){ $a < $b; } elsif($rel->equals(T_OTHER('=')) ){ $a == $b; } elsif($rel->equals(T_OTHER('>')) || $rel->equals(T_CS('\@@>'))){ $a > $b; } else { Error(":expected: Expected a relational token but got ".Stringify($rel)." in comparison conditional"); }} DefMacro('\ifnum Number Token Number', sub { ifHandler($_[0],compare($_[1]->valueOf,$_[2],$_[3]->valueOf)); }, isConditional=>1); DefMacro('\ifdim Dimension Token Dimension', sub { ifHandler($_[0],compare($_[1]->valueOf,$_[2],$_[3]->valueOf)); }, isConditional=>1); DefMacro('\ifodd Number', sub { ifHandler($_[0],$_[1]->valueOf % 2); }, isConditional=>1); # NOTE: We don't KNOW if we're in vertical, horizontal or inner mode!!!!!!! DefMacroI('\ifvmode', undef, sub { ifHandler($_[0],0); }, isConditional=>1); DefMacroI('\ifhmode', undef, sub { ifHandler($_[0],0); }, isConditional=>1); DefMacroI('\ifinner', undef, sub { ifHandler($_[0],0); }, isConditional=>1); DefMacroI('\ifmmode',undef, sub { ifHandler($_[0],LookupValue('IN_MATH')); }, isConditional=>1); DefMacro('\if XToken XToken', sub { ifHandler($_[0],$_[1]->getCharcode == $_[2]->getCharcode); }, isConditional=>1); DefMacro('\ifcat XToken XToken', sub { ifHandler($_[0],$_[1]->getCatcode == $_[2]->getCatcode); }, isConditional=>1); # !! ???? DefMacro('\ifx Token Token', sub { my($gullet,$token1,$token2)=@_; my $def1=LookupMeaning($token1); my $def2=LookupMeaning($token2); my $bool=0; if(defined $def1 != defined $def2){ # Don't both have defs or not have defs $bool=0; } elsif(!defined $def1 && !defined $def2){ # Neither have defs $bool = ($token1->getCatcode == $token2->getCatcode) && ($token1->getCharcode == $token2->getCharcode); } elsif($def1->equals($def2)){ # Same defn (hopefully covers same primitives ???) $bool = 1; } # But what about same \chardefs, etc.... ifHandler($gullet,$bool); }, isConditional=>1); # Kinda rough: We don't really keep track of modes as carefully as TeX does. # We'll assume that a box is horizontal if there's anything at all, # but it's not a vbox (!?!?) sub classify_box { my($boxnum)=@_; my $box = LookupValue('box'.$boxnum->valueOf); if(!$box){ undef; } elsif($box->isa('LaTeXML::Whatsit') && ($box->getDefinition eq LookupDefinition(T_CS('\vbox')))){ 'vbox'; } else { 'hbox'; }} DefMacro('\ifvoid Number', sub { ifHandler($_[0],!classify_box($_[1]));}, isConditional=>1); DefMacro('\ifhbox Number', sub { ifHandler($_[0],classify_box($_[1]) eq 'hbox');}, isConditional=>1); DefMacro('\ifvbox Number', sub { ifHandler($_[0],classify_box($_[1]) eq 'vbox');}, isConditional=>1); # Implementing this assumes we've got some notion of file numbers!!! DefMacroI('\ifeof', undef,sub { ifHandler($_[0],0); }, isConditional=>1); DefMacroI('\iftrue', undef,sub { ifHandler($_[0],1); }, isConditional=>1); DefMacroI('\iffalse',undef,sub { ifHandler($_[0],0); }, isConditional=>1); DefMacro('\ifcase Number', sub { my($gullet,$num)=@_; AssignValue(if_level=>LookupValue('current_if_level'), 'global'); $num = $num->valueOf; if($num > 0){ skipConditionalBody($gullet,$num); } return; }, isConditional=>1); #====================================================================== DefPrimitive('\relax',undef); DefMacro('\number Number', sub { Explode($_[1]->valueOf); }); # define it here (only approxmiately), since it's already useful. Let(T_CS('\protect'),T_CS('\relax')); #====================================================================== DefMacro('\romannumeral Number', sub { roman($_[1]->valueOf); }); DefMacro('\string Token ', sub { Explode($_[1]->getString); }); DefMacroI('\jobname',undef,Tokens()); # Set to the filename by initialization DefMacroI('\fontname', undef,sub { Explode("fontname not implemented"); }); DefMacro('\meaning Token',sub { my($gullet,$tok)=@_; my $meaning = LookupMeaning($tok); Explode(defined $meaning ? $meaning : 'undefined'); }); DefMacroI('\csname',undef,sub { my($gullet)=@_; my($token,@toks)=(); while(($token = $gullet->readXToken()) && ($token->getString ne '\endcsname')){ push(@toks,$token); } $token = T_CS("\\".ToString(Tokens(@toks))); Let($token, T_CS('\relax')) unless defined LookupMeaning($token); $token; }); DefPrimitive('\endcsname', sub { Error(":unexpected:\\endcsname Extra \\endcsname"); return; }); DefMacro('\expandafter Token Token',sub { my($gullet,$tok,$xtok)=@_; my $defn; if(defined($defn=LookupDefinition($xtok)) && $defn->isExpandable){ ($tok,$defn->invoke($gullet)); } # Expand $xtok ONCE ONLY! else { ($tok,$xtok); }}); # Insert magic token that Gullet knows not to expand the next one. DefMacroI('\noexpand',undef,sub { Token('',CC_NOTEXPANDED); }); DefMacroI('\topmark', undef, Tokens()); DefMacroI('\firstmark', undef, Tokens()); DefMacroI('\botmark', undef, Tokens()); DefMacroI('\splitfirstmark', undef, Tokens()); DefMacroI('\splitbotmark', undef, Tokens()); DefMacro('\input TeXFileName',sub { my($gullet,$path)=@_; $path = ToString($path); $path = $1 if $path =~ /^\{(.*)\}$/; # just in case my ($dir,$name,$type) = pathname_split($path); my $newpath; if(my $file = FindFile($path)){ $gullet->input($file); } # Possibly we should be trying for a style file (& we may end up in latex mode) elsif((! $dir) && (!$type || ($type eq 'tex')) # Attempt to load raw TeX && ($newpath=FindFile($name,type=>'sty'))){ # and there IS such a style file Info(":override Overriding input of $path with $newpath"); RequirePackage($name); } else { $STATE->noteStatus(missing=>$path); Error(":missing_file:$path Cannot find $path in paths " .join(', ',@{$STATE->lookupValue('SEARCHPATHS')})); } return; }); DefMacroI('\endinput',undef,sub { $_[0]->closeMouth(1); return; }); # \the DefMacro('\the Variable',sub { my($gullet,$variable)=@_; return () unless $variable; my($defn,@args) = @$variable; my $type = $defn->isRegister; if(!$type){ my $cs = ToString($defn->getCS); Error(":unexpected:\\the$cs You can't use $cs after \\the"); return (); } my $value = $defn->valueOf(@args); my @tokens = ($type eq 'Tokens' ? ($value ? $value->unlist :()) : Explode(ToString($value))); if($LaTeXML::NOEXPAND_THE){ # See \the for the sense in this. $gullet->neutralizeTokens(@tokens); } else { @tokens; }}); #********************************************************************** # Primitives # See The TeXBook, Chapter 24, Summary of Vertical Mode # and Chapter 25, Summary of Horizontal Mode. # Parsing of basic types (pp.268--271) is (mostly) handled in Gullet.pm #********************************************************************** #====================================================================== # Registers & Parameters # See Chapter 24, Summary of Vertical Mode # Define a whole mess of useless registers here ... # Values are from Appendix B, pp. 348-349 (for whatever its worth) #====================================================================== #====================================================================== # Integer registers; TeXBook p. 272-273 our %iparms= (pretolerance=>100, tolerance=>200, hbadness=>1000, vbadness=>1000, linepenalty=>10, hyphenpenalty=>50, exhyphenpenalty=>50, binoppenalty=>700, relpenalty=>500, clubpenalty=>150, widowpenalty=>150, displaywidowpenalty=>50, brokenpenalty=>100, predisplaypenalty=>10000, postdisplaypenalty=>0, interlinepenalty=>0, floatingpenalty=>0, outputpenalty=>0, doublehyphendemerits=>10000, finalhyphendemerits=>5000, adjdemerits=>10000, looseness=>0, pausing=>0, holdinginserts=>0, tracingonline=>0, tracingmacros=>0, tracingstats=>0, tracingparagraphs=>0, tracingpages=>0, tracingoutput=>0, tracinglostchars=>1, tracingcommands=>0, tracingrestores=>0, language=>0, uchyph=>1, lefthyphenmin=>0, righthyphenmin=>0, globaldefs=>0, defaulthyphenchar=>ord('-'), defaultskewchar=>-1, escapechar=>0, endlinechar=>0, newlinechar=>-1, maxdeadcycles=>0, hangafter=>0, fam=>-1, mag=>1000, magnification=>1000, delimiterfactor=>0, time=>0, day=>0, month=>0, year=>0, showboxbreadth=>5, showboxdepth=>3, errorcontextlines=>5); foreach my $p (keys %iparms){ DefRegister("\\$p",Number($iparms{$p})); } { my ($sec,$min,$hour,$mday,$mon,$year)=localtime(); AssignValue('\day' =>Number($mday), 'global'); AssignValue('\month'=>Number($mon+1), 'global'); AssignValue('\year' =>Number(1900+$year), 'global'); AssignValue('\time' =>Number(60*$hour+$min),'global'); } our @MonthNames=(qw( January February March April May June July August September October November December)); # Return a string for today's date. sub today { $MonthNames[LookupValue('\month')->valueOf-1] ." ".LookupValue('\day')->valueOf .', '.LookupValue('\year')->valueOf; } # Read-only Integer registers our %ro_iparms=(lastpenalty=>0, inputlineno=>0, badness=>0); foreach my $p (keys %ro_iparms){ DefRegister("\\$p",Number($ro_iparms{$p}),readonly=>1); } # Special integer registers (?) # = \spacefactor | \prevgraf | \deadcycles | \insertpenalties our %sp_iparms=(spacefactor=>0, prevgraf=>0, deadcycles=>0, insertpenalties=>0); foreach my $p (keys %sp_iparms){ DefRegister("\\$p",Number($sp_iparms{$p})); } #====================================================================== # Dimen registers; TeXBook p. 274 our %dparms=(hfuzz=>'0.1pt', vfuzz=>'0.1pt', overfullrule=>'5pt', emergencystretch=>0, hsize=>'6.5in', vsize=>'8.9in', maxdepth=>'4pt', splitmaxdepth=>'16383.99999pt', boxmaxdepth=>'16383.99999pt', lineskiplimit=>0, delimitershortfall=>'5pt', nulldelimiterspace=>'1.2pt', scriptspace=>'0.5pt', mathsurround=>0, predisplaysize=>0, displaywidth=>0, displayindent=>0, parindent=>'20pt', hangindent=>0, hoffset=>0, voffset=>0,); foreach my $p (keys %dparms){ DefRegister("\\$p",Dimension($dparms{$p})); } # Read-only dimension registers. our %ro_dparms=(lastkern=>0); foreach my $p (keys %ro_dparms){ DefRegister("\\$p",Dimension($ro_dparms{$p}), readonly=>1); } # Special dimension registers (?) # = \prevdepth | \pagegoal | \pagetotal | \pagestretch | \pagefilstretch # | \pagefillstretch | \pagefilllstretch | pageshrink | \pagedepth our %sp_dparms=(prevdepth=>0, pagegoal=>0, pagetotal=>0, pagestretch=>0, pagefilstretch=>0, pagefillstretch=>0, pagefilllstretch=>0, pageshrink=>0, pagedepth=>0); foreach my $p (keys %sp_dparms){ DefRegister("\\$p",Dimension($sp_dparms{$p})); } #====================================================================== # Glue registers; TeXBook p.274 our %gparms=(baselineskip=>0, lineskip=>0, parskip=>'0pt plus 1pt', abovedisplayskip=>'12pt plus 3pt minus 9pt', abovedisplayshortskip=>'0pt plus 3pt', belowdisplayskip=>'12pt plus 3pt minus 9pt', belowdisplayshortskip=>'0pt plus 3pt', leftskip=>0, rightskip=>0, topskip=>'10pt', splittopskip=>'10pt', tabskip=>0, spaceskip=>0, xspaceskip=>0, parfillskip=>'0pt plus 1fil'); foreach my $p (keys %gparms){ DefRegister("\\$p",Glue($gparms{$p})); } #====================================================================== # MuGlue registers; TeXBook p.274 our %mparms=(thinmuskip=>'3mu', medmuskip=>'4mu plus 2mu minus 4mu', thickmuskip=>'5mu plus 5mu'); foreach my $p (keys %mparms){ DefRegister("\\$p",Glue($mparms{$p})); } #====================================================================== # Token registers; TeXBook p.275 our @tparms= qw(output everypar everymath everydisplay everyhbox everyvbox everyjob everycr everyhelp); foreach my $p (@tparms){ DefRegister("\\$p",Tokens()); } #====================================================================== # Assignment, TeXBook Ch.24, p.275 #====================================================================== # = | #====================================================================== # Macros # See Chapter 24, p.275-276 # = | # = # = \def | \gdef | \edef | \xdef # = sub parseDefParameters { my($cs, $params)=@_; my @tokens = $params->unlist; # Now, recognize parameters and delimiters. my @params=(); my $n=0; while(@tokens){ my $t=shift(@tokens); if($t->getCatcode == CC_PARAM){ $n++; $t=shift(@tokens); Fatal(":expected:#$n Parameters for \"".ToString($cs)."\" not in order in ".ToString($params)) unless $n == (ord($t->getString)-ord('0')); # Check for delimiting text following the parameter #n my @delim=(); my($pc,$cc)=(-1,0); while(@tokens && (($cc=$tokens[0]->getCatcode) != CC_PARAM)){ my $d = shift(@tokens); push(@delim,$d) unless $cc == $pc && $cc==CC_SPACE; # BUT collapse whitespace! $pc = $cc;} # Found text that marks the end of the parameter if(@delim){ my $expected=Tokens(@delim); push(@params, LaTeXML::Parameters::newParameter('Until', 'Until:'.ToString($expected), extra=>[$expected])); } # Special case: trailing sole # => delimited by next opening brace. elsif((scalar(@tokens)==1) && ($tokens[0]->getCatcode == CC_PARAM)){ shift(@tokens); push(@params, LaTeXML::Parameters::newParameter('UntilBrace','UntilBrace')); } # Nothing? Just a plain parameter. else { push(@params, LaTeXML::Parameters::newParameter('Plain','{}')); }} else { # Initial delimiting text is required. my @lit=($t); while(@tokens && ($tokens[0]->getCatcode != CC_PARAM)){ push(@lit,shift(@tokens)); } my $expected = Tokens(@lit); push(@params,LaTeXML::Parameters::newParameter('Match', 'Match:'.ToString($expected), extra=>[$expected], novalue=>1)); } } (@params ? LaTeXML::Parameters->new(@params) : undef); } sub do_def { my($globally, $expanded, $gullet,$cs,$params,$body)=@_; $params = parseDefParameters($cs,$params); if($expanded){ local $LaTeXML::NOEXPAND_THE = 1; $body = Expand($body); } DefMacroI($cs,$params,$body,($globally ? (scope=>'global'):())); return; } DefPrimitive('\def SkipSpaces Token UntilBrace {}', sub { do_def(0,0,@_); }); DefPrimitive('\gdef SkipSpaces Token UntilBrace {}', sub { do_def(1,0,@_); }); DefPrimitive('\edef SkipSpaces Token UntilBrace {}', sub { do_def(0,1,@_); }); DefPrimitive('\xdef SkipSpaces Token UntilBrace {}', sub { do_def(1,1,@_); }); # = \global | \long | \outer # See Stomach.pm & Stomach.pm DefPrimitiveI('\global',undef,sub { $STATE->setPrefix('global'); return; }, isPrefix=>1); DefPrimitiveI('\long', undef,sub { $STATE->setPrefix('long'); return; }, isPrefix=>1); DefPrimitiveI('\outer', undef,sub { $STATE->setPrefix('outer'); return; }, isPrefix=>1); #====================================================================== # Non-Macro assignments; TeXBook Ch.24, pp 276--277 # = | \global # = | \relax # = { # = | # | | | # | | | # | \read to # | \setbox<8bit> # | \font # | # = # | # | # | # | # | # = at | scaled | # = <8bit> DefMacro('\read Number SkipKeyword:to Token',sub { my($gullet,$fh,$token)=@_; DefMacroI($token,undef,Tokens()); }); ##our %font_family=(r=>'serif',''=>'serif',ss=>'sansserif',tt=>'typewriter', ## vtt=>'typewriter',fib=>'fibonacci',fr=>'funnyroman', ## dh=>'dunhill',m=>'math',sy=>'symbol'); # Given a font, we'd like to map it to the "logical" names derived from LaTeX, # (w/ loss of fine grained control). # I'd like to use Karl Berry's font naming scheme # (See http://www.tug.org/fontname/html/) # but it seems to be a one-way mapping, and moreover, doesn't even fit CM fonts! # We'll assume a sloppier version: # family + series + variant + size our %font_family=(cmr=>{family=>'serif'}, cmss=>{family=>'sansserif'}, cmtt=>{family=>'typewriter'},cmvtt=>{family=>'typewriter'}, cmti=>{family=>'typewriter', shape=>'italic'}, cmfib=>{family=>'serif'}, cmfr=>{family=>'serif'}, cmdh=>{family=>'serif'}, cm=>{family=>'serif'}, ptm=>{family=>'serif'}, ppl=>{family=>'serif'}, pnc=>{family=>'serif'}, pbk=>{family=>'serif'}, phv=>{family=>'sansserif'}, pag=>{family=>'serif'}, pcr=>{family=>'typewriter'}, pzc=>{family=>'script'}, put=>{family=>'serif'}, bch=>{family=>'serif'}, psy=>{family=>'symbol'}, pzd=>{family=>'dingbats'}, ccr=>{family=>'serif'}, ccy=>{family=>'symbol'}, cmbr=>{family=>'sansserif'}, cmtl=>{family=>'typewriter'}, cmbrs=>{family=>'symbol'}, ul9=>{family=>'typewriter'}, txr=>{family=>'serif'}, txss=>{family=>'sansserif'}, txtt=>{family=>'typewriter'},txms=>{family=>'symbol'}, txsya=>{family=>'symbol'}, txsyb=>{family=>'symbol'}, pxr=>{family=>'serif'}, pxms=>{family=>'symbol'}, pxsya=>{family=>'symbol'}, pxsyb=>{family=>'symbol'}, futs=>{family=>'serif'}, uaq=>{family=>'serif'}, ugq=>{family=>'sansserif'}, eur=>{family=>'serif'}, eus=>{family=>'script'}, euf=>{family=>'fraktur'}, euex=>{family=>'symbol'}, # The following are actually math fonts. ms=>{family=>'symbol'}, ccm=>{family=>'serif', shape=>'italic'}, cmex=>{family=>'symbol'}, # Not really symbol, but... cmsy=>{family=>'symbol'}, ccitt=>{family=>'typewriter', shape=>'italic'}, cmbrm=>{family=>'sansserif', shape=>'italic'}, futm=>{family=>'serif', shape=>'italic'}, futmi=>{family=>'serif', shape=>'italic'}, txmi=>{family=>'serif', shape=>'italic'}, pxmi=>{family=>'serif', shape=>'italic'}, bbm=>{family=>'blackboard'}, bbmss=>{family=>'blackboard'}, ); our %font_series=(''=>'medium',m=>'medium', mc=>'medium', b=>'bold',bc=>'bold', bx=>'bold', sb=>'bold', sbc=>'bold', bm=>'bold'); our %font_shape =(''=>'upright',n=>'upright', i=>'italic',it=>'italic', sl=>'slanted', sc=>'smallcaps', csc=>'smallcaps'); our $FONTREGEXP = '('.join('|',sort { -($a cmp $b) } keys %font_family).')' . '('.join('|',sort { -($a cmp $b) } keys %font_series).')' . '('.join('|',sort { -($a cmp $b) } keys %font_shape).')' . '(\d*)'; # Decode a font size in points into a "logical" size. our @font_size_map=(0.60=>'tiny', 0.75=>'script', 0.85=>'footnote',0.95=>'small', 1.10=>'normal', 1.30=>'large', 1.55=>'Large', 1.85=>'LARGE', 2.25=>'huge', 1000.0=>'Huge'); sub abstract_font_size { my($size)=@_; if(defined $size){ my $scaled = $size/10.0; # ASSUMED nominal font 10pt!!! Set from doc!!! my @map = @font_size_map; while(@map){ return shift(@map) if($scaled <= shift(@map)); shift(@map); } 'Huge'; } else { 'normal'; }} sub lookupFontFamily { $font_family{ToString($_[0])}; } sub lookupFontSeries { $font_series{ToString($_[0])}; } sub lookupFontShape { $font_shape{ToString($_[0])}; } # Need to handle "at" too!!! DefPrimitive('\font Token SkipMatch:= SkipSpaces TeXFileName', sub { my($stomach,$cs,$name)=@_; my $gullet = $stomach->getGullet; $name = ToString($name); my %props=(); my $size = 1; if($name =~ /^$FONTREGEXP$/o){ my($fm,$sr,$sh)=($1,$2,$3); $size = $4; %props = %{$font_family{$fm}||{}}; $props{series}= $font_series{$sr} unless $props{series}; $props{shape} = $font_shape{$sh} unless $props{shape}; } else { Info(":unexpected:$name Unrecognized font \"$name\"; ".ToString($cs)." will have no effect"); } if($gullet->readKeyword('at')){ $size = $gullet->readDimension->ptValue; } if($gullet->readKeyword('scaled')){ $size *= ($gullet->readNumber->valueOf/1000); } $props{size} = abstract_font_size($size); $gullet->skipSpaces; ## print STDERR "Font $name == ".join(', ',map("$_=>$props{$_}",sort keys %props))."\n"; DefConstructorI($cs,undef,'',font=>{%props}); }); DefRegister('\count Number' => Number(0)); DefRegister('\dimen Number' => Dimension(0)); DefRegister('\skip Number' => Glue(0)); DefRegister('\muskip Number'=> MuGlue(0)); DefRegister('\toks Number' => Tokens()); # = | | \count<8bit> # = | | \dimen<8bit> # = | | \skip<8bit> # = | | \muskip<8bit> # = \advance # | \advance # | \advance # | \advance # | \multiply # | \divide DefPrimitive('\advance Variable SkipKeyword:by',sub { my($stomach,$var)=@_; return () unless $var; my($defn,@args)=@$var; $defn->setValue($defn->valueOf(@args)->add($stomach->getGullet->readValue($defn->isRegister)),@args); }); DefPrimitive('\multiply Variable SkipKeyword:by Number',sub { my($stomach,$var,$scale)=@_; return () unless $var; my($defn,@args)=@$var; $defn->setValue($defn->valueOf(@args)->multiply($scale->valueOf),@args); }); DefPrimitive('\divide Variable SkipKeyword:by Number',sub { my($stomach,$var,$scale)=@_; return () unless $var; my($defn,@args)=@$var; my $denom = $scale->valueOf; if($denom == 0){ Error(":misdefined:$scale Illegal \\divide by 0; assuming 1"); $denom = 1; } $defn->setValue($defn->valueOf(@args)->multiply(1/$denom),@args); }); # = \futurelet # | \let DefPrimitive('\let Token SkipMatch:= SkipSpaces Token', sub { my($stomach,$token1,$token2)=@_; Let($token1, $token2); return; }); DefMacro('\futurelet Token Token Token',sub{ my($stomach,$cs,$token1,$token2)=@_; Let($cs, $token2); ($token1,$token2); }); # = \chardef<8bit> # | \mathchardef <15bit> # | <8bit> # = \countdef | \dimendef | \skipdef | \muskipdef | toksdef # Almost like a register, but different... DefPrimitive('\chardef Token SkipMatch:= Number', sub { my($stomach,$newcs,$value)=@_; $STATE->installDefinition(LaTeXML::CharDef->new($newcs,$value)); return; }); # \mathchardef ? DefPrimitive('\countdef Token SkipMatch:= Number',sub { my($stomach,$cs,$num)=@_; my $count = '\count'.$num->valueOf; DefRegisterI($cs,undef, Number(0), getter=>sub { LookupValue($count); }, setter=>sub { AssignValue($count=>$_[0]); }); }); DefPrimitive('\dimendef Token SkipMatch:= Number',sub { my($stomach,$cs,$num)=@_; my $dimen = '\dimen'.$num->valueOf; DefRegisterI($cs,undef,Dimension(0), getter=>sub { LookupValue($dimen); }, setter=>sub { AssignValue($dimen=>$_[0]); }); }); DefPrimitive('\skipdef Token SkipMatch:= Number',sub { my($stomach,$cs,$num)=@_; my $glue = '\skip'.$num->valueOf; DefRegisterI($cs,undef, Glue(0), getter=>sub { LookupValue($glue); }, setter=>sub { AssignValue($glue=>$_[0]); }); }); DefPrimitive('\muskipdef Token SkipMatch:= Number',sub { my($stomach,$cs,$num)=@_; my $muglue = '\muskip'.$num->valueOf; DefRegisterI($cs,undef, MuGlue(0), getter=>sub { LookupValue($muglue); }, setter=>sub { AssignValue($muglue=>$_[0]); }); }); DefPrimitive('\toksdef Token SkipMatch:= Number',sub { my($stomach,$cs,$num)=@_; my $toks = '\toks'.$num->valueOf; DefRegisterI($cs,undef, Tokens(), getter=>sub { LookupValue($toks); }, setter=>sub { AssignValue($toks=>$_[0]); }); }); # NOTE: Get all these handled as registers # = | | \lastpenalty # | | \count<8bit> | <8bit> # | | | \parshape | \inputlineno # | \hyphenchar | \skewchar | \badness DefRegister('\lastpenalty',Number(0), readonly=>1); # \parshape !?!?? #DefRegister('\inputlineno',Number(0), # readonly=>1, # getter=>{ Number($stomach->getGullet->getMouth????? ->lineno); }); # \skewchar ??? DefRegister('\badness',Number(0), readonly=>1); # = \catcode | \mathcode | \lccode | \uccode | \sfcode | \delcode DefRegister('\catcode Number',Number(0), getter=>sub { my $cc = LookupCatcode(chr($_[0]->valueOf)); $cc = CC_OTHER unless defined $cc; Number($cc); }, setter=>sub { AssignCatcode(chr($_[1]->valueOf) => $_[0]->valueOf); }); # Stub definitions ??? DefRegister('\mathcode Number',Number(0)); DefRegister('\sfcode Number',Number(0)); DefRegister('\lccode Number',Number(0)); DefRegister('\uccode Number',Number(0)); DefRegister('\delcode Number',Number(0)); DefRegister('\hyphenchar{}',Number(ord('-'))); DefRegister('\skewchar{}',Number(0)); # no idea what the default is here DefMacro('\hyphenation{}', Tokens()); # Well, what ? # = | \font | # | <4bit> # = \textfont | \scriptfont | \scriptscriptfont # Doubtful that we can do anything useful with these. DefMacro('\textfont Number SkipMatch:= Token', sub { return; }); DefMacro('\scriptfont Number SkipMatch:= Token', sub { return; }); DefMacro('\scriptscriptfont Number SkipMatch:= Token', sub { return; }); # = | | \lastkern # | | \dimen<8bit> | <8bit> | \fontdimen DefRegister('\lastkern'=>Dimension(0), readonly=>1); # = \ht | \wd | \dp # Need some clever getter & setters! DefRegister('\ht Number',Dimension(0)); DefRegister('\wd Number',Dimension(0)); DefRegister('\dp Number',Dimension(0)); # Could be handled by setting dimensions whenever the box itself is set? # = | \lastskip | | \skip<8bit> DefRegister('\lastskip'=>Glue(0), readonly=>1); # = | \lastskip | | \muskip<8bit> # = # = \parshape # is 2n # = | # | | # | # = \fontdimen # | \hyphenchar | \skewchar # = \hyphenation # | \patterns # = <8bit> # = \errorstopmode | \scrollmode | \nonstopmode | \batchmode # These are no-ops; Basically, LaTeXML runs in scrollmode DefPrimitiveI('\errorstopmode', undef,undef); DefPrimitiveI('\scrollmode', undef,undef); DefPrimitiveI('\nonstopmode', undef,undef); DefPrimitiveI('\batchmode', undef,undef); # = # | DefPrimitive('\char Number', sub { $_[0]->invokeToken(T_OTHER(chr($_[1]->valueOf))); }); # = \box <8bit> | \copy <8bit> | \lastbox | \vsplit <8bit> to # | \hbox {} # | \vbox {} # | \vtop {} # = to | spread | # \setbox=\hbox to {} DefPrimitive('\setbox Number SkipMatch:=', sub { my($stomach)=@_; my @stuff = $stomach->invokeToken($stomach->getGullet->readXToken); AssignValue('box'.$_[1]->valueOf => shift(@stuff)); @stuff;}); # Is this the same ?? DefPrimitive('\sbox Number SkipMatch:= {}', sub { my($stomach)=@_; my @stuff = $stomach->invokeToken($stomach->getGullet->readXToken); AssignValue('box'.$_[1]->valueOf => shift(@stuff)); @stuff;}); DefPrimitive('\box Number', sub { LookupValue('box'.$_[1]->valueOf) || (); }); sub revert_spec { my($whatsit,$keyword)=@_; my $value = $whatsit->getProperty($keyword); ($value ? (Explode($keyword),$value->revert): ()); } DefParameterType('BoxSpecification',sub { my($gullet)=@_; if(my $key = $gullet->readKeyword('to','spread')){ LaTeXML::BoxDimensions->new($key=>$gullet->readDimension); }}, optional=>1, undigested=>1); # Risky: I think this needs to be digested as a body to work like TeX (?) # but parameter think's it's just parsing from gullet... DefParameterType('BoxContents',sub { my($gullet)=@_; my $t; while(($t=$gullet->readToken) && !Equals($t,T_BEGIN)){} # Skip till { or \bgroup my($contents,@stuff) = $STATE->getStomach->invokeToken(T_BEGIN); $contents; }, undigested=>1); # Cause it already is digested! sub REF { $_[0] && $_[0]->{$_[1]}; } DefConstructor('\hbox BoxSpecification BoxContents', "#2", mode=>'text', # Workaround for $ in alignment; an explicit \hbox gives us a normal $. # And also things like \centerline that will end up bumping up to block level! beforeDigest=>sub { Let(T_MATH,T_CS('\@text@alignment$')); Let(T_CS('\centerline'),T_CS('\relax')); }); # SHOULD Be a little smarter: if we're already in a block level context, don't open inline-block # but that doesn't really quite capture the logic.... DefConstructor('\vbox BoxSpecification BoxContents', "#2", # sub { my($document,$spec,$content)=@_; # if($document->isOpenable('ltx:block')){ # If already at block level # $document->absorb($content); } # else { # $document->insertElement('ltx:inline-block', # $content, # vattach=>'bottom', # height=>$spec && $$spec{height}, # 'pad-height'=>$spec && $$spec{spread}); }}, mode=>'text'); DefConstructor('\vtop BoxSpecification BoxContents', "#2", # sub { my($document,$spec,$content)=@_; # if($document->isOpenable('ltx:block')){ # If already at block level # $document->absorb($content); } # else { # $document->insertElement('ltx:inline-block', # $content, # vattach=>'top', # height=>$spec && $$spec{height}, # 'pad-height'=>$spec && $$spec{spread}); }}, mode=>'text'); sub read_rule_spec { my($stomach,$whatsit)=@_; my $gullet = $stomach->getGullet; while(my $key = $gullet->readKeyword('height','depth','width')){ $whatsit->setProperty($key=>$gullet->readDimension); } return; } DefConstructorI('\vrule', undef,"", afterDigest=>sub { read_rule_spec(@_); }, properties=>{isVerticalRule=>1}, reversion=>sub { (T_CS('\vbox'),revert_spec($_[0],'height'), revert_spec($_[0],'depth'),revert_spec($_[0],'width'));}); DefConstructorI('\hrule', undef,"", afterDigest=>sub { read_rule_spec(@_); }, properties=>{isHorizontalRule=>1}, reversion=>sub { (T_CS('\hbox'),revert_spec($_[0],'height'), revert_spec($_[0],'depth'),revert_spec($_[0],'width'));}); #====================================================================== # Remaining Mode independent primitives in Ch.24, pp.279-280 # \relax was done as expandable (isn't that right?) # } # Note, we don't bother making sure begingroup is ended by endgroup. # These define the handler for { } (or anything of catcode BEGIN, END) # These are actually TeX primitives, but we treat them as a Whatsit so they # remain in the constructed tree. DefConstructor('{','#body', beforeDigest=>sub{$_[0]->bgroup;}, captureBody=>1); DefConstructor('}', '', beforeDigest=>sub{$_[0]->egroup;}); # These are for those screwy cases where you need to create a group like box, # more than just bgroup, egroup, # BUT you DON'T want extra {, } showing up in any untex-ing. DefConstructor('\@hidden@bgroup','#body', beforeDigest=>sub{$_[0]->bgroup;}, captureBody=>1, reversion=>sub { $_[0]->getProperty('body')->revert; }); DefConstructor('\@hidden@egroup','',afterDigest=>sub { $_[0]->egroup; }, reversion=>''); DefPrimitive('\begingroup',sub { $_[0]->begingroup; }); DefPrimitive('\endgroup', sub { $_[0]->endgroup; }); # Debugging aids; Ignored! DefPrimitive('\show Token',undef); DefPrimitive('\showbox Number',undef); DefPrimitive('\showlists',undef); DefPrimitive('\showthe Token',undef); # DefPrimitive('\shipout ?? DefPrimitive('\ignorespaces SkipSpaces',undef); # \afterassignment ?? DefPrimitive('\aftergroup Token', sub { UnshiftValue(afterGroup=>$_[1]); }); # \uppercase, \lowercase DefMacro('\uppercase {}',sub { my($gullet,$arg)=@_; map( ($_->getCharcode == CC_LETTER ? T_LETTER(uc($_->getString)):$_), ($arg ? $arg->unlist :())); }); DefMacro('\lowercase {}',sub { my($gullet,$arg)=@_; map( ($_->getCharcode == CC_LETTER ? T_LETTER(lc($_->getString)):$_), ($arg ? $arg->unlist :())); }); DefPrimitive('\message{}',sub { my($stomach,$stuff)=@_; print STDERR ToString(Expand($stuff)); return; }); ## I'm thinking we want to mostly ignore the I/O stuff. ## Generally, it's used to move info around for multiple passes ## of aux, index, etc. DefPrimitive('\openin Number SkipMatch:= TeXFileName', undef); DefPrimitive('\openout Number SkipMatch:= TeXFileName', undef); DefPrimitive('\closein Number',undef); DefPrimitive('\closeout Number',undef); DefPrimitive('\immediate',undef); # \immediate\write DefPrimitive('\write Number {}', undef); #====================================================================== # Remaining semi- Vertical Mode primitives in Ch.24, pp.280--281 DefPrimitive('\special {}', undef); DefPrimitive('\penalty Number',undef); DefPrimitive('\kern Dimension',undef); DefPrimitive('\mkern MuGlue',undef); DefPrimitiveI('\unpenalty',undef,undef); DefPrimitiveI('\unkern', undef,undef); DefPrimitiveI('\unskip', undef,undef); DefPrimitive('\mark{}',undef); # \insert<8bit>{} DefPrimitive('\insert Number',undef); # Just let the insertion get processed(?) # \vadjust{} DefPrimitive('\vadjust {}',undef); # Ignorable? #====================================================================== # Remaining Vertical Mode primitives in Ch.24, pp.281--283 # \vskip, \vfil, \vfill, \vss, \vfilneg # = \leaders | \cleaders | \xleaders # = | | # = \vrule # = \hrule # = | # = width | height | depth # Stuff to ignore for now... foreach my $op ('\vskip Glue', '\vfil', '\vfill', '\vss', '\vfilneg', '\leaders', '\cleaders', '\xleaders'){ DefPrimitive($op,undef); } # \moveleft, \moveright DefConstructor('\moveleft Dimension MoveableBox', "#2", afterDigest=>sub{ $_[1]->setProperty(x=>$_[1]->getArg(1)->multiply(-1)); }); DefConstructor('\moveright Dimension MoveableBox', "#2", afterDigest=>sub{ $_[1]->setProperty(x=>$_[1]->getArg(1)); }); # \unvbox<8bit>, \unvcopy<8bit> DefMacro('\unvbox Number',sub { my $box = 'box'.$_[1]->valueOf; my $stuff = LookupValue($box); AssignValue($box,undef); $stuff; }); DefMacro('\unvcopy Number',sub { LookupValue('box'.$_[1]->valueOf); }); #====================================================================== # Basic alignment support needed by most environments & commands. #====================================================================== Tag('ltx:td', afterClose=>\&trimNodeWhitespace); #---------------------------------------------------------------------- # Primitive column types; # This is really LaTeX, but the mechanisms are used behind-the-scenes here, too. DefColumnType('|',sub { $LaTeXML::BUILD_TEMPLATE->addBetween(T_CS('\vrule')); return; }); DefColumnType('l',sub { $LaTeXML::BUILD_TEMPLATE->addColumn(after=>Tokens(T_CS('\hfil'))); return; }); DefColumnType('c',sub { $LaTeXML::BUILD_TEMPLATE->addColumn(before=>Tokens(T_CS('\hfil')), after=>Tokens(T_CS('\hfil'))); return; }); DefColumnType('r',sub { $LaTeXML::BUILD_TEMPLATE->addColumn(before=>Tokens(T_CS('\hfil'))); return; }); DefColumnType('p{Dimension}',sub { $LaTeXML::BUILD_TEMPLATE->addColumn(before=>Tokens(T_CS('\hbox'),T_BEGIN),#Tokens(T_BEGIN), after=>Tokens(T_END), align=>'justify', width=>$_[1]); return; }); DefColumnType('*{Number}{}', sub { my($gullet,$n,$pattern)=@_; map( $pattern->unlist, 1..$n->valueOf); }); DefColumnType('@{}',sub { my($gullet,$filler)=@_; $LaTeXML::BUILD_TEMPLATE->addBetween($filler->unlist); return; }); #---------------------------------------------------------------------- DefMacroI('\@start@alignment',undef, '\@open@alignment\@open@row\@open@column\@open@inner@column'); DefMacroI('\@finish@alignment',undef, '\@close@inner@column\@close@column\@close@row\@close@alignment'); #---------------------------------------------------------------------- # These are to be bound to &, \span, \cr and \\ # The macro layer expands into appropriate begin & end markers for rows & columns; # The constructor layer carries out any side effect and records a token for reversion. DefMacroI('\@alignment@align',undef, '\@close@inner@column\@close@column' .'\@alignment@align@marker' .'\@open@column\@open@inner@column'); DefConstructorI('\@alignment@align@marker',undef,'',reversion=>'&'); #DefMacro('\@alignment@span', DefMacroI('\span',undef, '\@close@inner@column' .'\@alignment@span@marker' .'\@open@inner@column'); DefConstructorI('\@alignment@span@marker',undef,'',reversion=>'\span', properties=>{alignmentSkippable=>1}); DefConstructorI('\omit',undef,'',properties=>{alignmentSkippable=>1}); DefMacroI('\@alignment@cr',undef, '\@close@inner@column\@close@column\@close@row' .'\@alignment@cr@marker' .'\@open@row\@open@column\@open@inner@column'); DefConstructorI('\@alignment@cr@marker',undef,'',reversion=>'\cr'); DefConstructorI('\default@cr',undef, "\n"); # Default binding. Let(T_CS('\cr'), T_CS('\default@cr')); Let(T_CS('\crcr'),T_CS('\cr')); # NOTE that this does NOT skip spaces before * or []!!!!! # As if: \@alignment@newline OptionalMatch:* [Dimension] sub readNewlineArgs { my($gullet)=@_; my $next = $gullet->readToken; my($star,$optional); if($next && $next->equals(T_OTHER('*'))){ $star = 1; $next = $gullet->readToken; } if($next && $next->equals(T_OTHER('['))){ $optional = $gullet->readUntil(T_OTHER(']')); $next = undef; } $gullet->unread($next) if $next; ($star,$optional); } DefMacroI('\@alignment@newline', undef,sub { my($gullet)=@_; readNewlineArgs($gullet); (T_CS('\@close@inner@column'), T_CS('\@close@column'), T_CS('\@close@row'), T_CS('\@alignment@newline@marker'), T_CS('\@open@row'), T_CS('\@open@column'), T_CS('\@open@inner@column')); }); DefConstructorI('\@alignment@newline@marker',undef,'',reversion=>Tokens(T_CS("\\\\"),T_CR)); DefConstructorI('\@alignment@hline',undef,'', afterDigest=>sub { LookupValue('Alignment')->addLine('t'); }, properties=>{isHorizontalRule=>1}, alias=>'\hline'); DefConstructorI('\@alignment@hrule',undef,'', afterDigest=>sub { LookupValue('Alignment')->addLine('t'); }, properties=>{isHorizontalRule=>1}, alias=>'\hrule'); DefConstructorI('\@alignment@vrule',undef,'', properties=>{isVerticalRule=>1}, alias=>'\vrule'); # Special forms for $ appearing within alignments. # Note that $ within a math alignment (eg array environment), # switches to text mode! There's no $$ for display math. # This is the "normal" case: $ appearing with an alignment that is in text mode. # It's just like regular $, except it doesn't look for $$ (no display math). DefPrimitiveI('\@text@alignment$', undef, sub { $_[0]->invokeToken(T_CS((LookupValue('IN_MATH') ?'\@@ENDINLINEMATH':'\@@BEGININLINEMATH'))); }); # This one is for $ appearing within an alignment that's already math. # This should switch to text mode (because it's balancing the hidden $ # wrapping each alignment cell!!!!!!) # However, it should be like a normal $ if it's inside something like \mbox # that itself makes a text box!!!!!! # Thus, we need to know at what boxing level we started the last math or text. # This is all complicated by the need to know _how_ we got into or out of math mode! # Gawd, this is awful! # NOTE: Probably the most "Right" thing to do would be to process # alignments in text mode only (like TeX), sneaking $'s in where needed, # but then afterwards, morph them into math arrays? # This would be complicated by the need to hide these $ from untex. DefPrimitiveI('\@math@alignment$', undef, sub { my($stomach)=@_; my $level = $stomach->getBoxingLevel; if((LookupValue('MATH_ALIGN_$_BEGUN')||0) == $level){ # If we're begun making _something_ with $. my @l=(); if(LookupValue('IN_MATH')){ # But we're somehow in math? @l = $stomach->invokeToken(T_CS('\@@ENDINLINEMATH')); } else { @l = $stomach->invokeToken(T_CS('\@@ENDINLINETEXT')); } AssignValue('MATH_ALIGN_$_BEGUN'=>0); # Reset this AFTER finishing the something @l; } else { AssignValue('MATH_ALIGN_$_BEGUN'=>$level+1); # Note that we've begun something if(LookupValue('IN_MATH')){ # If we're "still" in math $stomach->invokeToken(T_CS('\@@BEGININLINETEXT')); } else { $stomach->invokeToken(T_CS('\@@BEGININLINEMATH')); }}}); DefConstructorI('\@@BEGININLINETEXT',undef, "" . "#body" ."", alias=>'$', beforeDigest=> sub{ $_[0]->beginMode('text'); }, captureBody=>1); DefConstructorI('\@@ENDINLINETEXT',undef ,"", alias=>'$', beforeDigest=> sub{ $_[0]->endMode('text');}); # ???? DefPrimitiveI('\noalign', undef,undef); DefMacroI('\hidewidth', undef, Tokens()); DefMacro('\multispan{Number}', sub { my($gullet,$span)=@_; $span = $span->valueOf; (T_CS('\omit'),map((T_CS('\span'),T_CS('\omit')), 1..$span-1)); }); DefRegisterI('\@alignment@ncolumns',undef,Dimension(0), getter=>sub { Number(scalar(LookupValue('Alignment')->getTemplate->columns)); }); DefRegisterI('\@alignment@column',undef,Dimension(0), getter=>sub { Number(LookupValue('Alignment')->currentColumnNumber); }); DefMacro('\@multicolumn {Number} AlignmentTemplate {}', sub { my($gullet,$span,$template,$tokens)=@_; my $column = $template->column(1); $span = $span->valueOf; # First part, like \multispan (T_CS('\omit'),map((T_CS('\span'),T_CS('\omit')), 1..$span-1), # Next part, just put the template in-line, since it's only used once. ($column ? beforeCellUnlist($$column{before}) : ()), $tokens->unlist, ($column ? afterCellUnlist($$column{after}) : ()) ); }); DefMacroI('\if@in@alignment', undef,sub { ifHandler($_[0],LookupValue('Alignment')); }, isConditional=>1); sub alignmentBindings { my($template,$mode)=@_; if($template && !ref $template){ $template = parseAlignmentTemplate($template); } $mode = LookupValue('MODE') unless $mode; my $ismath = $mode =~/math$/; my $container = ($ismath ? 'ltx:XMArray' : 'ltx:tabular'); my $rowtype = ($ismath ? 'ltx:XMRow' : 'ltx:tr'); my $coltype = ($ismath ? 'ltx:XMCell' : 'ltx:td'); # my $alignment = LaTeXML::Util::Alignment->new(containerElement=>$container, # rowElement=>$rowtype, # colElement=>$coltype); my $alignment = LaTeXML::Util::Alignment ->new(openContainer =>sub{ $_[0]->openElement($container,@_[1..$#_]); }, closeContainer=>sub{ $_[0]->closeElement($container); }, openRow =>sub{ $_[0]->openElement($rowtype,@_[1..$#_]); }, closeRow =>sub{ $_[0]->closeElement($rowtype); }, openColumn =>sub{ $_[0]->openElement($coltype,@_[1..$#_]); }, closeColumn =>sub{ $_[0]->closeElement($coltype); }); AssignValue(Alignment=>$alignment); $alignment->setTemplate($template) if $template; Let(T_ALIGN, T_CS('\@alignment@align')); Let(T_CS("\\\\"), T_CS('\@alignment@newline')); Let(T_CS('\tabularnewline'), T_CS('\@alignment@newline')); Let(T_CS('\cr'), T_CS('\@alignment@cr')); Let(T_CS('\crcr'), T_CS('\@alignment@cr')); Let(T_CS('\hline'), T_CS('\@alignment@hline')); Let(T_CS('\hrule'), T_CS('\@alignment@hrule')); Let(T_CS('\vrule'), T_CS('\@alignment@vrule')); Let(T_MATH, ($ismath ? T_CS('\@math@alignment$') : T_CS('\@text@alignment$'))); Let(T_CS('\@open@row'),T_CS('\default@open@row')); Let(T_CS('\@close@row'),T_CS('\default@close@row')); return; } DefPrimitive('\@alignment@bindings AlignmentTemplate []',sub { my($stomach,$template,$mode)=@_; alignmentBindings($template,$mode); }); #---------------------------------------------------------------------- # To recognize where rows & columns start and stop, we need to # recognize things that have expanded into &, \cr, etc. # Additionally, \span creates a single column out of several. #---------------------------------------------------------------------- # Overall Alignment; DefPrimitive('\@close@alignment',sub { $_[0]->egroup;} ); DefConstructor('\@open@alignment SkipSpaces DigestedBody', "#1", reversion=>'#1', beforeDigest=>sub {$_[0]->bgroup; }, afterDigest=>sub { $_[1]->setProperty(alignment=>LookupValue('Alignment')); }); #---------------------------------------------------------------------- # Row; The content is stuffed into the Alignment, so we don't construct anything here. DefPrimitive('\default@close@row',sub { $_[0]->egroup;} ); DefConstructor('\default@open@row SkipSpaces DigestedBody', "", reversion=>'#1', beforeDigest=>sub { $_[0]->bgroup; LookupValue('Alignment')->newRow; return;}); #---------------------------------------------------------------------- # Column # Here, a column represents 1 or more "inner columns". # inner columns can be separated by \span's yielding a single column with # rowspan > 1. Also, inner columns recognize \omit which removes the # before & after tokens which would otherwise wrap the inner column. DefPrimitiveI('\@tabular@begin@heading', undef,sub { AssignValue(IN_TABULAR_HEAD=>1,'global'); }); DefPrimitiveI('\@tabular@end@heading', undef,sub { AssignValue(IN_TABULAR_HEAD=>0,'global'); }); DefPrimitiveI('\@close@column', undef,sub { $_[0]->egroup;} ); DefPrimitive('\@open@column SkipSpaces DigestedBody', sub { my($stomach,$boxes)=@_; my $alignment = LookupValue('Alignment'); my $n0 = LookupValue('alignmentStartColumn')+1; my $n1 = $alignment->currentColumnNumber; my $colspec = $alignment->getColumn($n0); my $align= $$colspec{align} || 'left'; my $border= ''; # Peel off any boxes from both sides until we get the "meat" of the column. # from this we can establish borders, alignment and emptiness. # But we, of course, immediately put them back... my @boxes = $boxes->unlist; my @saveleft=(); my @saveright=(); while(@boxes){ if($boxes[0]->getProperty('isFill')){ $align='right'; shift(@boxes); last; } elsif($boxes[0]->getProperty('isVerticalRule')){ $border .= 'l'; shift(@boxes); } elsif($boxes[0]->getProperty('isHorizontalRule')){ push(@saveleft,shift(@boxes)); } elsif($boxes[0]->getProperty('alignmentSkippable')){ push(@saveleft,shift(@boxes)); } elsif(ref $boxes[0] eq 'LaTeXML::Comment'){ push(@saveleft,shift(@boxes)); } # elsif($boxes[0]->getProperty('isSpace')){ elsif(isEmpty($boxes[0])){ shift(@boxes);} else { last; }} while(@boxes){ if($boxes[$#boxes]->getProperty('isFill')){ if($align eq 'right'){ $align='center'; } pop(@boxes); last; } elsif($boxes[$#boxes]->getProperty('isVerticalRule')){ $border .= 'r'; pop(@boxes); } elsif($boxes[$#boxes]->getProperty('isHorizontalRule')){ unshift(@saveright,pop(@boxes)); } elsif($boxes[$#boxes]->getProperty('alignmentSkippable')){ unshift(@saveright,pop(@boxes)); } elsif(ref $boxes[$#boxes] eq 'LaTeXML::Comment'){ unshift(@saveleft,pop(@boxes)); } # elsif($boxes[$#boxes]->getProperty('isSpace')){ elsif(isEmpty($boxes[$#boxes])){ pop(@boxes);} else { last; }} delete $$colspec{width} unless $align eq 'justify'; my $empty = scalar(@boxes) == 0; $align = undef if $empty; @boxes = (@saveleft,@boxes,@saveright); $boxes = (scalar(@boxes) == 1 ? $boxes[0] : ($boxes->isMath ? LaTeXML::MathList->new(@boxes) : LaTeXML::List->new(@boxes))); # record relevant info in the Alignment. $$colspec{align} = $align; $$colspec{border}= $border = ($$colspec{border}||'').$border; $$colspec{boxes} = $boxes; $$colspec{span} = $n1-$n0+1; $$colspec{empty} = 1 if $empty; $$colspec{head} = LookupValue('IN_TABULAR_HEAD'); for(my $i = $n0+1; $i <= $n1; $i++){ my $c = $alignment->getColumn($i); $c->{skipped}=1 if $c; } # $stomach->egroup; $boxes; }, beforeDigest=>sub { AssignValue(alignmentStartColumn=>LookupValue('Alignment')->currentColumnNumber); $_[0]->bgroup; }); AssignValue(ALIGNMENT_LINE_COMMANDS=>[]); PushValue(ALIGNMENT_LINE_COMMANDS=>T_CS('\hline')); PushValue(ALIGNMENT_LINE_COMMANDS=>T_CS('\cline')); PushValue(ALIGNMENT_LINE_COMMANDS=>T_CS('\label')); DefMacroI('\@close@inner@column', undef,sub { (T_CS('\@@eat@space'), afterCellUnlist(LookupValue('Alignment')->currentColumn->{after}), T_CS('\@@close@inner@column')); }); DefPrimitiveI('\@@close@inner@column', undef,sub { $_[0]->egroup; }); DefPrimitiveI('\@open@inner@column', undef,sub { my($stomach)=@_; my $colspec = LookupValue('Alignment')->nextColumn; $stomach->bgroup; my $gullet = $stomach->getGullet; my @lines=(); my @line_tokens = @{LookupValue('ALIGNMENT_LINE_COMMANDS')}; my @savedtokens=(); $$colspec{empty}=0; # Assume the column isn't empty # Scan for leading \omit, skipping over (& saving) \hline. while(my $tok=$gullet->readXToken){ if($tok->equals(T_SPACE)){ } # Skip leading space elsif(grep($tok->equals($_),@line_tokens)){ # Save line commands push(@lines,$stomach->invokeToken($tok)); } elsif(Equals($tok,T_BEGIN)){ # Crazy... seems { doesn't "block" \omit! push(@savedtokens,$tok); } else { ## if($tok->equals(T_CS('\omit'))){ # \omit removes the before/after tokens for this column. if(Equals($tok,T_CS('\omit'))){ # \omit removes the before/after tokens for this column. $$colspec{before}=$$colspec{after}=Tokens(); } ## elsif($tok->equals(T_CS('\@@eat@space'))){ # First non-empty token implies column is empty. elsif(Equals($tok,T_CS('\@@eat@space'))){ # First non-empty token implies column is empty. $$colspec{empty}=1; } $gullet->unread($tok); last; }} $gullet->unread(@savedtokens); $gullet->unread(beforeCellUnlist($$colspec{before})); (@lines,$STATE->getStomach->digestNextBody()); }); # NOTE: Watch here for problems with alignments. # The previous version threw away too much stuff (esp. metadata). # This one, I think, is more careful. # The issue is that it should throw away spaces (or things like spaces?) # so that various omit/span/fill/etc is properly recognized when analyzing columns. DefPrimitiveI('\@@eat@space',undef,sub { my $box; my @save=(); while($box = $LaTeXML::LIST[$#LaTeXML::LIST]){ if($box->getProperty('alignmentSkippable') || $box->getProperty('isFill')){ push(@save,pop(@LaTeXML::LIST)); } elsif(isEmpty($box)){ pop(@LaTeXML::LIST); } else { last; }} push(@LaTeXML::LIST,@save); return; }); # Yet more special case hacking. Sometimes the order of tokens works for # TeX, but confuses us... In particular the order of $ and \hfil! # \@open@column is too late, since the stuff is already digested. # Could _almost_ handle the extractions here, but there are several # rule operators that digest into whatsits with certain properties... sub beforeCellUnlist { my($tokens)=@_; return () unless $tokens; my @toks = $tokens->unlist; my @new = (); while(my $t = shift(@toks)){ ## if($t->equals(T_MATH) && @toks && $toks[0]->equals(T_CS('\hfil'))){ if(Equals($t,T_MATH) && @toks && Equals($toks[0],T_CS('\hfil'))){ push(@new,shift(@toks)); unshift(@toks,$t); } else { push(@new, $t); }} @new; } sub afterCellUnlist { my($tokens)=@_; return () unless $tokens; my @toks = $tokens->unlist; my @new = (); while(my $t = pop(@toks)){ ## if($t->equals(T_MATH) && @toks && $toks[$#toks]->equals(T_CS('\hfil'))){ if(Equals($t,T_MATH) && @toks && Equals($toks[$#toks],T_CS('\hfil'))){ unshift(@new,pop(@toks)); push(@toks,$t); } else { unshift(@new, $t); }} @new; } #---------------------------------------------------------------------- # \halign, See Chap.22 DefPrimitive('\halign BoxSpecification', sub { my($stomach,$spec,$contents)=@_; my $gullet=$stomach->getGullet; my $t = $gullet->readNonSpace; Error(":expected:\\bgroup Missing \\halign box") unless Equals($t,T_BEGIN); $stomach->bgroup; Let(T_ALIGN, T_CS('\undefined')); # KEEP these from being expanded here!!! Let(T_CS('\span'),T_CS('\undefined')); Let(T_CS('\omit'),T_CS('\undefined')); Let(T_CS('\cr'), T_CS('\default@cr')); Let(T_CS('\crcr'),T_CS('\default@cr')); Let(T_CS("\\\\"), T_CS('\default@cr')); # Read the template up till something equivalent to \cr my @template = (); while(($t=$gullet->readXToken) && !Equals($t,T_CS('\cr'))){ push(@template,$t); } # Read the rest until balanced } my @tokens = (); my $level=1; while($level && ($t=$gullet->readXToken)){ if(Equals($t,T_BEGIN)){ $level++; } elsif(Equals($t,T_END)){ $level--; } push(@tokens,$t) if $level; } $stomach->egroup; my $ismath = $STATE->lookupValue('IN_MATH'); my $b=1; # true if we're before a # in current column my @pre=(); my @post=(); my @cols=(); my @nonreps=(); foreach my $t (@template, T_ALIGN){ # put & at end, to save column! if($t->equals(T_PARAM)){ $b=0; } elsif($t->equals(T_ALIGN)){ if($b){ @nonreps=@cols; @cols=(); } # A & while we're before a column means Repeated columns else { # Finished column spec; add it # Try some magic for math, so we can create a valid math matrix (maybe!) # DAMN \halign can't be in math, anyway. # So, to get a matrix, we'll have to rewrite the alignment! if($ismath){ push(@pre,T_MATH); unshift(@post,T_MATH); } push(@cols,{before=>Tokens(stripDupMath(beforeCellUnlist(Tokens(@pre)))), after =>Tokens(stripDupMath(afterCellUnlist(Tokens(@post))))}); @pre=@post=(); $b=1; }} elsif($b){ push(@pre,$t) unless !@pre && $t->equals(T_SPACE); } else { push(@post,$t) unless !@post && $t->equals(T_SPACE); }} my $template = LaTeXML::AlignmentTemplate->new((@nonreps ? (columns=>[@nonreps],repeated=>[@cols]) :(columns=>[@cols]))); # print STDERR "Template = ".Stringify(Tokens(@template))."\n => ".$template->show."\n"; $stomach->bgroup; alignmentBindings($template); my @boxes = Digest(Invocation(T_CS('\@halign'), $spec,Tokens(@template), Tokens(T_CS('\@start@alignment'), @tokens, T_CS('\@finish@alignment')))); $stomach->egroup; @boxes; }); # Cleanup the pre & post tokens for halign columns in math mode. # If a pair of $..$ enclose stuff that is "OK" in math mode, we don't need the $. # Note that the 1st $ is switching OUT of math mode! sub stripDupMath { my(@tokens)=@_; my @poss = grep(Equals($tokens[$_],T_MATH), 0..$#tokens); ### pop(@poss) if scalar(@poss) % 2; # Get pairs! shift(@poss) if scalar(@poss) % 2; # Get pairs! while(@poss){ my($p2,$p1)=(pop(@poss),pop(@poss)); splice(@tokens,$p1,2) if $p2==$p1+1; } @tokens; } DefConstructor('\@halign BoxSpecification Undigested {}', sub { my($document,$spec,$template,$body,%props)=@_; constructAlignment($document,$body,attributes=>{width=>$$spec{to}, 'pad-width'=>$$spec{spread}}); }, reversion=>'\halign #1{#2\cr#3}', bounded=>1); # "Initialized" alignment; presets spacing, but since we're ignoring it anyway... Let(T_CS('\ialign'),T_CS('\halign')); # Overlapping alignments ??? DefMacro('\oalign{}', '\@@oalign{\@start@alignment#1\@finish@alignment}'); DefConstructor('\@@oalign{}', sub { my($document,$body,%props)=@_; constructAlignment($document,$body); }, reversion=>'\oalign{#1}', bounded=>1, beforeDigest=>sub { alignmentBindings('l'); }); # This is actually different; the lines should lie ontop of each other. # How should this be represented? DefMacro('\ooalign{}', '\@@ooalign{\@start@alignment#1\@finish@alignment}'); DefConstructor('\@@ooalign{}', sub { my($document,$body,%props)=@_; constructAlignment($document,$body); }, reversion=>'\ooalign{#1}', bounded=>1, beforeDigest=>sub { alignmentBindings('l'); }); #---------------------------------------------------------------------- DefConstructorI('\indent', undef,""); DefConstructorI('\noindent', undef,""); # represents a Logical Paragraph, whereas is a `physical paragraph'. # A para can contain both p and displayed equations and such. # Remember; \par closes, not opens, paragraphs! # Here, we want to close both an open p and para (if either are open). DefConstructorI('\par', undef, sub { $_[0]->maybeCloseElement('ltx:p'); $_[0]->maybeCloseElement('ltx:para'); }, alias=>"\\par\n"); Tag('ltx:para', autoClose=>1, autoOpen=>1); sub trimNodeWhitespace { my($document,$node)=@_; trimNodeLeftWhitespace($document,$node); trimNodeRightWhitespace($document,$node); } sub trimNodeLeftWhitespace { my($document,$node)=@_; if(my(@children)=$node->childNodes){ my $child = $children[0]; my $type = $child->nodeType; if($type == XML_TEXT_NODE){ my $string = $child->data; # if($string =~ s/^\s+//){ # with some trepidation, I don't think we want to trim nbsp! if($string =~ s/^ +//){ $child->setData($string); }} elsif($type == XML_ELEMENT_NODE){ trimNodeLeftWhitespace($document,$child); }}} sub trimNodeRightWhitespace { my($document,$node)=@_; if(my(@children)=$node->childNodes){ my $child = $children[-1]; my $type = $child->nodeType; if($type == XML_TEXT_NODE){ my $string = $child->data; if($string =~ s/\s+$//){ $child->setData($string); }} elsif($type == XML_ELEMENT_NODE){ trimNodeRightWhitespace($document,$child); }}} Tag('ltx:p', autoClose=>1, autoOpen=>1, afterClose=>\&trimNodeWhitespace); # \dump ??? DefPrimitiveI('\end',undef,sub { $_[0]->getGullet->flush; return; }); #====================================================================== # Horizontal Mode primitives in Ch.25, pp.285--287 # The following cause tex to start a new paragraph -- they switch to horizontal mode. # = | | \char | # | \noboundary | \unhbox | \unhcopy | \valign | \vrule # | \hskip | \hfil | \hfill | \hss | \hfilneg # | \accent | \discretionary | \- | \ | $ DefPrimitiveI('\noboundary',undef,undef); DefPrimitive('\hskip Glue',undef); DefPrimitive('\mskip MuGlue', undef); DefPrimitiveI('\hss',undef,undef); DefConstructorI('\hfil', undef,"?#isMath()( )", properties=>{isSpace=>1, isFill=>1}); DefConstructorI('\hfill', undef,"?#isMath()( )", properties=>{isSpace=>1, isFill=>1}); DefPrimitiveI('\hfilneg', undef,undef); # \lower # \raise # But apparently must really explicitly be an \hbox, \vbox or \vtop (?) # OR something that expands into one!! DefConstructor('\lower Dimension MoveableBox', "#2", afterDigest=>sub{ $_[1]->setProperty(y=>$_[1]->getArg(1)->multiply(-1)); }); DefConstructor('\raise Dimension MoveableBox', "#2", afterDigest=>sub{ $_[1]->setProperty(y=>$_[1]->getArg(1)); }); # \unhbox<8bit>, \unhcopy<8bit> DefPrimitive('\unhbox Number',sub { my $box = 'box'.$_[1]->valueOf; my $stuff = LookupValue($box); AssignValue($box,undef); ($stuff); }); DefPrimitive('\unhcopy Number',sub { (LookupValue('box'.$_[1]->valueOf)); }); # \vrule # \valign ??? DefConstructor('\vspace{}',""); # \indent, \noindent, \par; see above. # \accent Number ???? DefMacro('\accent Number',Tokens()); # How should these be translated? Depends on font?? DefMacro('\discretionary{}{}{}','#3'); # No hyphenation here! DefPrimitiveI('\-', undef,undef); DefPrimitive('\setlanguage Number',undef); #====================================================================== # Math mode stuff # See TeXBook Ch.26 #====================================================================== # Decide whether we're going into or out of math, inline or display. Tag('ltx:XMText', autoOpen=>1,autoClose=>1); DefPrimitiveI(T_MATH, undef,sub { my($stomach)=@_; my $gullet = $stomach->getGullet; my $mode = LookupValue('MODE'); my $op = '\@@BEGININLINEMATH'; if($mode eq 'display_math'){ if($gullet->ifNext(T_MATH)){ $gullet->readToken; } else { Fatal(":expected:\$ Missing \$ closing display math."); } $op = '\@@ENDDISPLAYMATH'; } elsif($mode eq 'inline_math'){ $op = '\@@ENDINLINEMATH'; } # elsif(!LookupValue('Alignment') && $gullet->ifNext(T_MATH)){ elsif($gullet->ifNext(T_MATH)){ $gullet->readToken; $op = '\@@BEGINDISPLAYMATH'; } $stomach->invokeToken(T_CS($op)); }); # Effectively these are the math hooks, redefine these to do what you want with math? DefConstructorI('\@@BEGINDISPLAYMATH',undef, "" . "" . "" . "#body" . "" . "" ."", alias=>'$$', beforeDigest=> sub{ $_[0]->beginMode('display_math'); }, captureBody=>1); DefConstructorI('\@@ENDDISPLAYMATH',undef, "", alias=>'$$', beforeDigest=> sub{ $_[0]->endMode('display_math'); }); DefConstructorI('\@@BEGININLINEMATH', undef, "" . "" . "#body" . "" ."", alias=>'$', beforeDigest=> sub{ $_[0]->beginMode('inline_math'); }, captureBody=>1); DefConstructorI('\@@ENDINLINEMATH', undef,"", alias=>'$', beforeDigest=> sub{ $_[0]->endMode('inline_math');}); # Add the TeX code from the object that created this node, # unless it has already been recorded on another node. sub add_TeX { my($document,$node,$thing)=@_; if($thing && (ref $thing eq 'LaTeXML::Whatsit') && !$thing->getProperty('_added_tex')){ local $LaTeXML::DUAL_BRANCH = 'presentation'; my $tex = UnTeX($thing); $LaTeXML::DUAL_BRANCH = 'content'; my $ctex = UnTeX($thing); $document->setAttribute($node,tex=>$tex); $document->setAttribute($node,'content-tex'=>$ctex) if $ctex ne $tex; $thing->setProperty('_added_tex',1); }} # Same as add_TeX, but add the code from the body of the object. sub add_body_TeX { my($document,$node,$thing)=@_; if($thing && !$thing->getProperty('_added_body_tex')){ if(defined(my $body = $thing->getProperty('body'))){ local $LaTeXML::DUAL_BRANCH = 'presentation'; my $tex = UnTeX($body); $LaTeXML::DUAL_BRANCH = 'content'; my $ctex = UnTeX($body); $document->setAttribute($node,tex=>$tex); $document->setAttribute($node,'content-tex'=>$ctex) if $ctex ne $tex; } $thing->setProperty('_added_body_tex',1); }} Tag('ltx:Math', afterOpen=>\&add_body_TeX); Tag('ltx:Math', afterClose=>\&cleanup_Math); sub cleanup_Math { my($document,$mathnode)=@_; # If the Math contains ONLY XMath that ONLY contain XMText, # it apparently isn't math at all!?! So pull up the contents of the XMText's. foreach my $xnode ($mathnode->childNodes){ return unless $document->getModel->getNodeQName($xnode) eq 'ltx:XMath'; foreach my $mnode ($xnode->childNodes){ return unless $document->getModel->getNodeQName($mnode) eq 'ltx:XMText'; }} # Replace Math/XMath/XMText/* by * replace_node($mathnode, map($_->childNodes,map($_->childNodes,$mathnode->childNodes))); } sub replace_node { my($oldnode,@newnodes)=@_; my $parent = $oldnode->parentNode; if(!@newnodes){ $parent->removeChild($oldnode); } else { my $new = shift(@newnodes); $parent->replaceChild($new,$oldnode); foreach my $n (@newnodes){ $parent->insertAfter($n,$new); $new = $n; }}} Let(T_CS('\vcenter'), T_CS('\vbox')); # \eqno & \leqno are really bizzare. # They should seemingly digest until $ (or while still in math mode), # and use that stuff as the reference number. # However, since people abuse this, and we're really not quite TeX, # we really can't do it Right. # Even a \begin{array} ends up expanding into a $ !!! DefMacroI('\eqno',undef,sub { my($gullet)=@_; my @stuff=(); # This is risky!!! while(my $t = $gullet->readXToken){ if(! defined $t){ Fatal(":unexpected:\eqno fell of the end!"); } # What do I need to explicitly list here!?!?!? UGGH! elsif(Equals($t,T_MATH) || Equals($t,T_CS('\]')) || Equals($t,T_CS('\begingroup')) # Totally wrong, but to catch expanded environments || ( ToString($t)=~ /^\\(?:begin|end)\{/)){ # any sort of environ begin or end??? # || Equals($t,T_CS('\end{equation}'))|| Equals($t,T_CS('\end{equation*}'))){ return (Invocation(T_CS('\@@eqno'),Tokens(@stuff)), $t); } else { push(@stuff,$t); }}}); Let(T_CS('\leqno'),T_CS('\eqno')); # Revert to nothing, since it really doesn't belong in the TeX string(?) DefConstructor('\@@eqno{}',"^ refnum='#eqnum'", reversion=>'', afterDigest=>sub { my $num = ToString($_[1]->getArg(1)); $num=~ s/^\{(.*)\}$/$1/; $num=~ s/^\((.*)\)$/$1/; $_[1]->setProperties(eqnum=>$num); }); #====================================================================== # Scripts are a bit of a strange beast, with respect to when the arguments # are processed, and what kind of object should be created. # # While scripts look like they take a normal TeX argument, they really # take the next BOX (AFTER expansion & digestion)! Thus, while # a^\frac{b}{c} and a^\mathcal{B} # DO work in TeX, other things like # a^\sqrt{3} or a^\acute{b} # DO NOT! (Hint: consider the expansions) # Note that with # \def\xyz{xyz} # a^\xyz => a^{x}yz # So, we try to mimic, but note that our boxes don't correspond 100% to TeX's # # Normally, sub/super scripts should be turned into a sort of postfix operator: # The parser will attach the script to the appropriate preceding object. # However, there are a few special cases involving empty boxes {}. # If the argument is an empty box $x^{}$, the whole script should just disappear. # If the PRECEDING box is {} (in ${}^{p}$, a sort of `floating' script should be created. # This may combine, in the parser, with the following object to generate # a prescript. our %scriptstylemap=(display=>'script', text=>'script', script=>'scriptscript', scriptscript=>'scriptscript'); # Note that this is also being used by alignment. sub isEmpty { my($box)=@_; my $ref = ref $box; if(! $box ){ return 1; } elsif($ref eq 'LaTeXML::Comment'){ return 1; } elsif($ref eq 'LaTeXML::Box'){ return $box->getString =~ /^\s*$/; } elsif($ref eq 'LaTeXML::MathBox'){ return $box->getString =~ /^\s*$/; } elsif($ref eq 'LaTeXML::Whatsit'){ return 1 if $box->getProperty('isSpace'); # A space-like Whatsit if(($box->getDefinition eq $STATE->lookupMeaning(T_BEGIN)) && !grep(!isEmpty($_), $box->getBody->unlist)){ return 1; }} return 0; } # my $is= # (!$box # || ($ref eq 'LaTeXML::Comment') # || $box->getProperty('isSpace') # A space-like Whatsit # || (($ref =~ /^LaTeXML::(Math)?Box$/) && ($box->getString =~ /^\s*$/)) # Space plain box # || (($ref eq 'LaTeXML::Whatsit') # Whatsit with nothing in it. # && ($box->getDefinition eq $STATE->lookupMeaning(T_BEGIN)) # && !grep(!isEmpty($_), $box->getBody->unlist))); # ##print STDERR "Box ".Stringify($box)." is empty: ".($is ? "yes":"no")."\n"; # $is; # } sub scriptHandler { my($stomach,$op)=@_; my $gullet = $stomach->getGullet; $gullet->skipSpaces; my $style = LookupValue('mathstyle'); # Bump the math style smaller. if(defined $style){ my $cs = '\@@POST'.$op; # Check if preceding box, if any, is empty {} my $prev = $LaTeXML::LIST[$#LaTeXML::LIST]; if(! $prev){ # No box at all? $cs = '\@@FLOATING'.$op; } elsif(isEmpty($prev)){ # Or empty (remove it) pop(@LaTeXML::LIST); $cs = '\@@FLOATING'.$op; } elsif((ref $prev eq 'LaTeXML::Whatsit') # Or previous sub/supscript. && (($prev->getDefinition eq $STATE->lookupMeaning(T_CS('\@@FLOATINGSUPERSCRIPT'))) || ($prev->getDefinition eq $STATE->lookupMeaning(T_CS('\@@FLOATINGSUBSCRIPT'))))){ $cs = '\@@FLOATING'.$op; } AssignValue(mathstyle=>$scriptstylemap{$style}); # Now, get following boxes # my @stuff = $stomach->invokeToken($gullet->readXToken); my @stuff=(); while(my $tok = $gullet->readXToken){ @stuff = $stomach->invokeToken($tok); last if @stuff; } Fatal(":expected:{ Missing { in sub/super-script argument") unless @stuff; my $script = shift(@stuff); # ONLY this box is the script! my $level = $stomach->getBoxingLevel; unshift(@stuff, LaTeXML::Whatsit->new(LookupDefinition(T_CS($cs)),[$script], locator=>$gullet->getLocator, font=>$script->getFont,isMath=>1, level=>$level)) if ToString($script) ne '{}'; # ONLY If Script is not empty!!! AssignValue(mathstyle=>$style); # revert @stuff; } else { # Non math use of _ ?? my $c = (($op eq 'SUPERSCRIPT') ? '^' : '_'); Error(":unexpected:$c Script $c can only appear in math mode"); LaTeXML::Box->new($c, $STATE->lookupValue('font'),$gullet->getLocator, (($op eq 'SUPERSCRIPT') ? T_SUPER : T_SUB)); }} DefPrimitiveI(T_SUPER, undef,sub{ scriptHandler($_[0],'SUPERSCRIPT'); }); DefPrimitiveI(T_SUB, undef,sub{ scriptHandler($_[0],'SUBSCRIPT'); }); DefConstructor('\@@POSTSUPERSCRIPT{}', "" . "#1" ."", alias=>'^'); DefConstructor('\@@POSTSUBSCRIPT{}', "" . "#1" ."", alias=>'_'); DefConstructor('\@@FLOATINGSUPERSCRIPT{}', "" . "#1" ."", alias=>'{}^'); DefConstructor('\@@FLOATINGSUBSCRIPT{}', "" . "#1" ."", alias=>'{}_'); ## NOTE: Strictly speaking, these two should examine the scriptpos # attribute of the base (it may have \limits,\nolimits) ## OR, alternatively, there could be separate \@OVERSCRIPT/\@UNDERSCRIPT macros ? DefConstructor('\@SUPERSCRIPT{}{}', "?#2(" . "" . "#1" . "#2" . ")" . "(#1)", reversion=> sub { my($whatsit,$base,$sup)=@_; ($sup && $sup->unlist ? (T_BEGIN,$base->revert,T_END, T_SUPER,T_BEGIN,$sup->revert,T_END) : $base->revert); }, properties=>{scriptpos=>sub{ "post".$_[0]->getBoxingLevel; }}); DefConstructor('\@SUBSCRIPT{}{}', "?#2(" . "" . "#1" . "#2" . ")" . "(#1)", reversion=>sub { my($whatsit,$base,$sub)=@_; ($sub && $sub->unlist ? (T_BEGIN,$base->revert,T_END, T_SUB,T_BEGIN,$sub->revert,T_END) : $base->revert); }, properties=>{scriptpos=>sub{ "post".$_[0]->getBoxingLevel; }}); # This only becomes active in math mode. AssignCatcode('math:\''=>1, 'global'); DefMacroI('\'',undef,sub{ my($gullet)=@_; my $n = 1; while($gullet->ifNext(T_OTHER('\''))){ $gullet->readToken; $n++; }; (T_SUPER,T_BEGIN,map(T_CS('\prime'), 1..$n),T_END); }); #====================================================================== # \choose & friends, also need special argument handling # After digesting the \choose (or whatever), grab the previous and following material # and store as args in the whatsit. our %fracstylemap=(display=>'text', text=>'script', script=>'scriptscript', scriptscript=>'scriptscript'); sub chooseArgHandler { my($stomach,$whatsit)=@_; my $style = LookupValue('mathstyle'); AssignValue(mathstyle=>$fracstylemap{$style}); # Bump the style smaller. # Unfortunately, the way we've done it, it's too late for the numerator!!! my @top = $stomach->regurgitate; my @bot = $stomach->digestNextBody(); my $closing = pop(@bot); # We'll leave whatever closed the list (endmath, endgroup...) # $whatsit->setArgs(LaTeXML::MathList->new(@top),LaTeXML::MathList->new(@bot)); $whatsit->setProperty(top=>LaTeXML::MathList->new(@top)); $whatsit->setProperty(bottom=>LaTeXML::MathList->new(@bot)); $whatsit->setProperty(style=>LookupValue('mathstyle')); AssignValue(mathstyle=>$style); $closing; } # leave the closing bit # Support here: Used by LaTeX, amsmath, but also amstex sub beforeFrac { $_[0]->bgroup; AssignValue(mathstyle=>$fracstylemap{LookupValue('mathstyle')}); } sub afterFrac { $_[0]->egroup; $_[1]->setProperty('style',LookupValue('mathstyle')); } # Needed by amsmath (at least) sub beforeTFrac { $_[0]->bgroup; AssignValue(mathstyle=>'text'); beforeFrac(@_); } sub afterTFrac { afterFrac(@_); $_[0]->egroup; } sub beforeDFrac { $_[0]->bgroup; AssignValue(mathstyle=>'display'); beforeFrac(@_); } sub afterDFrac { afterFrac(@_); $_[0]->egroup; } # WHY did I change to top/bottom instead of #1,#2 ???? # This will inhibit comparisons!!!! # Is it because of the delims forms already having args??? # No, because constructor doesn't know there are 2 extra args!! DefConstructorI('\choose',undef, "" . "" . "#top" . "#bottom" ."", afterDigest=>\&chooseArgHandler, reversion=>sub { my($whatsit)=@_; ($whatsit->getProperty('top')->revert, T_CS('\choose'), $whatsit->getProperty('bottom')->revert); }); DefConstructorI('\brace',undef, "" . "" # what meaning? . "#top" . "#bottom" ."", afterDigest=>\&chooseArgHandler, reversion=>sub { my($whatsit)=@_; ($whatsit->getProperty('top')->revert, T_CS('\choose'), $whatsit->getProperty('bottom')->revert); }); DefConstructorI('\brack',undef, "" . "" # what meaning? . "#top" . "#bottom" ."", afterDigest=>\&chooseArgHandler, reversion=>sub { my($whatsit)=@_; ($whatsit->getProperty('top')->revert, T_CS('\choose'), $whatsit->getProperty('bottom')->revert); }); DefConstructorI('\over',undef, "" . "" . "#top" . "#bottom" ."", afterDigest=>\&chooseArgHandler, reversion=>sub { my($whatsit)=@_; ($whatsit->getProperty('top')->revert, T_CS('\over'), $whatsit->getProperty('bottom')->revert); }); DefConstructorI('\atop',undef, "" . "" . "#top" . "#bottom" ."", afterDigest=>\&chooseArgHandler, reversion=>sub { my($whatsit)=@_; ($whatsit->getProperty('top')->revert, T_CS('\atop'), $whatsit->getProperty('bottom')->revert); }); DefConstructor('\overwithdelims Token Token', "" . "" . "#top" . "#bottom" ."", afterDigest=>\&chooseArgHandler, reversion=> sub { my($whatsit,@args)=@_; ($whatsit->getProperty('top')->revert, $whatsit->getDefinition->invocation(@args), $whatsit->getProperty('bottom')->revert); }); # But, wonder what the _meaning_ is! DefConstructor('\atopwithdelims Token Token', "" . "" . "#top" . "#bottom" ."", afterDigest=>\&chooseArgHandler, reversion=>sub { my($whatsit,@args)=@_; ($whatsit->getProperty('top')->revert, $whatsit->getDefinition->invocation(@args), $whatsit->getProperty('bottom')->revert); }); sub IsZero { my($dim)=@_; (!defined $dim) || ($dim->valueOf == 0); } DefConstructor('\above Dimension', "" . "" . "#top" . "#bottom" ."", afterDigest=>\&chooseArgHandler, reversion=> sub { my($whatsit,@args)=@_; ($whatsit->getProperty('top')->revert, $whatsit->getDefinition->invocation(@args), $whatsit->getProperty('bottom')->revert); }); DefConstructor('\abovewithdelims Token Token Dimension', "" . "" . "#top" . "#bottom" ."", afterDigest=>\&chooseArgHandler, reversion=> sub { my($whatsit,@args)=@_; ($whatsit->getProperty('top')->revert, $whatsit->getDefinition->invocation(@args), $whatsit->getProperty('bottom')->revert); }); #====================================================================== DefConstructorI('\cal', undef,'', font=>{family=>'caligraphic'}); # In principle, is a nice markup for emphasized. # Unfortunately, TeX really just treats it as a font switch. # Something like: \em et.al. \rm more stuff # works in TeX, but in our case, since there is no explicit {}, # the stays open! Ugh! # This could still be made to work, but merge font would # need to look at any open , and then somehow close it! ## DefConstructor('\@end@emph',''); ## DefConstructor('\em',"", ## afterDigest=>sub { UnshiftValue(beforeAfterGroup=>T_CS('\@end@emph')); }); # So, we'll just toggle between shape = italic and normal, for now. Sigh. DefConstructorI('\em',undef, '', beforeDigest=>sub { my $font = LookupValue('font'); my $shape = $font->getShape; AssignValue(font=>$font->merge(shape=>($shape eq 'italic' ? 'normal' : 'italic')), 'local'); }); # Change math font while still in text! DefPrimitiveI('\boldmath', undef,sub { AssignValue(mathfont=>LookupValue('mathfont')->merge(forcebold=>1), 'local'); }, forbidMath=>1); DefPrimitiveI('\unboldmath',undef,sub { AssignValue(mathfont=>LookupValue('mathfont')->merge(forcebold=>0), 'local'); }, forbidMath=>1); #====================================================================== # Alignments # & gives an error except within the right context # (which should redefine it!) DefConstructorI('&', undef,sub { Error(":unexpected:& Stray alignment \"&\""); }); #********************************************************************** # Plain; Extracted from Appendix B. #********************************************************************** #====================================================================== # TeX Book, Appendix B, p. 344 #====================================================================== # \dospecials ?? # Set up the mathcode table # Normally, the content branch contains the pure structure and meaning of a construct, # and the presentation is generated from lower level TeX macros that only concern # themselves with how to display the object. # Nevertheless, it is sometimes useful to know where the tokens in the presentation branch # came from; particularly what their presumed "meaning" is. # For example, when search-indexing pmml, or providing links to definitions from the pmml. # # The following constructor (see how it's used in DefMath), adds meaning attributes # whereever it seems sensible on the presentation branch, after it has been generated. DefConstructor('\@ASSERT@MEANING{}{}','#2',reversion=>'#2', afterConstruct=>sub { my($document,$whatsit)=@_; my $node=$document->getNode; # This should be the wrapper just added. my $meaning = ToString($whatsit->getArg(1)); addMeaningRec($document,$node,$meaning); $node; }); #====================================================================== # Properties for plain characters. # These are allowed in plain text, but need to act a bit special in math. DefMathI('=',undef,'=', role=>'RELOP', meaning=>'equals'); DefMathI('+',undef,'+', role=>'ADDOP', meaning=>'plus'); DefMathI('-',undef,'-', role=>'ADDOP', meaning=>'minus'); DefMathI('*',undef,'*', role=>'MULOP', meaning=>'times'); DefMathI('/',undef,'/', role=>'MULOP', meaning=>'divide', style=>'inline'); DefMathI('!',undef,'!', role=>'POSTFIX', meaning=>'factorial'); DefMathI(',',undef,',', role=>'PUNCT'); DefMathI('.',undef,'.', role=>'PERIOD'); DefMathI(';',undef,';', role=>'PUNCT'); DefMathI('(',undef,'(', role=>'OPEN'); DefMathI(')',undef,')', role=>'CLOSE'); DefMathI('[',undef,'[', role=>'OPEN'); DefMathI(']',undef,']', role=>'CLOSE'); DefMathI('|',undef,'|', role=>'VERTBAR'); #DefMath(':',';', role=>'METARELOP', name=>'colon'); # Seems like good default role # It seems that "MathLigature" should be adapted to make this sort of thing easy! AssignCatcode('math::'=>1, 'global'); DefMacroI(':',undef,sub{ my($gullet)=@_; if($gullet->ifNext(T_OTHER('='))){ $gullet->readToken; T_CS('\@colonequal'); } else { T_CS('\@colon'); }}); DefMathI('\@colon', undef,':', role=>'METARELOP', name=>'colon',reversion=>':'); # Seems like good default role DefMathI('\@colonequal',undef,':=', role=>'RELOP', meaning=>'assign',reversion=>':='); AssignCatcode('math:<'=>1, 'global'); AssignCatcode('math:>'=>1, 'global'); DefMacroI('<',undef,sub{ my($gullet)=@_; if($gullet->ifNext(T_OTHER('<'))){ $gullet->readToken; T_CS('\ll'); } # leq ? hmmmm else { T_CS('\@@<'); }}); DefMacroI('>',undef,sub{ my($gullet)=@_; if($gullet->ifNext(T_OTHER('>'))){ $gullet->readToken; T_CS('\gg'); } elsif($gullet->ifNext(T_OTHER('='))){ $gullet->readToken; T_CS('\geq'); } else { T_CS('\@@>'); }}); DefMathI('\@@>',undef, '>', role=>'RELOP', meaning=>'greater-than', name=>'', reversion=>'>'); DefMathI('\@@<',undef, '<', role=>'RELOP', meaning=>'less-than', name=>'', reversion=>'<'); #====================================================================== # Combine letters, when the fonts are right. (sorta related to mathcode) DefMathLigature(sub { my($document,@nodes)=@_; my @chars = (); my $font = $document->getNodeFont($nodes[$#nodes]); if($font->isSticky){ my $node; my $n=0; my $string=''; my $s=''; while(($node = pop(@nodes)) && ($document->getModel->getNodeQName($node) eq 'ltx:XMTok') && ($document->getNodeFont($node)->equals($font)) && (!$node->hasAttribute('name')) && (($node->getAttribute('role')||'UNKNOWN') eq 'UNKNOWN') && (($s=$node->textContent.$s) =~ /^[a-zA-Z]+$/)){ $n++; $string = $s; } ($n > 1 ? ($n, $string, role=>'UNKNOWN') : undef); }}); #====================================================================== # Combine digits in math. foreach my $digit (qw(0 1 2 3 4 5 6 7 8 9)){ DefMathI($digit,undef,$digit, role=>'NUMBER',meaning=>$digit); } our %space_chars = (negthinspace=>'', thinspace=>"\x{2009}", medspace=>"\x{2005}", thickspace=>"\x{2004}"); DefMathLigature(sub { my($document,@nodes)=@_; my @chars = (); my $font = $document->getNodeFont($nodes[$#nodes]); my ($n,$node,$string,$number)=(0,undef,'',''); while($node = pop(@nodes)){ my $qn = $document->getModel->getNodeQName($node); if($qn =~ /^(ltx:XMTok|ltx:XMWrap)$/){ my $r=($node->getAttribute('role')||''); if($r eq 'NUMBER'){ $string = $node->textContent . $string; $number = $node->getAttribute('meaning') . $number; } elsif($r eq 'PERIOD'){ $string = $node->textContent . $string; $number = '.'.$number; } else { last; }} elsif($qn eq 'ltx:XMHint'){ my $s; if(($s = $node->getAttribute('name'))&&($s = $space_chars{$s})){ $string = $s . $string; } else { last; }} else { last; } $n++; } if(($n > 1) && ($number =~ /\d/)){ ($n, $string, meaning=>$number, role=>'NUMBER'); }}); #====================================================================== # TeX Book, Appendix B, p. 345 RawTeX(' \chardef\active=13 \chardef\@ne=1 \chardef\tw@=2 \chardef\thr@@=3 \chardef\sixt@@n=16 \chardef\@cclv=255 \chardef\@cclvi=256 \chardef\@m=1000 \chardef\@M=10000 \chardef\@MM=20000'); #====================================================================== # TeX Book, Appendix B, p. 346 RawTeX(' \countdef\count@=255 \toksdef\toks@=0 \skipdef\skip@=0 \dimendef\dimen@i=1 \dimendef\dimen@ii=2'); # Various \count's are set; should we? #====================================================================== # TeX Book, Appendix B, p. 347 # \wlog ?? # From plain.tex DefPrimitive('\newcount Token',sub { DefRegisterI($_[1],undef,Number(0)); }); DefPrimitive('\newdimen Token',sub { DefRegisterI($_[1],undef,Dimension(0)); }); DefPrimitive('\newskip Token',sub { DefRegisterI($_[1],undef,Glue(0)); }); DefPrimitive('\newmuskip Token',sub { DefRegisterI($_[1],undef,MuGlue(0)); }); AssignValue(allocated_boxes=>0); DefPrimitive('\newbox Token',sub { my $n = LookupValue('allocated_boxes'); AssignValue(allocated_boxes=>$n+1,'global'); AssignValue("box$n",LaTeXML::List->new()); DefRegisterI($_[1],undef,Number($n)); }); DefPrimitive('\newhelp Token {}', sub { AssignValue(ToString($_[1])=>$_[2]); }); DefPrimitive('\newtoks Token', sub { DefRegisterI($_[1],undef,Tokens()); }); DefPrimitive('\newread Token', sub { DefRegisterI($_[1],undef,Number(0)); }); DefPrimitive('\newwrite Token', sub { DefRegisterI($_[1],undef,Number(0)); }); DefPrimitive('\newfam Token', sub { DefRegisterI($_[1],undef,Number(0)); }); DefPrimitive('\newlanguage Token',sub { DefRegisterI($_[1],undef,Number(0)); }); DefPrimitive('\newinsert Token', sub { DefRegisterI($_[1],undef,Number(0)); }); # \alloc@, \ch@ck # TeX plain uses \newdimen, etc. for these. # Is there any advantage to that? DefRegister('\maxdimen',Dimension(16383.99999*65536)); DefRegister('\hideskip',Glue(-1000*65536,'1fill')); DefRegister('\centering',Glue('0pt plus 1000pt minus 1000pt')); DefRegister('\p@',Dimension(65536)); DefRegister('\z@',Dimension(0)); DefRegister('\z@skip',Glue(0,0,0)); # First approximation. till I figure out \newbox # \newbox\voidb@x DefMacroI('\voidb@x',undef,Tokens()); #====================================================================== # TeX Book, Appendix B, p. 348 DefMacro('\newif DefToken',sub { my($ignore,$cs)=@_; my $name = ToString($cs); $name =~ s/^\\if//; DefMacroI($cs,undef, sub { ifHandler($_[0],LookupValue('Boolean:'.$name)); }, isConditional=>1); DefPrimitiveI(T_CS('\\'.$name.'true'),undef,, sub { AssignValue('Boolean:'.$name => 1); }); DefPrimitiveI(T_CS('\\'.$name.'false'),undef,sub { AssignValue('Boolean:'.$name => 0); }); }); # See the section Registers & Parameters, above for setting default values. #====================================================================== # TeX Book, Appendix B, p. 349 # See the section Registers & Parameters, above for setting default values. # These are originally defined with \newskip, etc DefRegister('\smallskipamount' => Glue('3pt plus1pt minus1pt')); DefRegister('\medskipamount' => Glue('6pt plus2pt minus2pt')); DefRegister('\bigskipamount' => Glue('12pt plus4pt minus4pt')); DefRegister('\normalbaselineskip' => Glue('12pt')); DefRegister('\normallineskip' => Glue('1pt')); DefRegister('\normallineskiplimit'=> Dimension('0pt')); DefRegister('\jot' => Dimension('3pt')); DefRegister('\interdisplaylinepenalty' => Number(100)); DefRegister('\interfootnotelinepenalty' => Number(100)); DefMacroI('\magstephalf',undef,'1095'); our @mags=(1000,1200,1440,1728,2074,2488); DefMacro('\magstep{}', sub { Explode($mags[ToString($_[1])]);}); #====================================================================== # TeX Book, Appendix B, p. 350 # Font stuff ... RawTeX(' \font\tenrm=cmr10 \font\sevenrm=cmr7 \font\fiverm=cmr5 \font\teni=cmmi10 \font\seveni=cmmi7 \font\fivei=cmmi7 \font\tensy=cmsy10 \font\sevensy=cmsy7 \font\fivesy=cmsy5 \font\tenex=cmex10 \font\tenbf=cmbx10 \font\sevenbf=cmbx7 \font\fivebf=cmbx5 \font\tensl=cmsl10 \font\tentt=cmtt10 \font\tenit=cmti10 \newfam\itfam \newfam\slfam \newfam\bffam \newfam\ttfam '); # Note: \newfam in math should be font switching(?) #====================================================================== # TeX Book, Appendix B, p. 351 # Old style font styles. # The trick is to create an empty Whatsit preserved till assimilation (for reversion'ing) # but to change the current font used in boxes. # (some of these were defined on different pages? or even latex...) Tag('ltx:text',autoOpen=>1,autoClose=>1); # Note that these, unlike \rmfamily, should set the other attributes to the defaults! DefConstructorI('\rm', undef,'', font=>{family=>'serif', series=>'medium', shape=>'upright'}); DefConstructorI('\sf', undef,'', font=>{family=>'sansserif', series=>'medium', shape=>'upright'}); DefConstructorI('\bf', undef, '', font=>{series=>'bold', family=>'serif', shape=>'upright'}); DefConstructorI('\it', undef, '', font=>{shape=>'italic', family=>'serif', series=>'medium'}); DefConstructorI('\tt', undef, '', font=>{family=>'typewriter', series=>'medium', shape=>'upright'}); # No effect in math for the following 2 ? DefConstructorI('\sl', undef, '', font=>{shape=>'slanted', family=>'serif', series=>'medium'}); DefConstructorI('\sc', undef, '', font=>{shape=>'smallcaps', family=>'serif', series=>'medium'}); DefConstructorI('\tiny', undef,'', font=>{size=>'tiny'}); DefConstructorI('\scriptsize', undef,'', font=>{size=>'script'}); DefConstructorI('\footnotesize', undef,'', font=>{size=>'footnote'}); DefConstructorI('\small', undef,'', font=>{size=>'small'}); DefConstructorI('\normalsize', undef,'', font=>{size=>'normal'}); DefConstructorI('\large', undef,'', font=>{size=>'large'}); DefConstructorI('\Large', undef,'', font=>{size=>'Large'}); DefConstructorI('\LARGE', undef,'', font=>{size=>'LARGE'}); DefConstructorI('\huge', undef,'', font=>{size=>'huge'}); DefConstructorI('\Huge', undef,'', font=>{size=>'Huge'}); DefConstructor('\mit', '', requireMath=>1, font=>{family=>'italic'}); DefPrimitiveI('\frenchspacing', undef,undef); DefPrimitiveI('\nonfrenchspacing',undef,undef); DefMacroI('\normalbaselines',undef, '\lineskip=\normallineskip\baselineskip=\normalbaselineskip\lineskiplimit=\normallineskiplimit'); DefMacroI('\space',undef,Tokens(T_SPACE)); DefMacroI('\lq',undef,"`"); DefMacroI('\rq',undef,"'"); Let(T_CS('\empty'),T_CS('\@empty')); DefMacroI('\null',undef,'\hbox{}'); Let(T_CS('\bgroup'),T_BEGIN); Let(T_CS('\egroup'),T_END); DefPrimitiveI('\endline', undef,undef); #====================================================================== # TeX Book, Appendix B, p. 352 DefPrimitiveI('\obeyspaces', undef,undef); DefPrimitiveI('\obeylines', undef,undef); RawTeX(' \def\loop#1\repeat{\def\body{#1}\iterate} \def\iterate{\body \let\next=\iterate \else\let\next=\relax\fi \next} \let\repeat=\fi '); DefConstructorI('\enskip', undef,"?#isMath()(\x{2000})", properties=>{isSpace=>1}); # EN QUAD DefConstructorI('\enspace', undef,"?#isMath()(\x{2000})", properties=>{isSpace=>1}); # EN QUAD DefConstructorI('\quad', undef,"?#isMath()(\x{2001})", properties=>{isSpace=>1}); # EM QUAD DefConstructorI('\qquad', undef,"?#isMath()(\x{2001}\x{2001})", properties=>{isSpace=>1}); # EM QUAD DefConstructorI('\thinspace', undef,"?#isMath()( )", properties=>{isSpace=>1}); DefConstructorI('\negthinspace',undef,"?#isMath()()", properties=>{isSpace=>1}); DefConstructorI('\thickspace', undef,"?#isMath()( )", properties=>{isSpace=>1}); DefConstructor('\hglue Glue', "?#isMath()(\x{2001})", properties=>{isSpace=>1}); # EM QUAD DefPrimitive('\vglue Glue', undef); DefPrimitiveI('\topglue', undef,undef); DefPrimitiveI('\nointerlineskip', undef,undef); DefPrimitiveI('\offinterlineskip',undef,undef); DefConstructorI('\smallskip', undef,""); DefConstructorI('\medskip', undef,""); DefConstructorI('\bigskip', undef,""); #====================================================================== # TeX Book, Appendix B, p. 353 DefPrimitiveI('\break', undef,undef); DefPrimitiveI('\nobreak', undef,undef); DefPrimitiveI('\allowbreak',undef,undef); DefConstructorI("~", undef,"?#isMath()(".UTF(0xA0).")", properties=>{isSpace=>1}); # NO-BREAK SPACE DefConstructorI('\nobreakspace',undef,"?#isMath()(".UTF(0xA0).")", properties=>{isSpace=>1}); # NO-BREAK SPACE DefMacroI('\slash',undef,'/'); DefPrimitiveI('\filbreak',undef,undef); DefMacroI('\goodbreak',undef,'\par'); DefMacroI('\eject',undef,'\par'); Let(T_CS('\newpage'),'\eject'); DefMacroI('\supereject',undef,'\par'); DefPrimitiveI('\removelastskip',undef,undef); DefMacroI('\smallbreak',undef,'\par'); DefMacroI('\medbreak', undef,'\par'); DefMacroI('\bigbreak', undef,'\par'); DefMacroI('\line',undef,'\hbox to \hsize'); DefMacro('\leftline{}','\line{#1\hss}'); DefMacro('\rightline{}','\line{\hss#1}'); DefConstructor('\centerline{}',sub { # "#1" my($document,$line)=@_; if($document->isOpenable('ltx:p')){ $document->insertElement('ltx:p',$line,class=>'centering'); } elsif($document->isOpenable('ltx:text')){ $document->insertElement('ltx:text',$line,class=>'centering'); $document->insertElement('ltx:break'); } else { $document->absorb($line); }}, bounded=>1); DefMacro('\llap{}','\hbox{#1}'); DefMacro('\rlap{}','\hbox{#1}'); DefMacroI('\m@th',undef,'\mathsurround=0pt '); # \strutbox DefMacroI('\strut',undef,Tokens()); RawTeX('\newbox\strutbox'); #====================================================================== # TeX Book, Appendix B. p. 354 # TODO: Not yet done!! # tabbing stuff!!! DefMacroI('\settabs', undef,undef); #====================================================================== # TeX Book, Appendix B. p. 355 DefPrimitive('\hang',undef); # TODO: \item, \itemitem not done! # This could probably be adopted from LaTeX, if the could auto-open # and close! DefConstructor('\item{}','#1'); DefConstructor('\itemitem{}','#1'); DefConstructor('\makelabel{}','#1'); DefMacro('\textindent{}','#1'); # Conceivably this should enclose the next para in a block? # Or add attribute to it? Or... DefPrimitiveI('\narrower',undef,undef); #---------------------------------------------------------------------- # General support for Front Matter. # Not (yet) used by TeX (finish plain?) # But provides support for LaTeX (and other formats?) for handling frontmatter. # # The idea is to accumulate any frontmatter material (title, author,...) # rather than directly drop it into the digested stream. # When we begin constructing the document, all accumulated material is output. # See LaTeX.ltxml for usage. # Note: could be circumstances where you'd want modular frontmatter? # (ie. frontmatter for each sectional unit) AssignValue(frontmatter=>{},'global'); # Add a new frontmatter item that will be enclosed in <$tag %attr>... # The content is the result of digesting $tokens. # \@add@frontmatter{tag}[attributes]{content} DefPrimitive('\@add@frontmatter {} OptionalKeyVals {}', sub { my($stomach,$tag,$keys,$tokens)=@_; $tag = ToString($tag); my $attr = ($keys ? {$keys->beDigested($stomach)->getHash} : undef); my $frontmatter = LookupValue('frontmatter'); my $inpreamble = LookupValue('inPreamble'); AssignValue(inPreamble=>0); my $datum = Digest(Tokens(T_BEGIN,$tokens,T_END)); AssignValue(inPreamble=>$inpreamble); push(@{$$frontmatter{$tag}},[$tag,$attr,$datum]); return; }); # Append a piece of data to an existing frontmatter item that is contained in <$tag> # If $label is given, look for an item which has label=>$label, # otherwise, just append to the last item in $tag. # \@add@to@frontmatter{tag}[label]{content} DefPrimitive('\@add@to@frontmatter {} [] {}', sub { my($stomach,$tag,$label,$tokens)=@_; $tag = ToString($tag); $label = ToString($label) if $label; my $frontmatter = LookupValue('frontmatter'); my $inpreamble = LookupValue('inPreamble'); AssignValue(inPreamble=>0); my $datum = Digest(Tokens(T_BEGIN,$tokens,T_END)); AssignValue(inPreamble=>$inpreamble); if($label){ my $entry; foreach my $item (@{$$frontmatter{$tag} || []}){ my($itag,$iattr,@stuff)=@$item; if($label eq ($$iattr{label}||'')){ push(@$item,$datum); return; }}} elsif(my $list = $$frontmatter{$tag}){ push(@{$$list[-1]},$datum); return;} push(@{$$frontmatter{$tag}},[$tag,($label ? {label=>$label} : undef),$datum]); return; }); # This is called by afterOpen (by default on ) to # output any frontmatter that was accumulated. my @frontmatter_elements = (qw(ltx:title ltx:toctitle ltx:subtitle ltx:creator ltx:date ltx:abstract ltx:keywords ltx:classification ltx:acknowledgements)); my %frontmatter_elements = map(($_=>1),@frontmatter_elements); sub insertFrontMatter { my($document)=@_; my $frontmatter = LookupValue('frontmatter'); foreach my $key (@frontmatter_elements,grep(!$frontmatter_elements{$_},keys %$frontmatter)){ if(my $list = $$frontmatter{$key}){ # Dubious, but assures that frontmatter appears in text mode... local $LaTeXML::BOX = LaTeXML::Box->new('', $STATE->lookupValue('font'),'',T_SPACE); foreach my $item (@$list){ my($tag,$attr,@stuff)=@$item; $document->openElement($tag,($attr ? %$attr : ())); map($document->absorb($_), @stuff); $document->closeElement($tag); }}} return; } Tag('ltx:document', afterOpen=>\&insertFrontMatter); DefConstructor('\beginsection{}', "#1"); # \proclaim ? # TODO: Not yet done; actually is much like LaTeX's theorem env. #====================================================================== # TeX Book, Appendix B. p. 356 DefPrimitiveI('\raggedright', undef,undef); DefPrimitiveI('\raggedleft', undef,undef); # this is actually LaTeX DefPrimitiveI('\ttraggedright', undef,undef); DefPrimitiveI('\leavevmode', undef,undef); #---------------------------------------------------------------------- # Actually from LaTeX; Table 3.2. Non-English Symbols, p.39 # The following shouldn't appear in math. DefConstructorI('\OE', undef,"\x{0152}"); # LATIN CAPITAL LIGATURE OE DefConstructorI('\oe', undef,"\x{0153}"); # LATIN SMALL LIGATURE OE DefConstructorI('\AE', undef,UTF(0xC6)); # LATIN CAPITAL LETTER AE DefConstructorI('\ae', undef,UTF(0xE6)); # LATIN SMALL LETTER AE DefConstructorI('\AA', undef,UTF(0xC5)); # LATIN CAPITAL LETTER A WITH RING ABOVE DefConstructorI('\aa', undef,UTF(0xE5)); # LATIN SMALL LETTER A WITH RING ABOVE DefConstructorI('\O', undef,UTF(0xD8)); # LATIN CAPITAL LETTER O WITH STROKE DefConstructorI('\o', undef,UTF(0xF8)); # LATIN SMALL LETTER O WITH STROKE DefConstructorI('\L', undef,"\x{0141}"); # LATIN CAPITAL LETTER L WITH STROKE DefConstructorI('\l', undef,"\x{0142}"); # LATIN SMALL LETTER L WITH STROKE DefConstructorI('\ss', undef,UTF(0xDF)); # LATIN SMALL LETTER SHARP S # apparently the rest can appear in math. DefConstructorI('\dag', undef,"\x{2020}"); # DAGGER DefConstructorI('\ddag', undef,"\x{2021}"); # DOUBLE DAGGER DefConstructorI('\S', undef,UTF(0xA7)); # SECTION SIGN DefConstructorI('\P', undef,UTF(0xB6)); # PILCROW SIGN DefConstructorI('\copyright',undef,UTF(0xA9)); # COPYRIGHT SIGN DefConstructorI('\pounds',undef,UTF(0xA3)); # POUND SIGN #---------------------------------------------------------------------- # Accents. LaTeX Table 3.1, p.38 #---------------------------------------------------------------------- # All of TeX's accents can (sorta) be handled by Unicode's combining accents # (which follow the character to be accented). # We'll let unicode normalization do the combination, if needed. # Also, note that \t is intended to combine multiple chars, but it appears to # work (via mozilla !?) best when the combining char is after the 1st char. # Further, the accents \d and \b seem to center the under dot or bar under multiple # chars --- how should this be handled in Unicode? # Since people sometimes try to get fancy by using an empty argument, # for each, I'm providing the combining code and an equivalent(?) spacing one. our %accents = ('\`' => ["\x{0300}",UTF(0x60)], # COMBINING GRAVE ACCENT & GRAVE ACCENT "\\'"=> ["\x{0301}",UTF(0xB4)], # COMBINING ACUTE ACCENT & ACUTE ACCENT '\^' => ["\x{0302}",UTF(0x5E)], # COMBINING CIRCUMFLEX ACCENT & CIRCUMFLEX ACCENT '\"' => ["\x{0308}",UTF(0xA8)], # COMBINING DIAERESIS & DIAERESIS '\~' => ["\x{0303}","~"], # COMBINING TILDE '\=' => ["\x{0304}",UTF(0xAF)], # COMBINING MACRON & MACRON '\.' => ["\x{0307}",UTF(0xB7)], # COMBINING DOT ABOVE & MIDDLE DOT (?) '\u' => ["\x{0306}","\x{02D8}"], # COMBINING BREVE & BREVE '\v' => ["\x{030C}","\x{02C7}"], # COMBINING CARON & CARON '\@ringaccent' => ["\x{030A}","o"], # COMBINING RING ABOVE & non-combining '\r' => ["\x{030A}","o"], # COMBINING RING ABOVE & non-combining '\H' => ["\x{030B}","\x{02DD}"], # COMBINING DOUBLE ACUTE ACCENT & non-combining '\c' => ["\x{0327}",UTF(0xB8)], # COMBINING CEDILLA & CEDILLA '\d' => ["\x{0323}",UTF(0xB7)], # COMBINING DOT BELOW & MIDDLE DOT (?) '\b' => ["\x{0331}",UTF(0xAF)], # COMBINING MACRON BELOW & MACRON '\t' => ["\x{0361}","-"], # COMBINING DOUBLE INVERTED BREVE & ???? What???? # this one's actually defined in mathscinet.sty, but just stick it here! '\lfhook'=>["\x{0326}",","], # COMBINING COMMA BELOW # I doubt that latter covers multiple chars...? # '\bar'=>"\x{0304}", # COMBINING MACRON or is this the longer overbar? ); # Defines an accent command using a combining char that follows the # 1st char of the argument. In cases where there is no argument, $standalonechar is used. sub DefAccent { my ($accent, $combiningchar, $standalonechar) = @_; DefConstructor($accent."{}", sub { my($document,$letter,%props)=@_; if(my @letters = map(($_ eq '\i' ? 'i':$_),map(ToString($_),$letter->unlist))){ # Put the accent AFTER the first char(?) $document->openText(NFC($letters[0].$combiningchar.join('',@letters[1..$#letters])), $letter->getFont);} else { # Empty argument??? $document->openText($standalonechar,$props{font}); }} ); } foreach my $accent (keys %accents) { DefAccent($accent, @{$accents{$accent}}); } #====================================================================== # TeX Book, Appendix B. p. 357 foreach my $op ('\hrulefill','\dotfill','\rightarrowfill','\leftarrowfill', '\upbracefill','\downbracefill'){ DefPrimitive($op,undef); } Let(T_CS('\bye'),T_CS('\end')); Let(T_CS('\sp'),T_SUPER); Let(T_CS('\sb'),T_SUB); DefConstructorI('\,',undef,"?#isMath()(\x{2009})", properties=>{isSpace=>1}); # THIN SPACE DefConstructorI('\!',undef,"?#isMath()()", properties=>{isSpace=>1}); DefConstructorI('\>',undef,"?#isMath()()", properties=>{isSpace=>1}); # ?? DefConstructorI('\;',undef,"?#isMath()(\x{2004})", properties=>{isSpace=>1}); # THREE-PER-EM SPACE DefConstructorI('\:',undef,"?#isMath()(\x{2005})", properties=>{isSpace=>1}); # FOUR-PER-EM SPACE DefConstructorI('\ ',undef,"?#isMath()(".UTF(0xA0).")", properties=>{isSpace=>1}); # EN SPACE DefConstructorI('\/',undef,"?#isMath()()", properties=>{isSpace=>1}); # What kind of magic might allow \mskip to translate these back into the above? DefMacroI('\thinmuskip',undef, "3 mu"); DefMacroI('\medmuskip', undef,"4mu plus 2mu minus 4mu"); DefMacroI('\thickmuskip',undef,"5mu plus 5mu"); #====================================================================== # TeX Book, Appendix B. p. 358 #---------------------------------------------------------------------- # Actually from LaTeX; Table 3.3, Greek, p.41 #---------------------------------------------------------------------- DefMathI('\alpha', undef,"\x{03B1}"); DefMathI('\beta', undef,"\x{03B2}"); DefMathI('\gamma', undef,"\x{03B3}"); DefMathI('\delta', undef,"\x{03B4}"); DefMathI('\epsilon' , undef,"\x{03F5}"); DefMathI('\varepsilon',undef,"\x{03B5}"); DefMathI('\zeta', undef,"\x{03B6}"); DefMathI('\eta', undef,"\x{03B7}"); DefMathI('\theta', undef,"\x{03B8}"); DefMathI('\vartheta', undef,"\x{03D1}"); DefMathI('\iota', undef,"\x{03B9}"); DefMathI('\kappa', undef,"\x{03BA}"); DefMathI('\lambda', undef,"\x{03BB}"); DefMathI('\mu', undef,"\x{03BC}"); DefMathI('\nu', undef,"\x{03BD}"); DefMathI('\xi', undef,"\x{03BE}"); DefMathI('\pi', undef,"\x{03C0}"); DefMathI('\varpi', undef,"\x{03D6}"); DefMathI('\rho', undef,"\x{03C1}"); DefMathI('\varrho', undef,"\x{03F1}"); DefMathI('\sigma', undef,"\x{03C3}"); DefMathI('\varsigma', undef,"\x{03C2}"); DefMathI('\tau', undef,"\x{03C4}"); DefMathI('\upsilon', undef,"\x{03C5}"); DefMathI('\phi', undef,"\x{03D5}"); DefMathI('\varphi', undef,"\x{03C6}"); DefMathI('\chi', undef,"\x{03C7}"); DefMathI('\psi', undef,"\x{03C8}"); DefMathI('\omega', undef,"\x{03C9}"); DefMathI('\Gamma', undef,"\x{0393}"); DefMathI('\Delta', undef,"\x{0394}"); DefMathI('\Theta', undef,"\x{0398}"); DefMathI('\Lambda', undef,"\x{039B}"); DefMathI('\Xi', undef,"\x{039E}"); DefMathI('\Pi', undef,"\x{03A0}"); DefMathI('\Sigma', undef,"\x{03A3}"); DefMathI('\Upsilon', undef,"\x{03A5}"); DefMathI('\Phi', undef,"\x{03A6}"); DefMathI('\Psi', undef,"\x{03A8}"); DefMathI('\Omega', undef,"\x{03A9}"); #---------------------------------------------------------------------- # Actually from LaTeX; Table 3.7. Miscellaneous Symbols, p.43 #---------------------------------------------------------------------- # Some should be differential operators, qualifiers, ... DefMathI('\aleph', undef,"\x{2135}"); DefMathI('\hbar', undef,"\x{210F}", role=>'ID', meaning=>'Planck-constant-over-2-pi'); DefMathI('\imath', undef,"\x{0131}"); DefMathI('\jmath', undef,"j"); DefMathI('\ell', undef,"\x{2113}"); DefMathI('\wp', undef,"\x{2118}", meaning=>'Weierstrass-p'); DefMathI('\Re', undef,"\x{211C}", role=>'OPFUNCTION', meaning=>'real-part'); DefMathI('\Im', undef,"\x{2111}", role=>'OPFUNCTION', meaning=>'imaginary-part'); DefMathI('\mho', undef,"\x{2127}"); DefMathI('\prime', undef,"\x{2032}", role=>'SUPOP'); DefMathI('\emptyset', undef,"\x{2205}", role=>'ID', meaning=>'empty-set'); DefMathI('\nabla', undef,"\x{2207}", role=>'OPERATOR'); DefMathI('\surd', undef,"\x{221A}", role=>'OPERATOR', meaning=>'root'); DefMathI('\top', undef,"\x{22A4}", role=>'ADDOP', meaning=>'top'); DefMathI('\bot', undef,"\x{22A5}", role=>'ADDOP', meaning=>'bottom'); DefMathI('\|', undef,"\x{2225}", role=>'VERTBAR', name=>'||', meaning=>'parallel-to'); DefMathI('\angle', undef,"\x{2220}"); # NOTE: This is probably the wrong role. # Also, should probably carry info about Binding for OpenMath DefMathI('\forall', undef,"\x{2200}", role=>'BIGOP', meaning=>'for-all'); DefMathI('\exists', undef,"\x{2203}", role=>'BIGOP', meaning=>'exists'); DefMathI('\neg', undef,UTF(0xAC), role=>'FUNCTION', meaning=>'not'); DefMathI('\lnot', undef,UTF(0xAC), role=>'FUNCTION', meaning=>'not'); DefMathI('\flat', undef,"\x{266D}"); DefMathI('\natural', undef,"\x{266E}"); DefMathI('\sharp', undef,"\x{266F}"); DefMathI('\backslash',undef,UTF(0x5C), role=>'MULOP'); DefMathI('\partial', undef,"\x{2202}", role=>'OPERATOR', meaning=>'partial-differential'); DefMathI('\infty', undef,"\x{221E}", role=>'ID', meaning=>'infinity'); DefMathI('\Box', undef,"\x{25A1}"); DefMathI('\Diamond', undef,"\x{25C7}"); DefMathI('\triangle', undef,"\x{25B3}"); DefMathI('\clubsuit', undef,"\x{2663}"); DefMathI('\diamondsuit',undef,"\x{2662}"); DefMathI('\heartsuit',undef,"\x{2661}"); DefMathI('\spadesuit',undef,"\x{2660}"); #---------------------------------------------------------------------- DefMath('\smallint',"\x{222B}", meaning=>'integral', role=>'INTOP', font=>{size=>'small'}, scriptpos=>\&doScriptpos); # INTEGRAL #---------------------------------------------------------------------- # Actually LaTeX; Table 3.8. Variable-sized Symbols, p.44. #---------------------------------------------------------------------- sub doScriptpos { (LookupValue('mathstyle') eq 'display' ? 'mid' : 'post'); } DefMathI('\sum', undef,"\x{2211}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'sum'); DefMathI('\prod', undef,"\x{220F}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'product'); DefMathI('\coprod', undef,"\x{2210}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'coproduct'); DefMathI('\int', undef,"\x{222B}", role=>'INTOP', meaning=>'integral'); DefMathI('\oint', undef,"\x{222E}", role=>'INTOP', meaning=>'contour-integral'); DefMathI('\bigcap', undef,"\x{22C2}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'intersection'); DefMathI('\bigcup', undef,"\x{22C3}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'union'); DefMathI('\bigsqcup', undef,"\x{2294}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'square-union'); DefMathI('\bigvee', undef,"\x{22C1}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'or'); DefMathI('\bigwedge', undef,"\x{22C0}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'and'); DefMathI('\bigodot', undef,"\x{22A1}", role=>'SUMOP', scriptpos=>\&doScriptpos); #meaning=> ? DefMathI('\bigotimes',undef,"\x{2297}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'tensor-product'); DefMathI('\bigoplus', undef,"\x{2295}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'direct-sum'); DefMathI('\biguplus', undef,"\x{2296}", role=>'SUMOP', scriptpos=>\&doScriptpos, meaning=>'symmetric-difference'); DefConstructorI('\limits', undef,sub { my $node = $_[0]->getNode; $_[0]->setAttribute($_[0]->getLastChildElement($node)||$node,scriptpos=>'mid'); }); DefConstructorI('\nolimits',undef,sub { my $node = $_[0]->getNode; $_[0]->setAttribute($_[0]->getLastChildElement($node)||$node,scriptpos=>'post'); }); #---------------------------------------------------------------------- # Actually from LaTeX; Table 3.4. Binary Operation Symbols, p.42 #---------------------------------------------------------------------- DefMathI('\pm', undef,UTF(0xB1), role=>'ADDOP', meaning=>'plus-or-minus'); DefMathI('\mp', undef,"\x{2213}", role=>'ADDOP', meaning=>'minus-or-plus'); DefMathI('\times', undef,UTF(0xD7), role=>'MULOP', meaning=>'times'); DefMathI('\div', undef,UTF(0xF7), role=>'MULOP', meaning=>'divide'); DefMathI('\ast', undef,"\x{2217}", role=>'MULOP'); DefMathI('\star', undef,"\x{22C6}", role=>'MULOP'); DefMathI('\circ', undef,"\x{2218}", role=>'MULOP', meaning=>'compose'); DefMathI('\bullet', undef,"\x{2219}", role=>'MULOP'); DefMathI('\cdot', undef,"\x{22C5}", role=>'MULOP'); ## , meaning=>'inner-product'); that's pushing it a bit far... # Need to classify set operations more carefully.... DefMathI('\cap', undef,"\x{2229}", role=>'ADDOP', meaning=>'intersection'); DefMathI('\cup', undef,"\x{222A}", role=>'ADDOP', meaning=>'union'); DefMathI('\uplus', undef,"\x{228C}", role=>'ADDOP'); DefMathI('\sqcap', undef,"\x{2293}", role=>'ADDOP', meaning=>'square-intersection'); DefMathI('\sqcup', undef,"\x{2294}", role=>'ADDOP', meaning=>'square-union'); DefMathI('\vee', undef,"\x{2228}", role=>'ADDOP', meaning=>'or'); DefMathI('\lor', undef,"\x{2228}", role=>'ADDOP', meaning=>'or'); DefMathI('\wedge', undef,"\x{2227}", role=>'ADDOP', meaning=>'and'); DefMathI('\land', undef,"\x{2227}", role=>'ADDOP', meaning=>'and'); DefMathI('\setminus', undef,"\x{2216}", role=>'ADDOP', meaning=>'set-minus'); DefMathI('\wr', undef,"\x{2240}", role=>'MULOP'); # Should this block be ADDOP or something else? DefMathI('\diamond', undef,"\x{22C4}", role=>'ADDOP'); DefMathI('\bigtriangleup', undef,"\x{25B3}", role=>'ADDOP'); DefMathI('\bigtriangledown',undef,"\x{25BD}", role=>'ADDOP'); DefMathI('\triangleleft', undef,"\x{25C1}", role=>'ADDOP'); DefMathI('\triangleright', undef,"\x{25B7}", role=>'ADDOP'); DefMathI('\lhd', undef,"\x{22B2}", role=>'ADDOP', meaning=>'subgroup-of'); DefMathI('\rhd', undef,"\x{22B3}", role=>'ADDOP', meaning=>'contains-as-subgroup'); DefMathI('\unlhd', undef,"\x{22B4}", role=>'ADDOP', meaning=>'subgroup-of-or-equals'); DefMathI('\unrhd', undef,"\x{22B5}", role=>'ADDOP', meaning=>'contains-as-subgroup-or-equals'); DefMathI('\oplus', undef,"\x{2295}", role=>'ADDOP', meaning=>'direct-sum'); DefMathI('\ominus', undef,"\x{2296}", role=>'ADDOP', meaning=>'symmetric-difference'); DefMathI('\otimes', undef,"\x{2297}", role=>'MULOP', meaning=>'tensor-product'); DefMathI('\oslash', undef,"\x{2298}", role=>'MULOP'); DefMathI('\odot', undef,"\x{2299}", role=>'MULOP', meaning=>'direct-product'); DefMathI('\bigcirc', undef,"\x{25CB}", role=>'MULOP'); DefMathI('\dagger', undef,"\x{2020}", role=>'MULOP'); DefMathI('\ddagger', undef,"\x{2021}", role=>'MULOP'); DefMathI('\amalg', undef,"\x{2210}", role=>'MULOP', meaning=>'coproduct'); #---------------------------------------------------------------------- # LaTeX; Table 3.5. Relation Symbols, p.43 #---------------------------------------------------------------------- DefMathI('\le', undef,"\x{2264}", role=>'RELOP', meaning=>'less-than-or-equals'); DefMathI('\ge', undef,"\x{2265}", role=>'RELOP', meaning=>'greater-than-or-equals'); DefMathI('\ne', undef,"\x{2260}", role=>'RELOP', meaning=>'not-equals'); DefMathI('\leq', undef,"\x{2264}", role=>'RELOP', meaning=>'less-than-or-equals'); DefMathI('\prec', undef,"\x{227A}", role=>'RELOP', meaning=>'precedes'); DefMathI('\preceq', undef,"\x{2AAF}", role=>'RELOP', meaning=>'precedes-or-equals'); DefMathI('\ll', undef,"\x{226A}", role=>'RELOP', meaning=>'much-less-than'); DefMathI('\subset', undef,"\x{2282}", role=>'RELOP', meaning=>'subset-of'); DefMathI('\subseteq', undef,"\x{2286}", role=>'RELOP', meaning=>'subset-of-or-equals'); DefMathI('\sqsubset', undef,"\x{228F}", role=>'RELOP', meaning=>'square-image-of'); DefMathI('\sqsubseteq',undef,"\x{2291}", role=>'RELOP', meaning=>'square-image-of-or-equals'); DefMathI('\in', undef,"\x{2208}", role=>'RELOP', meaning=>'element-of'); DefMathI('\vdash', undef,"\x{22A2}", role=>'METARELOP', meaning=>'proves'); DefMathI('\geq', undef,"\x{2265}", role=>'RELOP', meaning=>'greater-than-or-equals'); DefMathI('\succ', undef,"\x{227B}", role=>'RELOP', meaning=>'succeeds'); DefMathI('\succeq', undef,"\x{2AB0}", role=>'RELOP', meaning=>'succeeds-or-equals'); DefMathI('\gg', undef,"\x{226B}", role=>'RELOP', meaning=>'much-greater-than'); DefMathI('\supset', undef,"\x{2283}", role=>'RELOP', meaning=>'superset-of'); DefMathI('\supseteq', undef,"\x{2287}", role=>'RELOP', meaning=>'superset-of-or-equals'); DefMathI('\sqsupset', undef,"\x{2290}", role=>'RELOP', meaning=>'square-original-of'); DefMathI('\sqsupseteq',undef,"\x{2292}", role=>'RELOP', meaning=>'square-original-of-or-equals'); DefMathI('\ni', undef,"\x{220B}", role=>'RELOP', meaning=>'contains'); DefMathI('\dashv', undef,"\x{22A3}", role=>'METARELOP', meaning=>'does-not-prove'); DefMathI('\equiv', undef,"\x{2261}", role=>'RELOP', meaning=>'identical-to'); DefMathI('\sim', undef,"\x{223C}", role=>'RELOP', meaning=>'similar-to'); DefMathI('\simeq', undef,"\x{2243}", role=>'RELOP', meaning=>'similar-to-or-equals'); DefMathI('\asymp', undef,"\x{224D}", role=>'RELOP', meaning=>'asymptotically-equals'); DefMathI('\approx', undef,"\x{2248}", role=>'RELOP', meaning=>'almost-equals'); DefMathI('\cong', undef,"\x{2245}", role=>'RELOP', meaning=>'approximately-equals'); DefMathI('\neq', undef,"\x{2260}", role=>'RELOP', meaning=>'not-equals'); DefMathI('\doteq', undef,"\x{2250}", role=>'RELOP', meaning=>'approaches-limit'); DefMathI('\notin', undef,"\x{2209}", role=>'RELOP', meaning=>'not-element-of'); DefMathI('\models', undef,"\x{22A7}", role=>'RELOP', meaning=>'models'); DefMathI('\perp', undef,"\x{27C2}", role=>'RELOP', meaning=>'perpendicular-to'); DefMathI('\mid', undef,"\x{2223}", role=>'VERTBAR'); # DIVIDES (RELOP?) ?? well, sometimes... DefMathI('\parallel', undef,"\x{2225}", role=>'VERTBAR', meaning=>'parallel-to'); DefMathI('\bowtie', undef,"\x{22C8}", role=>'RELOP'); # BOWTIE DefMathI('\Join', undef,"\x{2A1D}", role=>'RELOP', meaning=>'join'); DefMathI('\smile', undef,"\x{2323}", role=>'RELOP'); # SMILE DefMathI('\frown', undef,"\x{2322}", role=>'RELOP'); # FROWN DefMathI('\propto', undef,"\x{221D}", role=>'RELOP', meaning=>'proportional-to'); DefMathI('\not',undef,"not", role=>'PREFIX', meaning=>'not'); #---------------------------------------------------------------------- # Match negations of many operators our %NOTS = ('='=>"\x{2260}", '<'=> "\x{226E}", '>'=>"\x{226F}", "\x{2208}"=>"\x{2209}", #\in=>\notin "\x{2264}"=>"\x{2270}", "\x{2265}"=>"\x{2271}", # Less eq, greater eq. "\x{227A}"=>"\x{2280}", "\x{227B}"=>"\x{2281}", # prec, succ "\x{2AAF}"=>"\x{22E0}", "\x{2AB0}"=>"\x{22E1}", # preceq, succeq "\x{2282}"=>"\x{2284}", "\x{2283}"=>"\x{2285}", # subset, supset "\x{2286}"=>"\x{2288}", "\x{2287}"=>"\x{2289}", # subseteq, supseteq "\x{2291}"=>"\x{22E2}", "\x{2290}"=>"\x{22E3}", # sqsubseteq, sqsupseteq "\x{2261}"=>"\x{2262}", # equiv "\x{224D}"=>"\x{226D}", "\x{2248}"=>"\x{2249}", # asymp, approx "\x{22B2}"=>"\x{22EA}", "\x{22B3}"=>"\x{22EB}", # lhd, rhd "\x{22B4}"=>"\x{22EC}", "\x{22B5}"=>"\x{22ED}", # unlhd, unrhd "\x{2203}"=>"\x{2204}", # Exists ); DefMathLigature(sub { my($document,@nodes)=@_; my ($n1,$n2,$op)=($nodes[$#nodes-1],$nodes[$#nodes]); my $c; if(defined $n1 && (($document->getModel->getNodeQName($n1) eq 'ltx:XMTok') && ($n1->textContent eq 'not')) && (($document->getModel->getNodeQName($n2) eq 'ltx:XMTok') && $NOTS{$c=$n2->textContent})){ my $m = $n2->getAttribute('meaning'); my $n = $n2->getAttribute('name') || $c; my $r = $n2->getAttribute('role'); (2, $NOTS{$c}, ### ($m ? (meaning=>"not-$m"):(name=>"not-$n"))); }}); ($m ? (meaning=>"not-$m"):()), ($n ? (name=>"not-$n") :()), ($r ? (role=>$r):()), ); }}); #---------------------------------------------------------------------- # \joinrel DefMathI('\relbar',undef, "-", role=>'RELOP'); # ??? DefMathI('\Relbar',undef, "=", role=>'RELOP'); # ??? # \joinrel is \mathrel{\mkern-3\mu} # Ah, but the Effect is to join 2 "relations" into one! DefPrimitiveI('\joinrel',undef,sub { my($stomach,$op)=@_; my $gullet = $stomach->getGullet; $gullet->skipSpaces; my $left = $LaTeXML::LIST[$#LaTeXML::LIST]; if(!$left){ # Nothing there?... return (); } # I guess this becomes a no-op??? else { pop(@LaTeXML::LIST); my @stuff=(); while(my $tok = $gullet->readXToken){ @stuff = $stomach->invokeToken($tok); last if @stuff; } return () unless @stuff; # no-op ???? my $right = shift(@stuff); (@stuff, LaTeXML::Whatsit->new(LookupDefinition(T_CS('\@@joinrel')),[$left,$right], locator=>$gullet->getLocator, font=>$right->getFont,isMath=>1)); }}); DefConstructor('\@@joinrel{}{}', sub { my($document,$left,$right)=@_; $document->absorb($left); $document->absorb($right); # Now if last 2 items are XMTok, replace by a single token with joined content (& attr?) my $node= $document->getNode; my @nodes = $document->getChildElements($node); if(scalar(@nodes) >= 2){ my @rels= ($nodes[$#nodes-1],$nodes[$#nodes]); if(grep($document->getNodeQName($_) eq 'ltx:XMTok',@rels )){ my %roles=(); map($roles{$_->getAttribute('role')}=1, @rels); my $role = (scalar(keys %roles)==1 ? [keys %roles]->[0] : ($roles{ARROW} ? 'ARROW' : 'RELOP')); map($node->removeChild($_), @rels); $document->insertElement('ltx:XMTok',[map($_->textContent,@rels)], role=>$role); }}}, reversion=>'#1\joinrel #2'); #---------------------------------------------------------------------- # LaTeX; Table 3.6. Arrow Symbols, p.43 #---------------------------------------------------------------------- # Arrows get treated somewhat like relations (or meta-relations), # but it's hard to associate any particular "meaning" to them. DefMathI('\leftarrow', undef,"\x{2190}", role=>'ARROW'); # LEFTWARDS ARROW DefMathI('\Leftarrow', undef,"\x{21D0}", role=>'ARROW'); # LEFTWARDS DOUBLE ARROW DefMathI('\rightarrow', undef,"\x{2192}", role=>'ARROW'); # RIGHTWARDS ARROW DefMathI('\Rightarrow', undef,"\x{21D2}", role=>'ARROW'); # RIGHTWARDS DOUBLE ARROW DefMathI('\leftrightarrow', undef,"\x{2194}", role=>'METARELOP'); # LEFT RIGHT ARROW DefMathI('\Leftrightarrow', undef,"\x{21D4}", role=>'METARELOP'); # LEFT RIGHT DOUBLE ARROW DefMathI('\iff', undef,"\x{21D4}", role=>'METARELOP', meaning=>'iff'); # LEFT RIGHT DOUBLE ARROW DefMathI('\mapsto', undef,"\x{21A6}", role=>'ARROW', meaning=>'maps-to'); DefMathI('\hookleftarrow', undef,"\x{21A9}", role=>'ARROW'); # LEFTWARDS ARROW WITH HOOK DefMathI('\leftharpoonup', undef,"\x{21BC}", role=>'ARROW'); # LEFTWARDS HARPOON WITH BARB UPWARDS DefMathI('\leftharpoondown', undef,"\x{21BD}", role=>'ARROW'); # LEFTWARDS HARPOON WITH BARB DOWNWARDS DefMathI('\rightleftharpoons', undef,"\x{21CC}", role=>'METARELOP'); # RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON DefMathI('\longleftarrow', undef,"\x{27F5}", role=>'ARROW'); # LONG LEFTWARDS ARROW DefMathI('\Longleftarrow', undef,"\x{27F8}", role=>'ARROW'); # LONG LEFTWARDS DOUBLE ARROW DefMathI('\longrightarrow', undef,"\x{27F6}", role=>'ARROW'); # LONG RIGHTWARDS ARROW DefMathI('\Longrightarrow', undef,"\x{27F9}", role=>'ARROW'); # LONG RIGHTWARDS DOUBLE ARROW DefMathI('\longleftrightarrow',undef,"\x{27F7}", role=>'METARELOP'); # LONG LEFT RIGHT ARROW DefMathI('\Longleftrightarrow',undef,"\x{27FA}", role=>'METARELOP'); # LONG LEFT RIGHT DOUBLE ARROW DefMathI('\longmapsto', undef,"\x{27FC}", role=>'ARROW'); # LONG RIGHTWARDS ARROW FROM BAR DefMathI('\hookrightarrow', undef,"\x{21AA}", role=>'ARROW'); # RIGHTWARDS ARROW WITH HOOK DefMathI('\rightharpoonup', undef,"\x{21C0}", role=>'ARROW'); # RIGHTWARDS HARPOON WITH BARB UPWARDS DefMathI('\rightharpoondown', undef,"\x{21C1}", role=>'ARROW'); # RIGHTWARDS HARPOON WITH BARB DOWNWARDS DefMathI('\leadsto', undef,"\x{219D}", role=>'ARROW', meaning=>'leads-to'); DefMathI('\uparrow', undef,"\x{2191}", role=>'ARROW'); # UPWARDS ARROW DefMathI('\Uparrow', undef,"\x{21D1}", role=>'ARROW'); # UPWARDS DOUBLE ARROW DefMathI('\downarrow', undef,"\x{2193}", role=>'ARROW'); # DOWNWARDS ARROW DefMathI('\Downarrow', undef,"\x{21D3}", role=>'ARROW'); # DOWNWARDS DOUBLE ARROW DefMathI('\updownarrow', undef,"\x{2195}", role=>'ARROW'); # UP DOWN ARROW DefMathI('\Updownarrow', undef,"\x{21D5}", role=>'ARROW'); # UP DOWN DOUBLE ARROW DefMathI('\nearrow', undef,"\x{2197}", role=>'ARROW'); # NORTH EAST ARROW DefMathI('\searrow', undef,"\x{2198}", role=>'ARROW'); # SOUTH EAST ARROW DefMathI('\swarrow', undef,"\x{2199}", role=>'ARROW'); # SOUTH WEST ARROW DefMathI('\nwarrow', undef,"\x{2196}", role=>'ARROW'); # NORTH WEST ARROW # \mapstochar (3237), \lhook(312C), \rhook(312D) # These are really wrong; I can't find the right Unicode Glyphs. # These are only fragments intended to be assembled into meaningful(?) symbols. DefMathI('\mapstochar', undef,"\x{2E20}"); # TeX 3237 DefMathI('\lhook', undef,"\x{2E26}"); # TeX 312C DefMathI('\rhook', undef,"\x{2E27}"); # TeX 312D #====================================================================== # TeX Book, Appendix B. p. 359 #DefMath('\ldots',"\x{2026}", role=>'ID'); # HORIZONTAL ELLIPSIS # Ah, since \ldots can appear in text.... DefConstructorI('\ldots',undef, "?#isMath(\x{2026})(\x{2026})", properties=>{font=>sub{ LookupValue('font')->specialize("\x{2026}");}}); # Since not DefMath! DefMathI('\cdots',undef,"\x{22EF}", role=>'ID'); # MIDLINE HORIZONTAL ELLIPSIS DefMathI('\vdots',undef,"\x{22EE}", role=>'ID'); # VERTICAL ELLIPSIS DefMathI('\ddots',undef,"\x{22F1}", role=>'ID'); # DOWN RIGHT DIAGONAL ELLIPSIS DefMathI('\colon',undef,':', role=>'METARELOP'); # Seems like good default role # Note that amsmath redefines \dots to be `smart'. # Aha, also can be in text... DefConstructorI('\dots',undef, "?#isMath(\x{2026})(\x{2026})", properties=>{font=>sub{ LookupValue('font')->merge(family=>'serif');}} ); # Since not DefMath! # And while we're at it... # Pretest for XMath to keep from interpreting math that the DOM may not allow!! ##DefMathRewrite(xpath=>'descendant-or-self::ltx:XMath',match=>'\cdot\cdot\cdot',replace=>'\cdots'); DefMathLigature(sub { my($document,@nodes)=@_; if((scalar(@nodes) > 3) && ! grep( ($document->getModel->getNodeQName($_) ne 'ltx:XMTok')|| ($_->textContent ne "\x{22C5}"), @nodes[$#nodes-2 .. $#nodes])){ (3, "\x{22EF}", name=>'cdots', role=>'ID'); }}); ##DefRewrite(regexp=>"/\\.\\.\\./\x{2026}/"); # ldots DefLigature("/\\.\\.\\./\x{2026}/", fontTest=>sub { $_[0]->getFamily ne 'typewriter'; }); # ldots #DefMathRewrite(xpath=>'descendant-or-self::ltx:XMath',match=>'...',replace=>'\ldots'); DefMathLigature(sub { my($document,@nodes)=@_; if((scalar(@nodes) >= 3) && ! grep( ($document->getModel->getNodeQName($_) ne 'ltx:XMTok')||($_->textContent ne "."), @nodes[$#nodes-2 .. $#nodes])){ (3, "\x{2026}", name=>'ldots', role=>'ID'); }}); #---------------------------------------------------------------------- # Math Accents. #---------------------------------------------------------------------- # LaTeX; Table 3.11. Math Mode Accents, p.50. # Are these all TeX (or LaTeX)? DefMath('\hat Digested', "\x{2303}", operator_role=>'OVERACCENT'); DefMath('\check Digested', "\x{2713}", operator_role=>'OVERACCENT'); # CHECK MARK DefMath('\breve Digested', "\x{02D8}", operator_role=>'OVERACCENT'); # BREVE DefMath('\acute Digested', UTF(0xB4), operator_role=>'OVERACCENT'); # ACUTE ACCENT DefMath('\grave Digested', UTF(0x60), operator_role=>'OVERACCENT'); # GRAVE ACCENT DefMath('\tilde Digested', UTF(0x7E), operator_role=>'OVERACCENT'); # TILDE DefMath('\bar Digested', UTF(0xAF), operator_role=>'OVERACCENT'); # MACRON DefMath('\vec Digested', "\x{2192}", operator_role=>'OVERACCENT'); # RIGHTWARDS ARROW DefMath('\dot Digested', "\x{02D9}", operator_role=>'OVERACCENT'); # DOT ABOVE DefMath('\ddot Digested', UTF(0xA8), operator_role=>'OVERACCENT'); # DIAERESIS DefMath('\overline Digested', UTF(0xAF), operator_role=>'OVERACCENT'); # MACRON DefMath('\overbrace Digested', "\x{FE37}", operator_role=>'OVERACCENT', # PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET scriptpos=>'mid'); DefMath('\widehat Digested', UTF(0x5E), operator_role=>'OVERACCENT'); # CIRCUMFLEX ACCENT [plain? also amsfonts] DefMath('\widetilde Digested', UTF(0x7E), operator_role=>'OVERACCENT'); # TILDE [plain? also amsfonts] DefMath('\underbrace Digested',"\x{FE38}", operator_role=>'UNDERACCENT', # PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET scriptpos=>'mid'); # NOTE that all the above accents REQUIRE math mode # EXCEPT underline, overrightarrow and overleftarrow! DefMath('\math@underline{}', UTF(0xAF), operator_role=>'UNDERACCENT', name=>'underline', alias=>'\underline'); DefConstructor('\text@underline{}', "#1"); DefMath('\math@overrightarrow{}', "\x{2192}", operator_role=>'OVERACCENT', name=>'overrightarrow', alias=>'\overrightarrow'); DefMath('\math@overleftarrow{}', "\x{2190}", operator_role=>'OVERACCENT', name=>'overleftarrow', alias=>'\overleftarrow'); # Careful: Use \protect so that it doesn't expand too early in alignments, etc. DefMacro('\underline{}', '\protect\ifmmode\math@underline{#1}\else\text@underline{#1}\fi'); Let(T_CS('\underbar'),T_CS('\underline')); # Will anyone notice? DefMacro('\overrightarrow{}', '\protect\ifmmode\math@overrightarrow{#1}\else$\math@overrightarrow{#1}$\fi'); DefMacro('\overleftarrow{}', '\protect\ifmmode\math@overleftarrow{#1}\else$\math@overleftarrow{#1}$\fi'); #---------------------------------------------------------------------- # LaTeX; Table 3.10. Delimiters, p.47 #---------------------------------------------------------------------- # The meaning of OPEN/CLOSE tends to depend upon the pairing, # rather than the individual tokens. # This meaning is handled in MathParser (for now) DefConstructorI('\{',undef, "?#isMath({)({)"); DefConstructorI('\}',undef, "?#isMath(})(})"); Let(T_CS('\lbrace'),T_CS('\{')); Let(T_CS('\lbrack'),T_CS('[')); Let(T_CS('\rbrace'),T_CS('\}')); Let(T_CS('\rbrack'),T_CS(']')); DefMathI('\lfloor', undef,"\x{230A}", role=>'OPEN'); # LEFT FLOOR DefMathI('\lceil', undef,"\x{2308}", role=>'OPEN'); # LEFT CEILING DefMathI('\langle', undef,"\x{2329}", role=>'OPEN'); # LEFT-POINTING ANGLE BRACKET DefMathI('\rfloor', undef,"\x{230B}", role=>'CLOSE'); # RIGHT FLOOR DefMathI('\rceil', undef,"\x{2309}", role=>'CLOSE'); # RIGHT CEILING DefMathI('\rangle', undef,"\x{232A}", role=>'CLOSE'); # RIGHT-POINTING ANGLE BRACKET # Not sure these should be defined here, or latex, or even latex compat mode. DefMathI('\lgroup', undef,"(", font=>{series=>'bold'}, role=>'OPEN'); DefMathI('\rgroup', undef,")", font=>{series=>'bold'}, role=>'CLOSE'); DefMathI('\bracevert', undef, "|", font=>{series=>'bold'}, role=>'VERTBAR'); ## DefMath('\lmoustache',"???", font=>{series=>'bold'}, role=>'OPEN'); ## DefMath('\rmoustache',"???", font=>{series=>'bold'}, role=>'OPEN'); # TeX marks some symbols as delimiters which can be used with \left,\right, # but many of which have different grammatical roles otherwise, eg. arrows, <, >. # Short of setting up TeX's complicated encoding machinery, I need an explicit # mapping. Unfortunately, this doesn't (yet) support people declaring thier own delimiters! # This duplicates in slightly different way what DefMath has put together. our %DELIMITER_MAP = ('(' =>{char=>"(", lrole=>'OPEN', rrole=>'CLOSE'}, ')' =>{char=>")", lrole=>'OPEN', rrole=>'CLOSE'}, '[' =>{char=>"[", lrole=>'OPEN', rrole=>'CLOSE'}, ']' =>{char=>"]", lrole=>'OPEN', rrole=>'CLOSE'}, '\{' =>{char=>"{", lrole=>'OPEN', rrole=>'CLOSE'}, '\}' =>{char=>"}", lrole=>'OPEN', rrole=>'CLOSE'}, '\lfloor' =>{char=>"\x{230A}", lrole=>'OPEN', rrole=>'CLOSE', name=>'lfloor'}, '\rfloor' =>{char=>"\x{230B}", lrole=>'OPEN', rrole=>'CLOSE', name=>'rfloor'}, '\lceil' =>{char=>"\x{2308}", lrole=>'OPEN', rrole=>'CLOSE', name=>'lceil'}, '\rceil' =>{char=>"\x{2309}", lrole=>'OPEN', rrole=>'CLOSE', name=>'rceil'}, '\langle' =>{char=>"\x{2329}", lrole=>'OPEN', rrole=>'CLOSE', name=>'langle'}, '\rangle' =>{char=>"\x{232A}", lrole=>'OPEN', rrole=>'CLOSE', name=>'rangle'}, '<' =>{char=>"\x{2329}", lrole=>'OPEN', rrole=>'CLOSE', name=>'langle'}, '>' =>{char=>"\x{232A}", lrole=>'OPEN', rrole=>'CLOSE', name=>'rangle'}, '/' =>{char=>"/", lrole=>'MULOP', rrole=>'MULOP'}, '\backslash' =>{char=>UTF(0x5C), lrole=>'MULOP', rrole=>'MULOP', name=>'backslash'}, '|' =>{char=>"|", lrole=>'VERTBAR', rrole=>'VERTBAR'}, '\|' =>{char=>"\x{2225}", lrole=>'VERTBAR', rrole=>'VERTBAR'}, '\uparrow' =>{char=>"\x{2191}", lrole=>'OPEN', rrole=>'CLOSE', name=>'uparrow'}, # ?? '\Uparrow' =>{char=>"\x{21D1}", lrole=>'OPEN', rrole=>'CLOSE', name=>'Uparrow'}, # ?? '\downarrow' =>{char=>"\x{2193}", lrole=>'OPEN', rrole=>'CLOSE', name=>'downarrow'}, # ?? '\Downarrow' =>{char=>"\x{21D3}", lrole=>'OPEN', rrole=>'CLOSE', name=>'Downarrow'}, # ?? '\updownarrow'=>{char=>"\x{2195}", lrole=>'OPEN', rrole=>'CLOSE', name=>'updownarrow'}, # ?? '\Updownarrow'=>{char=>"\x{21D5}", lrole=>'OPEN', rrole=>'CLOSE', name=>'Updownarrow'}, # ?? ); sub lookup_delimiter { $DELIMITER_MAP{$_[0]}; } # This is a little messier than you'd think. # These effectively create a group between the \left,\right. DefMacro('\left Token','\@left #1\@hidden@bgroup'); DefMacro('\right Token','\@hidden@egroup\@right #1'); DefConstructor('\@left Token', "?#char(#char)()", afterDigest=>sub { my($stomach,$whatsit)=@_; my $arg = $whatsit->getArg(1); my $delim = ToString($arg); if($delim eq '.'){} elsif(my $entry = $DELIMITER_MAP{$delim}){ $whatsit->setProperties(role=>$$entry{lrole}, char=>$$entry{char}, name=>$$entry{name}); $whatsit->setFont($arg->getFont()); } elsif(($arg->getProperty('role')||'') eq 'OPEN'){} else { Warn(":expected:. Missing delimiter $delim (. inserted)"); } return; }, alias=>'\left'); DefConstructor('\@right Token', "?#char(#char)()", afterDigest=>sub { my($stomach,$whatsit)=@_; my $arg = $whatsit->getArg(1); my $delim = ToString($arg); if($delim eq '.'){} elsif(my $entry = $DELIMITER_MAP{$delim}){ $whatsit->setProperties(role=>$$entry{rrole}, char=>$$entry{char}, name=>$$entry{name}); $whatsit->setFont($arg->getFont()); } elsif(($arg->getProperty('role')||'') eq 'CLOSE'){} else { Warn(":expected:. Missing delimiter $delim (. inserted)"); } return; }, alias=>'\right'); sub addDelimiterRole { my($document,$role)=@_; my $current = $document->getNode; # This should be the wrapper just added. my $node = $document->getLastChildElement($current) || $current; my $delim = $node && $document->getFirstChildElement($node); my $delim_role = (($delim && $delim->getAttribute('role')) || ''); my $wrapper_role = ($delim_role =~ /^(OPEN|MIDDLE|CLOSE|VERTBAR)$/ ? $role : $delim_role); $document->setAttribute($node,role=>$wrapper_role) if $node && $wrapper_role; } # Defined in e-Tex and other places. DefConstructor('\middle Token ',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'MIDDLE'); }); DefConstructor('\bigl Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'OPEN'); }); DefConstructor('\bigm Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'MIDDLE'); }); DefConstructor('\bigr Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'CLOSE'); }); DefConstructor('\Bigl Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'OPEN'); }); DefConstructor('\Bigm Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'MIDDLE'); }); DefConstructor('\Bigr Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'CLOSE'); }); DefConstructor('\biggl Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'OPEN'); }); DefConstructor('\biggm Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'MIDDLE'); }); DefConstructor('\biggr Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'CLOSE'); }); DefConstructor('\Biggl Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'OPEN'); }); DefConstructor('\Biggm Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'MIDDLE'); }); DefConstructor('\Biggr Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0],'CLOSE'); }); # ? DefConstructor('\big Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0]); }); DefConstructor('\Big Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0]); }); DefConstructor('\bigg Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0]); }); DefConstructor('\Bigg Token',"#1", afterConstruct=>sub { addDelimiterRole($_[0]); }); Let(T_CS('\vert'),T_OTHER('|')); Let(T_CS('\Vert'),T_CS('\|')); #====================================================================== # TeX Book, Appendix B. p. 360 # \choose, et al, already handle above. DefMacro('\mathchoice{}{}{}{}',sub { my($gullet,$d,$t,$s,$ss)=@_; my $style = LookupValue('mathstyle') || 'display'; if ($style eq 'display'){ $d->unlist; } elsif($style eq 'text' ){ $t->unlist; } elsif($style eq 'script' ){ $s->unlist; } else { $ss->unlist; }}); DefMacro('\mathpalette{}{}', '\mathchoice{#1\displaystyle{#2}}{#1\textstyle{#2}}' .'{#1\scriptstyle{#2}}{#1\scriptscriptstyle{#2}}'); DefConstructor('\phantom{}',"?#isMath()()", properties=>{isSpace=>1}); DefConstructor('\hphantom{}',"?#isMath()()", properties=>{isSpace=>1}); DefConstructor('\vphantom{}',"?#isMath()()", properties=>{isSpace=>1}); DefConstructor('\mathstrut',"?#isMath()()", properties=>{isSpace=>1}); DefConstructor('\smash{}',"#1"); # well, what? #====================================================================== # TeX Book, Appendix B. p. 361 # This is actually LaTeX's definition, but let's just do it this way. DefConstructor('\sqrt[] Digested', "?#1(" . "#1#2" . ")" . "(" . "#2)"); DefConstructor('\root Until:\of {}', "" . "#1#2" .""); #---------------------------------------------------------------------- # LaTeX; Table 3.9. Log-like Functions, p.44. #---------------------------------------------------------------------- # NOTE: Classifying some as TRIGFUNCTION might clarify 'pi' ambiguities ? DefMathI('\arccos', undef,"arccos", role=>'OPFUNCTION', meaning=>'inverse-cosine'); DefMathI('\arcsin', undef,"arcsin", role=>'OPFUNCTION', meaning=>'inverse-sine'); DefMathI('\arctan', undef,"arctan", role=>'OPFUNCTION', meaning=>'inverse-tangent'); DefMathI('\arg', undef,"arg", role=>'OPFUNCTION', meaning=>'argument'); DefMathI('\cos', undef,"cos", role=>'TRIGFUNCTION', meaning=>'cosine'); DefMathI('\cosh', undef,"cosh", role=>'TRIGFUNCTION', meaning=>'hyperbolic-cosine'); DefMathI('\cot', undef,"cot", role=>'TRIGFUNCTION', meaning=>'cotangent'); DefMathI('\coth', undef,"coth", role=>'TRIGFUNCTION', meaning=>'hyperbolic-cotangent'); DefMathI('\csc', undef,"csc", role=>'TRIGFUNCTION', meaning=>'cosecant'); DefMathI('\deg', undef,"deg", role=>'OPFUNCTION', meaning=>'degree'); DefMathI('\det', undef,"det", role=>'LIMITOP', meaning=>'determinant', scriptpos=>\&doScriptpos); DefMathI('\dim', undef,"dim", role=>'LIMITOP', meaning=>'dimension'); DefMathI('\exp', undef,"exp", role=>'OPFUNCTION', meaning=>'exponential'); DefMathI('\gcd', undef,"gcd", role=>'OPFUNCTION', meaning=>'gcd', scriptpos=>\&doScriptpos); DefMathI('\hom', undef,"hom", role=>'OPFUNCTION'); DefMathI('\inf', undef,"inf", role=>'LIMITOP', meaning=>'infimum', scriptpos=>\&doScriptpos); DefMathI('\ker', undef,"ker", role=>'OPFUNCTION', meaning=>'kernel'); DefMathI('\lg', undef,"lg", role=>'OPFUNCTION'); DefMathI('\lim', undef,"lim", role=>'LIMITOP', meaning=>'limit', scriptpos=>\&doScriptpos); DefMathI('\liminf', undef,"lim inf", role=>'LIMITOP', meaning=>'limit-infimum', scriptpos=>\&doScriptpos); DefMathI('\limsup', undef,"lim sup", role=>'LIMITOP', meaning=>'limit-supremum', scriptpos=>\&doScriptpos); DefMathI('\ln', undef,"ln", role=>'OPFUNCTION', meaning=>'natural-logarithm'); DefMathI('\log', undef,"log", role=>'OPFUNCTION', meaning=>'logarithm'); DefMathI('\max', undef,"max", role=>'LIMITOP', meaning=>'maximum', scriptpos=>\&doScriptpos); DefMathI('\min', undef,"min", role=>'LIMITOP', meaning=>'minimum', scriptpos=>\&doScriptpos); DefMathI('\Pr', undef,"Pr", role=>'OPFUNCTION', scriptpos=>\&doScriptpos); DefMathI('\sec', undef,"sec", role=>'TRIGFUNCTION', meaning=>'secant'); DefMathI('\sin', undef,"sin", role=>'TRIGFUNCTION', meaning=>'sine'); DefMathI('\sinh', undef,"sinh", role=>'TRIGFUNCTION', meaning=>'hyperbolic-sine'); DefMathI('\sup', undef,"sup", role=>'LIMITOP', meaning=>'supremum', scriptpos=>\&doScriptpos); DefMathI('\tan', undef,"tan", role=>'TRIGFUNCTION', meaning=>'tangent'); DefMathI('\tanh', undef,"tanh", role=>'TRIGFUNCTION', meaning=>'hyperbolic-tangent'); #---------------------------------------------------------------------- # Modulo DefMath('\pmod{}', '\;\;(\textrm{mod} #1)', role=>'MODIFIER'); # , meaning=>'modulo'); DefMath('\bmod', 'mod', role=>'MODIFIEROP', meaning=>'modulo'); #====================================================================== # TeX Book, Appendix B. p. 362 DefMacro('\matrix{}', '\@@matrix{\@start@alignment#1\@finish@alignment}'); DefConstructor('\@@matrix{}', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix'}); }, reversion=>'\matrix{#1}', bounded=>1, beforeDigest=>sub { alignmentBindings(MatrixTemplate()); }); # TODO: This is wrong; I'm not even clear how this differs from \matrix DefMacro('\bordermatrix{}', '\@@bordermatrix{\@start@alignment#1\@finish@alignment}'); DefConstructor('\@@bordermatrix{}', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix'}); }, reversion=>'\bordermatrix{#1}', bounded=>1, beforeDigest=>sub { alignmentBindings(MatrixTemplate()); }); DefMacro('\pmatrix{}', '\@@pmatrix{\@start@alignment#1\@finish@alignment}'); DefConstructor('\@@pmatrix{}', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{name=>'Matrix', open=>'(',close=>')'}); }, reversion=>'\pmatrix{#1}', bounded=>1, beforeDigest=>sub { alignmentBindings(MatrixTemplate()); }); # Note that 2nd column in \cases is in text mode! DefMacro('\cases{}', '\@@cases{\@start@alignment#1\@finish@alignment}'); DefConstructor('\@@cases{}', sub { my($document,$body,%props)=@_; constructAlignment($document,$body,attributes=>{meaning=>'cases'}); }, reversion=>'\cases{#1}', bounded=>1, beforeDigest=>sub { my $col1 = {before=>Tokens(), after=>Tokens(T_CS('\hfil'))}; my $col2 = {before=>Tokens(T_CS('\hbox'),T_BEGIN), after=>Tokens(T_END,T_CS('\hfil'))}; alignmentBindings(LaTeXML::AlignmentTemplate->new(columns=>[$col1,$col2])); }); DefPrimitive('\openup Dimension',undef); # What should this do? (needs to work with alignments..) DefMacro('\displaylines{}','#1'); DefMacro('\eqalign{}', '\@@eqalign{\@start@alignment#1\@finish@alignment}'); DefConstructor('\@@eqalign{}', sub { my($document,$body,%props)=@_; constructAlignment($document,$body); }, reversion=>'\eqalign{#1}', bounded=>1, beforeDigest=>sub { alignmentBindings('rl'); }); DefMacro('\eqalignno{}', '\@@eqalignno{\@start@alignment#1\@finish@alignment}'); DefConstructor('\@@eqalignno{}', sub { my($document,$body,%props)=@_; constructAlignment($document,$body); }, reversion=>'\eqalignno{#1}', bounded=>1, beforeDigest=>sub { alignmentBindings('rll'); }); DefMacro('\leqalignno{}', '\@@leqalignno{\@start@alignment#1\@finish@alignment}'); DefConstructor('\@@leqalignno{}', sub { my($document,$body,%props)=@_; constructAlignment($document,$body); }, reversion=>'\leqalignno{#1}', bounded=>1, beforeDigest=>sub { alignmentBindings('rll'); }); DefRegister('\pageno'=>Number(0)); DefRegister('\headline'=>Tokens()); DefRegister('\footline'=>Tokens()); DefMacroI('\folio',undef, "1"); # What else? DefPrimitiveI('\nopagenumbers',undef,undef); DefMacroI('\advancepageno',undef,'\advance\pageno1\relax'); #====================================================================== # TeX Book, Appendix B. p. 363 DefPrimitive('\raggedbottom',undef); DefPrimitive('\normalbottom',undef); # if the mark is not simple, we add it to the content of the note # otherwise, to the attribute. DefConstructor('\footnote{}{}', "?#prenote(#prenote )()#2", afterDigest=>sub { my ($stomach, $whatsit) = @_; my $mark = $whatsit->getArg(1); my $change = 0; foreach my $token($mark->revert) { unless ($token->getCatcode == CC_LETTER || $token->getCatcode == CC_SPACE || $token->getCatcode == CC_OTHER) { $change = 1; last; }} $whatsit->setProperty(($change ? 'prenote' : 'mark')=>$mark); return; }); DefPrimitiveI('\footstrut', undef,undef); DefRegister('\footins'=>Dimension(0)); DefPrimitiveI('\topinsert', undef,undef); DefPrimitiveI('\midinsert', undef,undef); DefPrimitiveI('\pageinsert',undef,undef); DefPrimitiveI('\endinsert', undef,undef); # \topins ? #====================================================================== # TeX Book, Appendix B. p. 364 # Let's hope nobody is messing with the output routine... DefPrimitiveI('\footnoterule',undef,undef); DefPrimitiveI('\tracingall', undef,undef); #====================================================================== # End of TeX Book definitions. #====================================================================== #********************************************************************** # Stray stuff .... where to ? #********************************************************************** # Mostly ignorable, although it could add an attribute to an ancestor # to record the desired justification. # Spacing stuff DefConstructor('\@',''); # Math spacing. # Math style. DefConstructorI('\displaystyle', undef,'',afterDigest=>sub { AssignValue(mathstyle=>'display'); }); DefConstructorI('\textstyle', undef,'',afterDigest=>sub { AssignValue(mathstyle=>'text'); }); DefConstructorI('\scriptstyle', undef,'',afterDigest=>sub { AssignValue(mathstyle=>'script'); }); DefConstructorI('\scriptscriptstyle',undef,'',afterDigest=>sub { AssignValue(mathstyle=>'scriptscript'); }); #====================================================================== # Special Characters. DefConstructorI('\#',undef, '#'); DefConstructorI('\&', undef, '&'); DefMacroI('\%',undef,Tokens(T_OTHER('%'))); DefConstructorI("\\\$", undef,"\$"); DefConstructorI('\_', undef,'_'); # Discretionary times; just treat as invisible ? DefMathI('\*',undef,"\x{2062}", role=>'MULOP', name=>'', meaning=>'times'); # INVISIBLE TIMES (or MULTIPLICATION SIGN = 00D7) # These 3 should have some `name' assigned ... but what??? # NOTE that \mathord and \mathbin aren't really right here. # We need a finer granularity than TeX does: an ORD could be several things, # a BIN could be a MULOP or ADDOP. DefConstructor('\mathord{}',"#1", bounded=>1); # This is probably wrong.. #DefConstructor('\mathop{}', "#1", bounded=>1); DefConstructor('\mathop{}', "#1", bounded=>1); DefConstructor('\mathbin{}', "#1", bounded=>1); DefConstructor('\mathrel{}',"#1", bounded=>1); DefConstructor('\mathopen{}', "#1", bounded=>1); DefConstructor('\mathclose{}', "#1", bounded=>1); DefConstructor('\mathpunct{}', "#1", bounded=>1); DefMacro('\hiderel{}', "#1"); # Just ignore, for now... DefMathI('\to',undef,"\x{2192}", role=>'ARROW'); # RIGHTWARDS ARROW??? a bit more explicitly relation-like? # TeX's ligatures handled by rewrite regexps. DefLigature("/--/\x{2013}/", fontTest=>sub { $_[0]->getFamily ne 'typewriter'; }); # EN DASH (NOTE: With digits before & aft => \N{FIGURE DASH}) DefLigature("/---/\x{2014}/", fontTest=>sub { $_[0]->getFamily ne 'typewriter'; }); # EM DASH DefLigature("/\`\`/\x{201C}/", fontTest=>sub { $_[0]->getFamily ne 'typewriter'; }); DefLigature("/\'\'/\x{201D}/", fontTest=>sub { $_[0]->getFamily ne 'typewriter'; }); # This sorta seems like the normal effect, but not if fontenc is T1... ??? DefLigature("/\"/\x{201D}/", fontTest=>sub { $_[0]->getFamily ne 'typewriter'; }); # Yes, this one too! DefConstructorI('\TeX', undef,'TeX'); DefConstructorI('\i', undef,"\x{0131}"); # LATIN SMALL LETTER DOTLESS I DefConstructorI('\j', undef,"j"); # Apparently, no Unicode equivalent... DefConstructor('\buildrel Until:\over {}', "" . "" . "#2" . "#1" ."", properties=>{scriptpos=>sub{ "mid".$_[0]->getBoxingLevel; }}); #********************************************************************** # LaTeX Hook #********************************************************************** # This is used for plain TeX, but needs to be undone for LaTeX (or...)! RelaxNGSchema("LaTeXML"); Tag('ltx:section', autoClose=>1); Tag('ltx:document', autoClose=>1, autoOpen=>1); # No, \documentclass isn't really a primitive -- It's not even TeX! # But we define a number of stubs here that will automatically load # the LaTeX pool (which will presumably redefine them), and then # stuff the token back to be reexecuted. sub LaTeXTrigger { my($gullet,$cs)=@_; if(my $poolfile = FindFile("LaTeX.pool")){ $gullet->input($poolfile); } else { Fatal(":missing_file:LaTeX.pool.ltxml Installation error: Cannot find LaTeX pool module!"); } $gullet->unread(T_CS("\\".$cs)); (); } foreach my $trigger (qw(documentclass documentstyle newcommand renewcommand newenvironment renewenvironment NeedsTeXFormat ProvidesPackage RequirePackage makeatletter makeatother)){ DefMacroI("\\".$trigger, undef, sub { LaTeXTrigger($_[0],$trigger); }); } #********************************************************************** # LaTeXML Specific. # Support for Declarations & Presentation/Semantic Duality #********************************************************************** DefConstructor('\DUAL[]{}{}', "#2#3", reversion=>sub { my($whatsit)=@_; my($role,$content,$presentation)=$whatsit->getArgs; if(!$LaTeXML::DUAL_BRANCH) { $whatsit->getDefinition->invocation($role,$content, $presentation); } elsif($LaTeXML::DUAL_BRANCH eq 'content'){ $content->revert; } elsif($LaTeXML::DUAL_BRANCH eq 'presentation'){ $presentation->revert; } else{ Warn(":misdefined:$LaTeXML::DUAL_BRANCH Unknown DUAL_BRANCH: $LaTeXML::DUAL_BRANCH"); $whatsit->getDefinition->invocation($role,$content, $presentation); } }); sub addMeaningRec { my($document,$node,$meaning)=@_; if($node->nodeType == XML_ELEMENT_NODE){ if($document->getModel->getNodeQName($node) eq 'ltx:XMTok'){ if((($node->getAttribute('role')||'UNKNOWN') eq 'UNKNOWN') && !$node->getAttribute('meaning')){ $document->setAttribute($node,meaning=>$meaning); }} else { foreach my $c ($node->childNodes){ addMeaningRec($document,$c,$meaning); }}}} DefConstructor('\FCN{}', "#1", reversion=>'#1', alias=>''); DefConstructor('\ROLE{}{}', "#2", reversion=>'#2', alias=>''); # NOTE: work through this systematically! DefConstructor('\@SYMBOL{}', "#1", reversion=>'#1'); DefConstructor('\@APPLY{}', "#1", reversion=>'#1'); DefConstructor('\@MAYBEAPPLY{}{}', "?#2(#1#2)(#1)", reversion=>'#1#2'); DefConstructor('\@WRAP{}', "#1", reversion=>'#1'); DefConstructor('\@TOKEN{}', "", reversion=>''); DefMathI('\@APPLYFUNCTION', undef, "\x{2061}", reversion=>'', name=>'', role=>'APPLYOP'); DefMathI('\@INVISIBLETIMES',undef, "\x{2062}", reversion=>'', name=>'', meaning=>'times', role=>'MULOP'); DefMathI('\@INVISIBLECOMMA',undef, "\x{2063}", reversion=>'', name=>'', role=>'PUNCT'); # Would be nice to make the ID argument optional, but since these can appear in # optional arguments to other macros, we'll end up nesting [] !! DefConstructor('\@XMArg{}{}',"#2", reversion=>'#2', properties=>{id=>'#1'}, bounded=>1, beforeDigest=>sub { AssignValue(mathstyle=>'text') }); DefConstructor('\@XMRef{}',"", reversion=>sub{ my($whatsit)=@_; my $id = $_[0]->getArg(1); if(my $reversion = LookupValue('xref:'.ToString($id))){ $reversion->revert; } else { $whatsit->getDefinition->invocation($id); }}); DefConstructor('\@ERROR{}{}', "#2"); #********************************************************************** DefConstructorI('\WildCard', undef,"<_WildCard_/>"); DefConstructorI('\WildCardA',undef,"<_WildCard_/>"); DefConstructorI('\WildCardB',undef,"<_WildCard_/>"); DefConstructorI('\WildCardC',undef,"<_WildCard_/>"); #********************************************************************** # This constructor allows you to stick things in expansions for effect # but their reversion disappears, so they don't appear in the tex attribute (eg). DefConstructor('\@hidden{}','',reversion=>''); #********************************************************************** # After all other rewrites have acted, a little cleanup DefRewrite(xpath=>'descendant-or-self::ltx:XMWrap[count(child::*)=1]', replace=>sub { my($document,$wrap)=@_; if(my $node = $document->getFirstChildElement($wrap)){ foreach my $attribute ($wrap->attributes){ if($attribute->nodeType == XML_ATTRIBUTE_NODE){ my $attr = $attribute->nodeName; $document->setAttribute($node,$attr=>$attribute->getValue) unless $attr =~ /^_/; }} ## WHY THIS???? $document->getNode->appendChild($node); }}); #********************************************************************** 1; LaTeXML-0.7.0/lib/LaTeXML/Package/iopams.sty.ltxml0000644002506700454610000000733711214255161020543 0ustar miller891div# /====================================================================\ # | iopams.sty for LaTeXML | # | Generated by texscan --stub iopams.sty | # >====================================================================< # | Released to public domain. | # | Bruce Miller | # | http://dlmf.nist.gov/LaTeXML/ | # \====================================================================/ use strict; use LaTeXML::Package; RequirePackage('amsbsy'); RequirePackage('amsgen'); RequirePackage('amssymb'); RequirePackage('amsfonts'); DefMacroI('\balpha',undef,'\boldsymbol{\alpha}'); DefMacroI('\bbeta',undef,'\boldsymbol{\beta}'); DefMacroI('\bgamma',undef,'\boldsymbol{\gamma}'); DefMacroI('\bdelta',undef,'\boldsymbol{\delta}'); DefMacroI('\bepsilon',undef,'\boldsymbol{\epsilon}'); DefMacroI('\bzeta',undef,'\boldsymbol{\zeta}'); DefMacroI('\bfeta',undef,'\boldsymbol{\eta}'); DefMacroI('\btheta',undef,'\boldsymbol{\theta}'); DefMacroI('\biota',undef,'\boldsymbol{\iota}'); DefMacroI('\bkappa',undef,'\boldsymbol{\kappa}'); DefMacroI('\blambda',undef,'\boldsymbol{\lambda}'); DefMacroI('\bmu',undef,'\boldsymbol{\mu}'); DefMacroI('\bnu',undef,'\boldsymbol{\nu}'); DefMacroI('\bxi',undef,'\boldsymbol{\xi}'); DefMacroI('\bpi',undef,'\boldsymbol{\pi}'); DefMacroI('\brho',undef,'\boldsymbol{\rho}'); DefMacroI('\bsigma',undef,'\boldsymbol{\sigma}'); DefMacroI('\btau',undef,'\boldsymbol{\tau}'); DefMacroI('\bupsilon',undef,'\boldsymbol{\upsilon}'); DefMacroI('\bphi',undef,'\boldsymbol{\phi}'); DefMacroI('\bchi',undef,'\boldsymbol{\chi}'); DefMacroI('\bpsi',undef,'\boldsymbol{\psi}'); DefMacroI('\bomega',undef,'\boldsymbol{\omega}'); DefMacroI('\bvarepsilon',undef,'\boldsymbol{\varepsilon}'); DefMacroI('\bvartheta',undef,'\boldsymbol{\vartheta}'); DefMacroI('\bvaromega',undef,'\boldsymbol{\varomega}'); DefMacroI('\bvarymega',undef,'\boldsymbol{\varomega}'); DefMacroI('\bvarrho',undef,'\boldsymbol{\varrho}'); DefMacroI('\bvarzeta',undef,'\boldsymbol{\varsigma}'); # NB really sigma DefMacroI('\bvarsigma',undef,'\boldsymbol{\varsigma}'); DefMacroI('\bvarphi',undef,'\boldsymbol{\varphi}'); DefMacroI('\bGamma',undef,'\boldsymbol{\Gamma}'); DefMacroI('\bDelta',undef,'\boldsymbol{\Delta}'); DefMacroI('\bTheta',undef,'\boldsymbol{\Theta}'); DefMacroI('\bLambda',undef,'\boldsymbol{\Lambda}'); DefMacroI('\bXi',undef,'\boldsymbol{\Xi}'); DefMacroI('\bPi',undef,'\boldsymbol{\Pi}'); DefMacroI('\bSigma',undef,'\boldsymbol{\Sigma}'); DefMacroI('\bUpsilon',undef,'\boldsymbol{\Upsilon}'); DefMacroI('\bPhi',undef,'\boldsymbol{\Phi}'); DefMacroI('\bPsi',undef,'\boldsymbol{\Psi}'); DefMacroI('\bOmega',undef,'\boldsymbol{\Omega}'); DefMacroI('\bpartial',undef,'\boldsymbol{\partial}'); DefMacroI('\bell',undef,'\boldsymbol{\ell}'); DefMacroI('\bimath',undef,'\boldsymbol{\imath}'); DefMacroI('\bjmath',undef,'\boldsymbol{\jmath}'); DefMacroI('\binfty',undef,'\boldsymbol{\infty}'); DefMacroI('\bnabla',undef,'\boldsymbol{\nabla}'); DefMacroI('\bdot',undef,'\boldsymbol{\cdot}'); DefConstructorI('\opencircle', undef,"\x{25CB}"); DefConstructorI('\opensquare', undef,"\x{25A1}"); DefConstructorI('\opentriangle', undef,"\x{25B3}"); DefConstructorI('\opentriangledown',undef,"\x{25BD}"); DefConstructorI('\opendiamond', undef,"\x{25C7}"); DefConstructorI('\fullcircle', undef,"\x{25CF}"); DefConstructorI('\fullsquare', undef,"\x{25A0}"); DefConstructorI('\fulldiamond', undef,"\x{25C6}"); DefConstructorI('\fullstar', undef,"\x{2605}"); DefConstructorI('\fulltriangle', undef,"\x{25B2}"); DefConstructorI('\fulltriangledown',undef,"\x{25BC}"); 1; LaTeXML-0.7.0/lib/LaTeXML/Package/psfig.sty.ltxml0000644002506700454610000000223211214255161020350 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | psfig | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # # (See LaTeXML::Post::Graphics for suggested postprocessing) package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; #********************************************************************** # Is this close enough? RequirePackage('epsfig'); #********************************************************************** 1; LaTeXML-0.7.0/lib/LaTeXML/Package/eurosym.sty.ltxml0000644002506700454610000000305411214255161020746 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | eurosym.sty - Implementation for LaTeXML | # # | | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Catalin David | # # | http://dlmf.nist.gov/LaTeXML/ | # # \=====================================================================/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; RawTeX('\newif\if@EURleft'); DeclareOption('left', '\@EURlefttrue'); DeclareOption('right', '\@EURleftfalse'); DeclareOption('official', undef); DeclareOption('gen', undef); DeclareOption('gennorrow',undef); DeclareOption('genwide', undef); ProcessOptions(); DefMacro('\EUR{}','{\if@EURleft\euro\,\fi#1\if@EURleft\else\,\euro\fi}'); # People shouldn't be using these, but let's at least avoid errors. DefMacro('\eurobars',''); DefMacro('\eurobarsnarrow',''); DefMacro('\eurobarswide',''); DefMacro('\geneuro',''); DefMacro('\geneuronarrow',''); DefMacro('\geneurowide',''); DefMacro('\officialeuro', "\x{20AC}"); Let('\euro', '\officialeuro'); 1; LaTeXML-0.7.0/lib/LaTeXML/Package/tocbibind.sty.ltxml0000644002506700454610000000226411215766021021205 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | tocbibind | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # use strict; use LaTeXML::Package; #********************************************************************** # I'm inclined to think there's nothing to do here! #********************************************************************** foreach my $option (qw(notbib notindex nottoc notlof notlot)){ DeclareOption($option, undef); } ProcessOptions(); 1; LaTeXML-0.7.0/lib/LaTeXML/Package/fixltx2e.sty.ltxml0000644002506700454610000000220111214255161021001 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | fixltx2e | # # | Core TeX Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; # This package allows you to define the font used for # emphasis (\emph) within emphasis. # For latexml, that styling should be left to the ultimate output, # so we just define the command as a dummy. DefMacro('\eminnershape',""); 1; LaTeXML-0.7.0/lib/LaTeXML/Package/amsxtra.sty.ltxml0000644002506700454610000000302411214255161020717 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | amsmath | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # use strict; use LaTeXML::Package; #********************************************************************** # See amsldoc DefMacro('\sphat',Tokens(T_SUPER,T_OTHER('^'))); DefMacro('\spcheck','^{\vee}'); DefMacro('\sptilde',Tokens(T_SUPER,T_OTHER('~'))); DefMacro('\spdot','^{\dot}'); DefMacro('\spddot','^{\dot\dot}'); DefMacro('\spdddot','^{\dot\dot\dot}'); DefMacro('\spbreve','^{\smile}'); # close enough? # Oh what the heck... DefMacro('\fracwithdelims[]{}{}{}{}','#2\frac{#4}{#5}#3'); # I can't quite figure out what the point of this one is, # and can't find documentation. DefMacro('\accentedsymbol{}{}','\def\#1{$#2}'); #********************************************************************** 1; LaTeXML-0.7.0/lib/LaTeXML/Package/amsfonts.sty.ltxml0000644002506700454610000000542211214255161021076 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | amsfonts | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # # # See amsfndoc package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; # DefConstructor('\mathbb{}', '#1', bounded=>1, requireMath=>1, font=>{family=>'blackboard'}); DefMacro('\Bbb{}','\mathbb{#1}'); DefMacro('\bold{}','\mathbb{#1}'); # Also defined in eufrak DefConstructor('\mathfrak{}','#1', bounded=>1, requireMath=>1, font=>{family=>'fraktur'}); DefMacro('\frak{}','\mathfrak{#1}'); # Not necessarily math DefConstructor('\checkmark',"\x{2713}"); # CHECK MARK DefConstructor('\circledR',UTF(0xAE)); # REGISTERED SIGN DefConstructor('\maltese',"\x{2720}"); # MALTESE CROSs DefConstructor('\yen',UTF(0xA5)); # YEN SIGN # Math # These are delimiters, but open or close?? DefMath('\ulcorner',"\x{231C}"); # TOP LEFT CORNER DefMath('\urcorner',"\x{231D}"); # TOP RIGHT CORNER DefMath('\llcorner',"\x{231E}"); # BOTTOM LEFT CORNER DefMath('\lrcorner',"\x{231F}"); # BOTTOM RIGHT CORNER DefMath('\dashrightarrow',"\x{21E2}", role=>'ARROW'); # RIGHTWARDS DASHED ARROW DefMath('\dashleftarrow', "\x{21E0}", role=>'ARROW'); # LEFTWARDS DASHED ARROW DefMath('\dasharrow', "\x{21E2}", role=>'ARROW'); # RIGHTWARDS DASHED ARROW DefMath('\square',"\x{25A1}"); # WHITE SQUARE DefMath('\lozenge',"\x{25C6}"); # WHITE DIAMOND DefMath('\vartriangleright',"\x{22B3}"); # CONTAINS AS NORMAL SUBGROUP (\rhd) DefMath('\vartriangleleft',"\x{22B2}"); # NORMAL SUBGROUP OF (\lhd) DefMath('\trianglerighteq',"\x{22B5}"); # CONTAINS AS NORMAL SUBGROUP OR EQUAL TO (\unrhd) DefMath('\trianglelefteq',"\x{22B4}"); # NORMAL SUBGROUP OF OR EQUAL TO (\unlhd) DefMath('\rightsquigarrow',"\x{219D}", role=>'ARROW'); # RIGHTWARDS WAVE ARROW # amsfonts redefines various symbols already in TeX & LaTeX # \widehat, \widetilde, \rightleftharpoons,\angle # \hbar, \sqsubset, \sqsupset, \mho # amsfonts also redefines these, unless latexsym is loaded. # However, all these are already defined in TeX (from plain?) # \Box, \Diamond, \leadsto, \lhd, \unlhd, \rhd, \unrhd 1; LaTeXML-0.7.0/lib/LaTeXML/Package/revtex4_support.sty.ltxml0000644002506700454610000003043011214255161022436 0ustar miller891div# -*- CPERL -*- # /======================================================= # # | revtex4_support.sty - Implementation for LaTeXML | # # | | # # |=======================================================| # # | Part of LaTeXML : http://dlmf.nist.gov/LaTeXML/ | # # | Copyright (c) 2008 arXMLiv group | # # | Catalin David | # # | Released to Public Domain | # # =======================================================/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; RequirePackage('hyperref'); RequirePackage('natbib'); # not necessarily loaded? RequirePackage('revsymb'); RequirePackage('url'); RequirePackage('longtable'); # Not sure this strictly required RequirePackage('dcolumn'); # Aligned to RevTeX4 Authors guide (auguide) #====================================================================== # 4. The Front Matter #====================================================================== # 4.3 DefMacro('\title[]{}', '\@add@frontmatter{ltx:title}{#2}'); DefMacro('\doauthor{}{}{}','#1 #2 #3'); # -- ?? DefMacro('\address','\affiliation'); # DefMacro('\affiliation',''); DefConstructor('\@affiliation{}',"^ #1"); DefMacro('\affiliation{}','\@add@to@frontmatter{ltx:creator}{\@affiliation{#1}}'); DefMacro('\altaddress','\altaffiliation'); DefMacro('\altaffiliation','\affiliation'); DefMacro('\andname','and'); DefMacro('\collaboration',''); # Should have a look at this too DefMacro('\noaffiliation', Tokens()); DefConstructor('\@email{}',"^ #1"); DefMacro('\email [] Semiverbatim', '\@add@to@frontmatter{ltx:creator}{\@email{#2}}'); DefConstructor('\@homepage{}',"^ #1"); DefMacro('\homepage Semiverbatim','\@add@to@frontmatter{ltx:creator}{\@homepage{#1}}'); DefMacro('\firstname',''); # \let\firstname\@firstofone ?? DefConstructor('\surname{}',"#1"); # 4.4 DefMacro('\abstractname','Abstract'); # 4.5 DefMacro('\pacs{}','\@add@frontmatter{ltx:classification}[scheme=pacs]{#1}'); # 4.6 DefMacro('\keywords{}','\@add@frontmatter{ltx:keywords}{#1}'); # 4.7 DefMacro('\preprint{}', undef); # Extra stuff DefMacro('\blankaffiliation',''); DefMacro('\checkindate','\today'); DefMacro('\received[]{}', '\@add@frontmatter{ltx:date}[role=received]{#2}'); DefMacro('\revised[]{}', '\@add@frontmatter{ltx:date}[role=revised]{#2}'); DefMacro('\accepted[]{}', '\@add@frontmatter{ltx:date}[role=accepted]{#2}'); DefMacro('\published[]{}','\@add@frontmatter{ltx:date}[role=published]{#2}'); #====================================================================== # 5. The body of the paper #====================================================================== # 5.3 DefMacro('\widetext', ''); DefMacro('\endwidetext', ''); # These are called obsolete, but I can't even find them in earlier RevTeX's! DefMacro('\narrowtext',''); DefMacro('\endnarrowtext',''); DefMacro('\mediumtext',''); DefMacro('\endmediumtext',''); # 5.5 # Normally, we'd define the acknowledgements environment simply as: # DefEnvironment('{acknowledgements}', # "#body"); # However, people seem to insist on "misusing" it, by just saying # \acknowledgements... which actually "works". # So, we just open it, and let it autoclose. DefConstructor('\acknowledgements',""); DefConstructor('\acknowledgments', ""); DefConstructor('\endacknowledgements',""); DefConstructor('\endacknowledgments', ""); Tag("ltx:acknowledgements", autoClose=>1); DefMacro('\acknowledgmentsname','Acknowledgements'); # Extra stuff DefMacro('\thesection','\Roman{section}'); # Apparently the desired style. DefMacro('\thepagegrid','one'); DefMacro('\onecolumngrid',''); DefMacro('\twocolumngrid',''); DefMacro('\restorecolumngrid',''); DefPrimitive('\twocolumn', undef); DefConstructor('\rotatebox{Number}{}','#2'); # dummy defn, unless graphics loaded DefMacro('\pagesofar',''); DefConstructor('\endnote[]{}', "#2", mode=>'text', properties=> sub { ($_[1] ? (refnum=>$_[1]) : RefStepCounter('footnote')) }); ## DefConstructor('\endnotemark[]',""); DefConstructor('\endnotetext[]{}', "#2", mode=>'text'); #====================================================================== # 6. Math and Equations #====================================================================== # 6.5 # recommends amsmath's {subequations} # Extra stuff Let('\case','\frac'); Let('\slantfrac','\frac'); DefConstructor('\text{}', "#1", mode=>'text'); # RevTeX3 (obsolete in RevTeX4) DefConstructor('\bm{}', '#1', bounded=>1, requireMath=>1, font=>{forcebold=>1}); DefConstructor('\bbox{}', '#1', bounded=>1, requireMath=>1, font=>{forcebold=>1}); DefConstructor('\pmb{}', '#1', bounded=>1, requireMath=>1, font=>{forcebold=>1, family=>'blackboard'}); DefConstructor('\eqnum {}', '', afterDigest=>sub { AssignValue(EQUATIONROW_NUMBER=>ToString($_[1]), 'global'); }, mode=>'text'); # Redefined in revtex3_support DefMacro('\mathletters',''); DefMacro('\endmathletters',''); #====================================================================== # 7. Footnotes #====================================================================== #====================================================================== # 8. Citations and References #====================================================================== DefMacro('\onlinecite','\citealp'); Let('\textcite','\citet'); # RevTeX3; Obsolete for RevTeX4 (but semi-implemented there) # Should be a simple environment, but tends to be misused, so define separately DefConstructor('\references', "" . "#refname" . "", afterDigest=>sub { my $docid = ToString(Expand(T_CS('\thedocument@ID'))); ResetCounter('enumiv'); DefMacroI(T_CS('\thebibliography@ID'),undef,($docid ? "$docid.bib" : 'bib')); $_[1]->setProperty(id=>ToString(Expand(T_CS('\thebibliography@ID')))); $_[1]->setProperty(refname=>Digest(T_CS('\refname'))); # Fix for missing \bibitems! setupPseudoBibitem(); }); DefConstructor('\endreferences', ""); # bibliography and biblist are already set as autoClose. #====================================================================== # 9. Figures and Artwork #====================================================================== #====================================================================== # 10. Tables #====================================================================== # Used to put double rules before & after a tabular. DefEnvironment('{ruledtabular}','#body'); # No idea what this is really for, but this seems to be the jist of it. DefEnvironment('{quasitable}','#body', beforeDigest=>sub { Let(T_CS("\\begin{tabular}"),T_CS("\\begin{longtable}")); Let(T_CS("\\end{tabular}"), T_CS("\\end{longtable}")); Let(T_CS("\\tabular"), T_CS("\\longtable")); Let(T_CS("\\endtabular"), T_CS("\\endlongtable")); }); DefMacro('\squeezetable',''); #presentational # Extra stuff DefMacro('\toprule', '\hline\hline'); DefMacro('\colrule','\hline'); DefMacro('\botrule','\hline\hline'); DefMacro('\frstrut',''); DefMacro('\lrstrut',''); Let('\tableftsep','\tabcolsep'); Let('\tabmidsep','\tabcolsep'); Let('\tabrightsep','\tabcolsep'); Let(T_CS('\tablenote'),T_CS('\footnote')); Let(T_CS('\tablenotemark'),T_CS('\footnotemark')); Let(T_CS('\tablenotetext'),T_CS('\footnotetext')); # RevTeX3 (obsolete in RevTeX4) Let('\tableline','\colrule'); # This seems to be implied. RawTeX('\newcolumntype{d}{D{.}{.}{-1}}'); #====================================================================== # 11. Placement of Figures, Tables and Other Floats #====================================================================== DefPrimitive('\printfigures OptionalMatch:*',undef); DefPrimitive('\printtables OptionalMatch:*',undef); DefMacro('\oneapage',''); DefMacro('\printendnotes',''); #====================================================================== # 12. Rotating Floats #====================================================================== # Rotates the page DefEnvironment('{turnpage}','#body'); #====================================================================== # 13. RevTeX 4 symbols and the revsymb package #====================================================================== #====================================================================== # 14. Other RevTeX 4 Features #====================================================================== #====================================================================== # XX. Extra stuff #====================================================================== Let(T_CS('\MakeTextLowercase'), T_CS('\lowercase')); Let(T_CS('\MakeTextUppercase'),T_CS('\uppercase')); DefMacro('\NoCaseChange',''); # Macro & Control stuff. # Are these really intended for authors to use? DefMacro('\absbox',''); #what does \newbox\absbox mean? DefMacro('\addstuff{}{}',''); DefMacro('\appdef{}{}',''); DefMacro('\gappdef{}{}',''); DefMacro('\prepdef{}{}',''); DefMacro('\lineloop{}',''); DefMacro('\loopuntil{}',''); DefMacro('\loopwhile{}',''); DefMacro('\traceoutput', ''); DefMacro('\tracingplain', ''); DefMacro('\removephantombox',''); DefMacro('\removestuff',''); DefMacro('\replacestuff{}{}',''); DefMacro('\say[]', '\typeout{<\noexpand#1=\meaning#1>}'); DefMacro('\saythe[]','\typeout{<\noexpand#1=\the#1>}'); # Various extra i18n stuff. DefMacro('\copyrightname','??'); # ?? is that ok? that is what the .sty says, but... DefMacro('\journalname','??'); DefMacro('\lofname','List of Figures'); DefMacro('\lotname','List of Tables'); DefMacro('\notesname','Notes'); DefMacro('\numbername','number'); DefMacro('\ppname','pp'); DefMacro('\tocname','Contents'); DefMacro('\volumename','volume'); # Apparently some sort of document information? DefMacro('\volumenumber{}','#1'); DefMacro('\volumeyear{}','#1'); DefMacro('\issuenumber{}','#1'); DefMacro('\bibinfo{}{}','#2'); DefMacro('\eprint{}','eprint #1'); DefMacro('\eid{}','#1'); DefMacro('\startpage{}','\pageref{FirstPage}{#1}'); DefMacro('\endpage', '\pageref{LastPage}{#1}'); # Other pointless stuff. DefMacro('\flushing',''); DefMacro('\triggerpar','\par'); DefMacro('\fullinterlineskip',''); DefRegister('\footbox'=>LaTeXML::Box->new()); DefRegister('\intertabularlinepenalty'=>Number('100')); # These are called obsolete, but I can't even find them in earlier RevTeX's! DefMacro('\FL',''); DefMacro('\FR',''); DefMacro('\draft',''); DefMacro('\tighten', ''); #====================================================================== # The following really should only be defined for aps substyles # which include pra, etc. # I'll just define them all, and hope for no conflicts(?) DefMacro('\ao', 'Appl.~Opt.~'); DefMacro('\ap', 'Appl.~Phys.~'); DefMacro('\apl', 'Appl.~Phys.~Lett.~'); DefMacro('\apj', 'Astrophys.~J.~'); DefMacro('\bell', 'Bell Syst.~Tech.~J.~'); DefMacro('\jqe', 'IEEE J.~Quantum Electron.~'); DefMacro('\assp', 'IEEE Trans.~Acoust.~Speech Signal Process.~'); DefMacro('\aprop','IEEE Trans.~Antennas Propag.~'); DefMacro('\mtt', 'IEEE Trans.~Microwave Theory Tech.~'); DefMacro('\iovs', 'Invest.~Opthalmol.~Vis.~Sci.~'); DefMacro('\jcp', 'J.~Chem.~Phys.~'); DefMacro('\jmo', 'J.~Mod.~Opt.~'); DefMacro('\josa', 'J.~Opt.~Soc.~Am.~'); DefMacro('\josaa','J.~Opt.~Soc.~Am.~A '); DefMacro('\josab','J.~Opt.~Soc.~Am.~B '); DefMacro('\jpp', 'J.~Phys.~(Paris) '); DefMacro('\nat', 'Nature (London) '); DefMacro('\oc', 'Opt.~Commun.~'); DefMacro('\ol', 'Opt.~Lett.~'); DefMacro('\pl', 'Phys.~Lett.~'); DefMacro('\pra', 'Phys.~Rev.~A '); DefMacro('\prb', 'Phys.~Rev.~B '); DefMacro('\prc', 'Phys.~Rev.~C '); DefMacro('\prd', 'Phys.~Rev.~D '); DefMacro('\pre', 'Phys.~Rev.~E '); DefMacro('\prl', 'Phys.~Rev.~Lett.~'); DefMacro('\rmp', 'Rev.~Mod.~Phys.~'); DefMacro('\pspie','Proc.~Soc.~Photo-Opt.~Instrum.~Eng.~'); DefMacro('\sjqe', 'Sov.~J.~Quantum Elecron.~'); DefMacro('\vr', 'Vision Res.~'); #====================================================================== 1; LaTeXML-0.7.0/lib/LaTeXML/Package/elsart.sty.ltxml0000644002506700454610000000206311214255161020534 0ustar miller891div# /====================================================================\ # | elsart.sty for LaTeXML | # | Generated by texscan --stub --base=article.cls elsart.cls | # >====================================================================< # | Released to public domain. | # | Bruce Miller | # | http://dlmf.nist.gov/LaTeXML/ | # \====================================================================/ use strict; use LaTeXML::Package; # Generally ignorable options foreach my $option (qw(12pt 11pt 10pt oneside twoside onecolumn twocolumn symbold ussrhead nameyear doublespacing reviewcopy)){ DeclareOption($option, undef); } DeclareOption("seceqn", sub { AssignValue('@seceqn'=>1); }); DeclareOption("secthm", sub { AssignValue('@secthm'=>1); }); DeclareOption("amsthm", sub { AssignValue('@amsthm'=>1); }); ProcessOptions(); RequirePackage('elsart_support'); 1; LaTeXML-0.7.0/lib/LaTeXML/Package/gen-j-l.cls.ltxml0000644002506700454610000000210711214255161020434 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | gen-j-l | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # / Thanks to the arXMLiv group for # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; # Generic AMS Journal LoadClass('amsart', withoptions=>1); 1; LaTeXML-0.7.0/lib/LaTeXML/Package/yfonts.sty.ltxml0000644002506700454610000000323411214255161020565 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | yfonts | # # | Implementation for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package::Pool; use strict; use LaTeXML::Package; # # Not much to do for LaTeXML. DefConstructor('\frakfamily', '', font=>{family=>'fraktur'}); # These font families are otherwise unrecognized... DefConstructor('\swabfamily', '', font=>{family=>'schwabacher'}); DefConstructor('\gothfamily', '', font=>{family=>'gothic'}); # SHOULD set up fancy initials... DefMacro('\initfamily',''); DefPrimitive('\fraklines',undef); DefConstructor('\yinipar{}','\par\noindent\yinitpar{#1}'); # SHOULD set the initial in fancy font. DefConstructor('\yinitpar{}','#1'); # Nothing likely to every be used, but for completeness... DefMacro('\gothdefault','ygoth'); DefMacro('\swabdefault','yswab'); DefMacro('\frakdefault','yfrak'); DefMacro('\initdefault','yinitas'); Let('\grq','\textquoteleft'); Let('\grqq','\textquotedblleft'); 1; LaTeXML-0.7.0/lib/LaTeXML/Package/svmult.cls.ltxml0000644002506700454610000001216511214255161020542 0ustar miller891div# /====================================================================\ # | svmult.cls for LaTeXML | # | Generated by texscan --stub --base=article.cls svjour2.cls | # >====================================================================< # | Released to public domain. | # | Bruce Miller | # | http://dlmf.nist.gov/LaTeXML/ | # \====================================================================/ use strict; use LaTeXML::Package; #====================================================================== foreach my $option (qw(nospthms vecphys vecarrow norunningheads referee openbib oribibl chaprefs footinfo openany 10pt 11pt 12pt twoside fleqn sechang deutsch francais), # These could affect numbering... qw(numart book envcountresetchap envcountresetsect envcountsame envcountchap envcountresetsect envcountresetchap), qw(natbib)){ DeclareOption($option, undef); } # Other options could load sv
Abstract.
Acknowledgements.
Keywords:
Classification :
6 Chapter § Appendix § § 6 6 .
  • LaTeXML-0.7.0/lib/LaTeXML/style/LaTeXML-inline-xhtml.xsl0000644002506700454610000000736411214255162021525 0ustar miller891div  
    LaTeXML-0.7.0/lib/LaTeXML/style/navbar-right.css0000644002506700454610000000042011214255162020241 0ustar miller891div/* CSS for left navigation bar */ .navbar { display:block!important; position:fixed; left:80%; top:0px; width:20%; margin:0em; padding:1em; font: bold 75% sans-serif; } .navbar ul { margin-left:-2em; } .main { margin:0px; padding:1em 3em 1em 2em; width:75%; } LaTeXML-0.7.0/lib/LaTeXML/style/LaTeXML-picture-image.xsl0000644002506700454610000000233111214255162021635 0ustar miller891div {@tex} LaTeXML-0.7.0/lib/LaTeXML/style/amsart.css0000644002506700454610000000043511214255162017152 0ustar miller891div/* A somewhat amsart-like style */ h1, h2, h3, h4, h5, h6, .author .authorname { font-family:serif; font-variant:small-caps;} .author { font-family:serif; } h1, h2, h3 { text-align:center; color:#700303; } .para > p:first-child { text-indent: 2em; } p { text-align:justify; } LaTeXML-0.7.0/lib/LaTeXML/style/LaTeXML-webpage-xhtml.xsl0000644002506700454610000001632411214255162021655 0ustar miller891div 0 <xsl:value-of select="normalize-space(*/ltx:title)"/> <xsl:for-each select="//ltx:navigation/ltx:ref[@class='up']" > in <xsl:value-of select="@title"/></xsl:for-each> ,
    Appendices
    Contents
  • LaTeXML-0.7.0/lib/LaTeXML/style/LaTeXML-block-xhtml.xsl0000644002506700454610000005216011215766021021335 0ustar miller891div


    ()
  • {f:if(../ltx:figure/ltx:caption,../ltx:figure/ltx:caption/text(),@description)}
    LaTeXML-0.7.0/lib/LaTeXML/style/core.css0000644002506700454610000001177311215766021016624 0ustar miller891div/*====================================================================== Core CSS for LaTeXML documents converted to (X)HTML */ /* Generic Page layout */ /* Header & footer */ /*.header:before { content:url(latexml.png); }*/ .header,.footer { font-size:80%; } .header .previous, .footer .previous { float:left; } .header .up, .footer { display:block; text-align:center; } .header .next, .footer .next { float:right; } .header li { padding:0.1em 0.2em 0.1em 1em;} /* Main content */ .content { clear:both; padding-top:5px; border-top:1px solid; } .footer { margin-top:5px; border-top:1px solid; } /* if shown */ .navbar .toc li { margin-left:-0.5em; } .navbar li { white-space:nowrap; display:block; overflow:hidden; } .navbar li .here { white-space:normal; overflow:visible; } /*====================================================================== Titles & Frontmatter */ h1 { text-align:center; font-size: 150%; font-family:sans-serif;} h2 { font-family:sans-serif; padding-left:0.2em; margin-left:-0.5em; } h3 { font-family:sans-serif; padding-left:0.2em; margin-left:-0.3em; } /* h6 { display:run-in; }*/ /* Hack to simulate run-in! */ h6 { display:inline; font-size:100%; font-family:sans-serif; } h6:after { content:" "; } h6 + div.para, h6 + p { display:inline; } .subtitle { text-align:center; font-size: 120%; font-family:sans-serif; padding-left:0.2em; margin-left:-0.5em; } .author { text-align:center; font-family:sans-serif; } .author .personname { font-size: 130%; } .dedicatory { font-style:oblique; } .classification, .keywords { font-size:90%; margin-left:4em; } .abstract { margin:1em 4em 1em 4em; } .toc li { list-style-type:none; } .navbar { display: none; } /* override! */ .main { margin:0px; padding:1em 3em 1em 2em; } /*====================================================================== Blocks, Lists, Floats */ .inline-block { display:inline-block; } img.math { vertical-align:middle } div.equation { display:block; width:95%; text-align:center; } .equation span.refnum.left { position:absolute; left:2em; } .equation span.refnum.right { position:absolute; right:2em; } .equation td { width:auto; } table.equation, table.equationgroup { width:100%; } /* Hide this from IE */ tr > td.eqpad { width:50%; } dl.description dt { margin-right:0.5em; float:left; font-weight:bold; font-size:95%; } dl.description dd { margin-left:5em; } dl.description dl.description dd { margin-left:3em; } .theorem {margin:1em 0em 1em 0em; } .bibliography dt { margin-right:0.5em; float:left; } .bibliography dd { margin-left:3em; } .biblist { list-style-type:none; } .bibitem-tag { font-weight:bold; margin-left:-2em; width:3em; } /*.bibitem-tag + div { display:inline; }*/ .indexlist li { list-style-type:none; } .indexlist { margin-left:1em; padding-left:1em;} .listing td.linenumber, .listingblock td.linenumber { width:3em; text-align:right;} /*====================================================================== Borders and such */ .framed { border:1px solid black;} .tabular td, .tabular th { padding:0.1em 0.5em; } table { border-collapse:collapse; } /* Hmm... the star should be m:mtd */ td.t, th.t, *[class~="t"] { border-top:1px solid black; } td.r, th.r, *[class~="r"] { border-right:1px solid black; } td.b, th.b, *[class~="b"] { border-bottom:1px solid black; } td.l, th.l, *[class~="l"] { border-left:1px solid black; } td.th, th.tt, *[class~="tt"] { border-top:3px double black; } td.rr, th.rr, *[class~="rr"] { border-right:3px double black; } td.bb, th.bb, *[class~="bb"] { border-bottom:3px double black; } td.ll, th.ll, *[class~="ll"] { border-left:3px double black; } td[align="left"], th[align="left"], td[align="right"], th[align="right"], td[align="center"], th[align="center"] { white-space:nowrap; } /*====================================================================== Low-level Basics */ .TINY { font-size:50%; } .Tiny { font-size:60%; } .tiny { font-size:65%; } .script { font-size:70%; } .footnote { font-size:80%; } .small { font-size:90%; } .normal { font-size:100%; } .large { font-size:110%; } .Large { font-size:120%; } .LARGE { font-size:140%; } .huge { font-size:150%; } .Huge { font-size:170%; } .HUGE { font-size:200%; } .sansserif { font-family: sans-serif; } .typewriter { font-family: monospace; } .bold { font-weight: bold; } .medium { font-weight: normal; } .italic { font-style: italic; } .upright { font-style: normal; } .slanted { font-style: oblique; } .red { color:red; } .centering { text-align:center; } .flushleft { text-align:left; } .flushright { text-align:right; } .ERROR { color:red; } cite { font-style: normal; } /*====================================================================== pop-up footnotes */ .note .note_content {display:none; } .note .mark { color:blue; } .note:hover .note_content { display:block; position:absolute; z-index:10; width: 70%; right:5%; background:#E0E0E0; border:3px outset gray; } LaTeXML-0.7.0/lib/LaTeXML/style/LaTeXML-common.xsl0000644002506700454610000001012211214255162020367 0ustar miller891div LaTeXML-0.7.0/lib/LaTeXML/style/navbar-left.css0000644002506700454610000000054611214255162020067 0ustar miller891div/* CSS for left navigation bar */ .navbar { display:block!important; position:fixed; left:0px; top:0px; width:170px; margin:0em; padding:1em; font: bold 75% sans-serif; border: 3px double; } .navbar ul { margin-left:-2em; } .main { position:absolute; left:190px; top:0px; right:2px; margin:0px; padding:1em 3em 1em 2em; width:70%; } LaTeXML-0.7.0/lib/LaTeXML/Rewrite.pm0000644002506700454610000004077611214255167016011 0ustar miller891div# /=====================================================================\ # # | LaTeXML::Rewrite | # # | Rewrite Rules that modify the Constructed Document | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # #====================================================================== package LaTeXML::Rewrite; use strict; use LaTeXML::Global; sub new { my($class,$mode,@specs)=@_; my @clauses = (); while(@specs){ my($op,$pattern) = (shift(@specs),shift(@specs)); push(@clauses,['uncompiled',$op,$pattern]); } bless {mode=>$mode, math=>($mode eq 'math'), clauses=>[@clauses], labels=>{}}, $class; } sub clauses { @{$_[0]->{clauses}}; } sub rewrite { my($self,$document,$node)=@_; foreach my $node ($document->findnodes('//*[@labels]')){ my $labels = $node->getAttribute('labels'); if(my $id = $node->getAttribute('xml:id')){ foreach my $label (split(/ /,$labels)){ $$self{labels}{$label}=$id; }} else { Warn(":malformed Node has labels \"$labels\" but no xml:id ".Stringify($node)); }} $self->applyClause($document,$node,0,$self->clauses); } sub getLabelID { my($self,$label)=@_; if(my $id = $$self{labels}{LaTeXML::Package::CleanLabel($label)}){ $id; } else { Error(":malformed: No id for label $label in Rewrite"); undef; }} # Rewrite spec as input # scope => $scope : a scope like "section:1.2.3" or "label:eq.one"; translated to xpath # select => $xpath : selects subtrees based on xpath expression. # match => $code : called on $document and current $node: tests current node, returns $nnodes, if match # match => $string : Treats as TeX, converts Box, then DOM tree, to xpath # (The matching top-level nodes will be replaced, if replace is the next op.) # replace=> $code : removes the current $nnodes, calls $code with $document and removed nodes # replace=> $string : removes $nnodes # Treats $string as TeX, converts to Box and inserts to replace # the removed nodes. # attributes=>$hash : adds data from hash as attributes to the current node. # regexp => $string: apply regexp (subst) to all text nodes in/under the current node. # Compiled rewrite spec: # select => $xpath : operate on nodes selected by $xpath. # test => $code : Calls $code on $document and current $node. # Returns number of nodes matched. # replace=> $code : removes the current $nnodes, calls $code on them. # action => $code : invoke $code on current $node, without removing them. # regexp => $string: apply regexp (subst) to all text nodes in/under the current node. sub applyClause { my($self,$document,$tree,$n_to_replace,$clause,@more_clauses)=@_; if($$clause[0] eq 'uncompiled'){ $self->compileClause($document,$clause); } my($ignore,$op,$pattern)=@$clause; if($op eq 'trace'){ local $LaTeXML::Rewrite::DEBUG = 1; $self->applyClause($document,$tree,$n_to_replace,@more_clauses); } elsif($op eq 'ignore'){ $self->applyClause($document,$tree,$n_to_replace,@more_clauses); } elsif($op eq 'select'){ my($xpath,$nnodes)=@$pattern; my @matches = $document->findnodes($xpath,$tree); print STDERR "Rewrite selecting \"$xpath\" => ".scalar(@matches)." matches\n" if $LaTeXML::Rewrite::DEBUG; foreach my $node (@matches){ next unless $node->ownerDocument->isSameNode($tree->ownerDocument); # If still attached to original document! $self->applyClause($document,$node,$nnodes,@more_clauses); }} elsif($op eq 'multi_select'){ foreach my $subpattern (@$pattern){ my($xpath,$nnodes)=@$subpattern; my @matches = $document->findnodes($xpath,$tree); print STDERR "Rewrite selecting \"$xpath\" => ".scalar(@matches)." matches\n" if $LaTeXML::Rewrite::DEBUG; foreach my $node (@matches){ next unless $node->ownerDocument->isSameNode($tree->ownerDocument); # If still attached to original document! $self->applyClause($document,$node,$nnodes,@more_clauses); }}} elsif($op eq 'test'){ my $nnodes = &$pattern($document,$tree); print STDERR "Rewrite test at ".$tree->toString.": ".($nnodes ? $nnodes." to replace" : "failed")."\n" if $LaTeXML::Rewrite::DEBUG; $self->applyClause($document,$tree,$nnodes,@more_clauses) if $nnodes; } elsif($op eq 'wrap'){ if($n_to_replace > 1){ my $parent = $tree->parentNode; # Remove & separate nodes to be replaced, and sibling nodes following them. my @following = (); # Collect the matching and following nodes while(my $sib = $parent->lastChild){ $parent->removeChild($sib); unshift(@following,$sib); last if $$sib == $$tree; } my @replaced = map(shift(@following), 1..$n_to_replace); # Remove the nodes to be replaced $document->setNode($parent); $tree = $document->openElement('ltx:XMWrap', font=>$document->getNodeFont($parent)); print STDERR "Wrapping ".join(' ',map(Stringify($_),@replaced))."\n" if $LaTeXML::Rewrite::DEBUG; map($tree->appendChild($_), @replaced); # Add matched nodes to XMWrap map( $parent->appendChild($_), @following); # Add back the following nodes. } $self->applyClause($document,$tree,1,@more_clauses); } elsif($op eq 'replace'){ print STDERR "Rewrite replace at ".$tree->toString." using $pattern\n" if $LaTeXML::Rewrite::DEBUG; my $parent = $tree->parentNode; # Remove & separate nodes to be replaced, and sibling nodes following them. my @following = (); # Collect the matching and following nodes while(my $sib = $parent->lastChild){ $parent->removeChild($sib); unshift(@following,$sib); last if $$sib == $$tree; } my @replaced = map(shift(@following), 1..$n_to_replace); # Remove the nodes to be replaced # Carry out the operation, inserting whatever nodes. $document->setNode($parent); my $point = $parent->lastChild; &$pattern($document,@replaced); # Carry out the insertion. # Now collect the newly inserted nodes and store in a _Capture_ node. my @inserted = (); # Collect the newly added nodes. if($point){ while(my $sib = $parent->lastChild){ $parent->removeChild($sib); unshift(@inserted,$sib); last if $$sib == $$point; }} else { @inserted = $parent->childNodes; } my $insertion = $document->openElement('_Capture_', font=>$document->getNodeFont($parent)); map($insertion->appendChild($_), @inserted); # Apply PRECEDING rules to the insertion. ##### $document->getModel->applyRewrites($document,$insertion,$self); # Now remove the insertion and replace with rewritten nodes and replace the following siblings. @inserted = $insertion->childNodes; $parent->removeChild($insertion); map( $parent->appendChild($_), @inserted, @following); } elsif($op eq 'action'){ print STDERR "Rewrite action at ".$tree->toString." using $pattern\n" if $LaTeXML::Rewrite::DEBUG; &$pattern($tree); } elsif($op eq 'attributes'){ map( $tree->setAttribute($_,$$pattern{$_}), keys %$pattern); print STDERR "Rewrite attributes for ".Stringify($tree)."\n" if $LaTeXML::Rewrite::DEBUG; } elsif($op eq 'regexp'){ my @matches = $document->findnodes('descendant-or-self::text()',$tree); print STDERR "Rewrite regexp => ".scalar(@matches)." matches\n" if $LaTeXML::Rewrite::DEBUG; foreach my $text (@matches){ my $string = $text->textContent; if(&$pattern($string)){ $text->setData($string); }}} else { Error(":malformed: Unknown directive \"$op\" in Compiled Rewrite spec"); } } #********************************************************************** sub compileClause { my($self,$document,$clause)=@_; my($ignore,$op,$pattern)= @$clause; my($oop,$opattern)=($op,$pattern); if ($op eq 'label'){ if(ref $pattern eq 'ARRAY'){ # $op='multi_select'; $pattern = [map(["descendant-or-self::*[\@label='$_']",1], @$pattern)]; } $op='multi_select'; $pattern = [map(["descendant-or-self::*[\@xml:id='$_']",1], map($self->getLabelID($_),@$pattern))]; } else { # $op='select'; $pattern=["descendant-or-self::*[\@label='$pattern']",1]; }} $op='select'; $pattern=["descendant-or-self::*[\@xml:id='".$self->getLabelID($pattern)."']",1]; }} elsif($op eq 'scope'){ $op='select'; if($pattern =~ /^label:(.*)$/){ # $pattern=["descendant-or-self::*[\@label='$1']",1]; } $pattern=["descendant-or-self::*[\@xml:id='".$self->getLabelID($1)."']",1]; } elsif($pattern =~ /^id:(.*)$/){ $pattern=["descendant-or-self::*[\@xml:id='$1']",1]; } elsif($pattern =~ /^(.*):(.*)$/){ $pattern=["descendant-or-self::*[local-name()='$1' and \@refnum='$2']",1]; } else { Error(":malformed: Unrecognized scope pattern in Rewrite clause: \"$pattern\"; Ignoring it."); $op='ignore'; $pattern=[]; }} elsif($op eq 'xpath'){ $op='select'; $pattern=[$pattern,1]; } elsif($op eq 'match'){ if(ref $pattern eq 'CODE'){ $op='test'; } elsif(ref $pattern eq 'ARRAY'){ # Multiple patterns! $op = 'multi_select'; $pattern = [map( $self->compile_match($document,$_), @$pattern)]; } else { $op = 'select'; $pattern= $self->compile_match($document,$pattern); }} elsif($op eq 'replace'){ if(ref $pattern eq 'CODE'){} else { $pattern = $self->compile_replacement($document,$pattern); }} elsif($op eq 'regexp'){ $pattern = $self->compile_regexp($pattern); } print STDERR "Compiled clause $oop=>".ToString($opattern)." ==> $op=>".ToString($pattern)."\n" if $LaTeXML::Rewrite::DEBUG; $$clause[0]='compiled'; $$clause[1]=$op; $$clause[2]=$pattern; } #********************************************************************** sub compile_match { my($self,$document,$pattern)=@_; if(!ref $pattern){ $self->compile_match1($document,digest_rewrite(($$self{math} ? '$'.$pattern.'$' : $pattern))); } elsif($pattern->isaBox){ $self->compile_match1($document,$pattern); } else { Error(":malformed: Don't know what to do with match=>\"".Stringify($pattern)."\""); }} sub compile_match1 { my($self,$document,$patternbox)=@_; # Create a temporary document my $capdocument = LaTeXML::Document->new($document->getModel); my $capture = $capdocument->openElement('_Capture_', font=>LaTeXML::Font->new()); $capdocument->absorb($patternbox); ##### $capdocument->getModel->applyRewrites($capdocument,$capdocument->getDocument->documentElement,$self); my @nodes= ($$self{mode} eq 'math' ? $capdocument->findnodes("//ltx:XMath/*",$capture) : $capture->childNodes); my $frag = $capdocument->getDocument->createDocumentFragment; map($frag->appendChild($_), @nodes); # Convert the captured nodes to an XPath that would match them. my $xpath = domToXPath($capdocument,$frag); # For math, restrict to NOT operate on presentation branch of XMDual. # The semantics should already be associated with it, through the XMDual itself. # This assumes that any arguments in the presentation branch are by reference (XMRef) # to the same args in the content branch --- thus the args will still be matched. $xpath .= "[not(ancestor-or-self::*[parent::ltx:XMDual and not(following-sibling::*)])]" if $$self{math}; print STDERR "Converting \"".ToString($patternbox)."\"\n => xpath= \"$xpath\"\n" if $LaTeXML::Rewrite::DEBUG; [$xpath,scalar(@nodes)]; } sub XXXcompile_replacement { my($self,$document,$pattern)=@_; if(!ref $pattern){ $self->compile_replacement1(digest_rewrite(($$self{math} ? '$'.$pattern.'$' : $pattern))); } elsif($pattern->isaBox){ $self->compile_replacement1($pattern); } else { $self->compile_replacement1(digest_rewrite($pattern)); }} sub XXXcompile_replacement1 { my($self,$patternbox)=@_; $patternbox = $patternbox->getBody if $$self{math}; sub { $_[0]->absorb($patternbox); }} # Reworked to do digestion at replacement time. sub compile_replacement { my($self,$document,$pattern)=@_; if((ref $pattern) && $pattern->isaBox){ $pattern = $pattern->getBody if $$self{math}; sub { $_[0]->absorb($pattern); }} else { $pattern = Tokenize($$self{math} ? '$'.$pattern.'$' : $pattern) unless ref $pattern; sub { my $stomach = $STATE->getStomach; $stomach->bgroup; $STATE->assignValue(font=>LaTeXML::Font->new(), 'local'); $STATE->assignValue(mathfont=>LaTeXML::MathFont->new(), 'local'); my $box = $stomach->digest($pattern,0); $stomach->egroup; $box = $box->getBody if $$self{math}; $_[0]->absorb($box); } }} sub compile_regexp { my($self,$pattern)=@_; my $code = "sub { \$_[0] =~ s${pattern}g; }"; my $fcn = eval $code; Error(":malformed: Failed to compile regexp pattern \"$pattern\" into \"$code\": $!") if $@; $fcn; } #********************************************************************** sub digest_rewrite { my($string)=@_; my $stomach = $STATE->getStomach; $stomach->bgroup; $STATE->assignValue(font=>LaTeXML::Font->new(), 'local'); # Use empty font, so eventual insertion merges. $STATE->assignValue(mathfont=>LaTeXML::MathFont->new(), 'local'); my $box = $stomach->digest((ref $string ? $string : Tokenize($string)),0); $stomach->egroup; $box; } #********************************************************************** sub domToXPath { my($document,$node)=@_; "descendant-or-self::". domToXPath_rec($document,$node); } # May need some work here; our %EXCLUDED_MATCH_ATTRIBUTES=(scriptpos=>1); sub domToXPath_rec { my($document,$node,@extra_predicates)=@_; my $type = $node->nodeType; if($type == XML_DOCUMENT_FRAG_NODE){ my @nodes = $node->childNodes; domToXPath_rec($document,shift(@nodes) , domToXPath_seq($document,'following-sibling',@nodes), @extra_predicates); } elsif($type == XML_ELEMENT_NODE){ my $qname = $document->getNodeQName($node); return '*[true()]' if $qname eq '_WildCard_'; my @predicates =(); # Order the predicates so as to put most quickly restrictive first. if($node->hasAttributes){ foreach my $attribute (grep($_->nodeType == XML_ATTRIBUTE_NODE, $node->attributes)){ my $key = $attribute->nodeName; next if ($key =~ /^_/) || $EXCLUDED_MATCH_ATTRIBUTES{$key}; push(@predicates, "\@".$key."='".$attribute->getValue."'"); }} if($node->hasChildNodes){ my @children = $node->childNodes; if(! grep($_->nodeType != XML_TEXT_NODE,@children)){ # All are text nodes: push(@predicates, "text()='".$node->textContent."'"); } elsif(! grep($_->nodeType != XML_ELEMENT_NODE,@children)){ push(@predicates,domToXPath_seq($document,'child',@children)); } else { Fatal(":misdefined: Cannot generate XPath for mixed content on ".$node->toString); }} ### if($document->getModel->canHaveAttribute($qname,'font')){ ### if(my $font = $node->getAttribute('_font')){ ### push(@predicates,"\@_font and match-font('".$font."',\@_font)"); }} if($document->getModel->canHaveAttribute($qname,'font')){ if(my $font = $node->getAttribute('_font')){ my $pred = LaTeXML::Font::font_match_xpaths($font); ## print STDERR "Font $font => $pred\n"; push(@predicates,$pred); }} $qname."[".join(' and ',grep($_,@predicates,@extra_predicates))."]"; } elsif($type == XML_TEXT_NODE){ ### "text()='".$node->textContent."'"; }} "*[text()='".$node->textContent."']"; }} # $axis would be child or following-sibling sub domToXPath_seq { my($document,$axis,@nodes)=@_; if(@nodes){ $axis."::*[position()=1 and self::" . domToXPath_rec($document,shift(@nodes),domToXPath_seq($document,'following-sibling',@nodes)).']'; } else { (); }} #********************************************************************** 1; __END__ =pod =head1 NAME C - rewrite rules for modifying the XML document. =head1 DESCRIPTION C implements rewrite rules for modifying the XML document. =head2 Methods =over 4 =item C<< $rule->rewrite($document,$node); >> =back =head1 AUTHOR Bruce Miller =head1 COPYRIGHT Public domain software, produced as part of work done by the United States Government & not subject to copyright in the US. =cut LaTeXML-0.7.0/lib/LaTeXML/Util/0000755002506700454610000000000011215766043014732 5ustar miller891divLaTeXML-0.7.0/lib/LaTeXML/Util/MathMLLinebreaker.pm0000644002506700454610000007424311214255167020567 0ustar miller891div# /=====================================================================\ # # | LaTeXML::Util::MathMLLinebreaker | # # | MathML generator for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Util::MathMLLinebreaker; #====================================================================== # General MathML Line-Breaking Strategy. # # (1) Preparations: if top-level has trailing punctuation, # remove it to be added back, later. # # (2) Find all layouts that fit within a specified width. # This is done top-down by finding possible breaks within the current # node, along with (recursively) the possible layouts for children. # The pattern of possible breaks and which children are allowed to break # depends on the tag of the current node; eg. sub/superscripts don't break. # [handlers for each tag are defined at end of file] # # Each combination of these breaks is then considered by # computing the effective size & penalty. # The penalty is generally determined by the number of breaks, # but possibly weighted. # # These layouts are sorted in increasing width, and increasing penalty # for a given width. Layouts which are too wide, or have higher penalty # than the previous layout are pruned. # # (3) Apply the breaks specified by the best layout. # The last layout in a list of layouts will be the best in the sense # that it is the longest layout not longer than the target width, # and has least penalty of its width. #====================================================================== # NOTE This takes the array form for the MathML, before it has been # converted to a proper DOM tree. use strict; ####################################################################### # Parameters ####################################################################### our $DEBUG = 0; our $NOBREAK = 99999999; # penalty=$NOBREAK means don't break at all. our $POORBREAK_FACTOR= 10; # to make breaks less desirable. our $BADBREAK_FACTOR = 100; # to make breaks much less desirable. our $CONVERSION_FACTOR = 2; # to make breaks at converted ops less desirable # TODO: Integrate default operator dictionary, and recognize attributes # TODO: all addops, relops, # TODO: mult ops, but less desirable sub UTF { pack('U',$_[0]); } our %BREAKOPS = map(($_=>1), # Various addops "+","-",UTF(0xB1),"\x{2213}", # pm, mp ); our %RELATIONOPS = map(($_=>1), # Various relops "=", "<",">", "\x{2264}","\x{2265}","\x{2260}","\x{226A}", "\x{2261}","\x{223C}","\x{2243}","\x{224D}","\x{2248}","\x{2260}","\x{221D}", ); our %CONVERTOPS = ("\x{2062}"=>UTF(0xD7), # Invisible (discretionary) times ); binmode(STDOUT,":utf8") if $DEBUG; ####################################################################### # Top-level interface ####################################################################### sub new { my($class)=@_; my $self = bless {},$class; $self; } sub fitToWidth { my($self,$math,$mml,$width,$displaystyle)=@_; # Check for end punctuation; Remove it, if found. my @n; local $LaTeXML::MathMLLineBreaker::MATH = $math; local $LaTeXML::MathMLLineBreaker::PUNCT = undef; if((nodeName($mml) eq 'm:mrow') && (scalar(@n=nodeChildren($mml))==2) && (nodeName($n[1]) eq 'm:mo') && (textContent($n[1]) =~ /^[\.\,\;]$/)){ $mml = $n[0]; $LaTeXML::MathMLLineBreaker::PUNCT = $n[1]; } # Compute the possible layouts print STDERR "Starting layout of $mml\n" if $DEBUG; my $layouts = layout($mml,$width,0,$displaystyle,0,1); if($DEBUG){ print STDERR "Got ".scalar(@$layouts)." layouts:\n"; map(showLayout($_),@$layouts); } # Apply the best layout my $best = $$layouts[-1]; # Is there a case where $best is so bad we shouldn't even apply it? applyLayout($best); # If nobody has yet eaten the punctuation, add it back on. if($LaTeXML::MathMLLineBreaker::PUNCT){ $mml = ['m:mrow',{},$mml,$LaTeXML::MathMLLineBreaker::PUNCT]; } Warn("Got width $$best{width} > $width") if $$best{width} > $width+1; $mml; } sub Warn { my($message)=@_; my $p = $LaTeXML::MathMLLineBreaker::MATH; while($p && !$p->hasAttribute('xml:id')){ $p=$p->parentNode; } my $id = $p && $p->getAttribute('xml:id')||'?'; my $nm = $p && $p->getAttribute('refnum')||''; print STDERR "Warning in MathMLLinebreaker for math in $nm (id=$id):\n $message\n"; } ####################################################################### # Apply the breaks described in a layout to the MathML. ####################################################################### # Modify the mathml to incorporate a set of breaks. # This strategy uses mtable. # NOTE: There's an alignment issue. # In principle, a row could be broken that resides within another row. # In such a case, you'd want the table to align the 1st row's baseline to the material # on the left, but the material following should align to the last row's baseline!!! # MathML spec doesn't give any way of saying that! # So, currently, we've got code in asRow that forbids a break within anything # but the _LAST_ item within a line. sub applyLayout { my($layout)=@_; return unless $$layout{hasbreak}; # Do children first, so if there is punctuation & last child breaks, it can take up the punct. if($$layout{children}){ my @children_layout = @{$$layout{children}}; my $lastchild = pop(@children_layout); { local $LaTeXML::MathMLLineBreaker::PUNCT = undef; # Hide from all but last child map(applyLayout($_), @children_layout); } # Now, do last child; Maybe it will absorb the punctuation! applyLayout($lastchild); } # Now break up the current level. if(my $breakset = $$layout{breakset}){ # print "Applying ".layoutDescriptor($layout)."\n"; my $node = $$layout{node}; my @children = nodeChildren($node); # If this is a fenced row, we've got to manually fixup the fence size! if(nodeName($node) eq 'm:mrow'){ if((nodeName($children[0]) eq 'm:mo') && (textContent($children[0]) =~ /[\(\)\[\]\{\}]/)){ $children[0][1]{mathsize}=$$layout{rowheight}."em"; } if((nodeName($children[$#children]) eq 'm:mo') && (textContent($children[$#children]) =~ /[\(\)\[\]\{\}]/)){ $children[$#children][1]{mathsize}=$$layout{rowheight}."em"; } } my @rows = split_row($breakset,@children); # Replace any "converted" leading operators (ie. invisible times => \times) foreach my $row (@rows[1..$#rows]){ my $op = $$row[0]; # print STDERR " Split at ".textContent($op)."\n"; my $newop; if((nodeName($op) eq 'm:mo') && ($newop=$CONVERTOPS{textContent($op)})){ splice(@$op,2,scalar(@$op)-2, $newop); }} if($LaTeXML::MathMLLineBreaker::PUNCT){ $rows[$#rows] = [@{$rows[$#rows]},$LaTeXML::MathMLLineBreaker::PUNCT]; $LaTeXML::MathMLLineBreaker::PUNCT = undef; } my @firstrow = @{shift(@rows)}; splice(@$node,2,scalar(@children), ($$layout{lhs_pos} ? ["m:mtable",{align=>'baseline 1', columnalign=>'left'}, ["m:mtr",{}, ["m:mtd",{}, @firstrow[0..$$layout{lhs_pos}-1]], ["m:mtd",{}, @firstrow[$$layout{lhs_pos}..$#firstrow]]], map( ["m:mtr",{}, ["m:mtd",{}], ["m:mtd",{},@$_]], @rows)] : ["m:mtable",{align=>'baseline 1', columnalign=>'left'}, ["m:mtr",{},["m:mtd",{}, @firstrow]], map( ["m:mtr",{}, ["m:mtd",{}, ["m:mspace",{width=>$$layout{indentation}."em"}],@$_]],@rows)])); }} # This would use with linebreak attribute to break a row. # Unfortunately, Mozillae ignore this attribute... sub XXXXapplyLayout { my($layout)=@_; map(applyLayout($_), @{$$layout{children}} ) if $$layout{children}; if(my $breakset = $$layout{breakset}){ my $node = $$layout{node}; my @children = nodeChildren($node); my @lines = my @newchildren = (); foreach my $line (split_row($breakset,@children)){ push(@newchildren,["m:mspace",{linebreak=>"indentingnewline"}]) if @newchildren; push(@newchildren,@$line); } splice(@$node,2,scalar(@children), @newchildren); }} ####################################################################### # Utilities & Debugging aids ####################################################################### sub nodeName { my($node)=@_; my($tag,$attr,@children)=@$node; $tag; } sub getAttribute { my($node,$key)=@_; my($tag,$attr,@children)=@$node; $$attr{$key}; } sub nodeChildren { my($node)=@_; my($tag,$attr,@children)=@$node; @children; } sub textContent { my($node)=@_; my($tag,$attr,@children)=@$node; join('',@children); } sub min { (!defined $_[0] ? $_[1] : (!defined $_[1] ? $_[0] : ($_[0] < $_[1] ? $_[0] : $_[1]))); } sub max { (!defined $_[0] ? $_[1] : (!defined $_[1] ? $_[0] : ($_[0] > $_[1] ? $_[0] : $_[1]))); } sub describeLayouts { my($self,$layouts)=@_; my @layouts = @$layouts; my $min = $layouts[0]; my $max = $layouts[-1]; print "Layout ".scalar(@layouts)." layout options\n" ." best = $$max{width} x ($$max{height} + $$max{depth}) penalty = $$max{penalty}\n" ." narrowest = $$min{width} x ($$min{height} + $$min{depth}) penalty = $$min{penalty}\n"; showLayout($max); } sub showLayout { my($layout,$indent,$pos)=@_; $indent = 0 unless $indent; my $pre = (' ') x (2*$indent).(defined $pos ? "[$pos] ":""); print $pre.layoutDescriptor($layout)."\n"; if($$layout{children}){ my $p = 0; foreach my $child (@{$$layout{children}}){ showLayout($child,$indent+1,$p) if $$child{penalty}; $p++; }} } sub layoutDescriptor { my($layout)=@_; $$layout{type}." " ."(".$$layout{width}." x ".$$layout{height}." + ".$$layout{depth}.")" ."@".$$layout{penalty} .($$layout{breakset} ? ", b@".join(",",map("[".join(',',@$_)."]",@{$$layout{breakset}})) : ""); } ####################################################################### # Permutation things ####################################################################### # multiplex(@layouts) # Given a list of layouts arrays, (each representing the possible layouts of # each of the children of a node), multiplex them to return a list of # arrays containing one layout choice for each child. # That is to say, form all combinations choosing one $layout # from each of the $layouts lists in @layouts. sub multiplex { my($layouts,@siblings_layouts)=@_; if(@siblings_layouts){ my @multiplexed_siblings_layouts = multiplex(@siblings_layouts); my @multiplexed = (); foreach my $layout (@$layouts){ foreach my $multiplexed_sibling_layout (@multiplexed_siblings_layouts){ push(@multiplexed, [$layout,@$multiplexed_sibling_layout]); }} @multiplexed; } else { map([$_],@$layouts); }} # Given a list of break's (in order), form all choices of breaks. sub choices { my(@breaks)=@_; if(@breaks){ my $break = shift(@breaks); map( ($_,[$break,@$_]),choices(@breaks)); } else { ([]); }} ####################################################################### # Layout determination code ####################################################################### # The current code computes pretty much every possible layout, # which we'd select from later. # If it turns out this is too expensive, it would be good # to work out some kind of lazy expansion that could prune # ridiculous layouts before computing everything, or even layouts # that are worse than the current best for a given size. # Of course, at this point, we don't know anything about the size # of something till we do the full expansion, so... #====================================================================== # "layouts" == [ layout, ...] # represents a list of layout descriptors representing possible # arrangements & breakpoints for a given node. # Generally sorted by increasing width, and increasing penalty # "layout" aka layout descriptor # is a hash describing a possible layout arrangment. # The fields are: # node == the node that this layout applies to. # type == the tag name of the node, for convenience & debugging. # width == width of this layout (in extremely rough ems) # height == height of this layout box above baseline # depth == depth below baseline # penalty == undesirability of this layout # children == [ layout, ...] # being the layout descriptor for each child # breakset == [ break,...] # being a list of points to break at # hasbreak = 1 if this node, or any children have a line-break. # break = [pos,content,demerit] where pos is the (0 based) index of a breakpoint # ie. make child[pos] start the next line. #====================================================================== sub layout { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; # Get the Handler for this tag my $name = nodeName($node); $name =~ s/\w://; my $handler = "layout_$name"; eval { $handler = \&$handler; }; print STDERR "",(' ' x $level),"layout $name: ",$node,"...\n" if $DEBUG > 1; # Get the handler to compute the layouts my $layouts = &$handler($node,$target,$level, $displaystyle||0, $scriptlevel||0, $demerits||1); my $nlayouts = scalar(@$layouts); # Sort & prune the layouts my @layouts = prunesort($target,@$layouts); my $pruned = scalar(@layouts); print STDERR "",(' ' x $level),"$name: $nlayouts layouts" .($pruned < $nlayouts ? " pruned to $pruned":"") ." ".layoutDescriptor($$layouts[0]) .($nlayouts > 1 ? "...".layoutDescriptor($$layouts[$nlayouts-1]) : "") ."\n" if $DEBUG > 1; [@layouts]; } sub prunesort { my($target,@layouts)=@_; @layouts = sort { ($$a{width} <=> $$b{width}) || ($$a{penalty} <=> $$b{penalty}) } @layouts; my @goodlayouts= ( shift(@layouts) ); # always include at least the shortest/best foreach my $layout (@layouts){ if(($$layout{width} < $target) # If not too wide && ($goodlayouts[$#goodlayouts]->{penalty} > $$layout{penalty})){ # not worse than prev push(@goodlayouts,$layout); }} @goodlayouts; } ####################################################################### # Row line breaker. # This is the real workhorse. ####################################################################### # Here, of course, is where the Interesting stuff will happen. sub asRow { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my $type = nodeName($node); my @children = nodeChildren($node); if(grep( ref $_ ne 'ARRAY', @children)){ die "ROW has non-element: ".nodeName($node); } my $n = scalar(@children); if(!$n){ return [ { node=>$node, type=>$type, penalty=>0, width => 0, height => 0, depth=> 0} ]; } # Multiple children, possibly with breaks # Get the set of layouts for each child ## my @child_layouts = map(layout($_,$target,$level+1,$displaystyle,$scriptlevel,$demerits), my @child_layouts = map(layout($_,$target,$level+1,$displaystyle,$scriptlevel,$demerits+1), @children); # Now, we need all possible break points within the row itself. my @breaks = (); my ($lhs_pos,$lhs_width); if($demerits < $NOBREAK){ for(my $i=1; $i<$n-1; $i++){ my $child = $children[$i]; my $content = (nodeName($child) eq 'm:mo') && textContent($child); if(!$content){} elsif($RELATIONOPS{$content}){ push(@breaks, [$i,$content,$demerits]); if(! defined $lhs_pos){ $lhs_pos = $i; $lhs_width = sum(map($$_[-1]{width}, @child_layouts[0..$i-1])); $lhs_pos = 0 if $lhs_width > $target/4; }} elsif($BREAKOPS{$content}){ $lhs_pos = 0; push(@breaks, [$i,$content,$demerits]); } elsif($CONVERTOPS{$content}){ $lhs_pos = 0; ## push(@breaks, [$i,$content,$demerits*$CONVERSION_FACTOR]); } push(@breaks, [$i,$content,$demerits+$CONVERSION_FACTOR]); } }} my $indentation = ($lhs_pos ? $lhs_width : 2); # Form the set of all choices from the breaks. my @breaksets = choices(@breaks); print STDERR "",(" " x $level), $type," ", join("x", map(scalar(@$_),@child_layouts))," layouts", (@breaks ? ", breaks@".join(",",map("[".join(',',@$_)."]",@breaks)) ."(".scalar(@breaksets)." sets;" . product(map(scalar(@$_),@child_layouts),scalar(@breaksets))." combinations" .")" : "")."\n" if $DEBUG > 1; my @layouts = (); # For each set of breaks within this row # And for each layout of children # Form composite layouts, computing the size, penalty, and pruning. # NOTE: Would we like to prefer more evenly balanced splits? my $pruned=0; BREAKSET: foreach my $breakset (reverse @breaksets){ # prunes better reversed? # Since we only allow to break the last child in a row, # form subset of children's layouts # Namely, take only last (unbroken?) layout for all but last child in each row my @filtered_child_layouts=(); foreach my $xline (split_row($breakset,@child_layouts)){ my @xline_children_layouts = @$xline; while(@xline_children_layouts){ my $xchild_layouts = shift(@xline_children_layouts); if(@xline_children_layouts){ # More children? my @x = @$xchild_layouts; my $last = $x[$#x]; next BREAKSET if $$last{hasbreak}; push(@filtered_child_layouts,[$last]); } # take last else { push(@filtered_child_layouts,$xchild_layouts); }}} my @children_layouts = multiplex(@filtered_child_layouts); LAYOUT: foreach my $children_layout (@children_layouts){ my($width,$height,$depth,$penalty,$indent,$rowheight)=(0,0,0,0,0,0); $penalty = sum(map($$_[2],@$breakset)); # Last (best) layout, for comparison & pruning my $last = (@layouts && $layouts[$#layouts]); # Apply the breaks to split the children (actually their layout) into lines. foreach my $line (split_row($breakset,@$children_layout)){ my($w,$h,$d)=(0,0,0); my @line_children_layout = @$line; while(@line_children_layout){ # For each line of nodes, compute sizes, possibly prune my $child_layout = shift(@line_children_layout); $w += $$child_layout{width}; $penalty += $$child_layout{penalty}||0; # Skip to next breakset if we've gotten too wide, or worse than previous if($last && (($w > 1.5*$target) # || (($$last{width} < 1.5*$target) && ($penalty > $$last{penalty})))){ || (($$last{width} <= $w) && ($penalty > $$last{penalty})))){ $pruned++; next LAYOUT; } $h = max($h,$$child_layout{height}); $d = max($d,$$child_layout{depth}); } # Then combine the lines $width = max($width,$w+$indent); $indent = $indentation; if($height == 0){ $height = $h; $depth = $d; } else { $depth += $h + $d; } $rowheight = max($rowheight,$h+$d); } push(@layouts, { node=>$node,type=>$type, penalty=>$penalty, width=>$width, height=>$height, depth=>$depth, area=>$width*($depth+$height), indentation=>$indentation, rowheight=>$rowheight, lhs_pos=>$lhs_pos, (scalar(@$breakset) ? (breakset=>$breakset):()), hasbreak=>scalar(@$breakset)||scalar(grep($$_{hasbreak},@$children_layout)), children=>[@$children_layout]}); @layouts = prunesort($target,@layouts); }} ## }} ## @layouts = prunesort($target,@layouts); ## Add a penalty for smallest area (?) my($maxarea,$minarea) = (0,999999999); map($maxarea = max($maxarea,$$_{area}),@layouts); map($minarea = min($minarea,$$_{area}),@layouts); map( $$_{penalty} *= (1+($$_{area} -$minarea)/$maxarea), @layouts) if $maxarea > $minarea; @layouts = prunesort($target,@layouts); ## print STDERR "",(" " x $level), $type," pruned $pruned\n" if $pruned && ($DEBUG>1); Warn("Row (".nodeName($node).") got no layouts!") unless @layouts; [@layouts]; } sub split_row { my($breakset,@stuff)=@_; my @lines=(); my $pos=0; foreach my $break (@$breakset){ my($breakpos,$content,$demerit)=@$break; push(@lines, [ @stuff[$pos..$breakpos-1] ]); $pos = $breakpos; } push(@lines, [ @stuff[$pos..$#stuff] ]); @lines; } ####################################################################### # Layout handlers for various MathML tags # These are called layout_ ####################################################################### #====================================================================== # Trivial cases. #====================================================================== # These are just empty. sub layout_none { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my $content = textContent($node); $scriptlevel = min(0,max($scriptlevel,3)); [ { node=>$node, type=>"none", penalty=>0, width => 0, height => 0, depth=> 0} ]; } sub layout_empty { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my $content = textContent($node); $scriptlevel = min(0,max($scriptlevel,3)); [ { node=>$node, type=>"empty", penalty=>0, width => 0, height => 0, depth=> 0} ]; } #====================================================================== # Simple cases. #====================================================================== # These are just simple boxes that don't break. # Approximate their size. our @SIZE=(1.0, 0.71, 0.71*0.71,0.71*0.71*0.71); # TODO: spacing ? # TODO for mo: largeop ? sub simpleSize { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my $content = textContent($node); $scriptlevel = min(0,max($scriptlevel,3)); [ { node=>$node, type=>nodeName($node), penalty=>0, width => length($content)*$SIZE[$scriptlevel], height => $SIZE[$scriptlevel], depth=> 0} ]; } sub layout_mi { simpleSize(@_); } sub layout_mo { simpleSize(@_); } sub layout_mn { simpleSize(@_); } sub layout_mtext { simpleSize(@_); } sub layout_merror { simpleSize(@_); } #====================================================================== # Various row-line things. #====================================================================== sub layout_mrow { asRow(@_); } sub layout_mpadded { asRow(@_); } sub layout_mphantom { asRow(@_); } sub layout_menclose { asRow(@_); } sub layout_mfenced { asRow(@_); } # Close enough? sub layout_maction { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my $selection = getAttribute($node,'selection') || 0; my @children = nodeChildren($node); layout($children[$selection],$target,$level,$displaystyle,$scriptlevel,$demerits); } sub layout_mstyle { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; if(my $d = getAttribute($node,'displaystyle')){ $displaystyle = ($d eq 'true'); } if(my $s = getAttribute($node,'scriptlevel')){ if ($s =~ /^\+(\d+)$/){ $scriptlevel += $1; } elsif($s =~ /^\-(\d+)$/){ $scriptlevel -= $1; } elsif($s =~ /^(\d+)$/ ){ $scriptlevel = $1; }} asRow($node,$target,$level,$displaystyle, $scriptlevel,$demerits); } #====================================================================== # Fractions & Roots #====================================================================== # These allow the children to break, but with heavier penalty. sub layout_mfrac { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; # No break of mfrac itself # 2 children; break of children is poor [map( { node=>$node, type=>'mfrac', penalty => $$_[0]->{penalty} + $$_[1]->{penalty}, width => max($$_[0]->{width},$$_[1]->{width}), height => $$_[0]->{height} + $$_[0]->{depth} + 1, depth => $$_[1]->{height} + $$_[1]->{depth}, hasbreak => $$_[0]->{hasbreak} || $$_[1]->{hasbreak}, children=>$_}, multiplex(map( layout($_, $target,$level+1,0 ,$scriptlevel, $demerits*$POORBREAK_FACTOR), nodeChildren($node))))]; } sub layout_mroot { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; # no break of mroot itself, index doesn't break, break of base is bad my ($base,$index) = nodeChildren($node); my $indexlayout = layout($index,$target,$level+1, 0 ,$scriptlevel+1, $NOBREAK)->[0]; $target -= $$indexlayout{width}; my $baselayouts = layout($base, $target,$level+1, 0 ,$scriptlevel, $demerits*$BADBREAK_FACTOR); [map( { node=>$node, type=>'mroot', penalty => $$_[0]->{penalty} + $$_[1]->{penalty}, width => $$_[0]->{width} + $$_[1]->{width}, height => $$_[0]->{height}, depth => $$_[0]->{depth}, hasbreak => $$_[0]->{hasbreak} || $$_[1]->{hasbreak}, children => $_}, multiplex($baselayouts,[$indexlayout]))]; } sub layout_msqrt { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; # no break of msqrt itself, # 1 child or implied mrow; bad to break asRow($node,$target,$level+1,$displaystyle,$scriptlevel,$demerits*$BADBREAK_FACTOR); } #====================================================================== # Tables #====================================================================== # We're not allowing breaks within tables, but we still have a mess of sums & max's sub layout_mtable { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my @widths=(); my @heights=(); my @depths=(); foreach my $row (nodeChildren($node)){ my ($h,$d)=(0,0); my $i = 0; foreach my $col (nodeChildren($row)){ my $layout = layout($col,$target,$level+1, 0 ,$scriptlevel+1, $NOBREAK)->[0]; $widths[$i] = max($widths[$i] || 0, $$layout{width}); $h = max($h,$$layout{height}); $d = max($d,$$layout{depth}); $i++; } push(@heights,$h); push(@depths,$d); } my $width = sum(@widths); my($height,$depth); my $align = getAttribute($node,'align') || 'axis'; my $n = scalar(@heights); if($align =~ s/(\d+)//){ my $i = $1; ($height,$depth) = tableVAlignment($align,$heights[$i-1],$depths[$i-1]); $height += sum(@heights[0..$i-2]) + sum(@depths[0..$i-2]) if $i > 1; $depth += sum(@heights[$i..$n-1]) + sum(@depths[$i..$n-1]) if $i < $n; } else { $height = (sum(@heights)+sum(@depths))/2; $depth = $height; ($height,$depth) = tableVAlignment($align,$height,$depth); } [ { node=>$node, type=>nodeName($node), penalty => 0, width => $width, height => $height, depth => $depth} ]; } sub tableVAlignment { my($align,$height,$depth)=@_; if ($align eq 'top') { $depth = $height+$depth; $height = 0; } elsif($align eq 'bottom') { $height= $height+$depth; $depth = 0; } elsif($align eq 'center') { $height=($height+$depth)/2; $depth = $height; } elsif($align eq 'axis') { $height=($height+$depth)/2; $depth = $height; } elsif($align eq 'baseline'){} ($height,$depth); } sub sum { my(@x)=@_; my $sum = 0; foreach my $x (@x) { $sum += $x || 0; } $sum; } sub product { my(@x)=@_; my $prod = 1; foreach my $x (@x) { $prod *= $x || 1; } $prod; } #sub layout_mtr {} #sub layout_mlabeledtr {} sub layout_mtd { asRow(@_); } #====================================================================== # Various sub & super scripts #====================================================================== # TODO: What about movablelimits, accent on base ? sub asScripts { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits, $stacked,$basenode,@scriptnodes)=@_; # Scripts do not break, base is poor to break. my @layouts = (); foreach my $layoutset (multiplex(layout($basenode,$target,$level+1, $displaystyle,$scriptlevel,$demerits*$POORBREAK_FACTOR), map(layout($_,$target,$level+1,0,$scriptlevel+1,$NOBREAK), @scriptnodes))){ my($base,@scripts)=@$layoutset; my($width,$height,$depth,$penalty)=(0,0,0,0); while(@scripts){ my $sub = shift(@scripts); my $sup = shift(@scripts); $width += max($$sub{width},$$sup{width}); $height += max($height,$$sup{depth}+$$sup{height}); # Roughly.. $depth += max($depth, $$sub{depth}+$$sub{height}); $penalty+= $$sub{penalty}+$$sup{penalty}; } $penalty += $$base{penalty}; if($stacked){ $width = max($width,$$base{width}); $height += $$base{height}; $depth += $$base{depth}; } else { $width += $$base{width}; $height = $$base{height} + 0.5*$height; $depth = $$base{depth} + 0.5*$depth; } push(@layouts,{ node=>$node, type=>nodeName($node), penalty => $penalty, width => $width, height => $height, depth => $depth, hasbreak => scalar(grep($$_{hasbreak}, @$layoutset)), children => $layoutset}); } [@layouts]; } sub layout_msub { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my($base,$sub)=nodeChildren($node); asScripts($node,$target,$level,$displaystyle,$scriptlevel,$demerits, 0,$base,$sub,['m:none']); } sub layout_msup { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my($base,$sup)=nodeChildren($node); asScripts($node,$target,$level,$displaystyle,$scriptlevel,$demerits, 0,$base,['m:none'],$sup); } sub layout_msubsup { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my($base,$sub,$sup)=nodeChildren($node); asScripts($node,$target,$level,$displaystyle,$scriptlevel,$demerits, 0,$base,$sub,$sup); } sub layout_munder { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my($base,$sub)=nodeChildren($node); asScripts($node,$target,$level,$displaystyle,$scriptlevel,$demerits, 1,$base,$sub,['m:none']); } sub layout_mover { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my($base,$sup)=nodeChildren($node); asScripts($node,$target,$level,$displaystyle,$scriptlevel,$demerits, 1,$base,['m:none'],$sup); } sub layout_munderover { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my($base,$sub,$sup)=nodeChildren($node); asScripts($node,$target,$level,$displaystyle,$scriptlevel,$demerits, 1,$base,$sub,$sup); } sub layout_mmultiscripts { my($node,$target,$level,$displaystyle,$scriptlevel,$demerits)=@_; my($base,@scripts)=nodeChildren($node); @scripts = grep( nodeName($_) ne "m:mprescripts", @scripts); # Remove prescripts marker (if any). asScripts($node,$target,$level,$displaystyle,$scriptlevel,$demerits, 0,$base,@scripts); } #====================================================================== 1; LaTeXML-0.7.0/lib/LaTeXML/Util/Transform.pm0000644002506700454610000001377611214255167017260 0ustar miller891divpackage LaTeXML::Util::Transform; use strict; use LaTeXML::Global; use LaTeXML::Number; use LaTeXML::Util::Geometry; use Math::Trig; use Exporter; our @ISA = qw(Exporter); our @EXPORT = (qw(&Transform)); our $eps = 0.000001; sub Transform { LaTeXML::Util::Transform->new(@_); } sub new { my ($class, $transform) = @_; $transform = '' unless $transform; if (ref $transform eq 'ARRAY') { $transform = join(' ', @{$transform}); } if (ref $transform) { $transform = $transform->toString; } my $self = [1, 0, 0, 1, 0, 0]; if ($transform) { $transform =~ s/,/ /g; $transform =~ s/\s+$//; $transform =~ s/\s+/ /g; while ($transform) { $transform =~ s/^\s//; if ($transform =~ s/^translate\(([^\s]+) ([^\)]+)\)//) { $self = _multiply($self, [1, 0, 0, 1, $1, $2]); } elsif ($transform =~ s/^translate\(([^\)\s]+)\)//) { $self = _multiply($self, [1, 0, 0, 1, $1, 0]); } elsif ($transform =~ s/^rotate\(([^\)\s]+)\)//) { my $angle = radians($1); my ($c, $s) = (cos($angle), sin($angle)); $self = _multiply($self, [$c, $s, -$s, $c, 0, 0]); } elsif ($transform =~ s/^rotate\(([^\s]+) ([^\s]+) ([^\)]+)\)//) { my ($angle, $tx, $ty) = (radians($1), $2, $3); my ($c, $s) = (cos($angle), sin($angle)); $self = _multiply($self, [$c, $s, -$s, $c, $tx*(1-$c) + $ty*$s, $ty*(1-$c)-$tx*$s]); } elsif ($transform =~ s/^scale\(([^\s]+) ([^\)]+)\)//) { $self = _multiply($self, [$1, 0, 0, $2, 0, 0]); } elsif ($transform =~ s/^scale\(([^\)\s]+)\)//) { $self = _multiply($self, [$1, 0, 0, $1, 0, 0]); } elsif ($transform =~ s/^skewX\(([^\)]+)\)//) { my $angle = radians($1); my ($c, $s) = (cos($angle), sin($angle)); $self = _multiply($self, [1, 0, $s/$c, 1, 0, 0]) if $c != 0; } elsif ($transform =~ s/^skewY\(([^\)]+)\)//) { my $angle = radians($1); my ($c, $s) = (cos($angle), sin($angle)); $self = _multiply($self, [1, $s/$c, 0, 1, 0, 0]) if $c != 0; } elsif ($transform =~ s/^matrix\(([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([^\)]+)\)//) { $self = _multiply($self, [$1, $2, $3, $4, $5, $6]); } else { Error(":misdefined: Unable to parse transform '$transform'"); last; }}} bless($self, $class); } sub isIdentity { my ($a, $b, $c, $d, $e, $f) = @{$_[0]}; ($b, $c, $e, $f) = map(abs($_), ($b, $c, $e, $f)); ($a < 1+$eps && $a > 1-$eps && $b < $eps && $c < $eps && $d < 1+$eps && $d > 1-$eps && $e < $eps && $f < $eps); } sub isTranslation { my ($a, $b, $c, $d, $e, $f) = @{$_[0]}; ($b, $c, $e, $f) = map(abs($_), ($b, $c, $e, $f)); ($a < 1+$eps && $a > 1-$eps && $b < $eps && $c < $eps && $d < 1+$eps && $d > 1-$eps && ($e > $eps || $f > $eps)); } sub isRotation { my ($a, $b, $c, $d, $e, $f) = @{$_[0]}; (abs($a-$d) < $eps && abs($b+$c) < $eps && abs($a**2+$b**2 - 1) < $eps && abs($e) < $eps && abs($f) < $eps); } sub isScaling { my ($a, $b, $c, $d, $e, $f) = @{$_[0]}; ($b, $c, $e, $f) = map(abs($_), ($b, $c, $e, $f)); (($a > 1+$eps || $a < 1-$eps) && $b < $eps && $c < $eps && ($d > 1+$eps || $d < 1-$eps) && $e < $eps && $f < $eps); } sub inverse { my $self = $_[0]; bless(_inverse($self), ref $self); } sub differenceTo { my $self = $_[0]; my $to = ($_[1] && ref $_[1] && ref $self eq ref $_[1]) ? $_[1] : (ref $self)->new($_[1]); bless(_multiply(_inverse($self), $to), ref $self); } sub addPre { my $self = $_[0]; my $what = ($_[1] && ref $_[1] && ref $self eq ref $_[1]) ? $_[1] : (ref $self)->new($_[1]); bless(_multiply($what, $self), ref $self); } sub addPost { my $self = $_[0]; my $what = ($_[1] && ref $_[1] && ref $self eq ref $_[1]) ? $_[1] : (ref $self)->new($_[1]); bless(_multiply($self, $what), ref $self); } sub removePre { my $self = $_[0]; my $what = ($_[1] && ref $_[1] && ref $self eq ref $_[1]) ? $_[1] : (ref $self)->new($_[1]); bless(_multiply($self, _inverse($what)), ref $self); } sub removePost { my $self = $_[0]; my $what = ($_[1] && ref $_[1] && ref $self eq ref $_[1]) ? $_[1] : (ref $self)->new($_[1]); bless(_multiply(_inverse($what), $self), ref $self); } sub apply { my ($self, $x, $y) = @_; my ($a, $b, $c, $d, $e, $f) = @{$self}; my $pair = 0; if (!defined $y) { $y = $x->getY->valueOf; $x = $x->getX->valueOf; $pair = 1; } my ($ax, $ay) = ($a*$x+$c*$y+$e, $b*$x+$d*$y+$f); $pair ? Pair(Dimension($ax), Dimension($ay)) : ($ax, $ay); } sub unapply { my ($self, $x, $y) = @_; my ($a, $b, $c, $d, $e, $f) = @{$self}; my $pair = 0; if (!defined $y) { $y = $x->getY->valueOf; $x = $x->getX->valueOf; $pair = 1; } my $dt = $a*$d-$b*$c; return unless $dt; my ($ax, $ay) = (($c*$f-$d*$e)/$dt + $d*$x/$dt - $c*$y/$dt, ($b*$e-$a*$f)/$dt - $b*$x/$dt + $a*$y/$dt); $pair ? Pair(Dimension($ax), Dimension($ay)) : ($ax, $ay); } sub equals { my ($a1, $b1, $c1, $d1, $e1, $f1) = @{$_[0]}; my ($a2, $b2, $c2, $d2, $e2, $f2) = @{$_[1]}; my @diff = grep(abs > $eps, ($a1-$a2, $b1-$b2, $c1-$c2, $d1-$d2, $e1-$e2, $f1-$f2)); $#diff == -1; } sub toString { my ($self, $ptValue) = @_; return '' if $self->isIdentity(); my ($a, $b, $c, $d, $e, $f) = @{$self}; if ($ptValue) { $e = Dimension($e)->ptValue(); $f = Dimension($f)->ptValue(); } return 'rotate('.(trunc(3,_aCS($a, $b))).')' if $self->isRotation(); ($e, $f) = trunc(3, ($e, $f)); return "translate($e,$f)" if $self->isTranslation(); ($a, $d) = trunc(3, ($a, $d)); return "scale($a,$d)" if $self->isScaling(); ($b, $c) = trunc(3, ($b, $c)); return "matrix($a,$b,$c,$d,$e,$f)"; } sub ptValue { $_[0]->toString(1); } sub _aCS { my ($c, $s) = @_; my $r = rad2deg(acos($c)); $r = 360 - $r if $s < 0; $r; } sub _multiply { my ($a1, $b1, $c1, $d1, $e1, $f1) = @{$_[0]}; my ($a2, $b2, $c2, $d2, $e2, $f2) = @{$_[1]}; [$a1*$a2+$b2*$c1, $a2*$b1+$b2*$d1, $a1*$c2+$c1*$d2, $b1*$c2+$d1*$d2, $e1+$a1*$e2+$c1*$f2, $b1*$e2+$f1+$d1*$f2]; } sub _inverse { my ($a, $b, $c, $d, $e, $f) = @{$_[0]}; my $dt = $a*$d-$b*$c; return unless $dt; [$d/$dt, -$b/$dt, -$c/$dt, $a/$dt, ($c*$f-$d*$e)/$dt, ($b*$e-$a*$f)/$dt]; } 1; LaTeXML-0.7.0/lib/LaTeXML/Util/Color.pm0000644002506700454610000000666411214255167016361 0ustar miller891div# /=====================================================================\ # # | LaTeXML::Util::Color | # # | Helpful routines for color conversion | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Util::Color; use strict; use LaTeXML::Global; use LaTeXML::Util::Transform; use Exporter; our @ISA = qw(Exporter); our @EXPORT= (qw(&ConvertColor &RGB &Gray2RGB &HSB2RGB &CMYK2RGB)); sub round { int($_[0]+0.5*($_[0] <=> 0)); } sub ConvertColor { my ($model, $spec) = @_; my $color = 0; if ($model =~ /gray/) { $color = '#'.Gray2RGB($spec); } elsif ($model =~ /rgb/) { $color = '#'.RGB($spec); } elsif ($model =~ /cmyk/) { $color = '#'.CMYK2RGB($spec); } elsif ($model =~ /hsb/) { $color = '#'.HSB2RGB($spec); } elsif ($model =~ /named/){ $color = $spec; } else { Warn(":unexpected:$model Unknown color model: $model"); } $color; } sub RGB { my ($_r, $_g, $_b) = map(round($_*255), _ValueList($_[0])); _RGB($_r, $_g, $_b); } sub Gray2RGB { my $n = round($_[0]*255); _RGB($n, $n, $n); } # adapted from http://www.ficml.org/jemimap/style/color/hsvwheel.phps sub HSB2RGB { my ($h, $s, $b) = _ValueList($_[0]); my ($_r, $_g, $_b); $h = $h*360; $s = $s*100; $b = $b*100; my $max = round($b*51/20); my $min = round($max*(1 - $s/100)); if ($min == $max) { ($_r,$_g,$_b) = ($max, $max, $max); } else { my $d = $max - $min; my $h6 = $h/60; if ($h6 <= 1) { ($_r,$_g,$_b) = ($max, round($min + $h6*$d), $min); } elsif ($h6 <= 2) { ($_r,$_g,$_b) = (round($min - ($h6 - 2)*$d), $max, $min); } elsif ($h6 <= 3) { ($_r,$_g,$_b) = ($min, $max, round($min + ($h6 - 2)*$d)); } elsif ($h6 <= 4) { ($_r,$_g,$_b) = ($min, round($min - ($h6 - 4)*$d), $max); } elsif ($h6 <= 5) { ($_r,$_g,$_b) = (round($min + ($h6 - 4)*$d), $min, $max); } else { ($_r,$_g,$_b) = ($max, $min, round($min - ($h6 - 6)*$d)); }} _RGB($_r, $_g, $_b); } # http://en.wikipedia.org/wiki/CMYK#Converting_CMYK_to_RGB sub CMYK2RGB { my ($c, $m, $y, $k) = _ValueList($_[0]); my ($_r, $_g, $_b) = map(round((1-$_*(1-$k)-$k)*255), ($c, $m, $y)); _RGB($_r, $_g, $_b); } # given R, G, B, compute the RGB value sub _RGB { toHex((($_[0] << 16) + ($_[1] << 8) + $_[2]), 6); } # explode a string into the float values it is made of # separator can be ' ' or ',' sub _ValueList { my $L = $_[0]; return unless $L; $L =~ s/^\s+//; $L =~ s/\s+$//; $L =~ s/\s+/ /g; $L =~ s/\s*,\s*/,/g; if ($L =~ / /) { split(/ /,$L); } else { split(/,/,$L); }} # toHex(number, digits); # if number is to small, it will be padded with '0'es sub toHex { my @N = qw(0 1 2 3 4 5 6 7 8 9 A B C D E F); local *makeHex = sub { $_[0]<16?$N[$_[0]]:makeHex(int($_[0]/16)).makeHex($_[0]%16); }; my $h = makeHex($_[0]); my $t = ($_[1]?$_[1]:0)-length($h); $t = 0 if $t<0; ('0'x$t).$h; } 1; LaTeXML-0.7.0/lib/LaTeXML/Util/KeyVal.pm0000644002506700454610000002236611215766022016471 0ustar miller891div# -*- CPERL -*- # /=====================================================================\ # # | KeyVal | # # | Support for key-value pairs for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Util::KeyVal; use strict; use LaTeXML::Package; our @ISA = qw(Exporter); our @EXPORT= (qw(&ReadRequiredKeyVals &ReadOptionalKeyVals &DefKeyVal &KeyVal &KeyVals)); #====================================================================== # New Readers for required and optional KeyVal sets. # These can also be used as parameter types. # They create a new data KeyVals object sub ReadRequiredKeyVals { my($gullet,$keyset)=@_; if($gullet->ifNext(T_BEGIN)){ (readKeyVals($gullet,$keyset,T_END)); } else { Error(":expected:{ Missing keyval arguments"); (LaTeXML::KeyVals->new($keyset,T_BEGIN,T_END,)); }} sub ReadOptionalKeyVals { my($gullet,$keyset)=@_; ($gullet->ifNext(T_OTHER('[')) ? (readKeyVals($gullet,$keyset,T_OTHER(']'))) : undef); } #====================================================================== # This new declaration allows you to define the type associated with # the value for specific keys. sub DefKeyVal { my($keyset,$key,$type,$default)=@_; my $paramlist=LaTeXML::Package::parseParameters($type,"KeyVal $key in set $keyset"); AssignValue('KEYVAL@'.$keyset.'@'.$key => $paramlist); AssignValue('KEYVAL@'.$keyset.'@'.$key.'@default' => Tokenize($default)) if defined $default; return; } #====================================================================== # These functions allow convenient access to KeyVal objects within constructors. # Access the value associated with a given key. # Can use in constructor: eg. sub KeyVal { my($keyval,$key)=@_; (defined $keyval) && $keyval->getValue($key); } # Access the entire hash. # Can use in constructor: sub KeyVals { my($keyval)=@_; (defined $keyval ? $keyval->getKeyVals : {}); } #====================================================================== # A KeyVal argument MUST be delimited by either braces or brackets (if optional) # This method reads the keyval pairs INCLUDING the delimiters, (rather than parsing # after the fact), since some values may have special catcode needs. our $T_EQ = T_OTHER('='); our $T_COMMA = T_OTHER(','); sub readKeyVals { my($gullet,$keyset,$close)=@_; my $startloc = $gullet->getLocator(); my $open = $gullet->readToken; $keyset = ($keyset ? ToString($keyset) : '_anonymous_'); my @kv=(); while(1) { $gullet->skipSpaces; # Read the keyword. my($ktoks,$delim)=$gullet->readUntil($T_EQ,$T_COMMA,$close); Error(":expected:".Stringify($close)." Fell off end expecting ".Stringify($close)." while reading KeyVal key starting at $startloc") unless $delim; my $key= ToString($ktoks); $key=~s/\s//g; if($key){ my $keydef=LookupValue('KEYVAL@'.$keyset.'@'.$key); my $value; if($delim->equals($T_EQ)){ # Got =, so read the value # WHOA!!! Secret knowledge!!! my $type = ($keydef && (scalar(@$keydef)==1) && $keydef->[0]->{type}) || 'Plain'; my $typedef = $LaTeXML::Parameters::PARAMETER_TABLE{$type}; StartSemiverbatim if $typedef && $$typedef{semiverbatim}; ($value,$delim)=$gullet->readUntil($T_COMMA,$close); if(($type eq 'Plain') || ($typedef && $$typedef{undigested})){} # Fine as is. elsif($type eq 'Semiverbatim'){ # Needs neutralization $value = $value->neutralize; } else { ($value) = $keydef->reparseArgument($gullet,$value) } EndSemiverbatim if $typedef && $$typedef{semiverbatim}; } else { # Else, get default value. $value = LookupValue('KEYVAL@'.$keyset.'@'.$key.'@default'); } push(@kv,$key); push(@kv,$value); } Error(":expected:".Stringify($close)." Fell off end expecting ".Stringify($close)." while reading KeyVal value starting at $startloc") unless $delim; last if $delim->equals($close); } LaTeXML::KeyVals->new($keyset,$open,$close,@kv); } #********************************************************************** # This defines the KeyVal data object that can appear in the datastream # along with tokens, boxes, etc. # Thus it has to be digestible. # KeyVals: representation of keyval arguments, # Not necessarily a hash, since keys could be repeated and order may # be significant. #********************************************************************** # Where does this really belong? # The values can be Tokens, after parsing, or Boxes, after digestion. # (or Numbers, etc. in either case) # But also, it has a non-generic API used above... # If Box-like, it could have a beAbsorbed method; which would do what? # Should it convert to simple text? Or structure? # If latter, there needs to be a key => tag mapping. package LaTeXML::KeyVals; use LaTeXML::Global; use LaTeXML::Package; use base qw(LaTeXML::Object); # Spec?? sub new { my($class,$keyset,$open,$close,@pairs)=@_; my %hash = (); my @pp=@pairs; while(@pp){ my($k,$v) = (shift(@pp),shift(@pp)); if(!defined $hash{$k}){ $hash{$k}=$v; } # Hmm, accumulate an ARRAY if multiple values for given key. # This is unlikely to be what the caller expects!! But what? elsif(ref $hash{$k} eq 'ARRAY'){ push(@{$hash{$k}},$v); } else { $hash{$k}=[$hash{$k},$v]; }} bless {keyset=>$keyset, open=>$open, close=>$close, keyvals=>[@pairs], hash=>{%hash}},$class; } sub getValue { my($self,$key)=@_; $$self{hash}{$key}; } sub setValue { my($self,$key,$value)=@_; if(defined $value){ $$self{hash}{$key}=$value; } else { delete $$self{hash}{$key}; }} sub getPairs { my($self)=@_; @{$$self{keyvals}}; } sub getKeyVals { my($self)=@_; $$self{hash}; } sub getHash { my($self)=@_; map( ($_ => ToString($$self{hash}{$_})), keys %{$$self{hash}}); } sub beDigested { my($self,$stomach)=@_; my $keyset = $$self{keyset}; my @kv=@{$$self{keyvals}}; my @dkv=(); while(@kv){ my($key,$value)=(shift(@kv),shift(@kv)); my $keydef=LookupValue('KEYVAL@'.$keyset.'@'.$key); my $dodigest = (ref $value) && (!$keydef || !$$keydef[0]{undigested}); push(@dkv,$key, ($dodigest ? $value->beDigested($stomach) : $value)); } (ref $self)->new($$self{keyset},$$self{open},$$self{close},@dkv); } sub revert { my($self)=@_; my $keyset = $$self{keyset}; my @tokens=(); my @kv=@{$$self{keyvals}}; while(@kv){ my($key,$value)=(shift(@kv),shift(@kv)); my $keydef=LookupValue('KEYVAL@'.$keyset.'@'.$key); push(@tokens,T_OTHER(','),T_SPACE) if @tokens; push(@tokens,Explode($key)); push(@tokens,T_OTHER('='), ($keydef ? $keydef->revertArguments($value) : $value->revert)) if $value; } unshift(@tokens,$$self{open} ) if $$self{open}; push( @tokens,$$self{close}) if $$self{close}; @tokens; } sub unlist { $_[0]; } # ???? sub toString { my($self)=@_; my $string=''; my @kv=@{$$self{keyvals}}; while(@kv){ my($key,$value)=(shift(@kv),shift(@kv)); $string .= ', ' if $string; $string .= $key.'='.ToString($value); } $string; } #====================================================================== 1; __END__ =pod =head1 NAME C - support for keyvals =head1 DESCRIPTION Provides a parser and representation of keyval pairs C represents parameters handled by LaTeX's keyval package. =head2 Declarations =over 4 =item C<< DefKeyVal($keyset,$key,$type); >> Defines the type of value expected for the key $key when parsed in part of a KeyVal using C<$keyset>. C<$type> would be something like 'any' or 'Number', but I'm still working on this. =back =head2 Accessors =over 4 =item C<< KeyVal($arg,$key) >> This is useful within constructors to access the value associated with C<$key> in the argument C<$arg>. =item C<< KeyVals($arg) >> This is useful within constructors to extract all keyvalue pairs to assign all attributes. =back =head2 KeyVal Methods =over 4 =item C<< $value = $keyval->getValue($key); >> Return the value associated with C<$key> in the C<$keyval>. =item C<< @keyvals = $keyval->getKeyVals; >> Return the hash reference containing the keys and values bound in the C<$keyval>. Note that will only contain the last value for a given key, if they were repeated. =item C<< @keyvals = $keyval->getPairs; >> Return the alternating keys and values bound in the C<$keyval>. Note that this may contain multiple entries for a given key, if they were repeated. =item C<< $keyval->digestValues; >> Return a new C object with all values digested as appropriate. =back =head1 AUTHOR Bruce Miller =head1 COPYRIGHT Public domain software, produced as part of work done by the United States Government & not subject to copyright in the US. =cut LaTeXML-0.7.0/lib/LaTeXML/Util/Pathname.pm0000644002506700454610000003205711214255167017033 0ustar miller891div# /=====================================================================\ # # | LaTeXML::Util::Pathname | # # | Pathname Utilities for LaTeXML | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # #====================================================================== # Sanely combine features of File::Spec and File::Basename # Somehow, both modules tend to bite me at random times. # eg. sometimes Basename's fileparse doesn't extract extension. # sometimes File::Spec seems to do too many filesystem checks (gets slow!) # File::Spec->splitpath "may or may not ... trailing '/'" ... Huh? #====================================================================== # My first instinct is that this should bless the pathnames, # but strings as pathnames come so naturally in perl; # But I may still do it... #====================================================================== # Some portability changes for Windows, thanks to Ioan Sucan. #====================================================================== # Packages in the LaTeXML::Util package set have no dependence on LaTeXML # objects or context. #====================================================================== package LaTeXML::Util::Pathname; use strict; use File::Spec; use File::Copy; use Cwd; use Exporter; our @ISA = qw(Exporter); our @EXPORT = qw( &pathname_find &pathname_findall &pathname_make &pathname_canonical &pathname_split &pathname_directory &pathname_name &pathname_type &pathname_timestamp &pathname_concat &pathname_relative &pathname_absolute &pathname_is_absolute &pathname_cwd &pathname_mkdir &pathname_copy); # NOTE: For absolute pathnames, the directory component starts with # whatever File::Spec considers to be the volume, or "/". #====================================================================== # Ioan Sucan suggests switching this to '\\' for windows, but notes # that it works as it is, so we'll leave it (for now). our $SEP = '/'; #====================================================================== # pathname_make(dir=>dir, name=>name, type=>type); # Returns a pathname. This will be an absolute path if # dir (or the first, if dir is an array), is absolute. sub pathname_make { my(%pieces)=@_; my $pathname= ''; my $dir = $pieces{dir}; $dir = join($SEP,@$dir) if $dir && (ref $dir eq 'ARRAY'); $pathname .= $dir if $dir; $pathname .= $SEP if $pathname && $pieces{name}; $pathname .= $pieces{name} if $pieces{name}; $pathname .= '.'.$pieces{type} if $pieces{type}; pathname_canonical($pathname); } # Split the pathname into components (dir,name,type). # If pathname is absolute, dir starts with volume or '/' sub pathname_split { my($pathname)=@_; $pathname = pathname_canonical($pathname); my($vol,$dir,$name)=File::Spec->splitpath($pathname); # Hmm, for /, we get $dir = / but we want $vol='/' ????? if($vol) { $dir = $vol.$dir; } elsif(File::Spec->file_name_is_absolute($pathname)){ $dir = $SEP.$dir; } my $type = ''; $type = $1 if $name =~ s/\.([^\.]+)$//; ($dir,$name,$type); } use Carp; sub pathname_canonical { my($pathname)=@_; confess "Undefined pathname!" unless defined $pathname; # File::Spec->canonpath($pathname); } $pathname =~ s|^~|$ENV{HOME}|; $pathname =~ s|//+|/|g; $pathname =~ s|/\./|/|g; # Collapse any foo/.. patterns, but not ../.. while($pathname =~ s|/(?!\.\./)[^/]+/\.\.(/\|$)|$1|){} $pathname =~ s|^\./||; $pathname; } # Convenient extractors; sub pathname_directory { my($dir,$name,$type)=pathname_split(@_); $dir; } sub pathname_name { my($dir,$name,$type)=pathname_split(@_); $name; } sub pathname_type { my($dir,$name,$type)=pathname_split(@_); $type; } #====================================================================== sub pathname_concat { my($dir,$file)=@_; File::Spec->catpath('',$dir || '',$file); } #====================================================================== # Is $pathname an absolute pathname ? # pathname_is_absolute($pathname) => (0|1) sub pathname_is_absolute { my($pathname)=@_; $pathname && File::Spec->file_name_is_absolute(pathname_canonical($pathname)); } # pathname_relative($pathname,$base) => $relativepathname # Return $pathname as a pathname relative to $base. sub pathname_relative { my($pathname,$base)=@_; File::Spec->abs2rel(pathname_canonical($pathname),pathname_canonical($base)); } sub pathname_absolute { my($pathname,$base)=@_; File::Spec->rel2abs(pathname_canonical($pathname),$base && pathname_canonical($base)); } #====================================================================== # Actual file system operations. sub pathname_timestamp { -f $_[0] ? (stat($_[0]))[9] : 0; } sub pathname_cwd { cwd(); } sub pathname_mkdir { my($directory)=@_; return undef unless $directory; $directory = pathname_canonical($directory); my($volume,$dirs,$last)=File::Spec->splitpath($directory); my(@dirs)=(File::Spec->splitdir($dirs),$last); for(my $i=0; $i <= $#dirs; $i++){ my $dir = File::Spec->catpath($volume,File::Spec->catdir(@dirs[0..$i]),''); if(! -d $dir){ mkdir($dir) or return undef; }} return $directory; } # copy a file, preserving attributes, if possible. # Why doesn't File::Copy preserve attributes on Unix !?!?!? sub pathname_copy { my($source,$destination)=@_; # If it _needs_ to be copied: $source = pathname_canonical($source); $destination = pathname_canonical($destination); if((!-f $destination) || (pathname_timestamp($source) > pathname_timestamp($destination))){ if(my $destdir = pathname_directory($destination)){ pathname_mkdir($destdir) or return undef; } ### if($^O =~ /^(MSWin32|NetWare)$/){ # Windows ### # According to Ioan, this should work: ### system("xcopy /P $source $destination")==0 or return undef; } ### else { # Unix ### system("cp --preserve=timestamps $source $destination")==0 or return undef; } # Hopefully this portably copies, preserving timestamp. copy($source,$destination) or return undef; my($atime,$mtime)= (stat($source))[8,9]; utime $atime,$mtime,$destination; # And set the modification time } return $destination; } #====================================================================== # pathname_find($pathname, paths=>[...], types=>[...]) => $absolute_pathname; # Find a file corresponding to $pathname returning the absolute, # completed pathname if found, else undef # * If $pathname is a not an absolute pathname # (although it may still have directory components) # then if search $paths are given, search for it relative to # each of the directories in $paths, # else search for it relative to the current working directory. # * If types is given, then search (in each searched directory) # for the first file with the given extension. # The extension "" (empty string) means to search for the exact name. # * If types is not given, search for the exact named file # without additional extension. # * If installation_subdir is given, look in that subdirectory of where LaTeXML # was installed, by appending it to the paths. our @INSTALLDIRS = grep(-d $_, map("$_/LaTeXML", @INC)); sub pathname_find { my($pathname,%options)=@_; return undef unless $pathname; my @paths = candidate_pathnames($pathname,%options); foreach my $path (@paths){ return $path if -f $path; }} sub pathname_findall { my($pathname,%options)=@_; return undef unless $pathname; my @paths = candidate_pathnames($pathname,%options); grep(-f $_, @paths); } # It's presumably cheep to concatinate all the pathnames, # relative to the cost of testing for files, # and this simplifies overall. sub candidate_pathnames { my($pathname,%options)=@_; my @dirs=(''); $pathname = pathname_canonical($pathname); if(!pathname_is_absolute($pathname)){ my $cwd = pathname_cwd(); # Complete the search paths by prepending current dir to relative paths, # but have at least the current dir. @dirs = ($options{paths} ? map( (pathname_is_absolute($_) ? pathname_canonical($_) : pathname_concat($cwd,$_)), @{$options{paths}}) : ($cwd)); # And, if installation dir specified, append it. if(my $subdir = $options{installation_subdir}){ push(@dirs,map(pathname_concat($_,$subdir),@INSTALLDIRS)); }} # extract the desired extensions. my @exts = (); if($options{types}){ foreach my $ext (@{$options{types}}){ if($ext eq ''){ push(@exts,''); } elsif($pathname =~ /\.\Q$ext\E$/i){ push(@exts,''); } else { # Half attempt at case insensitivity; not actually correct, though. ## Disabled, since it screws up on the Mac's partially case-insensitive (?) filesystem. ## push(@exts,'.'.lc($ext)) if $ext =~/[A-Z]/; ## push(@exts,'.'.uc($ext)) if $ext =~/[a-z]/; push(@exts, '.'.$ext); }}} push(@exts,'') unless @exts; my @paths = (); # Now, combine; precedence to leading directories. foreach my $dir (@dirs){ foreach my $ext (@exts){ push(@paths,pathname_concat($dir,$pathname.$ext)); }} @paths; } #====================================================================== 1; __END__ =pod =head1 NAME C - portable pathname and file-system utilities =head1 DESCRIPTION This module combines the functionality L and L to give a consistent set of filename utilties for LaTeXML. A pathname is represented by a simple string. =head2 Pathname Manipulations =over 4 =item C<< $path = pathname_make(%peices); >> Constructs a pathname from the keywords in pieces dir : directory name : the filename (possibly with extension) type : the filename extension =item C<< ($dir,$name,$type) = pathname_split($path); >> Splits the pathname C<$path> into the components: directory, name and type. =item C<< $path = pathname_canonical($path); >> Canonicallizes the pathname C<$path> by simplifying repeated slashes, dots representing the current or parent directory, etc. =item C<< $dir = pathname_directory($path); >> Returns the directory component of the pathname C<$path>. =item C<< $name = pathname_name($path); >> Returns the name component of the pathname C<$path>. =item C<< $type = pathname_type($path); >> Returns the type component of the pathname C<$path>. =item C<< $path = pathname_concat($dir,$file); >> Returns the pathname resulting from concatenating the directory C<$dir> and filename C<$file>. =item C<< $boole = pathname_is_absolute($path); >> Returns whether the pathname C<$path> appears to be an absolute pathname. =item C<< $path = pathname_relative($path,$base); >> Returns the path to file C<$path> relative to the directory C<$base>. =item C<< $path = pathname_absolute($path,$base); >> Returns the absolute pathname resulting from interpretting C<$path> relative to the directory C<$base>. If C<$path> is already absolute, it is returned unchanged. =back =head2 File System Operations =over 4 =item C<< $modtime = pathname_timestamp($path); >> Returns the modification time of the file named by C<$path>, or undef if the file does not exist. =item C<< $path = pathname_cwd(); >> Returns the current working directory. =item C<< $dir = pathname_mkdir($dir); >> Creates the directory C<$dir> and all missing ancestors. It returns C<$dir> if successful, else undef. =item C<< $dest = pathname_copy($source,$dest); >> Copies the file C<$source> to C<$dest> if needed; ie. if C<$dest> is missing or older than C<$source>. It preserves the timestamp of C<$source>. =item C<< $path = pathname_find($name,%options); >> Finds the first file named C<$name> that exists and that matches the specification in the keywords C<%options>. An absolute pathname is returned. If C<$name> is not already an absolute pathname, then the option C determines directories to recursively search. It should be a list of pathnames, any relative paths are interpreted relative to the current directory. If C is omitted, then the current directory is searched. If the option C is given, it indicates, in addition to the above, a directory relative to the LaTeXML installation directory to search. This allows files included with the distribution to be found. The C option specifies a list of filetypes to search for. If not supplied, then the filename must match exactly. =item C<< @paths = pathname_findall($name,%options); >> Like C, but returns all matching paths that exist. =back =head1 AUTHOR Bruce Miller =head1 COPYRIGHT Public domain software, produced as part of work done by the United States Government & not subject to copyright in the US. =cut LaTeXML-0.7.0/lib/LaTeXML/Util/ObjectDB.pm0000644002506700454610000002134011214255167016703 0ustar miller891div# /=====================================================================\ # # | LaTeXML::Util::ObjectDB | # # | Database of Objects for crossreferencing, etc | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Util::ObjectDB; use strict; use LaTeXML::Util::Pathname; use DB_File; use Storable qw(nfreeze thaw); use strict; use Encode; use Carp; our @ISA=qw(Storable); #====================================================================== # NOTES: # (1) If we can do make-like processing, when an entry is marked as # modified, any referrers to it also need processing. # (and we could defer a save if nothing was dirty) #====================================================================== # Some Definitions: # * Object: places a link will take you to. Several types # * chunk: any significant document object with a reference # number: sectional chunks, equations, ... # * index : the target is the entry in the index itself. # a back reference can take you to where the \index was invoked. # * bib : the target is the entry in the bibliography. # a back reference can take you to the \cite. # #====================================================================== our @DBS=(); END { map($_->finish, @DBS); } #====================================================================== # Creating an ObjectDB object, hooking up initial database. sub new { my($class, %options)=@_; my $dbfile = $options{dbfile}; if($dbfile && $options{clean}){ warn "\nWARN: Removing Object database file $dbfile!!!\n"; unlink($dbfile); } my $self = bless {dbfile=>$dbfile, objects=>{}, externaldb=>{}, verbosity => $options{verbosity}||0, read_write => $options{read_write}, }, $class; if($dbfile){ ## my $flags = ($options{read_write} ? O_RDWR|O_CREAT : O_RDONLY); my $flags = O_RDWR|O_CREAT; tie %{$$self{externaldb}}, 'DB_File', $dbfile,$flags or die "Couldn't attach DB $dbfile for object table"; } push(@DBS,$self); $self; } sub status { my($self)=@_; my $status = scalar(keys %{$$self{objects}})." objects"; # if($$self{dbfile}){ ... $status; } #====================================================================== # This saves the db sub XXXfinish { my($self)=@_; if($$self{externaldb} && $$self{dbfile}){ my $n=0; my %types=(); my $opened = $$self{opened_timestamp}; foreach my $key (keys %{$$self{objects}}){ my $row = $$self{objects}{$key}; next if $$row{timestamp} < $opened; $n++; my %item = %$row; delete $item{key}; # Don't store these # $$row{timestamp}=$opened; ##print STDERR "Saving: ".$row->show."\n"; $$self{externaldb}{Encode::encode('utf8',$key)} = nfreeze({%item}); } print STDERR "ObjectDB Stored $n objects (".scalar(keys %{$$self{externaldb}})." total)\n" if $$self{verbosity} > 0; untie %{$$self{externaldb}}; } $$self{externaldb}=undef; $$self{objects}=undef; } sub finish { my($self)=@_; if($$self{externaldb} && $$self{dbfile}){ my $n=0; my %types=(); foreach my $key (keys %{$$self{objects}}){ my $row = $$self{objects}{$key}; # Skip saving, unless there's some difference between stored value if(my $stored = $$self{externaldb}{Encode::encode('utf8',$key)}){ # Get the external object next if compare_hash($row,thaw($stored)); } $n++; my %item = %$row; ##print STDERR "Saving: ".$row->show."\n"; $$self{externaldb}{Encode::encode('utf8',$key)} = nfreeze({%item}); } print STDERR "ObjectDB Stored $n objects (".scalar(keys %{$$self{externaldb}})." total)\n" if $$self{verbosity} > 0; untie %{$$self{externaldb}}; } $$self{externaldb}=undef; $$self{objects}=undef; } sub compare { my($a,$b)=@_; my $ra = ref $a; if(! $ra){ if(ref $b){ 0; } else { $a eq $b; }} elsif($ra ne ref $b){ 0; } elsif($ra eq 'HASH'){ compare_hash($a,$b); } elsif($ra eq 'ARRAY'){ compare_array($a,$b); } else { $a eq $b;}} sub compare_hash { my($a,$b)=@_; my %attr = (); map($attr{$_}=1, keys %$a); map($attr{$_}=1, keys %$b); (grep( !( (defined $$a{$_}) && (defined $$b{$_}) && compare($$a{$_}, $$b{$_}) ), keys %attr) ? 0 : 1); } sub compare_array { my($a,$b)=@_; my @a = @$a; my @b = @$b; while(@a && @b){ return 0 unless compare(shift(@a),shift(@b)); } (@a || @b ? 0 : 1); } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sub getKeys { my($self)=@_; # Get union of all keys in externaldb & local objects. my %keys = (); map($keys{$_}=1, keys %{$$self{objects}}); map($keys{Encode::decode('utf8',$_)}=1, keys %{$$self{externaldb}}); keys %keys; } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Lookup of various kinds of things in the DB. #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Lookup the Object associated with label # If it is not already fetched from the external db (if any), fetch it now. sub lookup { my($self,$key)=@_; return undef unless defined $key; my $entry = $$self{objects}{$key}; # Get the local copy. return $entry if $entry; $entry = $$self{externaldb}{Encode::encode('utf8',$key)}; # Get the external object if($entry){ $entry = thaw($entry); $$entry{key} = $key; bless $entry, 'LaTeXML::Util::ObjectDB::Entry'; $$self{objects}{$key} = $entry; } $entry; } #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Register various interesting document nodes. #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Register the labeled object $node, creating, or filling in, and # returning a Chunk entry. sub register { my($self,$key,%props)=@_; carp("Missing key for object!") unless $key; my $entry = $self->lookup($key); if(!$entry){ $entry = {key=>$key}; bless $entry, 'LaTeXML::Util::ObjectDB::Entry'; $$self{objects}{$key}=$entry; } $entry->setValues(%props); $entry; } #******************************************************************************** # DB Entries #******************************************************************************** package LaTeXML::Util::ObjectDB::Entry; use strict; use LaTeXML::Common::XML; our $XMLParser = LaTeXML::Common::XML::Parser->new(); sub new { my($class,$key,%data)=@_; bless {key=>$key,%data},$class; } sub key { $_[0]->{key}; } # Get/Set a value (column) in the DBRow entry, noting whether it modifies the entry. # Note that XML data is stored in it's serialized form, prefixed by "XML::". sub getValue { my($self,$attr)=@_; my $value = $$self{$attr}; if($value && $value =~ /^XML::/){ $value = $XMLParser->parseChunk(substr($value,5)); } $value; } sub setValues { my($self,%avpairs)=@_; foreach my $attr (keys %avpairs){ my $value = $avpairs{$attr}; if(((ref $value) || '') =~ /^XML::/){ # The node is cloned so as to copy any inherited namespace nodes. $value = "XML::".$value->cloneNode(1)->toString; } if(! defined $value){ if(defined $$self{$attr}){ delete $$self{$attr}; }} elsif((! defined $$self{$attr}) || ($$self{$attr} ne $value)){ $$self{$attr}=$value; }}} # Note an association with this entry # Roughly equivalent to $$entry{key1}{key2}{...}=1, # but keeps track of modification timestamps. --- not any more! sub noteAssociation { my($self,@keys)=@_; my $hash = $self; while(@keys){ my $key = shift(@keys); if(defined $$hash{$key}){ $hash = $$hash{$key}; } else { $hash = $$hash{$key} = (@keys ? {} : 1); }}} # Debugging aid use Text::Wrap; sub show { my($self)=@_; my $string = "ObjectDB Entry for: $$self{key}\n"; foreach my $attr (grep($_ ne 'key', keys %{$self})){ $string .= wrap(sprintf(' %16s : ',$attr),(' 'x20), showvalue($self->getValue($attr)))."\n"; } $string; } sub showvalue { my($value)=@_; if((ref $value) =~ /^XML::/){ $value->toString; } elsif(ref $value eq 'HASH'){ "{".join(', ',map("$_=>".showvalue($$value{$_}), keys %$value))."}"; } elsif(ref $value eq 'ARRAY'){ "[".join(', ',map(showvalue($_),@$value))."]"; } else { "$value"; }} #====================================================================== 1; LaTeXML-0.7.0/lib/LaTeXML/Util/Alignment.pm0000644002506700454610000007205111214255167017212 0ustar miller891div# /=====================================================================\ # # | LaTeXML::Util::Alignment | # # | Support for tabular/array environments | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Util::Alignment; use strict; use LaTeXML::Package; use Exporter; our @ISA = qw(Exporter); our @EXPORT= (qw( &constructAlignment &ReadAlignmentTemplate &parseAlignmentTemplate &MatrixTemplate)); #====================================================================== # An "Alignment" is an array/tabular construct as: # ... # or, for math mode # ... # (where initially, each XMCell will contain an XMArg to indicate # individual parsing of each cell's content is desired) # data should have: # containerElement => name of the container element # rowElement => name of row element # colElement => name of col element. sub new { my($class, %data)=@_; bless { %data, template=>LaTeXML::AlignmentTemplate->new(), rows=>[], current_column=>0, current_row=>undef}, $class; } ### sub setMath { my($self)=@_; $$self{isMath} = 1; } ### sub getTemplate { my($self,$template)=@_; $$self{template}; } sub setTemplate { my($self,$template)=@_; $$self{template}=$template; } ### sub currentRow { my($self)=@_; $$self{current_row}; } sub newRow { my($self)=@_; my $row = $$self{template}->clone; $$self{current_row} = $row; $$self{current_column} = 0; push(@{$$self{rows}}, $row); $row; } sub removeRow { my($self)=@_; my @rows = @{$$self{rows}}; if(@rows){ my $row = pop(@rows); $$self{rows} = [@rows]; $row; } else { undef; }} sub prependRows { my($self,@rows)=@_; unshift(@{$$self{rows}},@rows); } sub appendRows { my($self,@rows)=@_; push(@{$$self{rows}},@rows); } sub rows { my($self)=@_; @{$$self{rows}}; } ### sub addLine { my($self,$border,@cols)=@_; my $row = $$self{current_row}; if(@cols){ foreach my $c (@cols){ my $colspec = $row->column($c); $$colspec{border} .= $border; }} else { foreach my $colspec (@{$$row{columns}}){ $$colspec{border} .= $border; }} return; } ### sub nextColumn { my($self)=@_; my $colspec = $$self{current_row}->column( ++$$self{current_column} ); if(!$colspec){ Error(":unexpected:& Extra alignment tab"); $$self{current_row}->addColumn(align=>'center'); $colspec = $$self{current_row}->column( $$self{current_column} ); } $colspec; } sub currentColumnNumber { my($self)=@_; $$self{current_column}; } sub currentColumn { my($self)=@_; $$self{current_row}->column($$self{current_column}); } sub getColumn { my($self,$n)=@_; $$self{current_row}->column($n); } # sub missingColumns { # my($self)=@_; # my $n = scalar(@{$$self{current_row}{columns}}); # $n - $$self{current_column}; } #====================================================================== # Constructing the XML for the alignment. #====================================================================== # Normalize an alignment after construction # Tasks: # (1) a trailing \\ in the alignment will generate an empty row. # Note that the trailing \\ is required to get an \hline at the bottom! # It is empty in the sense that no cells have "real" content # but may have content generated from the template! # This emptiness is sensed by inner@column. # So, if we find such an empty row, we need to remove it, # but copy it's top border to a bottom border of the preceding row! # (2) Some table constructs, particularly Knuth's fancy ones, # have empty columns for spacing purposes. # These likely should be removed from the "logical" table we construct. # Here, emptiness should probably be that there is no text content # in the cell's at all (template data is presumably meaningful). # But here, also, border data may need to be moved (but l/r borders) # (3) put border attributes in a "normal" form to ease use as html's class attribute. # Ie: group by l/r/t/b w/ spaces between groups. # # OR, since I'm doing so much manipulation here, # maybe it just makes sense to build the entire XML from the alignment construction? # This would avoid lots of back & forth between the alignment & xml. # NOTE: Another cleanup issue: # With \halign, Knuth seems to like to introduce many empty columns for spacing. # It may be useful to remove such columns? # Probably have to sub constructAlignment { my($document,$body,%props)=@_; my $alignment = $body->getProperty('alignment'); $alignment->setMath if $body->isMath; my %attr = ($props{attributes} ? %{$props{attributes}} : ()); my $node = $alignment->beAbsorbed($document,%attr); # If requested to guess headers (unless cells are already marked) if($props{guess_headers} && !$document->findnodes('descendant::ltx:td[contains(@class,"thead")]',$node)){ guess_alignment_headers($document,$node,$alignment); } $node; } sub beAbsorbed { my($self,$document,%attributes)=@_; my $ismath = $$self{isMath}; my @rows = @{$$self{rows}}; # If last row is "empty", remove it, while copying it's top border to the bottom of prev. if(!grep(! $$_{empty}, @{$rows[-1]->{columns}})){ my $nc = scalar(@{$rows[-1]->{columns}}); for(my $c = 0; $c < $nc; $c++){ my $border = $rows[$#rows]{columns}[$c]{border}||''; $border =~ s/[^tT]//g; $border =~ s/./b/g; $rows[$#rows-1]{columns}[$c]{border} .= $border; } pop(@rows); pop(@{$$self{rows}}); } # Mark any cells that are covered by rowspans for(my $i=0; $i{columns}}; for(my $j=0; $j 1){ my $nc = $$col{colspan}||1; for(my $ii=$i+1; $ii<$i+$nr; $ii++){ if(my $rrow = $rows[$ii]){ for(my $jj=$j; $jj<$j+$nc; $jj++){ if(my $ccol = $$rrow{columns}[$jj]){ $$ccol{skipped}=1; }}}}}}} # We _should_ attach boxes to the alignment and rows, # but (ATM) we've only got sensible boxes for the cells. # $document->openElement($$self{containerElement},%attributes); &{$$self{openContainer}}($document,%attributes); foreach my $row (@{$$self{rows}}){ # $document->openElement($$self{rowElement}, # 'xml:id'=>$$row{id},refnum=>$$row{refnum}); &{$$self{openRow}}($document,'xml:id'=>$$row{id},refnum=>$$row{refnum}); foreach my $cell (@{$$row{columns}}){ next if $$cell{skipped}; # Normalize the border attribute my $border = join(' ',sort(map(split(/ */,$_),$$cell{border}||''))); $border =~ s/(.) \1/$1$1/g; my $empty = !$$cell{boxes} || !scalar($$cell{boxes}->unlist); # $$cell{cell} = $document->openElement($$self{colElement}, $$cell{cell} = &{$$self{openColumn}}($document, align=>$$cell{align}, width=>$$cell{width}, (($$cell{span}||1) != 1 ? (colspan=>$$cell{span}) : ()), (($$cell{rowspan}||1) != 1 ? (rowspan=>$$cell{rowspan}) : ()), ($border ? (border=>$border):()), ($$cell{head} ? (thead=>'true'):())); if(!$empty){ local $LaTeXML::BOX = $$cell{boxes}; $document->openElement('ltx:XMArg', rule=>'Anything,') if $ismath; $document->absorb($$cell{boxes}); $document->closeElement('ltx:XMArg') if $ismath; } # $document->closeElement($$self{colElement}); } &{$$self{closeColumn}}($document); } # $document->closeElement($$self{rowElement}); } &{$$self{closeRow}}($document); } # $document->closeElement($$self{containerElement}); &{$$self{closeContainer}}($document); } #====================================================================== #====================================================================== # newcolumntype # defines \NC@rewrite@ # As macro # or "constructor" (or just sub that creates a column) sub ReadAlignmentTemplate { my($gullet)=@_; $gullet->skipSpaces; local $LaTeXML::BUILD_TEMPLATE = LaTeXML::AlignmentTemplate->new(columns=>[], tokens=>[]); my @tokens=(T_BEGIN); my $nopens = 0; while(my $open = $gullet->readToken){ if($open->equals(T_BEGIN)){ $nopens++; } else { $gullet->unread($open); last; }} my $defn; while(my $op = $gullet->readToken){ if($op->equals(T_SPACE)){} elsif($op->equals(T_END)){ while(--$nopens && ($op=$gullet->readToken)->equals(T_END)){} last unless $nopens; $gullet->unread($op); } elsif(defined($defn=$STATE->lookupDefinition(T_CS('\NC@rewrite@'.ToString($op)))) && $defn->isExpandable){ # A variation on $defn->invoke, so we can reconstruct the reversion my @args = $defn->readArguments($gullet); my @exp = $defn->doInvocation($gullet,@args); if(@exp){ # This just expanded into other stuff $gullet->unread(@exp); } else { push(@tokens,$op); if(my $param = $defn->getParameters){ push(@tokens,$param->revertArguments(@args)); }}} elsif($op->equals(T_BEGIN)){ # Wrong, but a safety valve $gullet->unread($gullet->readBalanced->unlist); } else { Warn(":unexpected:".Stringify($op)." Unrecognized tabular template \"".Stringify($op)."\""); }} push(@tokens,T_END); $LaTeXML::BUILD_TEMPLATE->setReversion(@tokens); return $LaTeXML::BUILD_TEMPLATE; } sub parseAlignmentTemplate { my($spec)=@_; my $gullet = $STATE->getStomach->getGullet; $gullet->openMouth(LaTeXML::Mouth->new("{".$spec."}"),1); my $template = ReadAlignmentTemplate($gullet); $gullet->closeMouth(1); $template; } sub MatrixTemplate { LaTeXML::AlignmentTemplate->new(repeated=>[{before=>Tokens(T_CS('\hfil')), after=>Tokens(T_CS('\hfil'))}]); } { package LaTeXML::AlignmentTemplate; use base qw(LaTeXML::Object); use LaTeXML::Global; sub new { my($class,%data)=@_; $data{columns}=[] unless $data{columns}; $data{repeating} = 1 if $data{repeating} || $data{repeated}; $data{repeated} = [] unless $data{repeated}; $data{non_repeating} = scalar(@{$data{columns}}); $data{save_before} = [] unless $data{save_before}; map( $$_{empty}=1, @{$data{columns}}); map( $$_{empty}=1, @{$data{repeated}}); bless {%data}, $class; } sub revert { my($self)=@_; @{ $$self{tokens} }; } # Methods for constructing a template. sub setReversion { my($self,@tokens)=@_; $$self{tokens} = [@tokens]; } sub setRepeating { my($self)=@_; $$self{repeating}=1; } sub addBefore { my($self,@tokens)=@_; push(@{$$self{save_before}},@tokens); } sub addAfter { my($self,@tokens)=@_; $$self{current_column}{after} = Tokens(@{ $$self{current_column}{after}},@tokens); } sub addBetween { my($self,@tokens)=@_; my @cols = @{$$self{columns}}; if($$self{current_column}){ $self->addAfter(@tokens); } else { $self->addBefore(@tokens); }} sub addColumn { my($self,%properties)=@_; my $col = {%properties}; my @before=(); push(@before,@{$$self{save_before}}) if $$self{save_before}; push(@before,$properties{before}->unlist) if $properties{before}; $$col{before} = Tokens(@before); $$col{after} = Tokens() unless $properties{after}; $$col{head} = $properties{head}; $$col{empty} = 1; $$self{save_before}=[]; $$self{current_column} = $col; if($$self{repeating}){ $$self{non_repeating} = scalar(@{$$self{columns}}); push(@{$$self{repeated}},$col); } else { push(@{$$self{columns}},$col); }} # Methods for using a template. sub clone { my($self)=@_; my @dup = (); foreach my $cell (@{$$self{columns}}){ push(@dup, { %$cell }); } bless {columns=>[@dup], repeated=>$$self{repeated}, non_repeating=>$$self{non_repeating}, repeating=>$$self{repeating}}, ref $self; } sub show { my($self)=@_; my @strings=(); push(@strings,"\nColumns:\n"); foreach my $col(@{$$self{columns}}){ push(@strings, "\n{".join(', ',map("$_=>".Stringify($$col{$_}),keys %$col)).'}'); } if($$self{repeating}){ push(@strings,"\nRepeated Columns:\n"); foreach my $col(@{$$self{repeated}}){ push(@strings, "\n{".join(', ',map("$_=>".Stringify($$col{$_}),keys %$col)).'}'); }} join(', ',@strings); } sub column { my($self,$n)=@_; my $N = scalar(@{$$self{columns}}); if(($n > $N) && $$self{repeating}){ my @rep = @{$$self{repeated}}; if(my $m = scalar(@rep)){ for(my $i=$N; $i<$n; $i++){ my %dup = %{ $rep[($i-$$self{non_repeating}) % $m] }; push(@{$$self{columns}},{%dup}); }}} $$self{columns}->[$n-1]; } sub columns { my($self)=@_; @{$$self{columns}}; } } #====================================================================== # Experimental alignment heading heuristications. #====================================================================== # We attempt to recognize patterns of rows/columns that indicate which might be headers. # We'll characterize the cells by alignment, content and borders. # Then, assuming that headers will be first and be noticably `different' from data lines, # and also that the data lines will have similar structure, we'll attempt to # recognize groups of header lines and groups data lines, possibly alternating. sub guess_alignment_headers { my($document,$table,$alignment)=@_; # Assume that headers don't make sense for nested tables. # OR Maybe we should only do this within table environments??? return if $document->findnodes("ancestor::ltx:tabular",$table); my $tag = $document->getModel->getNodeQName($table); my $ismath = $tag eq 'ltx:XMArray'; local $LaTeXML::TR = ($ismath ? 'ltx:XMRow' : 'ltx:tr'); local $LaTeXML::TD = ($ismath ? 'ltx:XMCell' : 'ltx:td'); # Build a view of the table by extracting the rows, collecting & characterizing each cell. my @rows = collect_alignment_rows($document,$table,$alignment); # Flip the rows around to produce a column view. my @cols = (); return unless @rows; for(my $c = 0; $c < scalar(@{$rows[0]}); $c++){ push(@cols, [map($$_[$c], @rows)]); } # Attempt to recognize header lines. alignment_characterize_lines(0,@rows); alignment_characterize_lines(1,@cols); # Did we go overboard? my %n=(h=>0,d=>0); foreach my $r (@rows){ foreach my $c (@$r){ $n{$$c{cell_type}}++; }} print STDERR "$n{h} header, $n{d} data cells\n" if $LaTeXML::Alignment::DEBUG; if($n{d} == 1){ # Or any other heuristic? foreach my $r (@rows){ foreach my $c (@$r){ $$c{cell_type}='d'; $$c{cell}->removeAttribute('thead') if $$c{cell}; }}} # Regroup the rows into thead & tbody elements. alignment_regroup($document,$table,@rows) unless $ismath; # Debugging report! summarize_alignment([@rows],[@cols]) if $LaTeXML::Alignment::DEBUG; } #====================================================================== # Regroup the rows into thead & tbody sub alignment_regroup { my($document,$table,@rows)=@_; my ($group,$grouptype)=(undef,0); foreach my $xrow ($document->findnodes("ltx:tr",$table)){ my $rowtype = (grep($$_{cell_type} ne 'h', @{ shift(@rows)} ) ? 'tbody' : 'thead'); if($grouptype ne $rowtype){ $group = $table->addNewChild($xrow->getNamespaceURI, $grouptype = $rowtype); $table->insertBefore($group,$xrow); } $group->appendChild($xrow); } } #====================================================================== # Build a View of the alignment, with characterized cells, for analysis. sub collect_alignment_rows { my($document,$table,$alignment)=@_; my @rows = (); foreach my $arow (@{$$alignment{rows}}){ push(@rows, [ ] ); my $c=0; foreach my $col (@{$$arow{columns}}){ push(@{$rows[$#rows]}, $col); $$col{cell_type} = 'd'; $$col{content_class} = ($$col{cell} ? classify_alignment_cell($document,$$col{cell}) : '?'); $$col{content_length} =($$col{cell} ? length($$col{cell}->textContent) : 0); my %border = (t=>0, r=>0, b=>0, l=>0); # Decode border map($border{$_}++, split(/ */,$$col{border}||'')); $border{t}=$rows[$#rows-1][$c]{b} if $#rows > 0; # Copy prev bottom border to top. $border{l}=$rows[$#rows][$c-1]{r} if $c > 0; # Copy prev right border to left. map($$col{$_} = $border{$_}, keys %border); $c++; }} @rows; } # Return one of: i(nteger), t(ext), m(ath), ? (unknown) or '_' (empty) (or some combination) # or 'mx' for alternating text & math. sub classify_alignment_cell { my($document,$xcell)=@_; my $content = $xcell->textContent; my $class=''; if($content =~ /^\s*\d+\s*$/){ $class = 'i'; } else { my @nodes = $xcell->childNodes; while(@nodes){ my $ch = shift(@nodes); my $chtype = $ch->nodeType; if($chtype == XML_TEXT_NODE){ my $text = $ch->textContent; $class .= 't' unless $text=~/^\s*$/ || (($class eq 'm') && ($text=~/^\s*[\.,;]\s*$/)); } elsif($chtype == XML_ELEMENT_NODE){ my $chtag = $document->getModel->getNodeQName($ch); if($chtag eq 'ltx:text'){ # Font would be useful, but haven't "resolved" it, yet! $class .= 't' unless $class eq 't'; } elsif($chtag eq 'ltx:Math'){ $class .= 'm' unless $class eq 'm'; } elsif($chtag eq 'ltx:XMText'){ $class .= 't' unless $class eq 't'; } elsif($chtag eq 'ltx:XMArg'){ unshift(@nodes,$ch->childNodes); } elsif($chtag =~ /^ltx:XM/){ $class .= 'm' unless $class eq 'm'; } else { $class .= '?' unless $class; } }}} $class = 'mx' if $class && (($class =~ /^((m|i)t)+(m|i)?$/)||($class =~ /^(t(m|i))+t?$/)); $class || '_'; } #====================================================================== # Scan pairs of rows/columns attempting to recognize differences that # might indicate which are headers and which are data. # Warning: This section is full of "magic numbers" # guessed by sampling various test cases. our $MIN_ALIGNMENT_DATA_LINES=1; # (or 2?) our $MAX_ALIGNMENT_HEADER_LINES=4; # We expect to find header lines at the beginning, noticably different from the eventual data lines. # Both header lines and data lines can consist of several neighboring lines. # Check that header lines are `similar' to each other. So, the strategy is to look # for a `hump' in the line differences and consider blocks containing these lines to be potential headers. sub alignment_characterize_lines { my($axis,@lines)=@_; my $n = scalar(@lines); return unless $n > 1; local @::TABLINES = @lines; print STDERR "\nCharacterizing $n ".($axis ? "columns" : "rows")."\n " if $LaTeXML::Alignment::DEBUG; # Establish a scale of differences for the table. my($diffhi,$difflo)=(0,99999999); for(my $l = 0; $l < $n-1; $l++){ my $d = alignment_compare($axis,1,$l,$l+1); $diffhi = $d if $d > $diffhi; $difflo = $d if $d < $difflo; } print STDERR "Lines are almost identical => Fail\n" if $diffhi < 0.05 && $LaTeXML::Alignment::DEBUG; return if $diffhi < 0.05; # virtually no differences. # local $::TAB_THRESHOLD = $difflo + 0.4*($diffhi-$difflo); local $::TAB_THRESHOLD = $difflo + 0.2*($diffhi-$difflo); local $::TAB_AXIS = $axis; print STDERR "\nDifferences $difflo -- $diffhi => threshold = $::TAB_THRESHOLD\n" if $LaTeXML::Alignment::DEBUG; # Find the first hump in differences. These are candidates for header lines. print STDERR "Scanning for headers\n " if $LaTeXML::Alignment::DEBUG; my $diff; my($minh,$maxh)=(1,1); while( ($diff=alignment_compare($axis,1,$maxh-1,$maxh)) < $::TAB_THRESHOLD){ $maxh++; } while( alignment_compare($axis,1,$maxh,$maxh+1) > $difflo + ($diff-$difflo)/6){ $maxh++; } $maxh = $MAX_ALIGNMENT_HEADER_LINES if $maxh > $MAX_ALIGNMENT_HEADER_LINES; print STDERR "\nFound from $minh--$maxh potential headers\n" if $LaTeXML::Alignment::DEBUG; my $nn = scalar(@{$lines[0]})-1; # The sets of lines 1--$minh, .. 1--$maxh are potential headers. for(my $nh = $maxh; $nh >= $minh; $nh--){ # for(my $nh = $minh; $nh <= $maxh; $nh++){ # Check whether the set 1..$nh is plausable. if(my @heads = alignment_test_headers($nh)){ # Now, change all cells marked as header from td => th. foreach my $h (@heads){ my $i = 0; foreach my $cell (@{$lines[$h]}){ $$cell{cell_type} = 'h'; if(my $xcell = $$cell{cell}){ if(($$cell{content_class} eq '_') # But NOT empty cells on outer edges. && (( ($i==0) && !$$cell{($axis==0 ? 'l' : 't')} ) ||(($i==$nn) && !$$cell{($axis == 0 ? 'r' : 'b')}))){} else { $$cell{cell}->setAttribute(thead=>'true');}} $i++; }} last; }} 1; } # Test whether $nhead lines makes a good fit for the headers sub alignment_test_headers { my($nhead)=@_; print STDERR "Testing $nhead headers\n" if $LaTeXML::Alignment::DEBUG; my ($headlength,$datalength)=(0,0); my @heads =(0..$nhead-1); # The indices of heading lines. $headlength = alignment_max_content_length($headlength,0,$nhead-1); my $nextline = $nhead; # Start from the end of the proposed headings. # Watch out for the assumed header being really data that is a repeated pattern. my $nrep = scalar(@::TABLINES)/$nhead; if(($nhead > 1) && ($nrep == int($nrep))){ print STDERR "Check for apparent header repeated $nrep times\n" if $LaTeXML::Alignment::DEBUG; my $matched = 1; for(my $r = 1; $r < $nrep; $r++){ $matched &&= alignment_match_head(0,$r*$nhead,$nhead); } print STDERR "Repeated headers: ".($matched ? "Matched=> Fail" : "Nomatch => Succeed")."\n" if $LaTeXML::Alignment::DEBUG; return if $matched; } # And find a following grouping of data lines. my $ndata = alignment_skip_data($nextline); return unless $ndata >= $nhead; # ???? Well, maybe if _really_ convincing??? return unless ($ndata >= $nhead) || ($ndata >= 2); # Check that the content of the headers isn't dramatically larger than the content in the data $datalength = alignment_max_content_length($datalength,$nextline,$nextline+$ndata-1); $nextline += $ndata; my $nd; # If there are more lines, they should match either the previous data block, or the head/data pattern. while($nextline < scalar(@::TABLINES)){ # First try to match a repeat of the 1st data block; # This would be the case when groups of data have borders around them. # Could want to match a variable number of datalines, but they should be similar!!!??!?!? if(($ndata > 1) && ($nd = alignment_match_data($nhead,$nextline,$ndata))){ $datalength = alignment_max_content_length($datalength,$nextline,$nextline+$nd-1); $nextline += $nd; } # Else, try to match the first header block; less common. elsif(alignment_match_head(0,$nextline,$nhead)){ push(@heads,$nextline..$nextline+$nhead-1); $headlength = alignment_max_content_length($headlength,$nextline,$nextline+$nhead-1); $nextline += $nhead; # Then attempt to match a new data block. # my $d = alignment_skip_data($nextline); # return unless ($d >= $nhead) || ($d >= 2); # $nextline += $d; } # No, better be the same data block? return unless ($nd = alignment_match_data($nhead,$nextline,$ndata)); $datalength = alignment_max_content_length($datalength,$nextline,$nextline+$nd-1); $nextline += $nd; } else { return; }} # Header content seems too large relative to data? print STDERR "header content = $headlength; data content = $datalength\n" if $LaTeXML::Alignment::DEBUG; if(($headlength > 10) && ($headlength > 0.9*$datalength)){ print STDERR "header content longer than data content\n" if $LaTeXML::Alignment::DEBUG; return; } print STDERR "Succeeded with $nhead headers\n" if $LaTeXML::Alignment::DEBUG; @heads; } sub alignment_match_head { my($p1,$p2,$nhead)=@_; print STDERR "Try match $nhead header lines from $p1 to $p2\n " if $LaTeXML::Alignment::DEBUG; my $nh = alignment_match_lines($p1,$p2,$nhead); my $ok = $nhead == $nh; print STDERR "\nMatched $nh header lines => ".($ok ? "Succeed" : "Failed")."\n" if $LaTeXML::Alignment::DEBUG; ($ok ? $nhead : 0); } sub alignment_match_data { my($p1,$p2,$ndata)=@_; print STDERR "Try match $ndata data lines from $p1 to $p2\n " if $LaTeXML::Alignment::DEBUG; my $nd = alignment_match_lines($p1,$p2,$ndata); my $ok = ($nd*1.0)/$ndata > 0.66; print STDERR "\nMatched $nd data lines => ".($ok ? "Succeed" : "Failed")."\n" if $LaTeXML::Alignment::DEBUG; ($ok ? $nd : 0); } # Match the $n lines starting at $i2 to those starting at $i1. sub alignment_match_lines { my($p1,$p2,$n)=@_; for(my $i = 0; $i < $n; $i++){ return $i if ($p1+$i >= scalar(@::TABLINES)) || ($p2+$i >= scalar(@::TABLINES)) || alignment_compare($::TAB_AXIS,0, $p1+$i, $p2+$i) >= $::TAB_THRESHOLD; } return $n; } # Skip through a block of lines starting at $i that appear to be data, returning the number of lines. # We'll assume the 1st line is data, compare it to following lines, # but also accept `continuation' data lines. sub alignment_skip_data { my($i)=@_; return 0 if $i >= scalar(@::TABLINES); print STDERR "Scanning for data\n " if $LaTeXML::Alignment::DEBUG; my $n = 1; while($i+$n < scalar(@::TABLINES)){ last unless (alignment_compare($::TAB_AXIS,1, $i+$n-1, $i+$n) < $::TAB_THRESHOLD) # Accept an outlying `continuation line' as data, if mostly empty || (($n > 1) && (scalar(grep($$_{content_class} eq '_', @{$::TABLINES[$i+$n]})) > 0.4*scalar($::TABLINES[0]))); $n++; } print STDERR "\nFound $n data lines at $i\n" if $LaTeXML::Alignment::DEBUG; ($n >= $MIN_ALIGNMENT_DATA_LINES ? $n : 0); } sub alignment_max_content_length { my($length,$from,$to)=@_; foreach my $j ( ($from..$to) ){ foreach my $cell (@{$::TABLINES[$j]}){ $length = $$cell{content_length} if $$cell{content_length} && ($$cell{content_length} > $length); }} $length; } #====================================================================== # The comparator. our %cell_class_diff = ('_'=>{'_'=>0.0, m=>0.1, i=>0.1, t=>0.1, '?'=>0.1, mx=>0.1}, m =>{'_'=>0.1, m=>0.0, i=>0.1, mx=>0.2}, i =>{'_'=>0.1, m=>0.1, i=>0.0, mx=>0.2}, t =>{'_'=>0.1, t=>0.0, mx=>0.2}, '?'=>{'_'=>0.1, '?'=>0.0, mx=>0.2}, mx=>{'_'=>0.1, m=>0.2, i=>0.2, t=>0.2, '?'=>0.2, mx=>0.0}); # Compare two lines along $axis (0=row,1=column), returning a measure of the difference. # The borders are compared differently if # $foradjacency: we adjacent lines that might belong to the same block, # otherwise : comparing two lines that ought to have identical patterns (eg. in a repeated block) sub alignment_compare { my($axis, $foradjacency, $p1,$p2)=@_; my $line1 = $::TABLINES[$p1]; my $line2 = $::TABLINES[$p2]; return 0 if !($line1 && $line2); return 999999 if $line1 xor $line2; my @cells1 = @$line1; my @cells2 = @$line2; my $diff=0.0; while(@cells1 && @cells2){ my $cell1 = shift(@cells1); my $cell2 = shift(@cells2); $diff += 0.5 if (($$cell1{align}||'') ne ($$cell2{align}||'')); if(my $d = $cell_class_diff{$$cell1{content_class}}{$$cell2{content_class}}){ $diff += $d; } elsif($$cell1{content_class} ne $$cell2{content_class}){ $diff += 0.75; } # compare certain edges if($foradjacency){ # Compare edges for adjacent rows of potentially different purpose $diff += 0.3*scalar(grep($$cell1{$_} != $$cell2{$_}, ($axis == 0 ? qw(r l) : qw(t b)))); my $pedge = ($axis == 0 ? 'b' : 'r'); my $pother = ($axis == 0 ? 't' : 'l'); # Penalty for apparent divider between. $diff += 2.0*$$cell1{$pedge} unless ($$cell1{$pedge} == $$cell1{$pother}) && ($$cell1{$pedge} == $$cell2{$pedge}); } else { # Compare edges for rows from diff places for potential similarity $diff += 0.3*scalar(grep($$cell1{$_} != $$cell2{$_}, qw(r l t b))); } } $diff /= scalar(@$line1); print STDERR "$p1-$p2 => $diff; " if $LaTeXML::Alignment::DEBUG; return $diff; } #====================================================================== # Debugging. sub summarize_alignment { my($rows,$cols)=@_; my $r=0; my %acode = (right=>'r', left=>'l', center=>'c', justify=>'p'); my ($nrows,$ncols) = (scalar(@$rows),scalar(@{$$rows[0]})); print STDERR "\n"; foreach my $cell (@{$$rows[0]}){ print STDERR ' '.($$cell{t} ? ('-' x 6) : (' ' x 6)); } print STDERR "\n"; foreach my $row (@$rows){ my $maxb = 0; print STDERR ($$row[0]{l} ? ('|' x $$row[0]{l}) : ' '); foreach my $cell (@$row){ print STDERR sprintf(" %4s ", ($$cell{cell_type}||'?') .($$cell{align} ? $acode{$$cell{align}} : ' ') .($$cell{content_class}||'?') .($$cell{r} ? ('|' x $$cell{r}) : ' ')); $maxb = $$cell{b} if $$cell{b} > $maxb; } # print STDERR sprintf("%.3f",alignment_compare(0,1,$$rows[$r],$$rows[$r+1])) if ($r < $nrows-1); print STDERR "\n"; for(my $b = 0; $b < $maxb; $b++){ foreach my $cell (@$row){ print STDERR ' '.($b < $$cell{b} ? ('-' x 6) : (' ' x 6)); } print STDERR "\n"; } $r++; } print STDERR " "; # for(my $c = 0; $c < $ncols-1; $c++){ # print STDERR sprintf(" %.3f ",alignment_compare(1,1,$$cols[$c],$$cols[$c+1])); } print STDERR "\n"; } #====================================================================== 1; LaTeXML-0.7.0/lib/LaTeXML/Util/Geometry.pm0000644002506700454610000000353111214255167017064 0ustar miller891divpackage LaTeXML::Util::Geometry; use strict; use LaTeXML::Global; use LaTeXML::Number; use Math::Trig; use Exporter; our @ISA = qw(Exporter); our @EXPORT = (qw(&coordList &explodeCoord &radians &trunc &round &lineParams &pointPointDist &linePointDist &lineIntersect &lineAngle)); our $eps = 0.000001; sub coordList { my @points = @_; my ($l, $spc) = ('', ''); foreach (@points) { $l.=$spc.$_; if ($spc eq ' ' || $spc eq '') {$spc = ',';} elsif ($spc eq ',') {$spc = ' ';}} $l; } sub explodeCoord { my ($pts) = @_; return () unless $pts; $pts =~ s/,/ /g; $pts =~ s/\s+/ /g; $pts =~ s/^\s+//; $pts =~ s/\s+$//; split(/ /, $pts); } sub radians { $#_>0 ? map(deg2rad($_), @_) : deg2rad($_[0]); } sub trunc { my ($d, @ns) = @_; $d = 10**$d; for (my $i=0; $i<=$#ns; $i++) { $ns[$i] = round($ns[$i]*$d)/$d; } $#ns>0 ? @ns : $ns[0]; } sub round { int($_[0]+0.5*($_[0] <=> 0)); } sub lineParams { my ($P, $angle, $perpendicular) = @_; $angle = radians($angle); my ($c, $s) = (cos($angle), sin($angle)); my ($la, $lb) = $perpendicular ? (abs($c)>$eps ? (1, $s/$c) : (0, 1)) : (abs($c)>$eps ? (-$s/$c, 1) : (1, 0)); my $lc = - $la * $P->getX->valueOf - $lb * $P->getY->valueOf; ($la, $lb, $lc); } sub pointPointDist { my ($P1, $P2) = @_; sqrt($P1->getX->substract($P2->getX)->valueOf()**2 + $P1->getY->substract($P2->getY)->valueOf()**2); } sub linePointDist { my ($P, @l) = @_; abs($l[0]*$P->getX->valueOf + $l[1]*$P->getY->valueOf + $l[2])/sqrt($l[0]**2+$l[1]**2); } sub lineIntersect { my ($l1, $l2) = @_; my ($la, $lb, $lc) = @{$l1}; my ($La, $Lb, $Lc) = @{$l2}; Pair(Dimension(($lb*$Lc-$Lb*$lc)/($la*$Lb-$La*$lb)), Dimension(($la*$Lc-$La*$lc)/($La*$lb-$la*$Lb))); } sub lineAngle { my ($A, $B) = @_; rad2deg(atan2($B->getY->substract($A->getY)->valueOf, $B->getX->substract($A->getX)->valueOf)); } 1; LaTeXML-0.7.0/lib/LaTeXML/Box.pm0000644002506700454610000003026411214255167015107 0ustar miller891div# /=====================================================================\ # # | LaTeXML:Box, LaTeXML:List... | # # | Digested objects produced in the Stomack | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Box; use strict; use LaTeXML::Global; use base qw(LaTeXML::Object); sub new { my($class,$string,$font,$locator,$token)=@_; bless [$string,$font,$locator,$token],$class; } # Accessors sub isaBox { 1; } sub getString { $_[0][0]; } # Return the string contents of the box sub getFont { $_[0][1]; } # Return the font this box uses. sub isMath { 0; } # Box is text mode. sub getLocator { $_[0][2]; } sub getSource { $_[0][2]; } # So a Box can stand in for a List sub unlist { ($_[0]); } # Return list of the boxes sub revert { $_[0][3]; } sub toString { $_[0][0]; } # Methods for overloaded operators sub stringify { my($self)=@_; my $type = ref $self; $type =~ s/^LaTeXML:://; $type.'['.$$self[0].']'; } # Should this compare fonts too? sub equals { my($a,$b)=@_; (defined $b) && ((ref $a) eq (ref $b)) && ($$a[0] eq $$b[0]) && ($$a[1]->equals($$b[1])); } sub beAbsorbed { $_[1]->openText($_[0][0],$_[0][1]); } sub getProperty { undef; } #********************************************************************** # LaTeXML::MathBox #********************************************************************** package LaTeXML::MathBox; use strict; use LaTeXML::Global; use base qw(LaTeXML::Box); sub isMath { 1; } # MathBoxes are math mode. sub beAbsorbed { $_[1]->insertMathToken($_[0][0],font=>$_[0][1]); } #********************************************************************** # LaTeXML::Comment #********************************************************************** package LaTeXML::Comment; use strict; use LaTeXML::Global; use base qw(LaTeXML::Box); sub revert { (); } sub toString { ''; } sub beAbsorbed { $_[1]->insertComment($_[0][0]); } #********************************************************************** # LaTeXML::List # A list of boxes or Whatsits # (possibly evolve into HList, VList, MList) #********************************************************************** package LaTeXML::List; use strict; use LaTeXML::Global; use base qw(LaTeXML::Box); sub new { my($class,@boxes)=@_; my $box0 = $boxes[0]; bless [[@boxes], ($box0 ? $box0->getFont : undef), ($box0 ? $box0->getLocator : '')],$class; } sub isMath { 0; } # List's are text mode sub unlist { @{$_[0][0]}; } sub revert { my($self)=@_; map($_->revert,$self->unlist); } sub toString { my($self)=@_; join('',map($_->toString,$self->unlist)); } # Methods for overloaded operators sub stringify { my($self)=@_; my $type = ref $self; $type =~ s/^LaTeXML:://; # $type.'['.join(',',map($_->toString,$self->unlist)).']'; } # Not ideal, but.... $type.'['.join(',',map(Stringify($_),$self->unlist)).']'; } # Not ideal, but.... sub equals { my($a,$b)=@_; return 0 unless (defined $b) && ((ref $a) eq (ref $b)); my @a = $a->unlist; my @b = $b->unlist; while(@a && @b && ($a[0]->equals($b[0]))){ shift(@a); shift(@b); } return !(@a || @b); } sub beAbsorbed { map($_[1]->absorb($_), $_[0]->unlist); } #********************************************************************** # LaTeXML::MathList # A list of boxes or Whatsits # (possibly evolve into HList, VList, MList) #********************************************************************** package LaTeXML::MathList; use LaTeXML::Global; use base qw(LaTeXML::List); sub isMath { 1; } # MathList's are math mode. #********************************************************************** # What about Kern, Glue, Penalty ... #********************************************************************** # LaTeXML Whatsit. # Some arbitrary object, possibly with arguments. # Particularly as an intermediate representation for invocations of control # sequences that do NOT get expanded or processed, but are taken to represent # some semantic something or other. # These get preserved in the expanded/processed token stream to be # converted into XML objects in the document. #********************************************************************** package LaTeXML::Whatsit; use strict; use LaTeXML::Global; use base qw(LaTeXML::Box); # Specially recognized (some required?) properties: # font : The font object # locator : a locator string, where in the source this whatsit was created # isMath : whether this is a math object # id # body # trailer sub new { my($class,$defn,$args,%properties)=@_; bless {definition=>$defn, args=>$args||[], properties=>{%properties}},$class; } sub getDefinition { $_[0]{definition}; } sub isMath { $_[0]{properties}{isMath}; } sub getFont { $_[0]{properties}{font}; } # and if undef ???? sub setFont { $_[0]{properties}{font} = $_[1]; } sub getLocator { $_[0]{properties}{locator}; } sub getProperty { $_[0]{properties}{$_[1]}; } sub getProperties { %{$_[0]{properties}}; } sub setProperty { $_[0]{properties}{$_[1]}=$_[2]; return; } sub setProperties { my ($self, %props) = @_; while (my ($key, $value) = each %props) { $$self{properties}{$key} = $value if defined $value; } return; } sub getArg { $_[0]{args}->[$_[1]-1]; } sub getArgs { @{$_[0]{args}}; } sub setArgs { my($self,@args)=@_; $$self{args} = [@args]; return; } sub getBody { $_[0]{properties}{body}; } sub setBody { my($self,@body)=@_; my $trailer = pop(@body); $$self{properties}{body} = ($self->isMath ? LaTeXML::MathList->new(@body) : LaTeXML::List->new(@body)); $$self{properties}{trailer} = $trailer; return; } sub getTrailer { $_[0]{properties}{trailer}; } # So a Whatsit can stand in for a List sub unlist { ($_[0]); } sub revert { my($self)=@_; my $defn = $self->getDefinition; my $spec = $defn->getReversionSpec; if((defined $spec) && (ref $spec eq 'CODE')){ return &$spec($self,$self->getArgs); } else { my @tokens = (); if(defined $spec){ @tokens=LaTeXML::Expandable::substituteTokens($spec, map(($_ ? Tokens($_->revert) : $_), $self->getArgs)) if $spec ne ''; } else { my $alias = $defn->getAlias; if(defined $alias){ push(@tokens, T_CS($alias)) if $alias ne ''; } else { push(@tokens,$defn->getCS); } if(my $parameters = $defn->getParameters){ push(@tokens,$parameters->revertArguments($self->getArgs)); }} if(defined (my $body = $self->getBody)){ push(@tokens, $body->revert); if(defined (my $trailer = $self->getTrailer)){ push(@tokens, $trailer->revert); }} @tokens; }} sub toString { ToString(Tokens($_[0]->revert)); } # Methods for overloaded operators sub stringify { my($self)=@_; my $string = "Whatsit[".join(',',$self->getDefinition->getCS->getCSName, # map(ToString($_),$self->getArgs)); map(Stringify($_),$self->getArgs)); if(defined $$self{properties}{body}){ # $string .= $$self{properties}{body}->toString; # $string .= $$self{properties}{trailer}->toString; } $string .= Stringify($$self{properties}{body}); $string .= Stringify($$self{properties}{trailer}); } $string."]"; } sub equals { my($a,$b)=@_; return 0 unless (defined $b) && ((ref $a) eq (ref $b)); return 0 unless $$a{definition} eq $$b{definition}; # I think we want IDENTITY here, not ->equals my @a = @{$$a{args}}; push(@a, $$a{properties}{body}) if $$a{properties}{body}; my @b = @{$$b{args}}; push(@b, $$b{properties}{body}) if $$b{properties}{body}; while(@a && @b && ($a[0]->equals($b[0]))){ shift(@a); shift(@b); } return !(@a || @b); } sub beAbsorbed { my($self,$document)=@_; $self->getDefinition->doAbsorbtion($document,$self); } #### &{$self->getDefinition->getConstructor}($document,@{$$self{args}},$$self{properties});} #********************************************************************** 1; __END__ =pod =head1 NAME C - Representations of digested objects. =head1 DESCRIPTION These represent various kinds of digested objects =over 4 =item C represents text in a particular font; =item C =begin latex \label{LaTeXML::MathBox} =end latex represents a math token in a particular font; =item C =begin latex \label{LaTeXML::List} =end latex represents a sequence of digested things in text; =item C =begin latex \label{LaTeXML::MathList} =end latex represents a sequence of digested things in math; =item C =begin latex \label{LaTeXML::Whatsit} =end latex represents a digested object that can generate arbitrary elements in the XML Document. =back =head2 Common Methods All these classes extend L and so implement the C and C operations. =over 4 =item C<< $font = $digested->getFont; >> Returns the font used by C<$digested>. =item C<< $boole = $digested->isMath; >> Returns whether C<$digested> was created in math mode. =item C<< @boxes = $digested->unlist; >> Returns a list of the boxes contained in C<$digested>. It is also defined for the Boxes and Whatsit (which just return themselves) so they can stand-in for a List. =item C<< $string = $digested->toString; >> Returns a string representing this C<$digested>. =item C<< $string = $digested->revert; >> Reverts the box to the list of Cs that created (or could have created) it. =item C<< $string = $digested->getLocator; >> Get a string describing the location in the original source that gave rise to C<$digested>. =item C<< $digested->beAbsorbed($document); >> C<$digested> should get itself absorbed into the C<$document> in whatever way is apppropriate. =back =head2 Box Methods The following methods are specific to C and C. =over 4 =item C<< $string = $box->getString; >> Returns the string part of the C<$box>. =back =head2 Whatsit Methods Note that the font is stored in the data properties under 'font'. =over 4 =item C<< $defn = $whatsit->getDefinition; >> Returns the L responsible for creating C<$whatsit>. =item C<< $value = $whatsit->getProperty($key); >> Returns the value associated with C<$key> in the C<$whatsit>'s property list. =item C<< $whatsit->setProperty($key,$value); >> Sets the C<$value> associated with the C<$key> in the C<$whatsit>'s property list. =item C<< $props = $whatsit->getProperties(); >> Returns the hash of properties stored on this Whatsit. (Note that this hash is modifiable). =item C<< $props = $whatsit->setProperties(%keysvalues); >> Sets several properties, like setProperty. =item C<< $list = $whatsit->getArg($n); >> Returns the C<$n>-th argument (starting from 1) for this C<$whatsit>. =item C<< @args = $whatsit->getArgs; >> Returns the list of arguments for this C<$whatsit>. =item C<< $whatsit->setArgs(@args); >> Sets the list of arguments for this C<$whatsit> to C<@args> (each arg should be a C or C). =item C<< $list = $whatsit->getBody; >> Return the body for this C<$whatsit>. This is only defined for environments or top-level math formula. The body is stored in the properties under 'body'. =item C<< $whatsit->setBody(@body); >> Sets the body of the C<$whatsit> to the boxes in C<@body>. The last C<$box> in C<@body> is assumed to represent the `trailer', that is the result of the invocation that closed the environment or math. It is stored separately in the properties under 'trailer'. =item C<< $list = $whatsit->getTrailer; >> Return the trailer for this C<$whatsit>. See C. =back =head1 AUTHOR Bruce Miller =head1 COPYRIGHT Public domain software, produced as part of work done by the United States Government & not subject to copyright in the US. =cut LaTeXML-0.7.0/lib/LaTeXML/Package.pm0000644002506700454610000023564011215766022015715 0ustar miller891div# /=====================================================================\ # # | LaTeXML::Package | # # | Exports of Defining forms for Package writers | # # |=====================================================================| # # | Part of LaTeXML: | # # | Public domain software, produced as part of work done by the | # # | United States Government & not subject to copyright in the US. | # # |---------------------------------------------------------------------| # # | Bruce Miller #_# | # # | http://dlmf.nist.gov/LaTeXML/ (o o) | # # \=========================================================ooo==U==ooo=/ # package LaTeXML::Package; use strict; use Exporter; use LaTeXML::Global; use LaTeXML::Definition; use LaTeXML::Parameters; use LaTeXML::Util::Pathname; use Text::Balanced; use base qw(Exporter); our @EXPORT = (qw(&DefExpandable &DefMacro &DefMacroI &DefPrimitive &DefPrimitiveI &DefRegister &DefRegisterI &DefConstructor &DefConstructorI &dualize_arglist &DefMath &DefMathI &DefEnvironment &DefEnvironmentI &convertLaTeXArgs), # Class, Package and File loading. qw(&RequirePackage &LoadClass &FindFile &DeclareOption &PassOptions &ProcessOptions &ExecuteOptions &AddToMacro), # Counter support qw(&NewCounter &CounterValue &StepCounter &RefStepCounter &RefStepID &ResetCounter &GenerateID), # Document Model qw(&Tag &DocType &RelaxNGSchema &RegisterNamespace), # Document Rewriting qw(&DefRewrite &DefMathRewrite &DefLigature &DefMathLigature), # Mid-level support for writing definitions. qw(&Expand &Invocation &Digest &RawTeX &Let), # Support for structured/argument readers qw(&ReadParameters &DefParameterType &DefColumnType), # Access to State qw(&LookupValue &AssignValue &PushValue &PopValue &UnshiftValue &ShiftValue &LookupCatcode &AssignCatcode &LookupMeaning &LookupDefinition &InstallDefinition), # Random low-level token or string operations. qw(&CleanLabel &CleanIndexKey &CleanBibKey &CleanURL &UTF &roman &Roman), # Math & font state. qw(&MergeFont), qw(&CheckOptions), @LaTeXML::Global::EXPORT); #********************************************************************** # Initially, I thought LaTeXML Packages should try to be like perl modules: # once loaded, you didn't need to re-load them, only `initialize' them to # install their definitions into the current stomach. I tried to achieve # that through various package tricks. # But ultimately, most of a package _is_ installing defns in the stomach, # and it's probably better to allow a more TeX-like evaluation of definitions # in order, so \let and such work as expected. # So, it got simpler! # Still, it would be nice if there were `compiled' forms of .ltxml files! #********************************************************************** sub UTF { my($code)=@_; pack('U',$code); } sub coerceCS { my($cs)=@_; $cs = T_CS($cs) unless ref $cs; $cs = T_CS(ToString($cs)) unless ref $cs eq 'LaTeXML::Token'; $cs;} sub parsePrototype { my($proto)=@_; my $oproto = $proto; my $cs; if($proto =~ s/^\\csname\s+(.*)\\endcsname//){ $cs = T_CS('\\'.$1); } elsif($proto =~ s/^(\\[a-zA-Z@]+)//){ # Match a cs $cs = T_CS($1); } elsif($proto =~ s/^(\\.)//){ # Match a single char cs, env name,... $cs = T_CS($1); } elsif($proto =~ s/^(.)//){ # Match an active char ($cs) = TokenizeInternal($1)->unlist; } else { Fatal(":misdefined:$proto Definition prototype doesn't have proper control sequence: \"$proto\""); } $proto =~ s/^\s*//; ($cs, parseParameters($proto,$cs)); } # Convert a LaTeX-style argument spec to our Package form. # Ie. given $nargs and $optional, being the two optional arguments to # something like \newcommand, convert it to the form we use sub XXXXconvertLaTeXArgs { my($nargs,$optional)=@_; $nargs = (ref $nargs ? $nargs->toString : $nargs || 0); my $default = ($optional ? $optional->toString : undef); join('', ($optional ? ($default ? "[Default:$default]" : "[]") : ''), map('{}',1..($optional ? $nargs-1 : $nargs))); } sub convertLaTeXArgs { my($nargs,$optional)=@_; $nargs = $nargs->toString if ref $nargs; $nargs = 0 unless $nargs; my @params = (); if($optional){ push(@params,LaTeXML::Parameters::newParameter('Optional', "[Default:".$optional->toString."]", extra=>[$optional,undef])); $nargs--; } push(@params,map(LaTeXML::Parameters::newParameter('Plain','{}'), 1..$nargs)); LaTeXML::Parameters->new(@params); } #====================================================================== # Convenience functions for writing definitions. #====================================================================== sub LookupValue { $STATE->lookupValue(@_); } sub AssignValue { $STATE->assignValue(@_); return; } sub PushValue { $STATE->pushValue(@_); return; } sub PopValue { $STATE->popValue(@_); } sub UnshiftValue { $STATE->unshiftValue(@_); return; } sub ShiftValue { $STATE->shiftValue(@_); } sub LookupCatcode{ $STATE->lookupCatcode(@_); } sub AssignCatcode{ $STATE->assignCatcode(@_); return; } sub LookupMeaning { $STATE->lookupMeaning(@_); } sub LookupDefinition { $STATE->lookupDefinition(@_); } sub InstallDefinition { $STATE->installDefinition(@_); } sub Let { my($token1,$token2,$scope)=@_; ($token1)=TokenizeInternal($token1)->unlist unless ref $token1; ($token2)=TokenizeInternal($token2)->unlist unless ref $token2; $STATE->assignMeaning($token1,$STATE->lookupMeaning($token2),$scope); return; } sub Digest { $STATE->getStomach->digest(map((ref $_ ? $_ : Tokenize($_)),@_)); } sub ReadParameters { my($gullet,$spec)=@_; my $for = T_OTHER("Anonymous"); my $parm = parseParameters($spec,$for); ($parm ? $parm->readArguments($gullet,$for) : ()); } # Merge the current font with the style specifications sub MergeFont { AssignValue(font=>LookupValue('font')->merge(@_), 'local'); } # Dumb place for this, but where else... # The TeX way! (bah!! hint: try a large number) my @rmletters=('i','v', 'x','l', 'c','d', 'm'); sub roman_aux { my($n)=@_; my $div= 1000; my $s=($n>$div ? ('m' x int($n/$div)) : ''); my $p=4; while($n %= $div){ $div /= 10; my $d = int($n/$div); if($d%5==4){ $s.= $rmletters[$p]; $d++;} if($d > 4 ){ $s.= $rmletters[$p+int($d/5)]; $d %=5; } if($d) { $s.= $rmletters[$p] x $d; } $p -= 2;} $s; } # Convert the number to lower case roman numerals, returning a list of LaTeXML::Token sub roman { Explode(roman_aux(@_)); } # Convert the number to upper case roman numerals, returning a list of LaTeXML::Token sub Roman { Explode(uc(roman_aux(@_))); } #====================================================================== # Cleaners #====================================================================== # Gradually rethink all these and clarify. # Are they intended to be valid ID's (or fragment ids?) sub CleanLabel { my($label,$prefix)=@_; my $key = ToString($label); $key =~ s/\s+/_/g; ($prefix||"LABEL").":".$key; } sub CleanIndexKey { my($key)=@_; $key = ToString($key); $key =~ s/[^a-zA-Z0-9]//g; ## Shouldn't be case insensitive? ## $key =~ tr|A-Z|a-z|; $key; } # used as id. sub CleanBibKey { my($key)=@_; $key = lc(ToString($key)); $key =~ s/\s//g; $key; } sub CleanURL { my($url)=@_; $url = ToString($url); $url =~ s/\\~{}/~/g; $url; } #====================================================================== # Defining new Control-sequence Parameter types. #====================================================================== our $parameter_options = {nargs=>1,reversion=>1,optional=>1,novalue=>1, semiverbatim=>1,undigested=>1}; sub DefParameterType { my($type,$reader,%options)=@_; CheckOptions("DefParameterType $type",$parameter_options,%options); $LaTeXML::Parameters::PARAMETER_TABLE{$type}={reader=>$reader,%options}; return; } sub DefColumnType { my($proto,$expansion)=@_; $proto =~ s/^(.)//; my $char = $1; $proto =~ s/^\s*//; my $params = parseParameters($proto,$char); $expansion = TokenizeInternal($expansion) unless ref $expansion; DefMacroI(T_CS('\NC@rewrite@'.$char),$params,$expansion); } #====================================================================== # Counters #====================================================================== # This is modelled on LaTeX's counter mechanisms, but since it also # provides support for ID's, even where there is no visible reference number, # it is defined in genera. # These id's should be both unique, and parallel the visible reference numbers # (as much as possible). Also, for consistency, we add id's to unnumbered # document elements (eg from \section*); this requires an additional counter # (eg. UNsection) and mechanisms to track it. # Defines a new counter named $ctr. # If $within is defined, $ctr will be reset whenever $within is incremented. # Keywords: # idprefix : specifies a prefix to be used in formatting ID's for document structure elements # counted by this counter. Ie. subsection 3 in section 2 might get: id="S2.SS3" # idwithin : specifies that the ID is composed from $idwithin's ID,, even though # the counter isn't numbered within it. (mainly to avoid duplicated ids) # nested : a list of counters that correspond to scopes which are "inside" this one. # Whenever any definitions scoped to this counter are deactivated, # the inner counter's scopes are also deactivated. # NOTE: I'm not sure this is even a sensible implementation, # or why inner should be different than the counters reset by incrementing this counter. sub NewCounter { my($ctr,$within,%options)=@_; my $unctr = "UN$ctr"; # UNctr is counter for generating ID's for UN-numbered items. DefRegisterI(T_CS("\\c\@$ctr"),undef,Number(0)); AssignValue("\\c\@$ctr"=>Number(0),'global'); AssignValue("\\cl\@$ctr"=>Tokens(),'global') unless LookupValue("\\cl\@$ctr"); DefRegisterI(T_CS("\\c\@$unctr"),undef,Number(0)); AssignValue("\\c\@$unctr"=>Number(0),'global'); AssignValue("\\cl\@$unctr"=>Tokens(),'global') unless LookupValue("\\cl\@$unctr"); AssignValue("\\cl\@$within" => Tokens(T_CS($ctr),T_CS($unctr), (LookupValue("\\cl\@$within") ? LookupValue("\\cl\@$within")->unlist :())), 'global') if $within; AssignValue("\\cl\@UN$within" => Tokens(T_CS($unctr), (LookupValue("\\cl\@UN$within") ? LookupValue("\\cl\@UN$within")->unlist :())), 'global') if $within; AssignValue('nested_counters_'.$ctr =>$options{nested}) if $options{nested}; DefMacroI(T_CS("\\the$ctr"),undef,"\\arabic{$ctr}",scope=>'global'); my $prefix = $options{idprefix}; AssignValue('@ID@prefix@'.$ctr=>$prefix) if $prefix; $prefix = LookupValue('@ID@prefix@'.$ctr) unless $prefix; if(defined $prefix){ if(my $idwithin = $options{idwithin} || $within){ DefMacroI(T_CS("\\the$ctr\@ID"),undef, "\\expandafter\\ifx\\csname the$idwithin\@ID\\endcsname\\\@empty" ."\\else\\csname the$idwithin\@ID\\endcsname.\\fi" ." $prefix\\csname \@$ctr\@ID\\endcsname", scope=>'global'); } else { DefMacroI(T_CS("\\the$ctr\@ID"),undef,"$prefix\\csname \@$ctr\@ID\\endcsname", scope=>'global'); } DefMacroI(T_CS("\\\@$ctr\@ID"),undef,"0",scope=>'global'); } return; } sub CounterValue { my($ctr)=@_; $ctr = $ctr->toString if ref $ctr; my $value = LookupValue('\c@'.$ctr); if(!$value){ Warn(":expected: Counter $ctr was not defined; assuming 0"); $value = Number(0); } $value; } sub StepCounter { my($ctr)=@_; my $value = CounterValue($ctr); AssignValue("\\c\@$ctr"=>$value->add(Number(1)),'global'); DefMacroI(T_CS("\\\@$ctr\@ID"),undef, Tokens(Explode(LookupValue('\c@'.$ctr)->valueOf)), scope=>'global'); # and reset any within counters! if(my $nested = LookupValue("\\cl\@$ctr")){ foreach my $c ($nested->unlist){ ResetCounter($c->toString); }} Expand(T_CS("\\the$ctr")); } # HOW can we retract this? sub RefStepCounter { my($ctr)=@_; my $v = StepCounter($ctr); DefMacroI(T_CS("\\\@$ctr\@ID"),undef, Tokens(Explode(LookupValue('\c@'.$ctr)->valueOf)), scope=>'global'); my $id = Expand(T_CS("\\the$ctr\@ID")); DefMacroI(T_CS('\@currentlabel'),undef,$v); DefMacroI(T_CS('\@currentID'),undef,$id); # Any scopes activated for previous value of this counter (& any nested counters) must be removed. # This may also include scopes activated for \label deactivateCounterScope($ctr); # And install the scope (if any) for this reference number. AssignValue(current_counter=>$ctr,'local'); AssignValue('scopes_for_counter:'.$ctr => [$ctr.':'.ToString($v)],'local'); $STATE->activateScope($ctr.':'.ToString($v)); (refnum=>$v, id=>$id); } sub deactivateCounterScope { my($ctr)=@_; # print STDERR "Unusing scopes for $ctr\n"; if(my $scopes = LookupValue('scopes_for_counter:'.$ctr)){ map($STATE->deactivateScope($_), @$scopes); } foreach my $inner_ctr (@{LookupValue('nested_counters_'.$ctr) || []}){ deactivateCounterScope($inner_ctr); }} # For UN-numbered units sub RefStepID { my($ctr)=@_; my $unctr = "UN$ctr"; my $v = StepCounter($unctr); DefMacroI(T_CS("\\\@$ctr\@ID"),undef, Tokens(T_OTHER('x'),Explode(LookupValue('\c@'.$unctr)->valueOf)), scope=>'global'); my $id = Expand(T_CS("\\the$ctr\@ID")); DefMacroI(T_CS('\@currentID'),undef,$id); (id=>$id); } sub ResetCounter { my($ctr)=@_; AssignValue('\c@'.$ctr => Number(0),'global'); # and reset any within counters! if(my $nested = LookupValue("\\cl\@$ctr")){ foreach my $c ($nested->unlist){ ResetCounter($c->toString); }} return;} #********************************************************************** # This function computes an xml:id for a node, if it hasn't already got one. # It is suitable for use in Tag afterOpen as # Tag('ltx:para',afterOpen=>sub { GenerateID(@_,'p'); }); # It generates an id of the form . sub GenerateID { my($document,$node,$whatsit,$prefix)=@_; if(!$node->hasAttribute('xml:id')){ my $parent = $document->findnode('ancestor::*[@xml:id][1]',$node) || $document->getDocument->documentElement; my $ctrkey = '_ID_counter_'.$prefix; my $ctr = ($parent && $parent->getAttribute($ctrkey)) || 0; ## Old versions don't like this!!! ## my $parent_id = $parent && $parent->getAttribute('xml:id'); my $parent_id = $parent && $parent->getAttributeNS("http://www.w3.org/XML/1998/namespace",'id'); my $id = ($parent_id ? $parent_id."." : '').$prefix. (++$ctr); $parent->setAttribute($ctrkey=>$ctr) if $parent; $document->setAttribute($node,'xml:id'=>$id); }} #====================================================================== # Readers for reading various data types #====================================================================== sub Expand { $STATE->getStomach->getGullet->expandTokens(@_); } sub Invocation { my($token,@args)=@_; if(my $defn = LookupDefinition((ref $token ? $token : T_CS($token)))){ Tokens($defn->invocation(@args)); } else { Fatal(":undefined:".Stringify($token)." Cannot invoke ".Stringify($token)."; it is undefined"); Tokens(); }} #====================================================================== # Non-exported support for defining forms. #====================================================================== sub CheckOptions { my($operation,$allowed,%options)=@_; my @badops = grep(!$$allowed{$_}, keys %options); Error(":misdefined:$operation $operation does not accept options:".join(', ',@badops)) if @badops; } sub requireMath { my $cs = ToString($_[0]); Warn(":unexpected:$cs $cs should only appear in math mode") unless LookupValue('IN_MATH'); return; } sub forbidMath { my $cs = ToString($_[0]); Warn(":unexpected:$cs $cs should not appear in math mode") if LookupValue('IN_MATH'); return; } #********************************************************************** # Definitions #********************************************************************** #====================================================================== # Defining Expandable Control Sequences. #====================================================================== # Define an expandable control sequence. It will be expanded in the Gullet. # The $replacement should be a LaTeXML::Tokens (the arguments will be # substituted for any #1,...), or a sub which returns a list of tokens (or just return;). # Those tokens, if any, will be reinserted into the input. # There are no options to these definitions. our $expandable_options = {isConditional=>1, scope=>1, locked=>1}; sub DefExpandable { my($proto,$expansion,%options)=@_; Warn(":misdefined:DefExpandable DefExpandable ($proto) is deprecated; use DefMacro"); DefMacro($proto,$expansion,%options); } # Define a Macro: Essentially an alias for DefExpandable # For convenience, the $expansion can be a string which will be tokenized. our $macro_options = {isConditional=>1, scope=>1, locked=>1}; sub DefMacro { my($proto,$expansion,%options)=@_; CheckOptions("DefMacro ($proto)",$macro_options,%options); DefMacroI(parsePrototype($proto),$expansion,%options); } sub DefMacroI { my($cs,$paramlist,$expansion,%options)=@_; if(!defined $expansion){ $expansion = Tokens(); } $cs = coerceCS($cs); $STATE->installDefinition(LaTeXML::Expandable->new($cs,$paramlist,$expansion,%options), $options{scope}); AssignValue(ToString($cs).":locked"=>1) if $options{locked}; return; } sub RawTeX { my($text)=@_; Digest(TokenizeInternal($text)); return; } #====================================================================== # Define a primitive control sequence. #====================================================================== # Primitives are executed in the Stomach. # The $replacement should be a sub which returns nothing, or a list of Box's or Whatsit's. # The options are: # isPrefix : 1 for things like \global, \long, etc. # registerType : for parameters (but needs to be worked into DefParameter, below). our $primitive_options = {isPrefix=>1,scope=>1, requireMath=>1, forbidMath=>1,beforeDigest=>1, locked=>1}; sub DefPrimitive { my($proto,$replacement,%options)=@_; CheckOptions("DefPrimitive ($proto)",$primitive_options,%options); DefPrimitiveI(parsePrototype($proto),$replacement,%options); } sub DefPrimitiveI { my($cs,$paramlist,$replacement,%options)=@_; $replacement = sub { (); } unless defined $replacement; $cs = coerceCS($cs); $STATE->installDefinition(LaTeXML::Primitive ->new($cs,$paramlist,$replacement, beforeDigest=> flatten(($options{requireMath} ? (sub{requireMath($cs);}):()), ($options{forbidMath} ? (sub{forbidMath($cs);}):()), $options{beforeDigest}), isPrefix=>$options{isPrefix}), $options{scope}); AssignValue(ToString($cs).":locked"=>1) if $options{locked}; return; } our $register_options = {readonly=>1, getter=>1, setter=>1}; our %register_types = ('LaTeXML::Number' =>'Number', 'LaTeXML::Dimension'=>'Dimension', 'LaTeXML::Glue' =>'Glue', 'LaTeXML::MuGlue' =>'MuGlue', 'LaTeXML::Tokens' =>'Tokens', ); sub DefRegister { my($proto,$value,%options)=@_; CheckOptions("DefRegsiter ($proto)",$register_options,%options); DefRegisterI(parsePrototype($proto),$value,%options); } sub DefRegisterI { my($cs,$paramlist,$value,%options)=@_; $cs = coerceCS($cs); my $type = $register_types{ref $value}; my $name = $cs->toString; my $getter = $options{getter} || sub { LookupValue(join('',$name,map($_->toString,@_))) || $value; }; my $setter = $options{setter} || ($options{readonly} ? sub { my($value,@args)=@_; Error(":unexpected:$name Cannot assign to register $name"); return; } : sub { my($value,@args)=@_; AssignValue(join('',$name,map($_->toString,@args)) => $value); }); # Not really right to set the value! AssignValue($cs->toString =>$value) if defined $value; $STATE->installDefinition(LaTeXML::Register->new($cs,$paramlist, $type,$getter,$setter, readonly=>$options{readonly}), 'global'); return; } sub flatten { [map((defined $_ ? (ref $_ eq 'ARRAY' ? @$_ : ($_)) : ()), @_)]; } #====================================================================== # Define a constructor control sequence. #====================================================================== # The arguments, if any, will be collected and processed in the Stomach, and # a Whatsit will be constructed. # It is the Whatsit that will be processed in the Document: It is responsible # for constructing XML Nodes. The $replacement should be a sub which inserts nodes, # or a string specifying a constructor pattern (See somewhere). # # Options are: # bounded : any side effects of before/after daemans are bounded; they are # automatically enclosed by bgroup/egroup pair. # mode : causes a switch into the given mode during the Whatsit building in the stomach. # reversion : a string representing the preferred TeX form of the invocation. # beforeDigest : code to be executed (in the stomach) before parsing & constructing the Whatsit. # Can be used for changing modes, beginning groups, etc. # afterDigest : code to be executed (in the stomach) after parsing & constructing the Whatsit. # useful for setting Whatsit properties, # properties : a hashref listing default values of properties to assign to the Whatsit. # These properties can be used in the constructor. our $constructor_options = {mode=>1, requireMath=>1, forbidMath=>1, font=>1, reversion=>1, properties=>1, alias=>1, nargs=>1, beforeDigest=>1, afterDigest=>1, beforeConstruct=>1, afterConstruct=>1, captureBody=>1, scope=>1, bounded=>1, locked=>1}; sub DefConstructor { my($proto,$replacement,%options)=@_; CheckOptions("DefConstructor ($proto)",$constructor_options,%options); DefConstructorI(parsePrototype($proto),$replacement,%options); } sub DefConstructorI { my($cs,$paramlist,$replacement,%options)=@_; $cs = coerceCS($cs); my $mode = $options{mode}; my $bounded = $options{bounded}; $STATE->installDefinition(LaTeXML::Constructor ->new($cs,$paramlist,$replacement, beforeDigest=> flatten(($options{requireMath} ? (sub{requireMath($cs);}):()), ($options{forbidMath} ? (sub{forbidMath($cs);}):()), ($mode ? (sub { $_[0]->beginMode($mode); }) :($bounded ? (sub {$_[0]->bgroup;}) :()) ), ($options{font}? (sub { MergeFont(%{$options{font}});}):()), $options{beforeDigest}), afterDigest => flatten($options{afterDigest}, ($mode ? (sub { $_[0]->endMode($mode) }) : ($bounded ? (sub{$_[0]->egroup;}):()) )), beforeConstruct=> flatten($options{beforeConstruct}), afterConstruct => flatten($options{afterConstruct}), nargs => $options{nargs}, alias => $options{alias}, reversion => ($options{reversion} && !ref $options{reversion} ? Tokenize($options{reversion}) : $options{reversion}), captureBody => $options{captureBody}, properties => $options{properties}||{}), $options{scope}); AssignValue(ToString($cs).":locked"=>1) if $options{locked}; return; } # DefMath Define a Mathematical symbol or function. # There are two sets of cases: # (1) If the presentation appears to be TeX code, we create an XMDual, # since the presentation may end up with structure, etc. # (2) But if the presentation is a simple string, or unicode, # it is just the content of the symbol; even if the function takes arguments. # ALSO # arrange that the operator token gets cs="$cs" # ALSO # Possibly some trick with SUMOP/INTOP affecting limits ? # Well, not exactly, but.... # HMM.... Still fishy. # When to make a dual ? # If the $presentation seems to be TeX (ie. it involves #1... but not ONLY!) our $math_options = {name=>1, meaning=>1, omcd=>1, reversion=>1, alias=>1, role=>1, operator_role=>1, reorder=>1, dual=>1, style=>1, font=>1, size=>1, scriptpos=>1,operator_scriptpos=>1, beforeDigest=>1, afterDigest=>1, scope=>1, nogroup=>1,locked=>1}; our $XMID=0; sub next_id { ## "LXID".$XMID++; } my $docid = LookupValue('DOCUMENTID'); ($docid ? "$docid.XM" : 'XM').++$XMID; } sub dualize_arglist { my(@args)=@_; my(@cargs,@pargs); foreach my $arg (@args){ if(defined $arg){ # my $id = next_id(); # push(@cargs, Invocation(T_CS('\@XMArg'),T_OTHER($id),$arg)); # push(@pargs, Invocation(T_CS('\@XMRef'),T_OTHER($id))); } StepCounter('@XMARG'); DefMacroI(T_CS('\@@XMARG@ID'),undef, Tokens(Explode(LookupValue('\c@@XMARG')->valueOf)), scope=>'global'); my $id = Expand(T_CS('\the@XMARG@ID')); push(@cargs, Invocation(T_CS('\@XMArg'),$id,$arg)); push(@pargs, Invocation(T_CS('\@XMRef'),$id)); } else { push(@cargs,undef); push(@pargs,undef); }} ( [@cargs],[@pargs] ); } # Quick reversal! # ( [@pargs],[@cargs] ); } sub DefMath { my($proto,$presentation,%options)=@_; CheckOptions("DefMath ($proto)",$math_options,%options); DefMathI(parsePrototype($proto),$presentation,%options); } sub DefMathI { my($cs,$paramlist,$presentation,%options)=@_; $cs = coerceCS($cs); my $nargs = ($paramlist ? scalar($paramlist->getParameters): 0); my $csname = $cs->getString; my $meaning = $options{meaning}; my $name = $csname; $name =~ s/^\\//; $name = $options{name} if defined $options{name}; $name = undef if (defined $name) && (($name eq $presentation) || ($name eq '') || ((defined $meaning) && ($meaning eq $name))); my $attr="name='#name' meaning='#meaning' omcd='#omcd' style='#style' size='#size'"; $options{role} = 'UNKNOWN' if ($nargs == 0) && !defined $options{role}; $options{operator_role} = 'UNKNOWN' if ($nargs > 0) && !defined $options{operator_role}; $options{reversion} = Tokenize($options{reversion}) if $options{reversion} && !ref $options{reversion}; # Store some data for introspection AssignValue(join("##","math_definition",$csname,$nargs, $options{role}||$options{operator_role}||'',$name||'', (defined $options{meaning} ? $options{meaning} :''), $STATE->getStomach->getGullet->getMouth->getSource, (ref $presentation ? '' : $presentation))=>1, global=>1); my %common =(alias=>$options{alias}||$cs->getString, (defined $options{reversion} ? (reversion=>$options{reversion}) : ()), beforeDigest=> flatten(sub{requireMath($csname);}, ($options{nogroup} ? () :(sub{$_[0]->bgroup;})), ($options{font} ? (sub { MergeFont(%{$options{font}});}) :()), $options{beforeDigest}), afterDigest => flatten($options{afterDigest}, ($options{nogroup} ? () :(sub{$_[0]->egroup;}))), beforeConstruct=> flatten($options{beforeConstruct}), afterConstruct => flatten($options{afterConstruct}), properties => {name=>$name, meaning=>$meaning, omcd=>$options{omcd}, role => $options{role}, operator_role=>$options{operator_role}, style=>$options{style}, size=>$options{size}, scriptpos=>$options{scriptpos}, operator_scriptpos=>$options{operator_scriptpos}}, scope=>$options{scope}); # If single character, Make the character active in math. if(length($csname) == 1){ AssignCatcode('math:'.$csname=>1, $options{scope}); } # If the presentation is complex, and involves arguments, # we will create an XMDual to separate content & presentation. # This involves creating 3 control sequences: # \cs macro that expands into \DUAL{pres}{content} # \cs@content constructor creates the content branch # \cs@presentation macro that expands into code in the presentation branch. ### if((ref $presentation eq 'CODE') ### || ((ref $presentation) && grep($_->equals(T_PARAM),$presentation->unlist)) if((ref $presentation) || ($presentation =~ /\#\d|\\./)){ my $cont_cs = T_CS($csname."\@content"); my $pres_cs = T_CS($csname."\@presentation"); # Make the original CS expand into a DUAL invoking a presentation macro and content constructor $STATE->installDefinition(LaTeXML::Expandable->new($cs,$paramlist, sub { my($self,@args)=@_; my($cargs,$pargs)=dualize_arglist(@args); Invocation(T_CS('\DUAL'), ($options{role} ? T_OTHER($options{role}):undef), Invocation($cont_cs,@$cargs), Invocation($pres_cs,@$pargs) )->unlist; }), $options{scope}); # Make the presentation macro. $presentation = TokenizeInternal($presentation) unless ref $presentation; $presentation = Invocation(T_CS('\@ASSERT@MEANING'), T_OTHER($meaning), $presentation) if $meaning; $STATE->installDefinition(LaTeXML::Expandable->new($pres_cs, $paramlist, $presentation), $options{scope}); $STATE->installDefinition(LaTeXML::Constructor->new($cont_cs,$paramlist, ($nargs == 0 ? "" : "" . "" . join('',map("#$_", ($options{reorder}? @{$options{reorder}} : (1..$nargs)))) .""), %common), $options{scope}); } else { my $end_tok = (defined $presentation ? ">$presentation" : "/>"); $common{properties}{font} = sub { LookupValue('font')->specialize($presentation); }; $STATE->installDefinition(LaTeXML::Constructor->new($cs,$paramlist, ($nargs == 0 # If trivial presentation, allow it in Text ? ($presentation !~ /(\(|\)|\\)/ ? "?#isMath(" . "#$_", 1..$nargs)) .""), %common), $options{scope}); } AssignValue(ToString($cs).":locked"=>1) if $options{locked}; return; } #====================================================================== # Define a LaTeX environment # Note that the body of the environment is treated is the 'body' parameter in the constructor. our $environment_options = {mode=>1, requireMath=>1, forbidMath=>1, properties=>1, nargs=>1, font=>1, beforeDigest=>1, afterDigest=>1, beforeConstruct=>1, afterConstruct=>1, afterDigestBegin=>1, beforeDigestEnd=>1, scope=>1, locked=>1}; sub DefEnvironment { my($proto,$replacement,%options)=@_; CheckOptions("DefEnvironment ($proto)",$environment_options,%options); ## $proto =~ s/^\{([^\}]+)\}\s*//; # Pull off the environment name as {name} ## my $paramlist=parseParameters($proto,"Environment $name"); ## my $name = $1; my($name,$paramspec)=Text::Balanced::extract_bracketed($proto,'{}'); $name =~ s/[\{\}]//g; $paramspec =~ s/^\s*//; my $paramlist=parseParameters($paramspec,"Environment $name"); DefEnvironmentI($name,$paramlist,$replacement,%options); } sub DefEnvironmentI { my($name,$paramlist,$replacement,%options)=@_; my $mode = $options{mode}; $name = $name->toString if ref $name; # This is for the common case where the environment is opened by \begin{env} $STATE->installDefinition(LaTeXML::Constructor ->new(T_CS("\\begin{$name}"), $paramlist,$replacement, beforeDigest=>flatten(($options{requireMath} ? (sub{requireMath($name);}):()), ($options{forbidMath} ? (sub{forbidMath($name);}):()), ($mode ? (sub { $_[0]->beginMode($mode);}) : (sub {$_[0]->bgroup;})), sub { AssignValue(current_environment=>$name); }, ($options{font}? (sub { MergeFont(%{$options{font}});}):()), $options{beforeDigest}), afterDigest =>flatten($options{afterDigestBegin}), beforeConstruct=> flatten(sub{$STATE->pushFrame;},$options{beforeConstruct}), # Curiously, it's the \begin whose afterConstruct gets called. afterConstruct => flatten($options{afterConstruct},sub{$STATE->popFrame;}), nargs=>$options{nargs}, captureBody=>1, properties=>$options{properties}||{}, ), $options{scope}); $STATE->installDefinition(LaTeXML::Constructor ->new(T_CS("\\end{$name}"),"","", beforeDigest =>flatten($options{beforeDigestEnd}), afterDigest=>flatten($options{afterDigest}, sub { my $env = LookupValue('current_environment'); Error(":unexpected:\\end{$name} Cannot close environment $name; current are " .join(', ',$STATE->lookupStackedValues('current_environment'))) unless $env && $name eq $env; return; }, ($mode ? (sub { $_[0]->endMode($mode);}) :(sub{$_[0]->egroup;}))), ),$options{scope}); # For the uncommon case opened by \csname env\endcsname $STATE->installDefinition(LaTeXML::Constructor ->new(T_CS("\\$name"), $paramlist,$replacement, beforeDigest=>flatten(($options{requireMath} ? (sub{requireMath($name);}):()), ($options{forbidMath} ? (sub{forbidMath($name);}):()), ($mode ? (sub { $_[0]->beginMode($mode);}):()), ($options{font}? (sub { MergeFont(%{$options{font}});}):()), $options{beforeDigest}), afterDigest =>flatten($options{afterDigestBegin}), beforeConstruct=> flatten(sub{$STATE->pushFrame;},$options{beforeConstruct}), # Curiously, it's the \begin whose afterConstruct gets called. afterConstruct => flatten($options{afterConstruct},sub{$STATE->popFrame;}), nargs=>$options{nargs}, captureBody=>T_CS("\\end$name"), # Required to capture!! properties=>$options{properties}||{}), $options{scope}); $STATE->installDefinition(LaTeXML::Constructor ->new(T_CS("\\end$name"),"","", beforeDigest =>flatten($options{beforeDigestEnd}), afterDigest=>flatten($options{afterDigest}, ($mode ? (sub { $_[0]->endMode($mode);}):())), ),$options{scope}); if($options{locked}){ AssignValue("\\begin{$name}:locked"=>1); AssignValue("\\end{$name}:locked"=>1); AssignValue("\\$name:locked"=>1); AssignValue("\\end$name:locked"=>1); } return; } #====================================================================== # Declaring and Adjusting the Document Model. #====================================================================== # Specify the properties of a Node tag. our $tag_options = {autoOpen=>1, autoClose=>1, afterOpen=>1, afterClose=>1}; sub Tag { my($tag,%properties)=@_; CheckOptions("Tag ($tag)",$tag_options,%properties); my $model = $STATE->getModel; $model->setTagProperty($tag,autoOpen=>$properties{autoOpen}) if $properties{autoOpen}; $model->setTagProperty($tag,autoClose=>$properties{autoClose}) if $properties{autoClose}; # ADD after daemons to any already present. $model->setTagProperty($tag, afterOpen=>flatten($model->getTagProperty($tag,'afterOpen'), $properties{afterOpen})) if $properties{afterOpen}; $model->setTagProperty($tag, afterClose=>flatten($model->getTagProperty($tag,'afterClose'), $properties{afterClose})) if $properties{afterClose}; return; } sub DocType { my($rootelement,$pubid,$sysid,%namespaces)=@_; my $model = $STATE->getModel; $model->setDocType($rootelement,$pubid,$sysid); foreach my $prefix (keys %namespaces){ $model->registerDocumentNamespace($prefix=>$namespaces{$prefix}); } return; } # What verb here? Set, Choose,... sub RelaxNGSchema { my($schema,%namespaces)=@_; my $model = $STATE->getModel; $model->setRelaxNGSchema($schema,); foreach my $prefix (keys %namespaces){ $model->registerDocumentNamespace($prefix=>$namespaces{$prefix}); } return; } sub RegisterNamespace { my($prefix,$namespace)=@_; $STATE->getModel->registerNamespace($prefix,$namespace); return; } #====================================================================== # Package, Class and File Loading #====================================================================== # Find a file: # If the raw option is given, # it searches for the file. # If $ext is given or $file ends with a known extension # (eg. .sty for packages, .cls for classes, etc): # the file is sought first as $file.$ext.ltxml then as $file.$ext # Otherwise, the file is sought in a more TeX-like fashion: # the file is sought as $file.tex.ltxml, $file.tex, $file.ltxml or $file. # [ie. if raw=>1, we do _not_ loo for .ltxml forms] our $findfile_options = {raw=>1, type=>1}; sub FindFile { my ($file,%options)=@_; CheckOptions("FindFile ($file)",$findfile_options,%options); my $paths = LookupValue('SEARCHPATHS'); $file = ToString($file); $file .= ".$options{type}" if $options{type}; if($options{raw}){ pathname_find("$file",paths=>$paths); } elsif($options{type} || ($file =~ /\.(tex|pool|sty|cls|clo|cnf|cfg)$/)){ # explicit or known extensions pathname_find("$file.ltxml",paths=>$paths,installation_subdir=>'Package') || pathname_find("$file",paths=>$paths); } else { pathname_find("$file.tex.ltxml",paths=>$paths,installation_subdir=>'Package') || pathname_find("$file.tex",paths=>$paths) || pathname_find("$file.ltxml",paths=>$paths,installation_subdir=>'Package') || pathname_find("$file",paths=>$paths); }} # Declare an option for the current package or class # If $option is undef, it is the default. # $code can be a sub (as a primitive), or a string to be expanded. # (effectively a macro) sub DeclareOption { my($option,$code)=@_; $option = ToString($option) if ref $option; PushValue('@declaredoptions',$option) if $option; my $cs = ($option ? '\ds@'.$option : '\default@ds'); # print STDERR "Declaring option: ".($option ? $option : '')."\n"; if((!defined $code) || (ref $code eq 'CODE')){ DefPrimitiveI($cs,undef,$code); } else { DefMacroI($cs,undef,$code); } return; } # Pass the sequence of @options to the package $name (if $ext is 'sty'), # or class $name (if $ext is 'cls'). sub PassOptions { my($name,$ext,@options)=@_; PushValue('opt@'.$name.'.'.$ext, map(ToString($_),@options)); # print STDERR "Passing to $name.$ext options: ".join(', ',@options)."\n"; return; } # Process the options passed to the currently loading package or class. # If inorder=>1, they are processed in the order given (like \ProcessOptions*), # otherwise, they are processed in the order declared. # Unless noundefine=>1 (like for \ExecuteOptions), all option definitions # undefined after execution. our $processoptions_options = {inorder=>1}; sub ProcessOptions { my(%options)=@_; CheckOptions("ProcessOptions",$processoptions_options,%options); my $name = ToString(Digest(T_CS('\@currname'))); my $ext = ToString(Digest(T_CS('\@currext'))); my @declaredoptions = @{LookupValue('@declaredoptions')}; my @curroptions = @{LookupValue('opt@'.$name.'.'.$ext)}; # print STDERR "\nProcessing options for $name.$ext: ".join(', ',@curroptions)."\n"; my $defaultcs = T_CS('\default@ds'); # Execute options in declared order (unless \ProcessOptions*) if($options{inorder}){ # Execute options in order (eg. \ProcessOptions*) foreach my $option (@curroptions){ DefMacroI('\CurrentOption',undef,$option); my $cs = T_CS('\ds@'.$option); if(LookupDefinition($cs)){ # print STDERR "\nUsing option $option to $name.$ext\n"; Digest($cs); } elsif($defaultcs){ # print STDERR "\nUsing option $option to $name.$ext with default handler\n"; Digest($defaultcs); }}} else { # Execute options in declared order (eg. \ProcessOptions) foreach my $option (@declaredoptions){ if(grep($option eq $_,@curroptions)){ @curroptions = grep($option ne $_, @curroptions); # Remove it, since it's been handled. # print STDERR "\nUsing option $option to $name.$ext\n"; DefMacroI('\CurrentOption',undef,$option); Digest(T_CS('\ds@'.$option)); }} # Now handle any remaining options (eg. default options), in the given order. foreach my $option (@curroptions){ DefMacroI('\CurrentOption',undef,$option); # print STDERR "\nUsing option $option to $name.$ext with default handler\n"; Digest($defaultcs); }} # Now, undefine the handlers? foreach my $option (@declaredoptions){ Let(T_CS('\ds@'.$option),T_CS('\relax')); } return; } sub ExecuteOptions { my(@options)=@_; my %unhandled=(); foreach my $option (@options){ my $cs = T_CS('\ds@'.$option); if(LookupDefinition($cs)){ DefMacroI('\CurrentOption',undef,$option); Digest($cs); } else { $unhandled{$option}=1; }} Warn(":unexpected: