Nachdem im ersten Teil dieser Serie die Grundlagen erläutert wurden, möchte ich nun einige Anwendungen zeigen. Jedes Programm, das weitere nachlädt, sollte die Directories der Variablen PATH nach dem zu ladenden Programm durchsuchen. Pfade werden in Environment-Variablen durch Komma oder Semikolon getrennt aufgelistet, das aktuelle Directory ist '.' ein abschließendes '' ist nicht erforderlich.
Ein Beispiel für die Suche in PATH ist die Funktion findfile. Sie sucht file in den Verzeichnissen von PATH. Ist PATH nicht vorhanden, wird im aktuellen Verzeichnis gesucht. Als Demo für diese Funktion dient FF_DEMO. Dieses Programm sucht ENV.TOS (aus Teil 1). ENV.TOS kann nun in einem der Verzeichnisse von PATH versteckt werden, FF_DEMO wird es schon finden.
Eine weitere standardisierte Anwendung für Environment-Variablen ist das XARG-Verfahren, das auf Allan Pratt und Dale Schumacher zurückgeht. Es erlaubt die Übergabe von beliebig vielen Parametern an Programme. Die Standard-Kommandozeile ist ja auf 124 Zeichen begrenzt. Man legt folgende Struktur an:
typedef struct {
char xarg_magic[4]; /* enthält "xArg" */
int xargc; /* entspricht argc in main() */
char **xargv; /* entspricht argv in main() */
char *xiovector; /* z.Zt. unbenutzt */
char *xparent; /* Zeiger auf Basepage des aufrufenden Programms */
} XARG;
Einen Zeiger auf diese Struktur übergibt man in der Environment-Variablen jeArg, und zwar als achtstellige Hex-Konstante, etwa „xArg=000310D8“. Das aufgerufene Programm überprüft zunächst die Gültigkeit der Struktur. Xarg_magic muß „xArg“ enthalten, xparent muß auf die Basepage des aufrufenden Programmes zeigen (dieser Zeiger ist in der eigenen Basepage enthalten). Dann sind die Argumente unbedingt zu kopieren, denn der Speicher gehört dem aufrufenden Programm.
Ein ähnliches Verfahren mit der Bezeichnung ARGV wurde vor einiger Zeit von Atari USA zum Standard erhoben. Dabei wird die gesamte Kommandozeile im Environment übergeben. Der Variablen „AKGV=“, deren Inhalt beliebig ist, folgen alle zu übergebenden Argumente, jeweils durch 0 getrennt. Das erste Byte der normalen Kommandozeile, das die Länge enthält, wird auf 127 gesetzt (normalerweise <= 124). Das aufgerufene Programm muß die ganze Sache aus dem Environment löschen. Dazu überschreibt es das ‘A’ von „ARGV“ mit O. Der Vorteil gegenüber XARG ist, daß sich alle Parameter im Speicher des nachgeladenen Programms befinden. Das Environment wird ja vom TOS kopiert.
Hierzu das Programm STARTUP.TTP. Es verarbeitet XARG- und ARGV-Argumente und kann als startup für C-Programme benutzt werden. Als Demo dient xargdemo.tos, das seine Parameter an startup.ttp per Kommandozeile, per XARG und per ARGV übergibt.
Literatur:
[1] Atari ST Profibuch, Jankowski, Reschke, Rabich, Sybex 1988
/* =============================================*
* *
* findfile.c *
* *
* Sucht file in allen Verzeichnissen von PATH, *
* gibt kompletten Pfadnamen zurück, *
* oder NULL bei vergeblicher Suche *
* *
* 24.05.90 Jan Bolt *
* *
* Turbo C *
* (c) MAXON Computer GmbH 1991 ================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tos.h>
#define is_file(f) (Fsfirst(f,0) == 0)
char *findfile(char *file)
{
static char tmp[PATH_MAX];
char *path, *p;
if (strchr(file, '\\') || strchr(file, ':'))
/* file enthält Pfad */
return (is_file(file)) ? file : NULL;
if ((path=getenv("PATH")) == NULL ||
/* falls PATH nicht existiert */
*path == '\0') /* oder leer */
path = "."; /* path = akt Dir */
while (*path != '\0')
{
p = tmp;
while (*path != '\0' &&
*path != ';' &&
*path != ',') /* Directory aus PATH */
*p++ = *path++;
/* nach tmp kopieren */
if (*path != '\0') /* Separator überspringen */
path++;
if (p[-1] != '\\') /* Directory mit \ */
*p++ = '\\'; /* abschließen */
strcpy(p, file); /* file anhängen */
if (is_file(tmp))
return tmp;
}
return NULL;
}
/* =============================================*
* *
* ff_demo.c *
* *
* Demo findfile *
* *
* muß mit putenv.o, findfile.o gelinkt werden *
* *
* 24.05.90 Jan Bolt *
* *
* Turbo C *
* (c) MAXON Computer GmbH 1991 ===============*/
#include <stdio.h>
#include <stdlib.h>
/*=============== Hauptprogramm ===============*/
int main ()
{
static char file[] = "env.tos";
char *p, *findfile(char *file);
int putenv(char *entry);
if (getenv("PATH") == NULL)
putenv("PATH=\\bin;bin;.");
if ((p = findfile(file)) == NULL)
printf("%s nicht gefunden !\n", file);
else
printf("%s\n", p);
getchar();
return 0;
}
/* =============================================*
* *
* startup.c *
* *
* Startup Modul für Turbo C *
* *
* - Verarbeitung von XARG Argumenten *
* - Verarbeitung von ARGV Argumenten *
* *
* 07.06.90 Jan Bolt Version 210990 *
* *
* Turbo C *
* (c) MAXON Computer GmbH 1991 ===============*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tos.h>
/*========= Hauptprogramm =====================*/
int do_main(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++)
printf("argv[%d]='%s'\n", i, argv[i]);
return 0;
}
/* strdup() fehlt in TC Lib */
char *strdup(const char *str)
{
char *p;
if ((p = malloc(strlen(str)+1)) != NULL)
strcpy(p, str);
return p;
}
/*======== XARG-, ARGV- Verarbeitung =========*/
#define ENSMEM -39 /* TOS-Fehler out of mem */
#define XARG_MAGIC 0x78417267 /* "xArg" */
typedef struct /* XARG-Struktur */
{
char xarg_magic[4];
int xargc;
char **xargv;
char *xiovector;
BASPAG *xparent;
} XARG;
int main(int nargc, char *nargv[])
{
extern BASPAG *_BasPag;
XARG *xarg;
int argc, i, rv;
char *xenv, **argv;
if ((xenv = getenv("xArg")) != NULL &&
(xarg = (XARG *)strtoul(xenv, NULL, 16)) != NULL &&
((long)xarg & 1) == 0 &&
*(long *)xarg->xargmagic-=XARG_MAGIC &&
xarg->xparent == _BasPag->p_parent)
{
printf("XARG:\n");
/* XARG-Struktur ist gültig. Argumente müssen kopiert */
/* werden, sie befinden sich im Speicher des Parent. */
/* Speicher wird dynamisch mit malloc zugewiesen */
argc = xarg->xargc;
if ((argv = malloc((argc+1)*sizeof(char *))) == NULL)
return ENSMEM;
argv[argc] = NULL;
for (i = 0; i < argc; i++)
if ((argv[i] = strdup(xarg->xargv[i])) = NULL)
return ENSMEM;
rv = do_main(argc, argv);
for (i = 0; i < argc; i++)
free(argv[i]);
free(argv);
return rv;
}
if ((xenv = getenv("ARGV")) != NULL &&
*_BasPag->p_cmdlin = 127) /* Länge Kommandozeile - 127? */
{
printf("ARGV:\n");
/* ARGV ist gültig. Es gilt einen Vektor von */
/* Zeigern auf die Argumente zu bilden, argc */
/* ist zu diesem Zeitpunkt leider nicht bekannt. */
/* Speicher wird dynamisch mit malloc zugewiesen. */
xenv[-5] = '\0'; /* "ARGV=" löschen */
while (*xenv++) /* ggf Wert überspringen */
;
argc = 0;
if ((argv = malloc(sizeof(char *))) == NULL)
return ENSMEM;
while (*xenv)
{
argv[argc++] = xenv;
if ((argv = realloc(argv (argc+1)* sizeof(char *))) == NULL)
return ENSMEM;
while (*xenv++);
}
argv[argc] = NULL;
rv = do_main(argc, argv);
free(argv);
return rv;
}
printf("Kommandozeile:\n");
return do_main(nargc, nargv);
}
/* =============================================*
* *
* xargdemo.c *
* *
* Demo XARG-Verfahren *
* *
* muß mit putenv.o gelinkt werden *
* *
* 17.02.90 Jan Bolt Version 210990 *
* *
* Turbo C *
* (c) MAXON Computer GmbH 1991 ===============*/
#include <stdio.h>
#include <stdlib.h>
#include <tos.h>
typedef struct
{
char xarg_magic[4]; /* enthält "xArg" */
int xargc; /* argc */
char **xargv; /* argv */
char *xiovector; /* bisher unbenutzt */
BASPAG *xparent; /* Zeiger auf aufrufendes Prg */
} XARG;
/*============= Hauptprogramm ===============*/
main()
{
int putenv(char *entry);
extern BASPAG *_BasPag; /* Zeiger auf eigene Basepage */
char env[14], *p;
static char cmd[] = "\x8p1 p2 p3";
static char *xargs[] = {"startup",
"xp1",
"xp2",
"xp3",
NULL};
static XARG xarg = {'x','A','r','g',4,xargs, NULL,NULL};
xarg.xparent = _BasPag;
/* Parameter per Kommandozeile */
Pexec(0, "startup.ttp", (COMMAND *)cmd, NULL);
getchar();
/* Parameter per XARG */
sprintf(env, "xArg=%081X", &xarg); /* Zeiger auf xarg in */
if (!putenv(env)) /* in xArg=übergeben */
fprintf(stderr, "environment overflow !\n");
else
Pexec (0, "startup.ttp", (COMMAND *)cmd, NULL);
getchar();
putenv("xArg"); /* xArg löschen */
/* Parameter per ARGV */
if (!putenv("ARGV= startup ap1 ap2 ap3"))
fprintf(stderr, "environment overflow!\n");
else
{
/* Argumente durch 0 trennen */
p = getenv("ARGV");
while (*p)
if (*p++ == ' ')
p[-1] = 0;
cmd[0] = 127;
Pexec(0, "startup.ttp", (COMMAND *)cmd, NULL);
}
getchar();
return 0;
}