Da wir nun wissen, wie Environment-Strings funktionieren und wie sie anzuwenden sind, wollen wir sehen, was unter GEM damit anzufangen ist. Alles in Teil 2 Gesagte gilt natürlich auch für GEM.
Das Environment des GEM wird beim Start des AES festgelegt. Dazu ein kleiner Ausflug zu MS-DOS (gibt’s auch noch), das ja bekanntlich unserem TOS sehr ähnlich ist. Nach dem Booten befindet man sich dort in der Kommando-Shell command.com. Das Environment wird mittels autoexec.bat gesetzt. GEM (befindet sich auf der Platte) kann nun aus der Shell mit diesem Environment gestartet werden. Der ST beherbergt GEM im ROM. Dort wird es nach dem Booten gestartet, und dort wird auch das Environment erzeugt. Atari hat eine Einflußmöglichkeit für den Anwender leider vergessen.
Wer das Programm env.tos aus Teil 1 einmal direkt vom Desktop aus gestartet hat, bekam das Environment des GEM zu Gesicht. In den allermeisten Fällen gibt es hier nichts Vernünftiges zu sehen. Schade, aber warum nicht? Wie gesagt, das GEM-Environment wird bei Start des AES festgelegt. Das AES ist ein Programm wie jedes andere und bekommt beim Aufruf (mit Pexec) natürlich einen Zeiger auf die Environment-Strings mit auf den Weg. Ich habe einen Auszug der Systeminitialisierung des TOS 1.4 disassembliert (rom.lst). Die Grundinitialisierung ist an dieser Stelle schon erledigt. Es wird zunächst die Systemvariable _cmdload getestet. Ist sie TRUE (!= 0), wird das Programm „command.prg“ gestartet, nachdem der AUTO-Ordner abgearbeitet wurde. _cmdload kann durch ein Programm im Boot-Sektor gesetzt werden, im Normalfall steht hier FALSE (0). In diesem Fall wird nach Abarbeitung des AUTO-Ordners das AES gestartet. Dazu wird mit Pexec(5,...) eine Basepage für das ROM-Programm erzeugt, das dann mit Pexec(4,...) gestartet wird. Dabei wird die Adresse des Environments ($840) übergeben, das zuvor erzeugt wurde. Hier sollte „PATH=X:\“ stehen (X = Boot-Laufwerk), was spärlich genug ist. Durch mehrere bugs entsteht aber immer „PATH= “. Können wir daran nun drehen, ohne gleich das ROM zu patchen? Ja, denn vor Start des AES wird ja der AUTO-Ordner ausgeführt. Installieren wir dort ein Programm, das das AES startet, können wir ein vernünftiges Environment setzen. Setenv.c ist die Quelle eines solchen Programms. Es vollzieht den Ablauf im ROM nach, erzeugt jedoch ein Environment, das mit der Datei setenv.inf konfiguriert werden kann. Jede Zeile in der Datei erzeugt einen Environment-String. Setenv.inf könnte z.B. so aus sehen:
PATH=c:\bin;c:\turbo_c\bin;.
SHELL=c:\bin\mupfel.prg LIB=c:\lib
INCLUDE=c:\include TMP=e:\tmp
CLIPBRD=e:\clipbrd
Ist setenv.inf nicht vorhanden, wird „PATH=;x:;.“ (x=Boot-Laufwerk) erzeugt. Setenv.prg sollte als letztes Programm im AUTO-Ordner stehen, folgende Programme werden natürlich nicht mehr ausgeführt. Setenv.inf muß im Root-Directory des Bootlaufwerks stehen. Einige TOS-Versionen (nicht 1.4) überschreiben das sechste Zeichen des Environments mit ';'. Im Zweifelsfall sollte PATH deshalb in der ersten Zeile stehen und als sechstes Zeichen ';' enthalten. Zu beachten ist außerdem, daß einige Festplattentreiber auf ähnliche Weise Environment-Strings setzen. Hier können Konflikte auftreten.
Es sei betont, daß wir das Environment für GEM gesetzt haben. Wegen des Vererbungsprinzips kann dies nach Start des GEM nicht mehr verändert werden, wohl aber für folgende Programme. Übrigens wird unser GEM-Environment auch an Accessories vererbt.
Die Environment-Variablen, die wir GEM verpaßt haben, können wir mit der Funktion shel_envrn abfragen. Da die Funktion oft falsch dokumentiert ist, hier die Deklaration in C: int shel_envrn(char **sh_epvalue, char *sh_eparm). In _sh_eparm_ übergibt man den Variablennamen, _sh_epvalue_ enthält nach dem Aufruf einen Zeiger auf den Inhalt der Variablen bzw. NULL, falls die Variable nicht existiert. Hierzu das Demo-Programm _path.prg_, das PATH abfragt.
Nachzuladende Programme kann man in den Verzeichnissen der GEM-Environment-Variablen PATH suchen. Dazu bietet das AES die Funktion shel_find, mit der auch das Desktop zu startende Programme sucht. Die Deklaration in C ist: int shel_find(char *sh_pbuff). In _sh_pbuff_ übergibt man den Namen des gesuchten Programms. Shel_find sucht dann im aktuellen Verzeichnis und in allen Verzeichnissen von PATH. Shel_find liefert 1, falls das Programm gefunden wurde, sonst 0. Sh Jpbuff bleibt unverändert im zweiten Fall, ansonsten steht hier der komplette Zugriffspfad. Enthält PATH als sechstes Zeichen (s.o.), so wird auch das Wurzelverzeichnis des aktuellen Laufwerks durchsucht. Daß eine zugehörige Resource-Datei evtl, im gleichen Verzeichnis steht, stört nicht, denn shel_find wird auch von rsrc_load benutzt, um die Resource-Datei zu finden. Zu dieser Funktion das Programm sh_find.prg, das eine Datei namens „find_me.prg“ sucht und den Zugriffspfad ausgibt. Eine solche Datei (Inhalt spielt keine Rolle) kann nun irgendwo auf der Platte versteckt werden; falls das Directory in PATH enthalten ist, wird sie auch gefunden.
Ich hoffe, mit diesem Beitrag die Benutzung der Environment-Strings auf dem ST etwas populärer gemacht zu haben.
Literatur:
[1] Atari ST Profibuch, Jankowski, Reschke, Rabich, Sybex 1988
*** rom.lst ***
*** TOS 1.4 'Power Up' ***
GEMDOS equ 1
PEXEC equ 75
_bootdev equ $446
_cmdload equ $482
_sysbase equ $4f2
exec_os equ $4fe
* Grundinitialisierung ist erledigt
fc046e tst.w _cmdload
fc0474 beq $fc0494 ; 0 -> AES (ROM) starten
fc0476 bsr $fc0bfa ; \auto\*.prg ausführen
fc047a move.l #$fc0000,_sysbase ; Anfang OS
fc0484 pea $fc052b(pc) ; envptr = ""
fc0488 pea $fc052b (pc) ; cmdline = ""
fc048c pea $fc0518 (pc) ; prgfile = "COMMAND.PRG"
fc0490 clr.w -(sp) ; mode
fc0492 bra $fc04fc ; Pexec (0,prgfile,cmdline, envptr)
fc0494 bsr $fc0bfa ; \auto\*.prg ausführen
fc0498 move.l #$fc0000,_sysbase ; anfang os
fc04a2 lea $fc050c(pc),a0 ; AES environment
fc04a6 move.l #$840,a1
fc04ac cmpi.b #'#',(a0) ; nach $840 kopieren
fc04b0 bne $fc04b4 ; # = Platzhalter
fc04b2 move.l a1,a2 ; für Boot-Laufwerk
fc04b4 move.b (a0)+,(a1)+
fc04b6 bpl $fc04ac
fc04b8 move.b _bootdev,d0 ; bug, sollte move.w sein!
fc04be add.b #'A',d0 ; Boot-Laufwerk bei #
fc04c2 move.b d0,(a2) ; eintragen
fc04c4 pea $840 ; envptr
fc04ca pea $fc052b ; cmdline = ""
fc04d0 pea $fc052b(pc) ; prgfile = ""
fc04d4 move.w #5,-(sp) ; basepage erzeugen
fc04d8 move.w #PEX£C,-(sp) ; mit
fc04dc trap #GEMDOS ; Pexec (5,prgfile,cmdline,envptr)
fc04de adda.w #14,sp ; bug, sollte 16 sein!
fc04e2 move.l d0,a0 ; in p_tbase
fc04e4 move.l exec_os,8(a0) ; Anfangsadresse AES eintragen
fc04ec pea $840 ; envptr
fc04f2 move.l a0,-(sp) ; basepage
fc04f4 pea $fc052b(pc) ; prgfile = ""
fc04f8 move.w #4,-(sp) ; AES starten mit
fc04fc move.w #PEXEC,-(sp) ; Pexec (4,prgfile,basepage,envptr)
fc0500 trap #GEMDOS
fc0502 adda.w #14,sp ; bug, sollte 16 sein!
fc0506 jmp $fc0030 ; Neustart OS
fc050c 50 41 54 48 3d 00 23 3a 5c 00 00 ff 43 4f 4d 4d
'PATH=.#:\...COMM
fc051c 41 4e 44 2e 50 52 47 00 47 45 4d 2e 50 52 47 00
'AND.PRG.GEM.PRG.
fc052c 00 00 80 01 70 03 61 00 00 f4 20 79 00 00 04 7a
'...p.a..t y...z
/*==============================================*
* *
* setenv.c *
* *
* startet AES im AUTO-Ordner *
* und setzt Environment-Variablen *
* *
* sollte letztes Programm im AUTO-Ordner sein *
* *
* Linken mit Option -s=512 (512 byte Stack reichen) *
* *
* 20.01.90 Jan Bolt (c) MAXON Computer 1991 *
* *
* TURBO C *
*==============================================*/
#include <stdio.h>
#include <tos.h>
#define ENV_LEN 256
#define _bootdev (int *)0x446
#define _cmdload (int *)0x482
#define _sysbase (void **)0x4f2
#define exec_os (void **)0x4fe
#define ROM_START (void *)0xfc0000
char *envstr(void) /* environment strings generieren */
{
char c;
int fd, i = 0;
static char env[ENV_LEN+1] = "PATB=;#:;.\0”;
if ((fd = Fopen("setenv.inf",0)) < 0)
env[6] = 'a' + *_bootdev;
else
{
while (Fread(fd, 1, &c) == 1 && i < (ENV_LEN-2))
{
switch (c)
{
case '\r' ; break;
case ’\n' : env[i++] = '\0'; break;
default : env[i++] = c;
}
}
env(i++] = '\0';
env[i] = '\0';
Fclose(fd);
}
return env;
}
void do_main (void)
{
BASPAG *basepage;
char *envp; /* Zeiger auf environment */
*_sysbase = ROM_START; /* Beginn OS setzen */
if (*_cmdload) /* command prg starten */
{
Pexec(0, "command.prg", (COMMAND *)"", NULL);
}
else /* AES starten */
{
envp = envstr(); /* environment holen */
basepage = (BASPAG *)Pexec(5, NULL, NULL, envp);
basepage->p_tbase = *exec_os;
Pexec(4, NULL, (void *)basepage, envp);
}
}
/*====== Hauptprogramm ======*/
int main()
{
Supexec (do_main) ; /* do_main im Supervisor Modus ausführen */
return 0;
}
/*==============================================*
* *
* path.c *
* *
* Anzeigen der AES Environment Variablen PATH *
* *
* 31.12.89 Jan Bolt Version 210990 *
* *
* Turbo C (c) MAXON Computer 1991 *
*==============================================*/
#include <stdio.h>
#include <aes.h>
void alert(char *str)
{
char tmp[128];
sprintf (tmp, "[0][%s ][ OK ]", str);
form_alert(1, tmp);
}
/*====== Hauptprogramm ======*/
int main()
{
char *path;
if (appl_init() < 0)
return 1;
shel_envrn(&path, "PATH=");
if (path != NULL)
alert(path);
return (appl_exit() == 0);
}
/*==============================================*
* *
* sh_find.c *
* *
* Demo shel_find *
* *
* 21.01.90 Jain Bolt Version 210990 *
* *
* Turbo C (c) MAXON Computer 1991 *
*==============================================*/
#include <stdio.h>
#include <aes.h>
void alert(char *str, int k)
{
char tmp[128];
sprintf(tmp, "[0][%s |%d J[ OK ]", str, k);
form_alert(1, tmp );
}
/*====== Hauptprogramm ======*/
int main()
{
int s;
static char path[PATH_MAX] = "find_me.prg";
if (appl_init() < 0)
return 1;
s = shel_find(path);
alert(path, s);
return (appl_exit() = 0);
}