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:
\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:
\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:
\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:
\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
\documentclass{commands}
!{begindocument}
!{section}{Testüberschrift}
Das geht. Das geht auch!{}
!{enddocument}
zu
[![Testausgabe][1]][1]
führen, während
\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:
\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:
\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:
\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.
[1]: https://texwelt.de/wissen/upfiles/test_20190302_170145.png