From daaba06df119fec117592087e9609d7d6fcc9bd7 Mon Sep 17 00:00:00 2001 From: deyan Date: Mon, 14 Oct 2024 18:05:39 -0400 Subject: [PATCH 1/2] trim whitespace in loading LaTeX classes and packages --- lib/LaTeXML/Engine/LaTeX.pool.ltxml | 73 +++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 14 deletions(-) diff --git a/lib/LaTeXML/Engine/LaTeX.pool.ltxml b/lib/LaTeXML/Engine/LaTeX.pool.ltxml index 1fac2dd67..10a8bdda1 100644 --- a/lib/LaTeXML/Engine/LaTeX.pool.ltxml +++ b/lib/LaTeXML/Engine/LaTeX.pool.ltxml @@ -55,11 +55,16 @@ DefConstructor('\documentclass OptionalSemiverbatim SkipSpaces Semiverbatim []', beforeDigest => sub { onlyPreamble('\documentclass'); }, afterDigest => sub { my ($stomach, $whatsit) = @_; - my $options = $whatsit->getArg(1); + my $options = ToString($whatsit->getArg(1)); my $class = ToString($whatsit->getArg(2)); + my @options; + if ($options) { + $options =~ s/^\s+//; + $options =~ s/\s+$//; + @options = split(/\s*,\s*/, $options); } $class =~ s/\s+//g; LoadClass($class, - options => [($options ? split(/\s*,\s*/, ToString($options)) : ())], + options => [@options], after => Tokens(T_CS('\AtBeginDocument'), T_CS('\warn@unusedclassoptions'))); return; }); @@ -80,8 +85,13 @@ DefConstructor('\documentstyle OptionalSemiverbatim SkipSpaces Semiverbatim []', my ($stomach, $whatsit) = @_; my $class = ToString($whatsit->getArg(2)); $class =~ s/\s+//g; - my $options = $whatsit->getArg(1); - $options = [($options ? split(/\s*,\s*/, ToString($options)) : ())]; + my $options = ToString($whatsit->getArg(1)); + my @options; + if ($options) { + $options =~ s/^\s+//; + $options =~ s/\s+$//; + @options = split(/\s*,\s*/, $options); } + $options = [@options]; # Watch out; In principle, compatibility mode wants a .sty, not a .cls!!! # But, we'd prefer .cls, since we'll have better bindings. # And in fact, nobody's likely to write a binding for a .sty that wants to be a class anyway. @@ -872,9 +882,14 @@ DefConstructor('\usepackage OptionalSemiverbatim Semiverbatim []', "", beforeDigest => sub { onlyPreamble('\usepackage'); }, afterDigest => sub { my ($stomach, $whatsit) = @_; - my $options = $whatsit->getArg(1); + my $options = ToString($whatsit->getArg(1)); + my @options; + if ($options) { + $options =~ s/^\s+//; + $options =~ s/\s+$//; + @options = split(/\s*,\s*/, $options); } + $options = [@options]; my $packages = $whatsit->getArg(2); - $options = [($options ? split(/\s*,\s*/, (ToString($options))) : ())]; for my $pkg (split(',', ToString($packages))) { $pkg =~ s/\s+//g; next if !$pkg || $pkg =~ /^%/; @@ -885,9 +900,14 @@ DefConstructor('\RequirePackage OptionalSemiverbatim Semiverbatim []', "", beforeDigest => sub { onlyPreamble('\RequirePackage'); }, afterDigest => sub { my ($stomach, $whatsit) = @_; - my $options = $whatsit->getArg(1); + my $options = ToString($whatsit->getArg(1)); + my @options; + if ($options) { + $options =~ s/^\s+//; + $options =~ s/\s+$//; + @options = split(/\s*,\s*/, $options); } + $options = [@options]; my $packages = $whatsit->getArg(2); - $options = [($options ? split(/\s*,\s*/, (ToString($options))) : ())]; for my $pkg (split(',', ToString($packages))) { $pkg =~ s/\s+//g; next if !$pkg || $pkg =~ /^%/; @@ -898,10 +918,15 @@ DefConstructor('\LoadClass OptionalSemiverbatim Semiverbatim []', "", beforeDigest => sub { onlyPreamble('\LoadClass'); }, afterDigest => sub { my ($stomach, $whatsit) = @_; - my $options = $whatsit->getArg(1); - my $class = ToString($whatsit->getArg(2)); + my $options = ToString($whatsit->getArg(1)); + my @options; + if ($options) { + $options =~ s/^\s+//; + $options =~ s/\s+$//; + @options = split(/\s*,\s*/, $options); } + $options = [@options]; + my $class = ToString($whatsit->getArg(2)); $class =~ s/\s+//g; - $options = [($options ? split(/\s*,\s*/, (ToString($options))) : ())]; LoadClass($class, options => $options); return; }); @@ -952,13 +977,27 @@ DefPrimitive('\PassOptionsToPackage{}{}', sub { my ($stomach, $options, $name) = @_; $name = ToString($name); $name =~ s/\s+//g; - PassOptions($name, 'sty', split(/\s*,\s*/, ToString(Expand($options)))); }); + my $options = ToString(Expand($options)); + my @options; + if ($options) { + $options =~ s/^\s+//; + $options =~ s/\s+$//; + @options = split(/\s*,\s*/, $options); } + $options = [@options]; + PassOptions($name, 'sty', $options); }); DefPrimitive('\PassOptionsToClass{}{}', sub { my ($stomach, $options, $name) = @_; $name = ToString($name); $name =~ s/\s+//g; - PassOptions($name, 'cls', split(/\s*,\s*/, ToString(Expand($options)))); }); + my $options = ToString(Expand($options)); + my @options; + if ($options) { + $options =~ s/^\s+//; + $options =~ s/\s+$//; + @options = split(/\s*,\s*/, $options); } + $options = [@options]; + PassOptions($name, 'cls', $options); }); DefConstructor('\RequirePackageWithOptions Semiverbatim []', "", @@ -1001,7 +1040,13 @@ DefPrimitiveI('\@unknownoptionerror', undef, sub { DefPrimitive('\ExecuteOptions{}', sub { my ($gullet, $options) = @_; - ExecuteOptions(split(/\s*,\s*/, ToString(Expand($options)))); }); + my $options = ToString(Expand($options)); + my @options; + if ($options) { + $options =~ s/^\s+//; + $options =~ s/\s+$//; + @options = split(/\s*,\s*/, $options); } + ExecuteOptions(@options) if @options; }); DefPrimitive('\ProcessOptions OptionalMatch:*', sub { my ($stomach, $star) = @_; From 8d714abc8dbfb4dc886cc59f30cf0b84cb199a16 Mon Sep 17 00:00:00 2001 From: deyan Date: Thu, 31 Oct 2024 16:26:51 -0400 Subject: [PATCH 2/2] introduce TrimmedCommaList helper --- lib/LaTeXML/Engine/LaTeX.pool.ltxml | 68 +++++------------------------ lib/LaTeXML/Package.pm | 9 +++- 2 files changed, 19 insertions(+), 58 deletions(-) diff --git a/lib/LaTeXML/Engine/LaTeX.pool.ltxml b/lib/LaTeXML/Engine/LaTeX.pool.ltxml index 10a8bdda1..cdafdaeb2 100644 --- a/lib/LaTeXML/Engine/LaTeX.pool.ltxml +++ b/lib/LaTeXML/Engine/LaTeX.pool.ltxml @@ -55,16 +55,11 @@ DefConstructor('\documentclass OptionalSemiverbatim SkipSpaces Semiverbatim []', beforeDigest => sub { onlyPreamble('\documentclass'); }, afterDigest => sub { my ($stomach, $whatsit) = @_; - my $options = ToString($whatsit->getArg(1)); + my $options = [TrimmedCommaList($whatsit->getArg(1))]; my $class = ToString($whatsit->getArg(2)); - my @options; - if ($options) { - $options =~ s/^\s+//; - $options =~ s/\s+$//; - @options = split(/\s*,\s*/, $options); } $class =~ s/\s+//g; LoadClass($class, - options => [@options], + options => $options, after => Tokens(T_CS('\AtBeginDocument'), T_CS('\warn@unusedclassoptions'))); return; }); @@ -83,15 +78,9 @@ DefConstructor('\documentstyle OptionalSemiverbatim SkipSpaces Semiverbatim []', onlyPreamble('\documentstyle'); }, afterDigest => sub { my ($stomach, $whatsit) = @_; - my $class = ToString($whatsit->getArg(2)); + my $options = [TrimmedCommaList($whatsit->getArg(1))]; + my $class = ToString($whatsit->getArg(2)); $class =~ s/\s+//g; - my $options = ToString($whatsit->getArg(1)); - my @options; - if ($options) { - $options =~ s/^\s+//; - $options =~ s/\s+$//; - @options = split(/\s*,\s*/, $options); } - $options = [@options]; # Watch out; In principle, compatibility mode wants a .sty, not a .cls!!! # But, we'd prefer .cls, since we'll have better bindings. # And in fact, nobody's likely to write a binding for a .sty that wants to be a class anyway. @@ -882,13 +871,7 @@ DefConstructor('\usepackage OptionalSemiverbatim Semiverbatim []', "", beforeDigest => sub { onlyPreamble('\usepackage'); }, afterDigest => sub { my ($stomach, $whatsit) = @_; - my $options = ToString($whatsit->getArg(1)); - my @options; - if ($options) { - $options =~ s/^\s+//; - $options =~ s/\s+$//; - @options = split(/\s*,\s*/, $options); } - $options = [@options]; + my $options = [TrimmedCommaList($whatsit->getArg(1))]; my $packages = $whatsit->getArg(2); for my $pkg (split(',', ToString($packages))) { $pkg =~ s/\s+//g; @@ -900,13 +883,7 @@ DefConstructor('\RequirePackage OptionalSemiverbatim Semiverbatim []', "", beforeDigest => sub { onlyPreamble('\RequirePackage'); }, afterDigest => sub { my ($stomach, $whatsit) = @_; - my $options = ToString($whatsit->getArg(1)); - my @options; - if ($options) { - $options =~ s/^\s+//; - $options =~ s/\s+$//; - @options = split(/\s*,\s*/, $options); } - $options = [@options]; + my $options = [TrimmedCommaList($whatsit->getArg(1))]; my $packages = $whatsit->getArg(2); for my $pkg (split(',', ToString($packages))) { $pkg =~ s/\s+//g; @@ -918,14 +895,8 @@ DefConstructor('\LoadClass OptionalSemiverbatim Semiverbatim []', "", beforeDigest => sub { onlyPreamble('\LoadClass'); }, afterDigest => sub { my ($stomach, $whatsit) = @_; - my $options = ToString($whatsit->getArg(1)); - my @options; - if ($options) { - $options =~ s/^\s+//; - $options =~ s/\s+$//; - @options = split(/\s*,\s*/, $options); } - $options = [@options]; - my $class = ToString($whatsit->getArg(2)); + my $options = [TrimmedCommaList($whatsit->getArg(1))]; + my $class = ToString($whatsit->getArg(2)); $class =~ s/\s+//g; LoadClass($class, options => $options); return; }); @@ -977,26 +948,14 @@ DefPrimitive('\PassOptionsToPackage{}{}', sub { my ($stomach, $options, $name) = @_; $name = ToString($name); $name =~ s/\s+//g; - my $options = ToString(Expand($options)); - my @options; - if ($options) { - $options =~ s/^\s+//; - $options =~ s/\s+$//; - @options = split(/\s*,\s*/, $options); } - $options = [@options]; + $options = [TrimmedCommaList(Expand($options))]; PassOptions($name, 'sty', $options); }); DefPrimitive('\PassOptionsToClass{}{}', sub { my ($stomach, $options, $name) = @_; $name = ToString($name); $name =~ s/\s+//g; - my $options = ToString(Expand($options)); - my @options; - if ($options) { - $options =~ s/^\s+//; - $options =~ s/\s+$//; - @options = split(/\s*,\s*/, $options); } - $options = [@options]; + $options = [TrimmedCommaList(Expand($options))]; PassOptions($name, 'cls', $options); }); DefConstructor('\RequirePackageWithOptions Semiverbatim []', @@ -1040,12 +999,7 @@ DefPrimitiveI('\@unknownoptionerror', undef, sub { DefPrimitive('\ExecuteOptions{}', sub { my ($gullet, $options) = @_; - my $options = ToString(Expand($options)); - my @options; - if ($options) { - $options =~ s/^\s+//; - $options =~ s/\s+$//; - @options = split(/\s*,\s*/, $options); } + my @options = TrimmedCommaList(Expand($options)); ExecuteOptions(@options) if @options; }); DefPrimitive('\ProcessOptions OptionalMatch:*', sub { diff --git a/lib/LaTeXML/Package.pm b/lib/LaTeXML/Package.pm index 5dca9669a..74875490c 100644 --- a/lib/LaTeXML/Package.pm +++ b/lib/LaTeXML/Package.pm @@ -110,7 +110,7 @@ our @EXPORT = (qw(&DefAutoload &DefExpandable # Random low-level token or string operations. qw(&CleanID &CleanLabel &CleanIndexKey &CleanClassName &CleanBibKey &NormalizeBibKey &CleanURL - &ComposeURL + &ComposeURL &TrimmedCommaList &roman &Roman), # Math & font state. qw(&MergeFont), @@ -555,6 +555,13 @@ sub ComposeURL { $url, ($fragid ? '#' . CleanID($fragid) : ''))); } +sub TrimmedCommaList { + my ($text) = @_; + $text = ToString($text); + $text =~ s/^\s+//; + $text =~ s/\s+$//; + return split(/\s*,\s*/, $text); } + #====================================================================== # Defining new Control-sequence Parameter types. #======================================================================