Hallo zusammmen,

wir wollen eine Klasse namens commands erstellen und darin Befehle definieren. Sämtliche anderen Befehle auch die aus den genutzten Packages sollen (in dem Dokument in dem man commands nutzt) verboten sein und einen Error hervorrufen.

Ist dies möglich?

VG und vielen Dank

gefragt 27 Feb, 15:10

Timres's gravatar image

Timres
411
Akzeptiert: 0%

bearbeitet 28 Feb, 02:35

Ijon%20Tichy's gravatar image

Ijon Tichy
8.7k31022

1

Klingt schwierig. Denn um die anderen Befehle nicht nutzbar zu machen, müsstest Du sie wohl umdefinieren. Aber dafür musst Du sie erst mal alle beim Namen kennen. Ferner scheint es mir, als mache Struktur von TeX als Makrosprache es fast unmöglich, bestimmte Dinge umzudefinieren, sodass sie nicht mehr nutzbar sind, wenn Du gleichzeitig noch eine gewisse Gesamtfunktionalität erhalten möchtest. Wenn Du zum Beispiel möchtest, dass die Nutzung bestimmter TeX-Primitive verboten wird, dann würdest Du damit auch alle anderen Makros verbieten, die darauf aufbauen

(27 Feb, 15:44) moewe

Dazu muss man ein neues Format bauen und am Ende, bevor man \dump aufruft, die \def-Primitiven überschreiben, damit man keine neuen Befehle definieren kann. Sinnvoll ist das natürlich absolut nicht.

(27 Feb, 18:54) Henri
1

Wenn du eigene Befehle definierst und sämtlichen LaTeX-Kram verbietest, dann nutzt du LaTeX nicht. Dann kannst du dein Format TimTeX nennen. Ob dies sinnvoll sein wird, musst du entscheiden.

(02 Mär, 03:22) Johannes

Ich fürchte, diese Antwort wird dir nicht gefallen …

Kurzerklärung: Warum es nicht geht

Die Pakete werden grundsätzlich dadurch genutzt, dass ihre Makros/Befehle genutzt werden. Wenn man also die Nutzung von Befehlen für Anwender verhindern will, verhindert man die Nutzung gleichzeitig für die Klasse. So etwas wie Scopes existieren bei TeX nicht wirklich. Man kann also nicht für eine Benutzerklasse »Anwender« Befehlen eine andere Bedeutung (nämlich Fehlermeldung) geben als für eine andere Benutzerklasse »Dokumentklasse« (nämlich Ausführung der Originalbedeutung).

Beispiel:

Angenommen, ihr wollt verhindern, dass der Anwender die Anweisungen \sffamily und \bfseries aus dem LaTeX-Kern verwendet. Dann müsstet Ihr diese Anweisung umdefinieren:

Öffne in Overleaf
\renewcommand*{\sffamily}{%
  \ClassError{commands}{\string\sffamily\space not allowed}{Only commands' commands are allowed}%
}
\renewcommand*{\bfseries}{%
  \ClassError{commands}{\string\bfseries\space not allowed}{Only commands' commands are allowed}%
}

Wenn nun aber beispielsweise eure Klasse einen Befehl definiert:

Öffne in Overleaf
\newcommand*{\SansSerifAndBold}{\sffamily\bfseries}

so wird auch dieser Befehl die beiden Fehlermeldungen ausgeben. Da TeX eine Makrosprache ist, ist das auch unabhängig davon, ob zuerst \sffamily und \bfseries umdefiniert werden und dann \SansSerifAndBold definiert werden oder umgekehrt.

Nun könnte man natürlich auf die Idee kommen, vor dem Umdefinieren von \sffamily und \bfseries deren Bedeutung in internen Anweisungen zu speichern und dann diese zu verwenden:

Öffne in Overleaf
\RequirePackage{letltxmacro}
\LetLtxMacro\commands@sffamily\sffamily
\LetLtxMacro\commands@bfseries\bfseries
\renewcommand*{\sffamily}{%
  \ClassError{commands}{\string\sffamily\space not allowed}{Only commands' commands are allowed}%
}
\renewcommand*{\bfseries}{%
  \ClassError{commands}{\string\bfseries\space not allowed}{Only commands' commands are allowed}%
}
\newcommand*{\SansSerifAndBold}{\commands@sffamily\commands@bfseries}

Aber das wird nicht funktionieren. Denn der LaTeX-Kern (und unzählige Pakete) verwendet selbst ebenfalls \bfseries. Alle Definitionen, die auf dem Original-\bfseries aufbauen, und alle Definitionen, die wiederum auf solchen Definitionen aufbauen etc. würden dann die Fehlermeldung ausgeben oder müssten neu definiert werden.

Wenn ihr in eurer Klasse beispielsweise die Überschriften mit \bfseries oder \textbf fett setzt, dann wird auch das nicht mehr funktionieren.

Darüber hinaus müsste man natürlich auch die Anweisungen \LetLtxMacro und \GlobalLetLtxMacro, die durch das Paket letltxmacro hinzugekommen sind, anschließend wieder verhindern.

Und dann?

Und dann würde sich natürlich die Frage stellen, was mit den ganzen internen Makros ist. Der Benutzer könnte jetzt auch selbst einfach \csname commands@bfseries\endcsname aufrufen. Das kann man nicht verhindern, denn \csname und \endcsname sind für die Funktion des LaTeX-Kerns und unzähliger Pakete so essentiell, diese beiden kann man nicht zu Fehlermeldungen umdefinieren. Es gibt unzählige weitere Anweisungen wie \def, \let, \gdef, die man keinesfalls umdefinieren kann, weil sie intern ebenfalls benötigt werden. Man müsste schon einen neuen LaTeX-Kern schreiben, der keinerlei Benutzeranweisungen und Original-Primitive von TeX mehr direkt verwendet. (Fußnote: Das ist die Idee bei LaTeX3. Dort wird für jedes TeX-Primitiv ein gleichbedeutendes Makro in l3-Syntax definiert. Intern werden dann nur diese verwendet. Bisher werden aber natürlich die TeX-Primitive selbst nicht umdefiniert, weil sonst l3-Pakete nicht mit LaTeX2e funktionieren würden.) Und natürlich dürfte man dann keinerlei Pakete verwenden, sondern müsste auch die benötigten Pakete allesamt mit den neuen internen Makros, die die Primitive ersetzen, nachbauen. Eine eher theoretische Möglichkeit.

Was geht

Das einzige, was man tatsächlich recht einfach tun kann, ist zu verhindern, dass der Anwender selbst Pakete laden kann. Dazu muss man nur \RequirePackage nach dem Laden aller von der Klasse benötigten Pakete umdefinieren. Und natürlich kann man einzelne Anwenderanweisungen wie oben gezeigt umdefinieren, von denen man ganz sicher ist, dass sie auch nicht intern benötigt werden. Dazu muss man aber sowohl im LaTeX-Kern als auch der eigenen Klasse als auch aller von der Klasse (auch mittelbar) verwendeten Pakete wirklich nachsehen, ob die entsprechende Anweisung irgendwo intern verwendet wird.

Letztlich wird es aber immer auf eine Konvention hinaus laufen: Dem Anwender zu sagen, was er darf und was nicht. Und dann muss man darauf hoffen, dass der Anwender sich an die Regeln hält.

Was auch (nur sehr eingeschänkt) geht

Man kann natürlich auch eine komplett neue Sprache erfinden, die mit LaTeX nicht mehr viel zu tun hat. Beispielsweise könnte man basierend auf der Idee von Murmeltier eine Klasse schreiben, die \ als Command Character deaktiviert und dafür beispielsweise ! als aktives Zeichen definiert, mit dem Befehle ausgeführt werden können, die von der Klasse explizit freigegeben wurden:

Öffne in Overleaf
\ProvidesClass{commands}[2019/03/02 v0.1 not really LaTeX]
\LoadClassWithOptions{article}
% Alle Befehle, die mir `\commands@` beginnen, bezeichnen erlaubte Anweisungen
\newcommand*\commands@{!}
\newcommand*\commands@enddocument{%
  \catcode`\\=0
  \end{document}
}
\newcommand*\commands@begindocument{%
  \catcode`\\=0
  \catcode`@=12
  \begin{document}%
  \catcode`@=\active
  \catcode`\\=\active
}
\newcommand*\commands@section{\section}
\newcommand*{\latexcommandsnotallowed}{%
  \ClassError{commands}{(La)TeX commands are not allowed}{}%
}
\newcommand*{\notanallowedcommand}[1]{%
}
\newcommand*{\executecommand}[1]{%
  \ifcsname commands@#1\endcsname
    \csname commands@#1\expandafter\endcsname
  \else
    \ClassError{commands}{`\detokenize{#1}' is not an allowed command}{}%
  \fi
}
\catcode`X=0
Xcatcode`\\=\active
Xlet\Xlatexcommandsnotallowed
Xcatcode`!=Xactive
Xlet!Xexecutecommand
Xcatcode`X=11

Dann würde beispielsweise

Öffne in Overleaf
\documentclass{commands}

!{begindocument}
!{section}{Testüberschrift}
Das geht. Das geht auch!{}
!{enddocument}

zu

Testausgabe

führen, während

Öffne in Overleaf
\documentclass{commands}

!{begindocument}
!{section}{Testüberschrift}
Das geht. Das geht auch!{}

!{subsection}{Testüberschrift}
!{textbf}{Das geht nicht.}

\textbf{Und das auch nicht.}
!{enddocument}

Diverse Fehlermeldungen wegen nicht erlaubter Befehle erzeugt.

Mit LaTeX hätte so etwas dann aber nicht mehr wirklich viel zu tun. Die Syntax mit den !{…}-Befehlen wäre erheblich anders als mit \…-Befehlen. Immerhin, Pakete könnte man so nach dem Laden der Klasse auch nicht mehr laden. Man könnte aber noch immer nicht verhindern, dass der Anwender so etwas macht:

Öffne in Overleaf
\makeatletter
\newcommand*\commands@switchback{%
  \catcode`!=12
  \catcode`\\=0
}
\makeatother
\documentclass{commands}

!{switchback}
\begin{document}
\section{Testüberschrift}
\subsection{Reingefallen!}
\textbf{Du kannst nicht verhindern, dass ich das mache!}
\end{document}

Oder noch einfacher:

Öffne in Overleaf
\RequirePackage{scrlfile}
\AfterClass{commands}{%
  \catcode`!=12
  \catcode`\\=0
}
\documentclass{commands}

\begin{document}
\section{Testüberschrift}
\subsection{Reingefallen!}
\textbf{Du kannst nicht verhindern, dass ich das mache!}
\end{document}

Oder sogar noch einfacher und direkter:

Öffne in Overleaf
\edef\mydocumentclass{%
  \noexpand\documentclass{commands}
  \catcode`!=12
  \catcode`\noexpand\\=0
}
\mydocumentclass

\begin{document}
\section{Testüberschrift}
\subsection{Reingefallen!}
\textbf{Du kannst nicht verhindern, dass ich das mache!}
\end{document}

Was auch immer man versucht, es gibt also Grenzen und ein findiger Anwender findet immer eine Möglichkeit, auch noch so raffinierte Sperren zu umgehen. Das Minimum wäre daher ein anderes Format und spätestens dann wäre es eben nicht mehr LaTeX.

Permanenter link

beantwortet 28 Feb, 02:31

Ijon%20Tichy's gravatar image

Ijon Tichy
8.7k31022

bearbeitet 02 Mär, 12:39

»Was auch geht« mag theoretisch interessant sein. Wobei das Fazit am Ende die Überschrift eigentlich ad-absurdum führt. Wäre es da nicht sinnvoller, beispielsweise einen Markdown-Prozessor (ohne Möglichkeit der direkten Ausführung von TeX-Befehlen zu schreiben), der aus dem Markdown-Code ein LaTeX-Dokument mit bestimmter Klasse generiert, um daraus dann das PDF zu erzeugen? Da könnte man dann wirklich über die zur Verfügung stehenden Markdown-Befehle genau festlegen, was erlaubt ist und zu welchem Ergebnis führt. Hat dann mit LaTeX natürlich auch nicht mehr viel zu tun …

(02 Mär, 12:01) saputello

… Wobei man dann natürlich noch immer nicht verhindern kann, dass jemand eben nicht den Markdown-Prozessor verwendet, sondern direkt ein LaTeX-Dokument auch mit nicht erlaubten Befehlen erzeugt.

Letztlich läuft es also auf die Konvention hinaus, dem Anwender zu erklären, was man akzeptiert und was nicht. Und wenn er sich nicht daran hält, gibt es keine Sanktionen von Programmseite, sondern eine Ablehnung aus formalen Gründen.

(02 Mär, 12:05) saputello

Wenn Du unbedingt berserken willst, kannst Du das tun. Indem Du den catcode von \ umdefinierst, "gehen die Befehle nicht mehr".

Öffne in Overleaf
\documentclass{article}
\def~{\enddocument}
\begin{document}
\textbf{Hallo}

\catcode`\\=11

\typeout{nix geht mehr}

\def\x{\empty}

\textbf{Hallo nochmal}

~

% das Folgende wird ignoriert
f

\end{document}

alt text

Aber ich kann mir nicht vorstellen, wozu das gut sein soll. Und empfehlen kann ich erst recht nicht.

Permanenter link

beantwortet 01 Mär, 20:42

Gel%C3%B6scht's gravatar image

Gelöscht
(inaktiv)

bearbeitet 02 Mär, 12:06

saputello's gravatar image

saputello
10.4k93760

Die Befehle der selbst definierten Klasse commands sind davon dann aber auch betroffen. Wenn ich die Frage richtig verstehe, sollen die – und nur die – aber weiterhin verfügbar sein.

(02 Mär, 03:31) Ijon Tichy

@Ijon Tichy. Ja. Dann muss man "nur" irgendwelche anderen Charaktere aktiv machen, damit sie die Rolle vom ursprünglichen Backslash einnehmen in den neuen Kommandos. Die würden dann funktionieren. So was in der Art habe ich in dem Beispiel mit \enddocument gemacht, das funktioniert ja.

(02 Mär, 10:24) Gelöscht

Aber man kann ja schlecht für jeden Befehl ein anderes aktives Zeichen verwenden. Und mit LaTeX hat das dann auch nicht mehr viel zu tun. Auch wenn man nur ein aktives Zeichen hätte, dem dann der Befehl als Argument übergeben wird und man dann vor dessen Ausführung irgendwie testet, ob es ein Befehl aus commands ist, hätte das mit LaTeX nicht mehr viel zu tun. Und wenn man einfach ein anderes Zeichen zum Command-Character macht, dann hat man das ursprüngliche Ziel auch wieder nicht erreicht, weil darüber dann auch andere Befehle ausgeführt werden könnten.

(02 Mär, 10:46) Ijon Tichy

@Ijon Tichy Ich will die Diskussion hier nicht ausufern lassen. Aber es gibt durchaus Möglichkeiten, die beispielsweise in manchen der listings packages realisiert sind, das backslash inaktiv zu manchen und dafür einen anderen Charakter als escape char zu setzen, siehe etwa https://tex.stackexchange.com/a/7372/121799. Wir sind uns beide, glaube ich, einig, dass das Vorhaben des OP nicht besonders prickelnd ist. Meine Antwort ist nur, dass es im Prinzip geht, man es aber besser bleiben lassen soll.

(02 Mär, 11:28) Gelöscht

Du wirst aber extreme Schwierigkeiten haben zu verhindern, dass ein findiger Anwender das wieder durchbricht. Ich habe das in meiner erweiterten Antwort mal angerissen. Wobei der Code, der dort durch \commands@switchback ausgeführt wird, auch durchaus automatisch nach dem Laden der Klasse hätte ausgeführt werden können. Ich bleibe dabei: Wenn ein Anwender wirklich Anweisungen ausführen will, dann schafft er das auch. Also stimme ich dir nicht zu: Es geht mit einer Klasse auch im Prinzip nicht. Man braucht dafür min. ein neues Format.

(02 Mär, 11:50) Ijon Tichy

In der Tat: Spätestens, wenn der Anwender \documentclass durch eine eigene Anweisung ersetzt, bei der keine Kernanweisungen umdefiniert werden, deren Unversehrtheit der Klassenautor überprüfen könnte, dürfte es für einen Klassenautor in der Tat unmöglich sein das Zurückschalten auf normale LaTeX-Syntax nach dem Laden der Klasse zu verhindern. Es ist als letztlich eine Frage, wer bereit ist, wieviel Aufwand zu treiben, um an sein Ziel zu gelangen.

(02 Mär, 12:19) saputello

@saputello Man muss \documentclass nicht einmal ersetzen. Man muss es nur ein klein wenig in einer anderen Anweisung verstecken. Siehe ergänzte Antwort.

(02 Mär, 12:40) Ijon Tichy

@saputello @Ion Tichy Ich denke, wir stimmen weitenteils überein. Meine Antwort war wirklich nur, um zu zeigen, dass man die Befehle aushebeln kann ohne sie alle umdefinieren zu müssen (wie es in den Kommentaren unter der Frage suggeriert wird). Wir sind uns vermutlich auch einig, dass der Sinn des ganzen Unterfangens nicht klar ist. Ich wollte mit der Antwort niemandem auf die Füsse treten und stehe zu meiner Aussage "Indem Du den catcode von umdefinierst, "gehen die Befehle nicht mehr"."

(02 Mär, 14:10) Gelöscht
Ergebnis 5 von 8 Alle anzeigen
Deine Antwort auf die Frage (nicht auf andere Antworten)
Knebel-Vorschau

Folge dieser Frage

Per E-Mail:

Wenn Du Dich anmeldest, kannst Du Updates hier abonnieren

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üge einfach zwei Leerzeichen an die Stelle ein, an der die neue Zeile sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Zugeordnete Themen:

×51
×21
×13
×8
×2

Frage gestellt: 27 Feb, 15:10

Frage wurde angeschaut: 615 Mal

Zuletzt aktualisiert: 02 Mär, 14:10