Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

The following code fills a table using \STCopy. It generates an 'out of save size error'e [MiKTeX 2.9].

If I make the table smaller (by commenting a row out) or remove the max call (and use only the second argument of the call), it will work. Any ideas how to make it work 'as is'? Please note that the call to max is not directly the issue, as the problem can be replicated by removing it and just adding more rows to the table.

I've already set save size=50000.

Thanks!

\documentclass[a4paper, 12pt]{article}

\usepackage{spreadtab}
\usepackage{multirow}
\usepackage{rotating}

\begin{document}

\begin{table}[h]
\centering
\STautoround{0}
\begin{spreadtab}{{tabular}{|l|r||c|c|c||c|c|c||c|c|c||}}
\hline
% Data rows (hidden)
& & :={65}kt & :={[-1,0]}kt & :={[-1,0]}kt & :={85}kt & :={[-1,0]}kt & :={[-1,0]}kt & :={95}kt & :={[-1,0]}kt & :={[-1,0]}kt \SThiderow \\
& & :={500}ft & :={800}ft & :={1500}ft & :={[-3,0]}ft & :={[-3,0]}ft & :={[-3,0]}ft & :={[-3,0]}ft & :={[-3,0]}ft & :={[-3,0]}ft \SThiderow \\
& & :={1.68780986}ft/s & & & & & & & & \SThiderow \\
% Output
@ \multirow{7}{*}{\begin{sideways}\bf . \end{sideways}} & \bf :={0} & \STcopy{>,v}{max(5,c!2/((c!1-!b4)*!c!3)+0.5)}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s \\\cline{3-11}
& \bf \STcopy{v6}{b4+10} & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s \\\cline{3-11}
& \bf :={}               & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s \\\cline{3-11}
& \bf :={}               & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s \\\cline{3-11}
& \bf :={}               & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s \\\cline{3-11}
& \bf :={}               & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s \\\cline{3-11}
& \bf :={}               & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s \\\cline{3-11}
& \bf :={}               & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s & :={}s \\\hline
\end{spreadtab}
\end{table}

\end{document}

Edited to add:

I need all those :={}<unit> to display units of measure.

share|improve this question
1  
2  
In order to avoid the save stack error, the spreadtab environment (espacially if is a big table) must not be in a group. If you remove the \begin{table}[h] and \end{table}, no save stack error occur anymore. –  unbonpetit Nov 29 '12 at 6:53
    
@unbonpetit: thanks. How did you find that out? –  Mau Nov 29 '12 at 11:00
1  
@Mau the save stack is were TeX saves values that need to be restored at group end, so having less grouping is a likely workaround for running out of space:-) But the correct fix really is to write the macros not to use space that grows exponentially with the grouping depth. –  David Carlisle Nov 29 '12 at 12:03

1 Answer 1

up vote 4 down vote accepted

I haven't used spreadtab or xstring before but xstring repeatedly assigns \groupID using both local and global assignments which is the usual way of filling the save stack.

If I change a local copy so all assignments are global then your example works and I get

enter image description here

But I have no idea if that is the intended result>

The diff I applied is below.

Unrelated to your problem but a table argument of [h] just makes it highly likely that the table goes to the end of the document, always include p at least so something like [htp]


*** xstring.tex~    2012-11-29 09:38:39.484507200 +0000
--- xstring.tex 2012-11-29 09:41:38.830854400 +0000
***************
*** 427,433 ****
  % si l'occurrence n'existe pas ou qu'un des arguments est vide, toutes les chaines renvoy\'ees sont vides
  \def\@xs@cutafteroccur#1#2#3{%
    \def\@xs@reserved@D{#1}\let\@xs@reserved@C\@empty\def\@xs@reserved@E{#2}%
!   \decimalpart\z@\integerpart\z@\def\groupID{0}\let\@xs@nestlevel\z@
    \def\@xs@atendofgroup{%
        \expandafter\endgroup
        \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\expandafter{\@xs@reserved@C}}%
--- 427,433 ----
  % si l'occurrence n'existe pas ou qu'un des arguments est vide, toutes les chaines renvoy\'ees sont vides
  \def\@xs@cutafteroccur#1#2#3{%
    \def\@xs@reserved@D{#1}\let\@xs@reserved@C\@empty\def\@xs@reserved@E{#2}%
!   \decimalpart\z@\integerpart\z@\gdef\groupID{0}\let\@xs@nestlevel\z@
    \def\@xs@atendofgroup{%
        \expandafter\endgroup
        \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\expandafter{\@xs@reserved@C}}%
***************
*** 449,455 ****
        \let\@xs@reserved@E\@xs@reserved@D
        \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\@xs@reserved@D\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@C\@xs@argument@A}%
    \else
!       \let\@xs@reserved@C\@empty\let\@xs@reserved@E\@empty\let\groupID\@empty
    \fi}

  \@xs@newmacro*3\IfSubStr{1}{2}{0}{%
--- 449,455 ----
        \let\@xs@reserved@E\@xs@reserved@D
        \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\@xs@reserved@D\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@C\@xs@argument@A}%
    \else
!       \let\@xs@reserved@C\@empty\let\@xs@reserved@E\@empty\global\let\groupID\@empty
    \fi}

  \@xs@newmacro*3\IfSubStr{1}{2}{0}{%
***************
*** 534,540 ****
    \expandafter\expandafter\expandafter\@xs@cutafteroccur\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@C\expandafter}\expandafter{\@xs@reserved@A}{#2}%
    \def\@xs@reserved@A{#4}%
    \expandafter\expandafter\expandafter\@xs@cutafteroccur\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@C\expandafter}\expandafter{\@xs@reserved@A}{#1}%
!   \let\groupID\@empty
    \expandafter\@xs@testempty\expandafter{\@xs@reserved@C}%
    \if@xs@empty
        \expandafter\@secondoftwo
--- 534,540 ----
    \expandafter\expandafter\expandafter\@xs@cutafteroccur\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@C\expandafter}\expandafter{\@xs@reserved@A}{#2}%
    \def\@xs@reserved@A{#4}%
    \expandafter\expandafter\expandafter\@xs@cutafteroccur\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@C\expandafter}\expandafter{\@xs@reserved@A}{#1}%
!   \global\let\groupID\@empty
    \expandafter\@xs@testempty\expandafter{\@xs@reserved@C}%
    \if@xs@empty
        \expandafter\@secondoftwo
***************
*** 682,688 ****
        \expandafter
    \endgroup
    \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@E}{#6}%
!   \let\groupID\@empty}

  \def\exploregroups{\let\@xs@exploregroups\relax}
  \def\noexploregroups{\def\@xs@exploregroups{\let\@xs@toks0\relax}}
--- 682,688 ----
        \expandafter
    \endgroup
    \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@E}{#6}%
!   \global\let\groupID\@empty}

  \def\exploregroups{\let\@xs@exploregroups\relax}
  \def\noexploregroups{\def\@xs@exploregroups{\let\@xs@toks0\relax}}
***************
*** 694,700 ****
  \@xs@newmacro\StrSubstitute{0}{3}{1}{%
    \def\@xs@reserved@D{#2}\let\@xs@reserved@C\@empty\def\@xs@reserved@E{#3}%
    \def\@xs@argument@C{#3}\def\@xs@argument@D{#4}%
!   \decimalpart\z@\integerpart\z@\def\groupID{0}\let\@xs@nestlevel\z@
    \def\@xs@atendofgroup{%
        \expandafter\endgroup
        \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\expandafter{\@xs@reserved@C}}%
--- 694,700 ----
  \@xs@newmacro\StrSubstitute{0}{3}{1}{%
    \def\@xs@reserved@D{#2}\let\@xs@reserved@C\@empty\def\@xs@reserved@E{#3}%
    \def\@xs@argument@C{#3}\def\@xs@argument@D{#4}%
!   \decimalpart\z@\integerpart\z@\gdef\groupID{0}\let\@xs@nestlevel\z@
    \def\@xs@atendofgroup{%
        \expandafter\endgroup
        \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\expandafter{\@xs@reserved@C}}%
***************
*** 729,735 ****
    \def\@xs@reserved@C{#1}%
    \decimalpart\z@
    \let\@xs@nestlevel\z@
!   \def\groupID{0}%
    \let\@xs@atbegingroup\relax
    \def\@xs@atendofgroup{\endgroup\@xs@read@reserved@C}%
    \let\@xs@atnextsyntaxunit\relax
--- 729,735 ----
    \def\@xs@reserved@C{#1}%
    \decimalpart\z@
    \let\@xs@nestlevel\z@
!   \gdef\groupID{0}%
    \let\@xs@atbegingroup\relax
    \def\@xs@atendofgroup{\endgroup\@xs@read@reserved@C}%
    \let\@xs@atnextsyntaxunit\relax
***************
*** 749,755 ****
  \def\@xs@manage@groupID{%
    \begingroup\def\@xs@reserved@A{0}%
    \ifx\@xs@reserved@A\groupID% si on arrive du groupe de niveau 0
!       \endgroup\edef\groupID{\number\integerpart}% on met simplement le niveau
    \else
        \endgroup\expandafter\@xs@addtomacro\expandafter\groupID\expandafter{\expandafter,\number\integerpart}%
    \fi}
--- 749,755 ----
  \def\@xs@manage@groupID{%
    \begingroup\def\@xs@reserved@A{0}%
    \ifx\@xs@reserved@A\groupID% si on arrive du groupe de niveau 0
!       \endgroup\xdef\groupID{\number\integerpart}% on met simplement le niveau
    \else
        \endgroup\expandafter\@xs@addtomacro\expandafter\groupID\expandafter{\expandafter,\number\integerpart}%
    \fi}
***************
*** 760,768 ****
  % Cette macro interne coupe la chaine #2 apr\`es l'unit\'e syntaxique n°#1
  % Le d\'ebut est assign\'e dans \@xs@reserved@B et la fin dans \@xs@reserved@C
  \def\@xs@StrSplit@i#1#2{%
!   \def\@xs@reserved@D{#1}\def\@xs@reserved@C{#2}\let\@xs@reserved@B\@empty\let\groupID\@empty
    \ifnum#1>\z@
!       \decimalpart\z@\integerpart\z@\def\groupID{0}\let\@xs@nestlevel\z@
        \def\@xs@atendofgroup{%
            \expandafter\endgroup
            \expandafter\@xs@addtomacro\expandafter\@xs@reserved@B\expandafter{\expandafter{\@xs@reserved@B}}%
--- 760,768 ----
  % Cette macro interne coupe la chaine #2 apr\`es l'unit\'e syntaxique n°#1
  % Le d\'ebut est assign\'e dans \@xs@reserved@B et la fin dans \@xs@reserved@C
  \def\@xs@StrSplit@i#1#2{%
!   \def\@xs@reserved@D{#1}\def\@xs@reserved@C{#2}\let\@xs@reserved@B\@empty\global\let\groupID\@empty
    \ifnum#1>\z@
!       \decimalpart\z@\integerpart\z@\gdef\groupID{0}\let\@xs@nestlevel\z@
        \def\@xs@atendofgroup{%
            \expandafter\endgroup
            \expandafter\@xs@addtomacro\expandafter\@xs@reserved@B\expandafter{\expandafter{\@xs@reserved@B}}%
***************
*** 794,800 ****
        \expandafter\expandafter\expandafter\@xs@StrSplit@i\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@C\expandafter}\expandafter{\@xs@reserved@B}%
    \expandafter\endgroup
    \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#4}%
!   \let\groupID\@empty}

  % supprime #2 unit\'es syntaxiques \`a gauche dans la chaine #1
  \@xs@newmacro\StrGobbleLeft{}{2}{1}{%
--- 794,800 ----
        \expandafter\expandafter\expandafter\@xs@StrSplit@i\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@C\expandafter}\expandafter{\@xs@reserved@B}%
    \expandafter\endgroup
    \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#4}%
!   \global\let\groupID\@empty}

  % supprime #2 unit\'es syntaxiques \`a gauche dans la chaine #1
  \@xs@newmacro\StrGobbleLeft{}{2}{1}{%
***************
*** 826,832 ****
    \let\@xs@reserved@B\@empty
    \def\@xs@reserved@C{#1}\def\@xs@reserved@D{#2}%
    \ifnum#2>\z@
!       \def\groupID{0}\let\@xs@nestlevel\z@\integerpart\z@\decimalpart\z@
        \let\@xs@atbegingroup\relax
        \def\@xs@atendofgroup{\endgroup\@xs@read@reserved@C}%
        \def\@xs@atnextsyntaxunit{%
--- 826,832 ----
    \let\@xs@reserved@B\@empty
    \def\@xs@reserved@C{#1}\def\@xs@reserved@D{#2}%
    \ifnum#2>\z@
!       \gdef\groupID{0}\let\@xs@nestlevel\z@\integerpart\z@\decimalpart\z@
        \let\@xs@atbegingroup\relax
        \def\@xs@atendofgroup{\endgroup\@xs@read@reserved@C}%
        \def\@xs@atnextsyntaxunit{%
***************
*** 839,845 ****
        \@xs@read@reserved@C
    \fi
    \expandafter\@xs@testempty\expandafter{\@xs@reserved@B}%
!   \if@xs@empty\let\groupID\@empty\fi
    \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@B}{#3}}

  % Combien de fois compte t-on #2 dans #1 ?
--- 839,845 ----
        \@xs@read@reserved@C
    \fi
    \expandafter\@xs@testempty\expandafter{\@xs@reserved@B}%
!   \if@xs@empty\global\let\groupID\@empty\fi
    \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@B}{#3}}

  % Combien de fois compte t-on #2 dans #1 ?
***************
*** 849,855 ****
    \if@xs@empty
        \@xs@ReturnResult{0}{#3}%
    \else
!       \decimalpart\z@\integerpart\z@\def\groupID{0}\let\@xs@nestlevel\z@
        \def\@xs@atendofgroup{%
            \expandafter\endgroup
            \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\expandafter{\@xs@reserved@C}}%
--- 849,855 ----
    \if@xs@empty
        \@xs@ReturnResult{0}{#3}%
    \else
!       \decimalpart\z@\integerpart\z@\gdef\groupID{0}\let\@xs@nestlevel\z@
        \def\@xs@atendofgroup{%
            \expandafter\endgroup
            \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\expandafter{\@xs@reserved@C}}%
***************
*** 870,876 ****
        \expandafter\@xs@StrLen\expandafter{\@xs@reserved@C}[\@xs@reserved@C]%
        \expandafter\@xs@ReturnResult\expandafter{\number\numexpr\@xs@reserved@C+1}{#4}%
    \fi
!   \let\groupID\@xs@reserved@E}

  \def\comparestrict{\let\@xs@comparecoeff\@ne}
  \def\comparenormal{\let\@xs@comparecoeff\z@}
--- 870,876 ----
        \expandafter\@xs@StrLen\expandafter{\@xs@reserved@C}[\@xs@reserved@C]%
        \expandafter\@xs@ReturnResult\expandafter{\number\numexpr\@xs@reserved@C+1}{#4}%
    \fi
!   \global\let\groupID\@xs@reserved@E}

  \def\comparestrict{\let\@xs@comparecoeff\@ne}
  \def\comparenormal{\let\@xs@comparecoeff\z@}
***************
*** 975,981 ****
        \@xs@expandingroups
        \ifnum#1>\z@
            \integerpart#1\relax
!           \decimalpart\z@\def\groupID{0}\let\@xs@nestlevel\z@
            \def\@xs@atendofgroup{%
                \expandafter\endgroup
                \expandafter\@xs@addtomacro\expandafter\@xs@reserved@B\expandafter{\expandafter{\@xs@reserved@B}}%
--- 975,981 ----
        \@xs@expandingroups
        \ifnum#1>\z@
            \integerpart#1\relax
!           \decimalpart\z@\gdef\groupID{0}\let\@xs@nestlevel\z@
            \def\@xs@atendofgroup{%
                \expandafter\endgroup
                \expandafter\@xs@addtomacro\expandafter\@xs@reserved@B\expandafter{\expandafter{\@xs@reserved@B}}%
***************
*** 993,999 ****
        \global\let\@xs@reserved@B\@xs@reserved@B
    \endgroup
    \let#3\@xs@reserved@B
!   \let\groupID\@empty}
  \def\@xs@StrExpand@i#1{%
    \ifnum#1>\z@
        \let\@xs@reserved@B\@empty
--- 993,999 ----
        \global\let\@xs@reserved@B\@xs@reserved@B
    \endgroup
    \let#3\@xs@reserved@B
!   \global\let\groupID\@empty}
  \def\@xs@StrExpand@i#1{%
    \ifnum#1>\z@
        \let\@xs@reserved@B\@empty
share|improve this answer
    
thanks! The table is part of a 1-page document, so I wasn't fussy about placement :) –  Mau Nov 29 '12 at 11:03
    
I've preached many times on this site about avoiding {\def\xyz{something}\global\let\xyz\xyz}, this is one of the reasons why this is dangerous. I added the "xstring" tag to the question, so maybe the author can be notified. –  egreg Nov 29 '12 at 11:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.