Atarium: Wo ist meine Mupfel?

Diese Frage stellt sich nicht nur bei »Urmel aus dem Eis«, sondern auch beim Versuch von UNIX-Freaks, auf dem ST die Funktion »system()« aufzurufen. Die System-Variable »Shell« bietet sich als Ersatz an.

In diesem Monat wende ich mich wieder einmal dem leidigen Thema »nicht oder schlecht dokumentierte Systemvariable« zu. Bekanntlich hat ja Atari bis zum heutigen Tage keine vollständige und korrekte Dokumentation zu diesem Thema geliefert. Für einige Systemvariablen haben sich inzwischen sinnvolle Pseudo-Standards herausgebildet, die jedoch noch längst nicht jeder Programmierer kennt.

Zu diesen Systemvariablen gehört »_shell_p« ($4f6). Nachdem diese sehr praktische Einrichtung, die tatsächlich Verwendung findet, in [1] als »nie benutzt« eingestuft wurde, ist die Zeit für eine ausführliche Erläuterung reif.

Bereits in der ersten und bisher einzigen Atari-Dokumentation ([2]) gab Landon Dyer (Autor des Atari-Assemblers »Mad-Mac«) die offizielle Bezeichnung »shell_p« vor. Die Erläuterung (Zitat) »points to shell-specific context« ist — wenn schon nicht falsch — auf keinen Fall sonderlich hilfreich. Offenbar wußte man selbst bei Atari nicht genau, was es mit dieser Systemvariablen auf sich hat, oder es war jedem klar, so daß sich keiner die Mühe machte, den Rest der Programmiererwelt zu erleuchten.

An dieser Stelle kommt wieder einmal das Betriebssystem UNIX ins Spiel, das bekanntlich in einigen Aspekten TOS als Vorbild diente (leider in zu wenigen). UNIX stellt eine Bibliotheksroutine namens »systemO« zur Verfügung, die die Fähigkeiten der benutzten Kommandoshell an alle von dort aus gestarteten Programmen weiterreicht. Ein Kopiervorgang in einer UNIX-Anwendung sieht deshalb meist sehr einfach aus:

system("cp sourcename dest-name");

Auch der vorläufige ANSI-C-Standard [3] beschreibt die verlangte Funktionsweise genau (Tabelle 1). Turbo-C kennt zwar die Funktion »system()«, gibt aber stets Null zurück. Leider konnten wir die Programmierer von Heimsoeth bislang nicht davon überzeugen, eine vollständige »system()«-Routine zu implementieren. Gleiches gilt traurigerweise auch für die Ein-/Ausgabeumlenkung und die erweiterte Parameter-Übergabe...

Ob es nun so geplant war oder nicht — findige Köpfe sind auf die Idee gekommen, die »unbenutzte« Systemvariable »shell_p« auf genau die Routine der Kommando-Shell zeigen zu lassen, die den Inhalt einer Kommandozeile aus wertet. Die Vorteile liegen auf der Hand: Anwendungen, die über »shell_p« Systemaufrufe vornehmen, sind schneller zu programmieren und zudem leichter nach UNIX zu portieren. Der umgekehrte Fall trifft natürlich auch zu und ist selbstverständlich viel wichtiger. Vorreiter war dieses Mal wohl die PD-Command-Shell »Guläm« ([4]). Inzwischen haben Autoren anderer Shells nachgezogen (»Master« [5], »Craft« [6] und andere), so daß man inzwischen mit gutem Gewissen von einem Pseudo-Standard sprechen darf. Auch Dale Schumacher unterstützt in seinen PD-C-Libraries diese Art des Systemaufrufs ([7,8]).

Alle mir bekannten Kommando-Shells, die »shell_p« verwenden, sind UNIX-Shells. Deshalb darf man wohl mit gutem Gewissen die einfacheren Standard-UNIX-Befehle als Mindestbefehlsumfang voraussetzen (Tabelle 2). Damit läßt sich folgender Standard für die Verwendung von »shell_p« formulieren:

»shell_p« ($4f6) ist entweder ein Nullpointer, wenn keine entsprechende Shell installiert ist, oder ein Zeiger auf diejenige Routine der Shell, die UNIX-Shell-kompatible Kommandozeilen entgegennimmt und auswertet. Dazu wird ein Zeiger auf die mit Null abgeschlossene Kommandozeile als einziger Parameter auf dem Stack übergeben. Als Resultat erhält man den Return-Code des Kommandos in TOS-Codierung.

dc.l $86420135	; nach eigenen Versuchen NICHT korrekt, ausprobieren! 
jmp getlineviaue_ ; Zeiger auf Zeileneditor 
-> jmp callgulam_	; Zeiger auf Kommandozeilen-Interpreter; »shell_p« zeigt auf diesen JMP-Befehl

Listing 1.»shell_p« unter Guläm

dc.b 'MAST'	; Programmkennung nach dem unmodifizierten Braner-Verfahren (siehe auch [6]) 
dc.l old_shell	; ehemaliger Wert von »shell_p«
-> bra	master_shell ; Zeiger auf Kommandozeilen-Interpreter; »shell_p« zeigt auf diesen Branch-Befehl 
bra master_call ; ermöglicht die Abfrage von Environment-Variablen

Listing 2. »shell_p« unter Master 5.4

Kommen wir nun zu den Besonderheiten bei der Benutzung von »shell_p« unter den verschiedenen Shells. Master und Guläm stellen zusätzlich eine »Magic Number« zu Verfügung, die Auskunft gibt, ob sich das betreffende Programm installiert hat. Dies ist eine zweischneidige Angelegenheit, da die Versuchung groß ist, die Aufrufe von »system« auf nur eine einzige Shell abzustimmen — was natürlich nicht im Sinne des Erfinders ist. Als Sicherheitsabfrage vor der Verwendung Shellspezifischer Funktionen sind diese »Magic Numbers« hingegen gut geeignet. Am besten ist die Nutzung des XBRA-Verfahrens [9] wie in Master.

Bei Guläm (Listing 1) zeigt »shell_p« in eine weitere Sprungtabelle, die neben dem Standardvektor noch den in Guläm integrierten Zeileneditor zugänglich macht. Doch davor findet man eine »Magic Number«, deren Inhalt definitiv nicht mit der Dokumentation übereinstimmt. Und noch eine Warnung an die Benutzer dieser Shell: Guläm setzt nach Beendigung der Shell »shell_p« nicht zurück, so daß alle anschließend gestarteten Programme, die »system« aufrufen, mit hoher Wahrscheinlichkeit abstürzen.

# ANSI-Definition von »system«

Library: stdlib.h
Prototype: int system (const char *string );
Beschreibung: Die »system«-Funktion leitet die übergebene Zeichen kette zur Ausführung an das Betriebssystem weiter. Die Zeichenkette sollte für den Kommandoprozessor des Systems verständlich sein. Vor dem Aufruf sollte man alle offenen Dateien schließen.

Zur Abfrage, ob eine Shell vorhanden ist, ruft man »system« mit einem Nullpointer auf. Als Rückgabewert erhält man genau dann Null, wenn keine Shell installiert ist. Alle anderen Aufrufe von »system« ergeben einen implementationsabhängigen Rückgabewert.

Tabelle 1. »system« nach dem ANSI-Standard (aus [3])

Befehl Beschreibung
cd Directory wechseln
cp Dateien kopieren
mv Dateien kopieren und Ausgangsdatei löschen
rm Dateien löschen
mkdir Ordner anlegen
rmdir Ordner löschen
chmod Dateiattribute verändern
Is Directory anzeigen
cat Dateien ausgeben
setenv Environment-Variablen ändern
date Datum anzeigen oder setzen

Tabelle 2. Was jede Shell können sollte

Master ist ein mustergültiges Beispiel für ein Programm, bei dem sich die Programmierer die Mühe machten, alle Standards und Konventionen zu berücksichtigen. Beispiel: Master kommt mit allen bekannten Verfahren zur Übergabe extralanger Kommandozeilen zurecht (XARG-Methode, Mark-Williams-Methode etc). Nachdem beim Umbiegen bisher die ursprüngliche Braner-Methode ([8]) zum Einsatz kam, benutzen künftige Versionen das XBRA-Verfahren (Listing 2).

Betrachten wir zunächst den Fall, daß ein Nullpointer übergeben wurde. Hier überprüft man, ob »shell_p« ungleich 0 ist. Danach kann man eine 1 für »Shell vorhanden« zurückliefern, oder man schaut in der Environment-Variablen »SHELL« ([10]) nach, ob dort der Name und der Pfad der bevorzugten Shell eingetragen ist — auch in diesem Fall liefert man eine 1 zurück, sonst 0.

Soll tatsächlich etwas geschehen, beginnt der Test, ob »shell_p« auf irgend etwas zeigt. Wenn ja, ruft man indirekt die dort angegebene Routine auf und leitet den Integer-Return-Wert an die aufrufende Funktion zurück. Sonst sucht man wieder in der Environment-Variablen nach dem Namen einer Standard-Shell und startet diese gegebenenfalls. Dabei leitet man die übergebene Zeichenkette einfach als Parameter an die Shell weiter und hofft, daß diese etwas damit anfangen kann...

Kommt man so nicht weiter, das heißt es gibt keine Environment-Variable »SHELL«, bietet sich als letzten Ausweg noch folgendes an: Das erste Wort in der Zeichenkette wird als Name eines zu startenden Programms interpretiert, der Rest als die zu übergebenden Parameter. Dabei sollte man — falls vorhanden — die Environment-Variablen »PATH« für den Suchpfad und »SUFFIX« für die auszuprobierenden Extensions auswerten.

Nun einige Kurzinformationen für ewig Neugierige:

Literaturnachweis:

[1] Alex Esser: »Die Systemvariablen des TOS, Teil 2«, ST-Computer 12/1988

[2] Landon Dyer: »The Hitchhiker’s Guide to the Bios«, Atari Corp. 1985

[3] Darnell/Margoiis: »Software Engineering in C«, Springer Verlag Heidelberg — Berlin — New York, ISBN 0-387-96574-2

[4] Prakhaber Mateti: »A reference manual for Guläm«

[5] Naumann & Röder GbR: »Benutzerhandbuch und Referenzmanual für Master 5.4«

[6] Rupert Kaiser: »GEM ade — es lebe die Craft-Shell«, 68000er 3/1988

[7] Dale Schumacher: Dokumentation zu den PD-C-Libraries ’dLibs’

[8] Julian F. Reschke: »Schranken durchbrechen«, ST-Magazin 7/1988

[9] Julian F. Reschke: »GEM-Anwendungen sauber programmiert«, ST-Magazin 12/1988

[10] Julian F. Reschke: »Auch GEM nutzt Environment-Variablen«, 68000er 3/1988

[11] Andrew Tanenbaum: »Operating Systems: Design and implementation«, Prentice Hall 1987, ISBN 0-136373313

Bezugsquellen:

Craft-Shell: COMMEDIA, P.O.Box 6409, 1005 EK Amsterdam, Niederlande Master: Naumann & Röder GbR, Am Sportplatz 22, 6620 Völklingen

Minix ST: Steven Steinkraus, Feldtorweg 24,3406 Bovenden 1


Julian F. Reschke
Aus: ST-Magazin 02 / 1989, Seite 66

Links

Copyright-Bestimmungen: siehe Über diese Seite