diff --git a/lib/LaTeXML/Common/Font.pm b/lib/LaTeXML/Common/Font.pm index bf31f6fbb..5a0de3410 100644 --- a/lib/LaTeXML/Common/Font.pm +++ b/lib/LaTeXML/Common/Font.pm @@ -22,7 +22,7 @@ use LaTeXML::Common::Font::Metric; use LaTeXML::Common::Font::StandardMetrics; use LaTeXML::Common::Color; use List::Util qw(min max sum); -use base qw(LaTeXML::Common::Object); +use base qw(LaTeXML::Common::Object); # Note that this has evolved way beynond just "font", # but covers text properties (or even display properties) in general @@ -263,6 +263,7 @@ sub toString { # Perhaps it is more useful to list only the non-default components? sub stringify { + no warnings 'recursion'; my ($self) = @_; my ($fam, $ser, $shp, $siz, $col, $bkg, $opa, $enc, $lang, $mstyle, $flags) = @$self; $fam = 'serif' if $fam && ($fam eq 'math'); diff --git a/lib/LaTeXML/Common/Object.pm b/lib/LaTeXML/Common/Object.pm index 5e365789e..8e7f34a00 100644 --- a/lib/LaTeXML/Common/Object.pm +++ b/lib/LaTeXML/Common/Object.pm @@ -28,6 +28,7 @@ my %NOBLESS = map { ($_ => 1) } qw( SCALAR HASH ARRAY CODE REF GLOB LVALUE); # Since the next two are used in debugging and error messages, # be careful to avoid recursive errors sub Stringify { + no warnings 'recursion'; my ($object) = @_; my $string = eval { local $LaTeXML::IGNORE_ERRORS = 1; diff --git a/lib/LaTeXML/Core/List.pm b/lib/LaTeXML/Core/List.pm index 9a5c02e9e..34494341f 100644 --- a/lib/LaTeXML/Core/List.pm +++ b/lib/LaTeXML/Core/List.pm @@ -73,6 +73,7 @@ sub toString { # Methods for overloaded operators sub stringify { + no warnings 'recursion'; my ($self) = @_; my $type = ref $self; $type =~ s/^LaTeXML:://; diff --git a/lib/LaTeXML/Core/Parameter.pm b/lib/LaTeXML/Core/Parameter.pm index 31fbff912..bd05d30e0 100644 --- a/lib/LaTeXML/Core/Parameter.pm +++ b/lib/LaTeXML/Core/Parameter.pm @@ -126,6 +126,7 @@ sub reparse { return $value; }); } } sub digest { + no warnings 'recursion'; my ($self, $stomach, $value, $fordefn) = @_; # If semiverbatim, Expand (before digest), so tokens can be neutralized; BLECH!!!! if ($$self{semiverbatim}) { diff --git a/lib/LaTeXML/Core/Tokens.pm b/lib/LaTeXML/Core/Tokens.pm index 5fa66ef0c..0d29631b0 100644 --- a/lib/LaTeXML/Core/Tokens.pm +++ b/lib/LaTeXML/Core/Tokens.pm @@ -81,6 +81,7 @@ sub stringify { return "Tokens[" . join(',', map { $_->toString } @$self) . "]"; } sub beDigested { + no warnings 'recursion'; my ($self, $stomach) = @_; return $stomach->digest($self); } diff --git a/lib/LaTeXML/Core/Whatsit.pm b/lib/LaTeXML/Core/Whatsit.pm index 0651c3308..ee21008ed 100644 --- a/lib/LaTeXML/Core/Whatsit.pm +++ b/lib/LaTeXML/Core/Whatsit.pm @@ -175,6 +175,7 @@ sub getString { # Methods for overloaded operators sub stringify { + no warnings 'recursion'; my ($self) = @_; my $hasbody = defined $$self{properties}{body}; return "Whatsit[" . join(',', $self->getDefinition->getCS->getCSName, @@ -243,6 +244,7 @@ sub computeSize { @boxes = $boxes[0]->unlist; } } else { push(@boxes, $sizer); } + no warnings 'recursion'; return $$props{font}->computeBoxesSize([@boxes], %options); } } #====================================================================== diff --git a/lib/LaTeXML/Package/IEEEtran.cls.ltxml b/lib/LaTeXML/Package/IEEEtran.cls.ltxml index 7b62438da..fe42e7da5 100644 --- a/lib/LaTeXML/Package/IEEEtran.cls.ltxml +++ b/lib/LaTeXML/Package/IEEEtran.cls.ltxml @@ -180,8 +180,13 @@ RawTeX(<<'EoTeX'); \def\theparagraph{\thesubsubsection\alph{paragraph}} % I-A1a \fi EoTeX -DefMacro('\format@title@font@section', '\sc'); -DefMacro('\format@title@font@subsection', '\it'); +DefPrimitiveI('\ltx@ieeetran@it', undef, undef, + font => { shape => 'italic', family => 'serif', series => 'medium' }, locked => 1); +DefPrimitiveI('\ltx@ieeetran@sc', undef, undef, + font => { shape => 'smallcaps', family => 'serif', series => 'medium' }, locked => 1); + +DefMacro('\format@title@font@section', '\ltx@ieeetran@sc'); +DefMacro('\format@title@font@subsection', '\ltx@ieeetran@it'); DefMacro('\figurename', 'Fig.'); DefMacro('\tablename', 'TABLE'); DefMacro('\thetable', '\Roman{table}'); @@ -340,23 +345,39 @@ DefMacro('\IEEEiedlabeljustifyc', ''); DefMacro('\IEEEiedlabeljustifyl', ''); DefMacro('\IEEEiedlabeljustifyr', ''); -DefEnvironment('{IEEEitemize}', +# TODO: Use the optional argument. +# also, we skip the internal @-named variants for now. +DefEnvironment('{IEEEitemize}[]', "#body", properties => sub { beginItemize('itemize', '@item'); }, beforeDigestEnd => sub { Digest('\par'); }, locked => 1, mode => 'text'); -DefEnvironment('{IEEEenumerate}', +DefEnvironment('{IEEEenumerate}[]', "#body", properties => sub { beginItemize('enumerate', 'enum'); }, beforeDigestEnd => sub { Digest('\par'); }, locked => 1, mode => 'text'); -DefEnvironment('{IEEEdescription}', +DefEnvironment('{IEEEdescription}[]', "#body", beforeDigest => sub { Let('\makelabel', '\descriptionlabel'); }, properties => sub { beginItemize('description', '@desc'); }, beforeDigestEnd => sub { Digest('\par'); }, locked => 1, mode => 'text'); +# override LaTeX's default IED lists +Let('\itemize', '\IEEEitemize'); +Let('\enditemize', '\endIEEEitemize'); +Let('\enumerate', '\IEEEenumerate'); +Let('\endenumerate', '\endIEEEenumerate'); +Let('\description', '\IEEEdescription'); +Let('\enddescription', '\endIEEEdescription'); +Let(T_CS('\begin{itemize}'), '\IEEEitemize'); +Let(T_CS('\end{itemize}'), '\endIEEEitemize'); +Let(T_CS('\begin{enumerate}'), '\IEEEenumerate'); +Let(T_CS('\end{enumerate}'), '\endIEEEenumerate'); +Let(T_CS('\begin{description}'), '\IEEEdescription'); +Let(T_CS('\end{description}'), '\endIEEEdescription'); + # V1.7 provide string macros as article.cls does DefMacro('\contentsname', 'Contents'); DefMacro('\listfigurename', 'List of Figures'); diff --git a/lib/LaTeXML/Package/LaTeX.pool.ltxml b/lib/LaTeXML/Package/LaTeX.pool.ltxml index e7aba2021..27e8eeb93 100644 --- a/lib/LaTeXML/Package/LaTeX.pool.ltxml +++ b/lib/LaTeXML/Package/LaTeX.pool.ltxml @@ -290,7 +290,7 @@ DefConstructor('\lx@newline OptionalMatch:* [Glue]', sub { $document->insertElement('ltx:XMHint', undef, name => 'newline'); } else { my $context = $document->getElement; - if ($context->getAttribute('_vertical_mode_')) { } + if (!$context || $context->getAttribute('_vertical_mode_')) { } elsif (($document->getNodeQName($context) eq 'ltx:p') && $context->parentNode->getAttribute('_vertical_mode_')) { $document->maybeCloseElement('ltx:p'); } @@ -1372,7 +1372,7 @@ DefEnvironment('{flushright}', sub { sub setupAligningContext { my ($document) = @_; my $node = $document->getElement; - AssignValue(ALIGNING_NODE => [$node, $node->lastChild]); + AssignValue(ALIGNING_NODE => [$node, $node->lastChild]) if $node; return; } sub applyAligningContext { @@ -4971,6 +4971,8 @@ DefConstructor('\raisebox{Dimension}[Dimension][Dimension]{}', beforeDigest => sub { reenterTextMode(); }, sizer => sub { raisedSizer($_[0]->getArg(4), $_[0]->getArg(1)); }); +DefMacro('\@finalstrut{}', '\unskip\ifhmode\nobreak\fi\vrule\@width\z@\@height\z@\@depth\dp#1'); + #********************************************************************** # C.14 Pictures and Color #********************************************************************** @@ -5514,6 +5516,8 @@ DefPrimitiveI('\textregistered', undef, UTF(0xAE)); # REGISTERED SIGN DefPrimitiveI('\texttrademark', undef, "\x{2122}"); # TRADE MARK SIGN DefConstructor('\textsuperscript{}', "#1", mode => 'text'); +DefConstructor('\@textsuperscript{}', "#1", + mode => 'text', locked => 1); # This is something coming from xetex/xelatex ? Why define this way? #DefConstructor('\realsuperscript{}', "#1"); DefConstructor('\realsuperscript{}', "#1", diff --git a/lib/LaTeXML/Package/listings.sty.ltxml b/lib/LaTeXML/Package/listings.sty.ltxml index 1c953d114..a912fbf76 100644 --- a/lib/LaTeXML/Package/listings.sty.ltxml +++ b/lib/LaTeXML/Package/listings.sty.ltxml @@ -1355,7 +1355,16 @@ sub lstProcess_internal { my $classes = LookupValue('LST_CLASSES'); my $literate = LookupValue('LST_LITERATE'); my $lit_re = ($end_re ? $LaTeXML::LITERATE_INNER_RE : $LaTeXML::LITERATE_RE); + my $loop_guard = 'loop guard'; + while ($LaTeXML::listing ne '') { + if ($LaTeXML::listing eq $loop_guard) { + # we must make headway on every step, or we risk infinite loops + Error('listing', 'infinite_loop', undef, + "lstProcess_internal failed to execute correctly.", "content was: '$loop_guard'"); + $LaTeXML::listing = ''; + last; } + $loop_guard = $LaTeXML::listing; # Matched the ending regular expression? (typically a close delimiter) if ($end_re && $LaTeXML::listing =~ s/^($end_re)//s) { $LaTeXML::colnum += length($1); @@ -1449,7 +1458,6 @@ sub lstProcess_internal { elsif ($LaTeXML::QUOTED_RE && $LaTeXML::listing =~ s/^($LaTeXML::QUOTED_RE)//) { # Something quoted. # Don't just past together, and watch for leading \ (a common quoter) lstProcessPush(map { ($_ eq '\\' ? T_CS('\textbackslash') : T_OTHER($_)) } split('', $1)); - $LaTeXML::colnum += length($1); } else { if ($LaTeXML::listing =~ s/^(.)//s) { # Anything else, just pass through. diff --git a/lib/LaTeXML/Package/natbib.sty.ltxml b/lib/LaTeXML/Package/natbib.sty.ltxml index 60aeeae88..31edf8583 100644 --- a/lib/LaTeXML/Package/natbib.sty.ltxml +++ b/lib/LaTeXML/Package/natbib.sty.ltxml @@ -485,10 +485,13 @@ DefMacro('\shortcites Semiverbatim', ''); # \bibitem[\protect\citename{Jones et al., }1990]{key}... # \harvarditem[Jones et al.]{Jones, Baker, and Williams}{1990}{key}... -DefMacro('\bibitem', +DefMacro('\lx@nat@bibitem', ## '\reset@natbib@cites\refstepcounter{@bibitem}\@ifnextchar[{\@lbibitem}{\@lbibitem[\the@bibitem]}', '\reset@natbib@cites\refstepcounter{@bibitem}\@ifnextchar[{\@lbibitem}{\@lbibitem[]}', locked => 1); +# Careful: since OmniBus also defines \bibitem and LaTeX.pool has a save/restore mechanism, +# it is safer to \let to a constant natbib-specific macro definition. Test with arXiv:2007.09909 +Let('\bibitem', '\lx@nat@bibitem'); RawTeX(<<'EOTeX'); %%% diff --git a/lib/LaTeXML/Package/pgfmath.code.tex.ltxml b/lib/LaTeXML/Package/pgfmath.code.tex.ltxml index 7a76ba7ce..5cbe4ed2e 100644 --- a/lib/LaTeXML/Package/pgfmath.code.tex.ltxml +++ b/lib/LaTeXML/Package/pgfmath.code.tex.ltxml @@ -705,6 +705,7 @@ expr : | /0b[01]+/ { oct($item[1]); } # !!! | /0x[0-9a-fA-F]+/ { hex($item[1]); } | /0[0-9]+/ { oct($item[1]); } + | /\./ { 0.0; } # pgf treats a single dot as a zero UNIT : /(?:ex|em|pt|pc|in|bp|cm|mm|dd|cc|sp)/ diff --git a/lib/LaTeXML/Package/xcolor.sty.ltxml b/lib/LaTeXML/Package/xcolor.sty.ltxml index 71ff6bf41..ad57fd68e 100644 --- a/lib/LaTeXML/Package/xcolor.sty.ltxml +++ b/lib/LaTeXML/Package/xcolor.sty.ltxml @@ -290,7 +290,7 @@ sub DecodeColor { my $color_re = qr/($color_expr_re)(($func_expr_re)*)/; my $color; - if ($expression =~ /^$color_re$/) { + if ($expression =~ /^$color_re\s*$/) { #DG: Dear reader, I present to you: maintenance hell: my $prefix = $2 || $10; my $name = $3 || $11; diff --git a/lib/LaTeXML/Post/MathML.pm b/lib/LaTeXML/Post/MathML.pm index 66812a1f8..cf8477ab1 100644 --- a/lib/LaTeXML/Post/MathML.pm +++ b/lib/LaTeXML/Post/MathML.pm @@ -693,7 +693,8 @@ sub stylizeContent { if (my $default = $role && $default_token_content{$role}) { $text = $default; } else { - $text = ($iselement ? $item->getAttribute('name') || $item->getAttribute('meaning') || $role : '?'); + $text = ($iselement ? ($item->getAttribute('name') || $item->getAttribute('meaning') + || $role || '') : '?'); $color = 'red'; } } elsif (($text eq '-') && $role && (($role eq 'ADDOP') || ($role eq 'OPERATOR'))) { # MathML Core prefers unicode minus $text = "\x{2212}"; } @@ -720,7 +721,7 @@ sub stylizeContent { : ($plane1 ? $variant : undef)); my $u_text = ($tag ne 'm:mtext') && $u_variant && unicode_convert($text, $u_variant); if ((defined $u_text) && ($u_text ne '')) { # didn't remap the text ? Keep text & variant - $text = $u_text; + $text = $u_text || ''; $variant = ($plane1hack && ($variant ne $u_variant) && ($variant =~ /^bold/) ? 'bold' : undef); } # Possibly keep variant bold # Use class (css) to patchup some weak translations