Der folgende Code stellt eine Möglichkeit dar, neue (weil durch eine Umgebung gruppierte) Boxregister durch ihre Nummern, nicht durch \newsavebox etc anzusprechen. Vermutlich wiedermal "holprig" formuliert, aber immerhin. Besonders \setcounter{myregisterstart}{20} und \setcounter{myregisterstop}{23} wären durch Parameterübergabe besser zu lösen.

\documentclass[a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[ngerman]{babel}
\newcounter{myregisterstart} %
\newcounter{myregisterstop} %
\newenvironment{myregister} %
%BEGIN Bereich %
{%
\setcounter{myregisterstart}{20}
\setcounter{myregisterstop}{23}
\loop\ifnum\themyregisterstart<\themyregisterstop \relax%
\expandafter\setbox\themyregisterstart=\hbox{box\themyregisterstart \
Innerhalb der Umgebung angefordert }%
\stepcounter{myregisterstart} \relax \repeat %
}%
{%END Bereich
}% 
\begin{document}
\section{Vor der Umgebung}
\copy20
\copy21
\copy22
\begin{myregister}
\section{Erster Aufruf der Umgebung myregister} %
\setbox20=\hbox{box20 Innerhalb der Umgebung verändert}
\copy20
\copy21
\copy22
\end{myregister}
\section{Nach der Umgebung}
Abruf von box20 bis box22
\copy20
\copy21
\copy22
\begin{myregister}
\section{Zweiter Aufruf der Umgebung myregister} %
\setcounter{myregisterstart}{20}
\setcounter{myregisterstop}{23}
\loop\ifnum\themyregisterstart<\themyregisterstop \relax
\expandafter\setbox\themyregisterstart=\hbox{box\themyregisterstart \ Innerhalb der
Umgebung verändert} \stepcounter{myregisterstart} \relax\repeat
\copy20
\copy21
\copy22
\end{myregister}
\section{Nach der veränderten Umgebung}
Abruf von box20 bis box22
\copy20
\copy21
\copy22
\end{document}

gefragt 26 Jun '13, 01:47

ctansearch's gravatar image

ctansearch
(ausgesetzt)
Akzeptiert-Rate: 18%

bearbeitet 26 Jun '13, 10:54

cgnieder's gravatar image

cgnieder
22.1k253463

2

und was ist jetzt deine Frage??

(26 Jun '13, 08:17) Herbert

@ctansearch Du kannst Inline-Code darstellen, indem Du ihn zwischen Backticks schreibst `\code@stuff `, siehe die Markdown Syntax

(26 Jun '13, 10:59) cgnieder

Wenn Du Register nur lokal verwenden willst, solltest Du trotzdem nicht bereits belegte Register dafür verwenden. Jedenfalls gilt das, wenn Du Seiteneffekte während der Abarbeitung Deines Codes nicht ausschließen kannst. Solche Seiteneffekte können beispielsweise dann auftreten, wenn man fremde Makros innerhalb der entsprechenden Gruppe verwendet oder Ausgaben produziert, die einen Aufruf der asynchronen Ausgaberoutine von LaTeX nach sich ziehen können.

Der Grund für dieses Verbot ist einfach: Es ist nicht ausgeschlossen, dass die fremden Macros oder die Ausgaberoutine die Boxregister unverändert benötigen oder selbst verändern. Dies kann sogar global erfolgen, da einige Box-Primitiven auch \global erlauben.

Benötigt man einige wenige Register nur kurzzeitig, und will deshalb keine Register global belegen und damit dem Register-Pool entziehen, kann man die speziell dafür vom LaTeX-Kern vorgesehenen Register verwenden. Bei den Boxen ist das in erster Linie \@tempboxa. Aber auch in diesem Fall sollte man daran denken, dass der Aufruf eines Makros dieses Register jederzeit ändern kann. Man sollte es also wirklich nur lokal verwenden und nach einem Fremdmakro nicht mehr auf seinen Inhalt vertrauen. Im Idealfall hält man eigene Änderungen an \@tempboxa außerdem lokal.

Darüber hinaus gibt es bei einigen Registern noch eine Art stillschweigenden Vorrat an lokal verwendbaren Registern. Bei den Boxen sind das die Boxen 0 bis 9, die sozusagen kurzzeitig verwendet werden können.

Nach einer stillschweigenden Konvention sind die geraden Boxen 0, 2, 4, 6, und 8 dabei für lokale Änderungen vorgesehen. Man kann also beispielsweise mal eben Box 0 mit beliebigem Inhalt füllen, dann die Box manipulieren und direkt ausgeben. Zwischen dem Füllen der Box und der Ausgabe der Box sollten aber keine Aktionen stattfinden, die nicht unter der Kontrolle dessen stehen, der die Box füllt. Jede andere Anweisung darf die Box nämlich ebenfalls verwenden, kann sie also insbesondere auch löschen over verändern!

Die ungeraden Boxen 1, 3, 5, 7 und 9 sind für globale Änderungen vorgesehen. Hier darf man also nicht einmal beim Füllen der Box beliebigen Code verwenden, weil dieser diese Boxen selbst (global) verändern könnte.

Andere Boxen, die man nicht mit \newbox angefordert hat, darf man auf keinen Fall in einem Kontext verändern, in dem andere Makros oder die Ausgaberoutine zum Zuge kommen könnten. Wurden für diese nämlich die entsprechende Register mit \newbox oder \newsavebox reserviert, wären sie zum Einen durchaus berechtigt die entsprechende Register lokal oder global zu ändern und haben des Weiteren auch ein Anrecht auf die Unversehrtheit der Registerinhalte. Man würde also fremden Code kompromittieren. So etwas gehört sich nicht nur nicht, es verbietet sich von vorn herein!

Bei den Boxen kommt hinzu, dass diverse davon für inserts (siehe \newinsert) benötigt werden. Diese werden von LaTeX beispielsweise für Fußnoten verwendet und global vom Ende des normalen Registerpools belegt. Ebenso werden Boxregister für Gleitobjekte benötigt, die jedoch auf normalem Wege reserviert werden. Auch diese werden jedoch global belegt. Unerlaubte Verwendung fremder Boxregister kann also sehr schnell unabsehbare Nebenwirkungen haben!

Will man trotzdem einige Register lokal verwenden, so muss man Sorge dafür tragen, dass man diese Register aus dem Pool bezieht und kann sie auch nur dann wieder freigeben, wenn zwischenzeitlich nicht weitere Register belegt wurden. Dazu eine Beispielumgebung für LaTeX:

\makeatletter% Diese Anweisung wird nur benötigt, wenn der Code _nicht_ in einem Paket
             % oder einer Klasse verwendet wird.
\newcount\@firstlocalbox
\newcount\@lastlocalbox
\newenvironment{localboxes}[1]{% Der Parameter gibt die Anzahl der zu reservierenden
                               % Register an
  % Wir belegen die Register in einer Schleife, 
  % damit das auch mit etex.sty noch funktioniert!
  \@tempcnta=\z@
  \@firstlocalbox=\count14 % Hack: Verwendung von internem LaTeX-Wissen!
  \@whilenum\@tempcnta<#1 \do{%
    \advance\@tempcnta by\@ne
    \expandafter\newbox\csname localbox\romannumeral\the\@tempcnta\endcsname
  }%
  \@lastlocalbox=\count14 % Hack: Verwendung von internem LaTeX-Wissen!
}{%
  \ifnum \@lastlocalbox=\count14
    % Zwischenzeitlich hat niemand weitere Box-Register belegt,
    % also können wir die Register wieder ``freigeben''
    \global\count14=\@lastlocalbox
  \else
    \@latexerr{cannot release local box registers}\@ehc
  \fi
}
\makeatother% Diese Anweisung darf nur verwendet werden, wenn der Code _nicht_ 
            % in einem Paket oder einer Klasse verwendet wird.

Innerhalb der Umgebung sind die lokalen Boxregister dann unter den Namen \localboxi, \localboxii, \localboxiii, \localboxiv etc. ansprechbar.

Die Umgebung kann theoretisch auch geschachtelt verwendet werden. Falls nicht mehr genügend Register zur Verfügung stehen, wird derzeit ggf. mehrfach ein Fehler ausgegeben.

Einen noch besseren Ansatz bietet das Paket localloc. Dieses arbeitet aber nicht mit eTeX, also auch nicht mit dem etex-Paket zusammen.

Als Merksatz gilt: Verwende keine Register, die Du nicht selbst mit der entsprechenden Anweisung des verwendeten Formats reserviert hast!

Der Merksatz gilt nicht nur für LaTeX, sondern für alle Formate. Bei LaTeX und plainTeX heißt die Low-Level-Anweisung zur Reservierung von Boxregistern \newbox (diese wurde in obigem Beispielcode deshalb auch verwendet). LaTeX stellt darüber hinaus noch die Anwender-Anweisung \newsavebox bereit, die ihrerseits auf \newbox basiert und in der Regel vorzuziehen ist, weil sie mit denselben Sicherheitsmechanismen wie \newcommand ausgestattet ist.

Die Pakete localloc und etex basieren hingegen auf internem Wissen aus dem LaTeX-Kern über die Implementierung der \new…-Anweisungen zur Reservierung von Registern. Da sie in unterschiedlicher Weise an denselben Stellen der Implementierung eingreifen, sind sie leider inkompatibel zueinander und können nicht gleichzeitig verwendet werden!

Obiger Beispielcode für die lokale Reservierung von Boxregistern ist ebenfalls ein Teilverstoß gegen den Merksatz, da er zusätzlich internes Wissen über die Implementierung von \newbox verwendet. Er ist insbesondere nicht kompatibel mit localloc dafür aber mit etex. Der eigentliche Teilverstoß liegt aber nicht in der Reservierung von Boxregistern, die sauber per \newbox erfolgt. Der Teilverstoß liegt darin, dass diese mit Hilfe von internem Wissen wieder freigegeben werden. Genau daraus resultiert auch die Inkompatibilität mit localloc.

Die aufgezeigten Inkompatibilitäten sind nur ein sehr kleiner Ausschnitt aus den Gefahren, die aus Verstößen gegen den Merksatz resultieren.

Permanenter link

beantwortet 26 Jun '13, 09:23

saputello's gravatar image

saputello
11.1k174365
Akzeptiert-Rate: 51%

bearbeitet 27 Jun '13, 08:52

+1 Tolle Antwort. Schade, dass ich nur einmal stimme kann...

(26 Jun '13, 10:36) cgnieder

@saputello Sehr hilfreiche Antwort. Danke "Man würde also fremden Code kompromittieren." Genau das Problem versuch(t)e ich zu lösen, bzw zu vermeiden.

(26 Jun '13, 12:44) ctansearch

Tolle Antwort.

(26 Jun '13, 17:13) Marco_D

@saputello Falls Du Dich erinnerst, war der Ausgangspunkt und die Kernfrage, ob und wie man Boxen reservieren kann. Ich habe also das Problem aufgezeigt und suche nach der Lösung. Der Inhalt des "Merksatz" war der Ausgangspunkt und das Ziel der Fragen, die ich dazu gestellt habe.

(26 Jun '13, 20:00) ctansearch

@ctansearch: Die Frage, wie man Register reserviert, hatte ich eigentlich schon längst beantwortet: mit \newbox oder \newsavebox.

(27 Jun '13, 08:37) saputello

@Clemens: Du kannst mir ja Punkte dafür schenken. ;-) Eigentlich überlege ich, ob ich die Klarstellungen am Ende nicht wieder entferne, denn eigentlich war die Antwort ohne diese eher prägnanter und damit klarer …

(27 Jun '13, 10:23) saputello

@saputello Tut mir leid, im Moment drehen wir uns im Kreis.

Ich möchte wissen, wie man explizit und über die Nummer einer Box per \setboxxx diese für die Laufzeit eines Paketes reservieren kann, geschützt hält und wieder freigibt, nichts anderes.

(27 Jun '13, 10:59) ctansearch
2

@ctansearch: solange alle Pakete \newsavebox verwenden und mit symbolischen Boxnamen arbeiten, ist der Inhalt geschützt. Nicht mehr und nicht weniger. Verwendest du explizit die Boxregisternummern kannst du nur durch Gruppierung verhindern, dass du einen vorhandenen Inhalt überschreibst, wohingegen sowohl TeX als auch andere Pakete deinen Inhalt überschreiben können.

(27 Jun '13, 11:05) Herbert

@ctansearch: Wir drehen uns nur im Kreis, wenn Du nicht verstehst, dass das was Du willst technisch nicht möglich ist, sondern nur durch Konventionen erreicht wird, gegen die Du aber bisher immer wieder verstößt.

(27 Jun '13, 12:54) saputello
Ergebnis 5 von 9 show 4 more comments

Vielleicht meinst du so etwas:

\documentclass{article}
\parindent=0pt
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{multido}

\newcount\meineBoxen
\def\newMeineBox{%
  \expandafter\newsavebox\csname meineBox\the\meineBoxen\endcsname%
  \global\advance\meineBoxen by 1}    
\def\saveMeineBox#1#2{%
   \expandafter\savebox\expandafter{\csname meineBox#1\endcsname}{#2}}      
\def\useMeineBox#1{% 
   \expandafter\usebox\expandafter{\csname meineBox#1\endcsname}}

\begin{document}
\Multido{\i=0+1}{20}{%
  \newMeineBox%
  \saveMeineBox{\i}{Box \i}%
}

Überschreibe Box7 ...
\saveMeineBox7{Das ist Box sieben}%

\multido{\i=0+1}{20}{\useMeineBox{\i}\\}%

\end{document}

alt text

TeX kümmert sich dann um die Belegeung (aus dem Logfile)

\meineBox0=\box26
\meineBox1=\box27
\meineBox2=\box28
\meineBox3=\box29
\meineBox4=\box30
\meineBox5=\box31
\meineBox6=\box32
\meineBox7=\box33
\meineBox8=\box34
\meineBox9=\box35
\meineBox10=\box36
\meineBox11=\box37
\meineBox12=\box38
\meineBox13=\box39
\meineBox14=\box40
\meineBox15=\box41
\meineBox16=\box42
\meineBox17=\box43
\meineBox18=\box44
\meineBox19=\box45
Permanenter link

beantwortet 27 Jun '13, 12:29

Herbert's gravatar image

Herbert
5.1k34
Akzeptiert-Rate: 31%

bearbeitet 27 Jun '13, 12:30

So etwas ähnliches habe ich bereits in meiner Antwort zu http://texwelt.de/wissen/fragen/337/kann-man-in-texlatex-register-reservieren-bzw-blockieren gezeigt. BTW: Ich finde es recht unglücklich wie die offenbar wohl doch letztlich eine Frage über mehrere Fragen verteilt ist.

(27 Jun '13, 12:57) saputello
Deine Antwort
Vorschau umschalten

Folgen dieser Frage

Per E-Mail:

Wenn sie sich anmelden, kommen Sie für alle Updates hier in Frage

Per RSS:

Antworten

Antworten und Kommentare

Markdown-Grundlagen

  • *kursiv* oder _kursiv_
  • **Fett** oder __Fett__
  • Link:[Text](http://url.com/ "Titel")
  • Bild?![alt Text](/path/img.jpg "Titel")
  • nummerierte Liste: 1. Foo 2. Bar
  • zum Hinzufügen ein Zeilenumbruchs fügen Sie einfach zwei Leerzeichen an die Stelle an der die neue Linie sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Frage-Themen:

×18
×6

gestellte Frage: 26 Jun '13, 01:47

Frage wurde gesehen: 11,588 Mal

zuletzt geändert: 27 Jun '13, 13:00