home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1993-10-23 | 12.9 KB | 436 lines |
- IMPLEMENTATION MODULE cmdline;
- (*__NO_CHECKS__*)
- (*****************************************************************************)
- (* STATUS: OK *)
- (* --------------------------------------------------------------------------*)
- (* 12-Feb-93, Holger Kleinschmidt *)
- (*****************************************************************************)
-
- /* Folgende Zeile in 'C'-Kommentarklammern setzen, falls der Programmname
- * nicht ueber "shel_read()" ermittelt werden soll, wenn kein ARGV-Verfahren
- * benutzt wurde.
- * Da das Ermitteln des Programmnamens auf diese Weise fuer TOS-Programme
- * nicht ganz ``sauber'' ist, sollten die Kommentarklammern normalerweise
- * gesetzt sein!
- * Die GEM-Aufrufe sind fuer die GEM-Bibliothek ``crystal'' von
- * Ulrich Kaiser ausgelegt, wer eine andere GEM-Bibliothek verwendet, muss
- * die Aufrufe entsprechend anpassen.
- */
-
- /*
- #define USE_AES_FOR_ARGV0
- */
-
- VAL_INTRINSIC
- CAST_IMPORT
- OSCALL_IMPORT
-
- FROM SYSTEM IMPORT
- (* TYPE *) ADDRESS,
- (* PROC *) ADR, TSIZE;
-
- FROM types IMPORT
- (* CONST*) NULL,
- (* TYPE *) UNSIGNEDWORD, SIGNEDLONG, UNSIGNEDLONG;
-
- FROM CTYPE IMPORT
- (* PROC *) ISSPACE;
-
- FROM DosSystem IMPORT
- (* TYPE *) BasePtr, BasePage, CmdLine,
- (* PROC *) GetBasePage;
-
- FROM pSTRING IMPORT
- (* CONST*) EOS,
- (* TYPE *) StrRange, ArrayRange, StrPtr, StrArray,
- (* PROC *) EQUALN, AssignCToM2;
-
- #ifdef USE_AES_FOR_ARGV0
- FROM AES IMPORT
- (* PROC *) Version;
-
- FROM ApplMgr IMPORT
- (* PROC *) ApplInit, ApplExit;
-
- FROM ShelMgr IMPORT
- (* PROC *) ShelRead;
- #endif
-
- #include "oscalls.m2h"
-
- (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
-
- VAR
- (* Variablen mit Dauerinformation *)
-
- dta : ARRAY [0..43] OF CHAR; (* Platz fuer Default-DTA *)
- basePtr : BasePtr; (* -> BasePage des Programms *)
- ARGV : StrArray; (* -> Feld von Zeigern auf die Kommando-Argumente *)
- ENVP : StrArray; (* -> Feld von Zeigern auf die Environment-Variablen *)
- ARGC : CARDINAL; (* Anzahl der Kommando-Argumente *)
- prgName : CmdLine; (* Name des Programms, falls feststellbar *)
- cmdBuf : CmdLine; (* Arbeitskopie der Basepage-Kommandozeile *)
- null : StrPtr;
-
- (* Verschiedenes, bei Modulinitialisierung benutzt *)
-
- ENV : BOOLEAN; (* Programm hat ein Environment *)
- EXARG : BOOLEAN; (* ARGV-Verfahren wird benutzt *)
- envSize : CARDINAL;
- cmdLen : StrRange;
- i : ArrayRange;
- args : ArrayRange;
- vars : ArrayRange;
- c : CHAR;
- mem : ADDRESS;
- envPtr : StrPtr;
- cmdPtr : StrPtr;
- envIdx : StrRange;
- argIdx : StrRange;
- srcIdx : StrRange;
- dstIdx : StrRange;
- #ifdef USE_AES_FOR_ARGV0
- AUTO : BOOLEAN;
- #endif
-
- (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
-
- PROCEDURE main ((* -- /AUS *) VAR argc : ArrayRange;
- (* -- /AUS *) VAR argv : StrArray );
- (*T*)
- BEGIN
- argc := ARGC;
- argv := ARGV;
- END main;
-
- (*---------------------------------------------------------------------------*)
-
- PROCEDURE getenv ((* EIN/ -- *) REF var : ARRAY OF CHAR ): StrPtr;
- (*T*)
- VAR varIdx : StrRange;
- varPtr : StrPtr;
- val : ArrayRange;
-
- BEGIN
- val := 0;
- varPtr := ENVP^[0];
- WHILE varPtr <> NULL DO
- varIdx := 0;
- WHILE (VAL(CARDINAL,varIdx) <= VAL(CARDINAL,HIGH(var)))
- AND (var[VAL(CARDINAL,varIdx)] <> 0C)
- AND (var[VAL(CARDINAL,varIdx)] = varPtr^[varIdx])
- DO
- INC(varIdx);
- END;
-
- IF ( (VAL(CARDINAL,varIdx) > VAL(CARDINAL,HIGH(var)))
- OR (var[VAL(CARDINAL,varIdx)] = 0C))
- AND (varPtr^[varIdx] = '=')
- THEN
- RETURN(CAST(StrPtr,ADR(varPtr^[varIdx+1])));
- END;
-
- INC(val);
- varPtr := ENVP^[val];
- END;
-
- RETURN(NULL);
- END getenv;
-
- (*---------------------------------------------------------------------------*)
-
- PROCEDURE ArgCount ( ): CARDINAL;
- (*T*)
- BEGIN
- RETURN(ARGC);
- END ArgCount;
-
- (*---------------------------------------------------------------------------*)
-
- PROCEDURE GetArg ((* EIN/ -- *) i : CARDINAL;
- (* -- /AUS *) VAR arg : ARRAY OF CHAR );
- (*T*)
- BEGIN
- IF i < ARGC THEN
- AssignCToM2(ARGV^[VAL(ArrayRange,i)], arg);
- ELSE
- arg[0] := EOS;
- END;
- END GetArg;
-
- (*---------------------------------------------------------------------------*)
-
- PROCEDURE GetEnvVar ((* EIN/ -- *) REF var : ARRAY OF CHAR;
- (* -- /AUS *) VAR val : ARRAY OF CHAR ): BOOLEAN;
- (*T*)
- BEGIN
- AssignCToM2(getenv(var), val);
- RETURN(val[0] <> EOS);
- END GetEnvVar;
-
- (*===========================================================================*)
-
- BEGIN (* pCMDLINE *)
- GetBasePage(basePtr);
-
- EXARG := FALSE;
- ARGC := 0;
- args := 0;
- vars := 0;
- null := NULL;
- ARGV := CAST(StrArray,ADR(null));
- ENVP := CAST(StrArray,ADR(null));
- envPtr := basePtr^.pEnv;
-
- Fsetdta(ADR(dta)); (* damit bleibt die Kommandozeile ungeschoren *)
- basePtr^.pDta := ADR(dta);
-
-
- ENV := (envPtr <> NULL) AND (envPtr^[0] <> 0C);
- IF ENV THEN
- (* Zuerst wird nach ARGV gesucht, und, falls vorhanden, abgetrennt,
- * sodass der Rest einheitlich als Environment behandelt werden
- * kann. Das ARGV-Verfahren benutzt naemlich nicht das Standardformat
- * fuer Environmentvariablen und darf nicht bei der evtl. noetigen
- * Formatkorrektur des Environments beruecksichtigt werden.
- *)
- envIdx := 0;
- LOOP
- IF EXARG THEN
- INC(args);
- ELSE
- IF (envPtr^[envIdx] = 'A')
- AND (envPtr^[envIdx+1] = 'R')
- AND (envPtr^[envIdx+2] = 'G')
- AND (envPtr^[envIdx+3] = 'V')
- AND (envPtr^[envIdx+4] = '=')
- THEN
- envPtr^[envIdx] := 0C;
- envPtr^[envIdx+1] := 0C; (* Falls ARGV erste Variable *)
- IF MWCStyle OR (basePtr^.pCmdlin[0] = CHR(127)) THEN
- EXARG := TRUE;
- INC(envIdx, 5);
- WHILE envPtr^[envIdx] <> 0C DO
- INC(envIdx);
- END;
- INC(envIdx); (* Hier beginnt der Programmname *)
- IF envPtr^[envIdx] = 0C THEN
- EXARG := FALSE;
- EXIT; (* Environment zuende: kein ARGV *)
- ELSE
- argIdx := envIdx;
- args := 1;
- END;
- ELSE
- EXIT; (* ARGV entspricht nicht dem Atari-Standard *)
- END;
- END;
- END;
- WHILE envPtr^[envIdx] <> 0C DO
- INC(envIdx);
- END;
- INC(envIdx);
- IF envPtr^[envIdx] = 0C THEN EXIT; END;
- END; (* LOOP *)
- END; (* IF ENV *)
-
- IF args = 0 THEN
- args := 1; (* mindestens Programmname *)
- prgName := "";
- cmdBuf := basePtr^.pCmdlin;
-
- #ifdef USE_AES_FOR_ARGV0
- # warning ...using AES for argv[0]
-
- AUTO := FALSE;
- IF Version() = 0 THEN
- IF ApplInit() < 0 THEN
- AUTO := Version() = 0;
- ELSE
- ApplExit;
- END;
- END;
-
- IF NOT AUTO THEN
- (* AES bereits initialisiert *)
- ShelRead(prgName, cmdBuf);
- IF NOT EQUALN(ORD(cmdBuf[0])+1, cmdBuf, basePtr^.pCmdlin) THEN
- (* Plausibilitaetstest: Wenn die Kommandozeile nicht mit der aus
- * der Basepage uebereinstimmt, ist dieses Programm vermutlich
- * nicht mit "ShelWrite" gestartet worden, und die Ergebnisse
- * von "ShelRead()" stimmen nicht.
- * Dieser Test klappt nicht immer: z.B. nicht, wenn aufrufendes
- * Programm (per ShelWrite gestartet) und aufgerufenes
- * Programm (durch Pexec) ohne Argumente gestartet werden,
- * dann sind naemlich auch beide Kommandozeilen gleich.
- *)
- prgName := "";
- cmdBuf := basePtr^.pCmdlin;
- END;
- END;
- #endif
-
- (* Kommandozeile untersuchen, falls kein (korrektes) ARGV-Verfahren
- * verwendet wurde.
- * Es wird angenommen, dass im ersten Byte der Kommandozeile die
- * korrekte Laenge der Kommandozeile steht (ist das sicher?)!
- *
- * Zuerst muss die Anzahl der Argumente ermittelt werden.
- *)
- cmdLen := ORD(cmdBuf[0]); (* Laenge der Kommandozeile *)
- IF cmdLen > 124 THEN
- cmdLen := 124; (* max. 124 Zeichen ausschl. Laengenbyte *)
- END;
-
- dstIdx := 0;
- srcIdx := 1; (* Laengenbyte ueberspringen *)
- (* Ueberfluessige Leerzeichen zwischen den Argumenten entfernt;
- * dafuer werden sie mit Nullbyte abgeschlossen. Dieses wird aber
- * nur in einer Kopie der Basepage-Kommandozeile vorgenommen.
- *)
- REPEAT
- WHILE (srcIdx <= cmdLen) AND ISSPACE(cmdBuf[srcIdx]) DO
- (* Leerzeichen vor dem Argument entfernen.
- * Entfernt auch das abschliessende CR des Desktops.
- *)
- INC(srcIdx);
- END;
- IF cmdBuf[srcIdx] < ' ' THEN
- (* Controlzeichen (z.B. 0C) beendet auch die Kommandozeile *)
- srcIdx := cmdLen + 1;
- END;
- IF srcIdx <= cmdLen THEN
- WHILE (srcIdx <= cmdLen) AND (cmdBuf[srcIdx] > ' ') DO
- (* Argument ohne Leerzeichen nach vorne schieben *)
- cmdBuf[dstIdx] := cmdBuf[srcIdx];
- INC(srcIdx);
- INC(dstIdx);
- END;
- cmdBuf[dstIdx] := 0C; (* Argument durch Nullbyte abschliessen *)
- INC(srcIdx); (* Argumentende ueberspringen *)
- INC(dstIdx);
- INC(args);
- END;
- UNTIL srcIdx > cmdLen;
- END; (* IF args = 0 *)
-
- IF ENV THEN
- (* Jetzt muss das Environment evtl. korrigiert werden, da der
- * Desktop die Variablen in einem anderen Format als ueblich
- * ablegt (z.B.: "PATH=",0C,"A:\",0C, statt "PATH=A:\",0C).
- * Gleichzeitig wird die Anzahl der Variablen ermittelt.
- *)
- srcIdx := 0;
- dstIdx := 0;
- REPEAT
- REPEAT
- (* Variablenname kopieren, dabei evtl. nach vorne verschieben *)
- c := envPtr^[srcIdx];
- envPtr^[dstIdx] := c;
- INC(srcIdx);
- INC(dstIdx);
- UNTIL (c = 0C) OR (c = '=');
-
- IF (c = '=') THEN
- (* Variable hat evtl. einen Wert *)
- IF (envPtr^[srcIdx] = 0C) AND (envPtr^[srcIdx+1] <> 0C) THEN
- envIdx := srcIdx;
- REPEAT
- INC(envIdx);
- c := envPtr^[envIdx];
- UNTIL (c = 0C) OR (c = '=');
- IF c = 0C THEN
- (* eingeschobenes Nullbyte ignorieren *)
- INC(srcIdx);
- END;
- END;
- REPEAT
- (* Variablenwert kopieren, einschliesslich abschl. NullByte *)
- c := envPtr^[srcIdx];
- envPtr^[dstIdx] := c;
- INC(srcIdx);
- INC(dstIdx);
- UNTIL c = 0C;
- END;
- INC(vars);
- UNTIL envPtr^[srcIdx] = 0C;
- envPtr^[dstIdx] := 0C; (* Environment beendet *)
- END; (* IF ENV *)
-
- envSize := VAL(CARDINAL,(args + vars + 2)) * VAL(CARDINAL,TSIZE(StrPtr));
- (* + 2 wegen Nullpointer *)
- Malloc(VAL(UNSIGNEDLONG, envSize), mem);
- IF mem = NULL THEN
- args := 0;
- vars := 0;
- ELSE
- ENVP := CAST(StrArray,mem);
- IF ENV THEN
- envIdx := 0;
- FOR i := 0 TO vars - 1 DO (* !vars > 0 ist gesichert *)
- ENVP^[i] := CAST(StrPtr,ADR(envPtr^[envIdx]));
- REPEAT
- INC(envIdx);
- UNTIL envPtr^[envIdx] = 0C;
- INC(envIdx); (* Die Null *)
- END;
- END; (* IF ENV *)
- ENVP^[vars] := NULL;
-
- ARGV := CAST(StrArray,ADR(ENVP^[vars+1]));
- IF EXARG THEN
- envIdx := argIdx;
- FOR i := 0 TO args - 1 DO (* !args > 0 ist gesichert *)
- ARGV^[i] := CAST(StrPtr,ADR(envPtr^[envIdx]));
- REPEAT
- INC(envIdx);
- UNTIL envPtr^[envIdx] = 0C;
- INC(envIdx);
- END;
-
- (* Soviel wie moeglich vom ARGV-Environment in die Basepage-Kommandozeile
- * kopieren, falls dies vom Aufrufer nicht getan wurde. Der Programmname
- * wird uebersprungen.
- *)
- WITH basePtr^ DO
- pCmdlin[0] := CHR(127);
- IF args <= 1 THEN
- (* Nur Programmname, keine Argumente *)
- pCmdlin[1] := 0C;
- ELSE
- srcIdx := 0;
- dstIdx := 1;
- cmdPtr := ARGV^[1];
- WHILE dstIdx <= 124 DO
- IF cmdPtr^[srcIdx] <> 0C THEN
- pCmdlin[dstIdx] := cmdPtr^[srcIdx];
- ELSIF cmdPtr^[srcIdx+1] <> 0C THEN
- pCmdlin[dstIdx] := ' ';
- ELSE
- pCmdlin[dstIdx] := 0C;
- dstIdx := 125;
- END;
- INC(dstIdx);
- INC(srcIdx);
- END;
- pCmdlin[125] := 0C;
- END;
- END; (* WITH *)
- ELSE (* NOT EXARG *)
- ARGV^[0] := CAST(StrPtr,ADR(prgName));
- srcIdx := 0;
- FOR i := 1 TO args - 1 DO
- ARGV^[i] := CAST(StrPtr,ADR(cmdBuf[srcIdx]));
- REPEAT
- INC(srcIdx);
- UNTIL cmdBuf[srcIdx] = 0C;
- INC(srcIdx);
- END;
- END;
- ARGV^[args] := NULL;
- END; (* IF mem = NULL *)
-
- ARGC := VAL(CARDINAL,args);
- environ := ENVP;
- END cmdline.
-