[comp.lang.modula2] Command Line/Enviroment Module for MSDOS

elder@WPAFB-INFO2.ARPA ("INFOCEN - Greg Elder") (11/17/86)

    The following files are submitted as a contribution to INFO-MODULA-2.
I've written a module to use with the Logitech Modula-2/86 compiler and MS-DOS
for reading the command line arguments and looking up the values of environment
variables.  This module simulates the argc/argv features of C.  Also,
a procedure called GetEnv is provided which will search the environment for
a given string and return the string's value if found.  The following files
are provided:

	CMDENV.DEF -	Definition module for CmdEnv.
	CMDENV.MOD -	Implementation module for CmdEnv.
	CMDTEST.MOD -   A program to test the ArgC/ArgV variables provided by
			CmdEnv.
	ENVTEST.MOD -	A program to test the GetEnv procedure provided by
			CmdEnv.

Use an editor to extract the various files from this message.

To use, compile CMDENV.DEF and COMDENV.MOD.  Next, compile and link CMDTEST.MOD
and ENVTEST.MOD.  Use the Logitech program LOD2EXE to convert the resulting LOD
files to EXE files (CMDTEST.EXE and ENVTEST.EXE).

CMDTEST will list the arguments found on the command line.  For example,
typing
	A>cmdtest hello world

will produce
	ArgV[ 1]= hello
	ArgV[ 2]= world

When you run ENVTEST, you will be asked for an environment variable.  After
typing in one, the value of the varianble will be displayed (if the variable
is found).  For example,

	A>envtest
	Enter environment variable: COMSPEC
	COMSPEC= A:\COMMAND.COM

Type CONTROL-C to abort envtest.

I hope this module will be of benefit to some people.  I still consider myself
a novice Modula-2 programmer.  Any suggestions to improve my code are welcome.

Greg Elder
================ CUT HERE =====================================================
(*
 * Title:  Command Line/Environment Information (CmdEnv)
 * Author: Gregory Elder
 * Last Update:  September 25, 1986
 * Compiler: Logitech Modula-2/86
 * Description:
 * This module provides argc and argv features similar to C and a procedure
 * for getting the values of environment variables.  ArgC is the count of the
 * number of parameters on the command line.  ArgV is an array of pointers
 * to strings containing the various command line parameters.  GetEnv is
 * a procedure which, when given an enviroment variable, will return the
 * value the variable is set to.
 *
 *)

DEFINITION MODULE CmdEnv;

EXPORT QUALIFIED
	MaxArgs, ArgC, ArgV, GetEnv;
CONST
	MaxArgs     = 10;		(* Max arguments on the command line *)
	ArraySize   = 200;

TYPE
	StringPTR = POINTER TO ARRAY[0..ArraySize] OF CHAR;
	Args = ARRAY[0..MaxArgs] OF StringPTR;

VAR
	ArgC : CARDINAL;
	ArgV : Args;

PROCEDURE GetEnv(EnvVar : ARRAY OF CHAR; VAR Strg : ARRAY OF CHAR);

END CmdEnv.
============ CUT HERE ========================================================
(*
 * Title:  Command Line/Environment Information
 * Author: Gregory Elder
 * Last Update:  September 25, 1986
 * Compiler: Logitech Modula-2/86
 * Description:
 * This module provides argc and argv features similar to C and a procedure
 * for getting the values of environment variables.  ArgC is the count of the
 * number of parameters on the command line.  ArgV is an array of pointers
 * to strings containing the various command line parameters.  GetEnv is
 * a procedure which, when given an enviroment variable, will return the
 * value the variable is set to.
 *
 *)

IMPLEMENTATION MODULE CmdEnv;

FROM SYSTEM IMPORT
	AX, BX, CX, GETREG, SETREG, SWI, RTSVECTOR, ADDRESS;
FROM Storage IMPORT
	ALLOCATE;
FROM ASCII IMPORT
	nul;
FROM Strings IMPORT
	Length, CompareStr;


CONST
	CmdTailAdr  = 80H;
	EnvOffSet   = 2CH;

TYPE
	CardPTR = POINTER TO CARDINAL;

VAR
	PSP, AnAddress : ADDRESS;
	EnvPTR : StringPTR;
	EnvAdrSegment : CardPTR;

PROCEDURE ParseCmdLine;
VAR
	CmdLength, i, j, start : CARDINAL;
	CmdLine, Sptr : StringPTR;
	CmdAdr : ADDRESS;
BEGIN
	CmdAdr := PSP;
	INC(CmdAdr, CmdTailAdr);		(* Get command tail *)
	CmdLine := CmdAdr;
	i := 0;
	CmdLength := ORD(CmdLine^[i]) - 1;
	INC(i);
	WHILE (i <= CmdLength) AND (CmdLine^[i] = ' ') DO
		INC(i);
		END;
	WHILE (i <= CmdLength) AND (CmdLine^[i] # ' ') DO
		INC(i);
		END;
	ArgV[0] := NIL;
	ArgC := 0;
	WHILE i <= CmdLength DO
		WHILE (CmdLine^[i] = ' ') AND (i <= CmdLength) DO
			INC(i);
			END;
		IF i <= CmdLength THEN
			start := i;
			WHILE (CmdLine^[i] # ' ') AND (i <= CmdLength) DO
				INC(i);
				END;
			ALLOCATE(Sptr, i - start + 2);
			j := 0;
			WHILE start <= i DO
				Sptr^[j] := CmdLine^[start];
				INC(start);
				INC(j);
				END;
			Sptr^[j] := nul;
			IF ArgC < MaxArgs THEN
				INC(ArgC);
				ArgV[ArgC] := Sptr;
				END;
			END;
		END;
	i := ArgC + 1;
	LOOP
		IF i > MaxArgs THEN EXIT END;
		ArgV[i] := NIL;
		INC(i);
		END;
END ParseCmdLine;

PROCEDURE GetEnv(EnvVar : ARRAY OF CHAR; VAR Strg : ARRAY OF CHAR);
CONST
	StringSize = 40;
VAR
	i, j, len : CARDINAL;
	Str1, Str2 : ARRAY[0..StringSize-1] OF CHAR;
BEGIN
	len := Length(EnvVar);
	FOR i := 0 TO (len - 1) DO
		IF (EnvVar[i] >= 'a') AND (EnvVar[i] <= 'z') THEN
			Str1[i] := CHR(ORD(EnvVar[i]) - ORD('a') + ORD('A'));
		ELSE
			Str1[i] := EnvVar[i];
			END;
		END;
	Str1[i + 1] := nul;
	i := 0;
	LOOP
		j := 0;
		WHILE (EnvPTR^[i] # '=') AND (EnvPTR^[i] # nul) DO
			Str2[j] := EnvPTR^[i];
			INC(i);
			INC(j);
			END;
		Str2[j] := nul;
		INC(i);
		IF CompareStr(Str1, Str2) = 0 THEN
			j := 0;
			WHILE EnvPTR^[i] # nul DO
				Strg[j] := EnvPTR^[i];
				INC(i);
				INC(j);
				END;
			Strg[j] := nul;
			EXIT;
		ELSE
			WHILE EnvPTR^[i] # nul DO
				INC(i);
				END;
			END;
		INC(i);
		IF EnvPTR^[i] = nul THEN
			Strg[0] := nul;
			EXIT;
			END;
		END;
END GetEnv;

BEGIN

(* Get PSP *)

SETREG(AX, 026H);
SWI(RTSVECTOR);
GETREG(BX, PSP.OFFSET);
GETREG(CX, PSP.SEGMENT);

ParseCmdLine;

(* Set up environment pointer *)

AnAddress := PSP;
INC(AnAddress, EnvOffSet);
EnvAdrSegment := AnAddress;
AnAddress.SEGMENT := EnvAdrSegment^;
AnAddress.OFFSET := 0;
EnvPTR := AnAddress;
END CmdEnv.
==================== CUT HERE =================================================
(*
 * Title:  Command Line Test (CmdTest)
 * Author: Gregory Elder
 * Last Update: November 16, 1986
 * Compiler:  Logitech Modula-2/86 Version 2
 * Description:  This program provides a test for the CmdEnv module.  It
 * simply displays the arguments entered on the command line.  To use it
 * type the following at the DOS prompt:
 *
 *     A>cmdtest [arg1 ... arg10]
 *
 * The information in brackets is optional.  Up to 10 arguments may be
 * typed on the command line.  The program responds by listing the
 * arguments on separate lines.  For example, if you enter
 *
 *     A>cmdtest hello world
 *
 * The program responds with
 *
 *    ArgV[1]= hello
 *    ArgV[2]= world
 *
 *)

MODULE CmdTest;

FROM CmdEnv IMPORT
	ArgC, ArgV;
FROM InOut IMPORT
	WriteString, WriteLn, WriteCard;

VAR
	i : CARDINAL;

BEGIN
IF ArgC = 0 THEN
	WriteString("No Arguments on Command Line");
	WriteLn;
ELSE
	FOR i := 1 TO ArgC DO
		WriteString("ArgV[");
		WriteCard(i, 2);
		WriteString("]= ");
		WriteString(ArgV[i]^);
		WriteLn;
		END;
	END;
END CmdTest.
================ CUT HERE ====================================================
(*
 * Title:  Environment Test (EnvTest)
 * Author:  Gregory Elder
 * Last Update:  November 16, 1986
 * Compiler:  Logitech Modula-2/86 Version 2
 * Description:  Provides a test of the GetEnv procedure from the CmdEnv
 * module.  Prompts user for an environment variable then calls GetEnv
 * to search the environment for that variable.  If the variable is found,
 * its value is displayed to the user.  Type CONTROL-C to abort the program.
 * Test the program with the variables COMSPEC and PATH.
 *
 *)

MODULE EnvTest;

FROM CmdEnv IMPORT
	GetEnv;
FROM InOut IMPORT
	WriteString, WriteLn, ReadString;

VAR
	str1, str2 : ARRAY[0..79] OF CHAR;

BEGIN
str1[0] := 'A';
WHILE str1[0] # 0C DO
	WriteString("Enter environment variable: ");
	ReadString(str1);
	WriteLn;
	IF str1[0] # 0C THEN
		GetEnv(str1, str2);
		WriteString(str1);
		IF str2[0] # 0C THEN
			WriteString("= ");
			WriteString(str2);
		ELSE
			WriteString(" Not Found.");
			END;
		WriteLn;
		END;
	END;
END EnvTest.
------