6

I have a latex document which in the main part lists a number of "tasks" (for students to solve); to each task belongs a "script", however, all scripts are supposed to be printed in an appendix at the end of the document. For this purpose, the environment "skript" is built to copy its content to a file and re-insert it at the end of the LaTeX run. Tasks and scripts are numbered, and the numbers should correspond to each other.

And here is the problem: TeX seems to expand the script number only after re-inserting the scripts at the end of the document. However, at that time, the task counter is obviously at its maximum value leading to all scripts getting the same number.

Is there a way to get TeX to expand the task counter before storing it to the external file?

A minimal example is the following (where count is the task number):

\documentclass{article}
\usepackage{skripts}
\newcounter{count}

\begin{document}
    \refstepcounter{count}
    Here comes task \thecount:
    \begin{skript}
        \thecount
    \end{skript}

    \refstepcounter{count}
    Here comes task \thecount:
    \begin{skript}
        \thecount
    \end{skript}

    \refstepcounter{count}
    Here comes task \thecount:
    \begin{skript}
        \thecount
    \end{skript}

    \refstepcounter{count}
    Here comes task \thecount:
    \begin{skript}
        \thecount
    \end{skript}

    Now insert the scripts corresponding to the tasks at the document's end:

    \includeSkripts
\end{document}

Which outputs:

enter image description here

Obviously, \thecount, when used inside the "skript" environment has been evaluated only after the counter has been set to its highest value.

The package "skripts" (also in a minimal version) looks as follows:

\ProvidesPackage{skripts}[2009/11/03 v0.1 Styledefinitionen]

\usepackage{verbatim}

\newenvironment{ex@skripts}[1]{#1}{}

\newwrite\verbatim@outSkr % Define file. 
\immediate\openout\verbatim@outSkr=\jobname.skr  % Open file for writing. 

\def\skript{
\@bsphack
\let\do\@makeother\dospecials
\catcode`\^^M\active
\def\verbatim@processline{%
\immediate\write\verbatim@outSkr{\the\verbatim@line}}%
\immediate\write\verbatim@outSkr{\string\begin{ex@skripts}{Script}}
\verbatim@start}

\def\endskript{%
\immediate\write\verbatim@outSkr{\string\end{ex@skripts}}
\@esphack}

\newcommand*{\includeSkripts}{%
\immediate\closeout\verbatim@outSkr    % Close file. 
\InputIfFileExists{\jobname.skr}{}{}
\newwrite\verbatim@outSkr % Datei wird definiert 
\immediate\openout\verbatim@outSkr=\jobname.skr  % Open file for writing. 
}

Now, I am aware that according to this minimal example, there are several solutions to my problem (such as giving "count" as a parameter to the "skript" environment). However, in my actual, more complex context, it is important to solve the problem in the described setting without any structural changes to the environment.

EDIT: I already tried this quite crazy hack:

\romannumeral-`X\foo

which I got from here.

2 Answers2

4

One way to achieve this, is to write the content of the counter value explicitly to the file via \string, before the verbatim stuff starts.

\immediate\write\verbatim@outSkr{%
  \string\setcounter{count}{\number\value{count}}% 
}%

Writing \thecount verbatim into the skript file is useless for it will always use the last counter value (4 in this case), not the logical one which belongs to the actual script number.


\documentclass{article}
\usepackage{skripts}
\newcounter{count}

\begin{document}
    \refstepcounter{count}
    Here comes task \thecount:
    \begin{skript}
        \thecount
    \end{skript}

    \refstepcounter{count}
    Here comes task \thecount:
    \begin{skript}
        \thecount
    \end{skript}

    \refstepcounter{count}
    Here comes task \thecount:
    \begin{skript}
        \thecount
    \end{skript}

    \refstepcounter{count}
    Here comes task \thecount:
    \begin{skript}
        \thecount
    \end{skript}

    Now insert the scripts corresponding to the tasks at the document's end:

    \includeSkripts
\end{document}

\ProvidesPackage{skripts}[2009/11/03 v0.1 Styledefinitionen]

\usepackage{verbatim}

\newenvironment{ex@skripts}[1]{#1}{}

\newwrite\verbatim@outSkr % Datei wird definiert
\immediate\openout\verbatim@outSkr=\jobname.skr % Datei wrid zum
Schreiben geöffnet

\def\skript{% 
\immediate\write\verbatim@outSkr{%
\string\setcounter{count}{\number\value{count}}% 
}% 
\@bsphack
\let\do\@makeother\dospecials \catcode`\^^M\active
\def\verbatim@processline{%
\immediate\write\verbatim@outSkr{\the\verbatim@line}}%
\immediate\write\verbatim@outSkr{\string\begin{ex@skripts}{Script}}
\verbatim@start}

\def\endskript{%
\immediate\write\verbatim@outSkr{\string\end{ex@skripts}} \@esphack}

\newcommand*{\includeSkripts}{% 
\immediate\closeout\verbatim@outSkr %schließt die Datei
 \InputIfFileExists{\jobname.skr}{}{}
% No good idea!!!!!!
%\newwrite\verbatim@outSkr % Datei wird definiert
%\immediate\openout\verbatim@outSkr=\jobname.skr % Datei wrid zum Schreiben geöffnet 
}
2

You could have more counters to take care of, so I define a macro \skriptcounters that accepts a list of counter names; such a list is used to write a second argument to ex@Skript of the form \setcounter{<name>}{<value>}, where the value has been computed when the skript environment starts.

Just for showing how the thing works I used also the section counter (although it's not really good to change the value mid document; it's just by way of example).

\documentclass{article}

%\usepackage{skripts} % the code is in the document
\usepackage{verbatim}

\makeatletter
% here starts the code of skripts.sty
\newenvironment{ex@skripts}[2]{#2#1}{\par}

\newwrite\verbatim@outSkr % Datei wird definiert 
\immediate\openout\verbatim@outSkr=\jobname.skr  % Datei wrid zum Schreiben geöffnet 

\newcommand{\skriptcounters}[1]{%
  \gdef\skript@counters{#1}%
}
\skriptcounters{}% initialize

\newenvironment{skript}
 {%
  \@bsphack
  \let\do\@makeother\dospecials
  \catcode`\^^M\active
  \def\verbatim@processline{%
    \immediate\write\verbatim@outSkr{\the\verbatim@line}%
  }%
  \toks@={}%
  \@for\next:=\skript@counters\do{%
    \edef\skript@temp{\the\toks@\string\setcounter{\next}{\the\value{\next}}}%
    \toks@=\expandafter{\skript@temp}%
  }
  \immediate\write\verbatim@outSkr{%
    \string\begin{ex@skripts}{Script}{\the\toks@}%
  }
  \verbatim@start
 }
 {%
  \immediate\write\verbatim@outSkr{\string\end{ex@skripts}}%
  \@esphack
 }

\newcommand*{\includeSkripts}{%
  \immediate\closeout\verbatim@outSkr    % schließt die Datei 
  \InputIfFileExists{\jobname.skr}{}{}
%  \immediate\openout\verbatim@outSkr=\jobname.skr  % Datei wrid zum Schreiben geöffnet 
}
% end of code for skripts.sty (uncomment the \immediate line above)
\makeatother

\newcounter{count}
\skriptcounters{count,section}

\begin{document}

\section{Title}

\refstepcounter{count}
Here comes task \thecount:
\begin{skript}
  \thecount\ in Section \thesection
\end{skript}

\refstepcounter{count}
Here comes task \thecount:
\begin{skript}
  \thecount\ in Section \thesection
\end{skript}

\section{Another}

\refstepcounter{count}
Here comes task \thecount:
\begin{skript}
  \thecount\ in Section \thesection
\end{skript}

\refstepcounter{count}
Here comes task \thecount:
\begin{skript}
  \thecount\ in Section \thesection
\end{skript}

Now insert the scripts corresponding to the tasks at the document's end:

\section{Scripts}

\includeSkripts

\end{document}

The last \immediate has been commented out just for checking the contents of the skript environment.

Notice that the \end{skript} instruction should not be indented, or the environment will receive a blank line.

enter image description here

Here's the contents of the .skr file:

\begin{ex@skripts}{Script}{\setcounter{count}{1}\setcounter{section}{1}}
  \thecount\ in Section \thesection
\end{ex@skripts}
\begin{ex@skripts}{Script}{\setcounter{count}{2}\setcounter{section}{1}}
  \thecount\ in Section \thesection
\end{ex@skripts}
\begin{ex@skripts}{Script}{\setcounter{count}{3}\setcounter{section}{2}}
  \thecount\ in Section \thesection
\end{ex@skripts}
\begin{ex@skripts}{Script}{\setcounter{count}{4}\setcounter{section}{2}}
  \thecount\ in Section \thesection
\end{ex@skripts}
egreg
  • 1,121,712
  • Cool stuff! I will check that out, too. It may well be more suitable to my real scenario than SoundsOfSilence's solution. – lukas.coenig Mar 16 '15 at 17:48
  • @lukas.coenig I might try making it better with some aliasing in order not to clobber outside values. – egreg Mar 16 '15 at 17:52
  • @lukas.coenig: If you would have posted your real scenario another solution could have been provided ;-) –  Mar 16 '15 at 20:59
  • @SoundsOfSilence: Yes, but then people would have said: Are you crazy? Post an MWE! :-) But I am considering posting a more complex version as I'm afraid (not sure yet, however - it's unfortunately a little confusing) that both solution might not work for me... – lukas.coenig Mar 17 '15 at 06:07
  • @egreg: How would that go? (Just a verbal hint would be nice, so I can estimate how it would affect the applicability to my scenario.) – lukas.coenig Mar 17 '15 at 06:10
  • @lukas.coenig It's not so easy, actually, so maybe some more words on your scenario could help. – egreg Mar 17 '15 at 09:47
  • Ok, I will get back to you if it turns out that both your solutions don't work. (I'm just not sure yet how to create a less minimal example...) – lukas.coenig Mar 17 '15 at 19:15