IMPLEMENTATION MODULE EnvironUtils; (* * REPERTOIRE * Release 1.6 * By Charles Bradford and Cole Brecheen * (c) Copyright 1985-1991 PMI * Portland, Oregon * All rights reserved * (503) 236-1788 * * $Header: D:/logfiles/mods/environu.mov 1.9 17 Mar 1991 17:52:14 coleb $ *) (*EntryDiag: IMPORT Diagnostics; :EntryDiag*) IMPORT ByteFiddler; IMPORT ErrorManager; IMPORT LowLevel; IMPORT M2Strings; IMPORT FAPI; IMPORT PosUtils; IMPORT StrConv; IMPORT StrEdit; IMPORT StringIO; IMPORT SYSTEM; IMPORT VStorage; VAR Initialized : BOOLEAN; PROCEDURE Init(); BEGIN IF Initialized THEN RETURN; ELSE Initialized := TRUE; END; (*EntryDiag: Diagnostics.Init(); :EntryDiag*) ByteFiddler.Init(); ErrorManager.Init(); LowLevel.Init(); M2Strings.Init(); PosUtils.Init(); StrConv.Init(); StrEdit.Init(); StringIO.Init(); VStorage.Init(); END Init; PROCEDURE CutFirstParam(VAR TheStr : ARRAY OF CHAR); (* use when running under Logitech's run-time debugger *) VAR spot : CARDINAL; BEGIN StrEdit.CrunchBlanks(TheStr); spot := M2Strings.Pos(' ',TheStr); IF spot<=HIGH(TheStr) THEN M2Strings.Delete(TheStr, 0, spot+1); ELSE StrEdit.SetLength(TheStr, 0); END; END CutFirstParam; PROCEDURE GetProgParams(VAR ParamStr : ARRAY OF CHAR); VAR StrAdr : LowLevel.Address8086; knownLength, errcode, cnt, tmpw, CmdLineOffs : CARDINAL; tmpc : CHAR; LastWasNull: BOOLEAN; machineMode: CARDINAL; BEGIN machineMode := 0; (* Have to initialize machineMode because DOSGETMACHINEMODE is * actually expecting the address of a single byte; we use a * CARDINAL because JPI is obstinate about letting us compare * byte values with the constants in FAPI.DEF. *) errcode := FAPI.DOSGETMACHINEMODE(SYSTEM.ADR(machineMode)); IF machineMode = FAPI.MODE_REAL THEN StrAdr.seg := GetPSP(); StrAdr.off := 81H; knownLength := ORD(LowLevel.PeekByte(StrAdr.seg, StrAdr.off - 1)); ELSE knownLength := 0FFFFH; (* In protected mode, the command line follows the * environment block. Not so in real mode. It's in the PSP * in real mode. And in real mode, you have to pay attention * to the length byte that precedes the command line. You * can't count on null termination, which is the only thing * that signals the end of the command line in protected * mode. *) IF FAPI.DOSGETENV( SYSTEM.ADR(StrAdr.seg), SYSTEM.ADR(CmdLineOffs )) # 0 THEN ErrorManager.WARN( "Failed to get command line." ); END; StrAdr.off := CmdLineOffs; tmpc := LowLevel.PeekByte(StrAdr.seg,StrAdr.off ); WHILE (tmpc # 0C) DO (* Now we start on the fully qualified name of the program. *) INC(StrAdr.off); tmpc := LowLevel.PeekByte(StrAdr.seg, StrAdr.off); END; INC( StrAdr.off ); END; LowLevel.Fill( SYSTEM.ADR(ParamStr), HIGH(ParamStr) + 1, 0C ); (* Fill the whole thing with nulls so we don't have to worry about terminating the string in the right place. *) cnt := 0; tmpc := StrAdr.b^; (* If there are any parameters at all, this will always be a space. *) WHILE (tmpc # 0C) AND (tmpc # 377C) AND (cnt <= HIGH(ParamStr)) AND ((cnt + 1) < knownLength) DO (* Now we are on the parameters. *) INC(StrAdr.off); tmpc := StrAdr.b^; ParamStr[ cnt ] := tmpc; INC( cnt ); END; END GetProgParams; PROCEDURE ParsedParam( ParamNum: CARDINAL; VAR Result: ARRAY OF CHAR ): BOOLEAN; VAR ParamCnt, BlankSpot1, BlankSpot2: CARDINAL; FullLine: ARRAY [0..255] OF CHAR; BEGIN GetProgParams( FullLine ); StrEdit.CrunchBlanks( FullLine ); StrEdit.Append( FullLine, ' ' ); IF M2Strings.Length( FullLine ) > 1 THEN IF (ParamNum = 0) THEN ErrorManager.WARN('Zero passed to ParsedParam'); END; ParamCnt := 0; BlankSpot1 := 0; BlankSpot2 := 0; WHILE (ParamCnt < ParamNum) AND (BlankSpot2 <= HIGH(FullLine) ) DO BlankSpot2 := PosUtils.Positn( ' ', FullLine, BlankSpot2 ); INC( ParamCnt ); IF ParamCnt < ParamNum THEN BlankSpot1 := BlankSpot2; INC( BlankSpot2 ); END; END; IF BlankSpot2 > HIGH(FullLine) THEN RETURN(FALSE); ELSE IF BlankSpot1 # 0 THEN INC(BlankSpot1); END; M2Strings.Copy( FullLine, BlankSpot1, BlankSpot2 - BlankSpot1, Result ); RETURN(TRUE); END; ELSE RETURN(FALSE); END; END ParsedParam; PROCEDURE GetDosVersion(VAR major, minor : CARDINAL); VAR tmpc : CARDINAL; BEGIN tmpc := 0; FAPI.DOSGETVERSION( SYSTEM.ADR(tmpc )); major := ORD( CHAR(ByteFiddler.HighByte( tmpc )) ); minor := ORD( CHAR(ByteFiddler.LowByte( tmpc )) ); END GetDosVersion; PROCEDURE GetPSP() : CARDINAL; VAR rgstr : LowLevel.regpack; errcode, DosVersion, Subvers, PSPseg : CARDINAL; machineMode: CARDINAL; BEGIN machineMode := 0; (* Have to initialize machineMode because DOSGETMACHINEMODE is * actually expecting the address of a single byte; we use a * CARDINAL because JPI is obstinate about letting us compare * byte values with the constants in FAPI.DEF. *) errcode := FAPI.DOSGETMACHINEMODE(SYSTEM.ADR(machineMode)); IF machineMode = FAPI.MODE_REAL THEN GetDosVersion(DosVersion, Subvers); IF DosVersion >= 3 THEN rgstr.a.h := 142C; (* 62H *) ELSE rgstr.a.h := 121C; (* 51H *) END; LowLevel.msdos( rgstr); IF LowLevel.FlaggedError(rgstr.flags) THEN ErrorManager.WarnNumber("DOS error getting PSP:", ORD(rgstr.a.l)); END; RETURN (rgstr.b.x); ELSE ErrorManager.WARN("Attempt to GetPSP in protected mode"); END; RETURN(0); END GetPSP; PROCEDURE EnvironmentSeg(): CARDINAL; VAR pspSeg, envSeg, cmdlineOffs, errcode: CARDINAL; machineMode: CARDINAL; BEGIN machineMode := 0; (* Have to initialize machineMode because DOSGETMACHINEMODE is * actually expecting the address of a single byte; we use a * CARDINAL because JPI is obstinate about letting us compare * byte values with the constants in FAPI.DEF. *) errcode := FAPI.DOSGETMACHINEMODE(SYSTEM.ADR(machineMode)); IF machineMode = FAPI.MODE_REAL THEN (* We break out the steps to make them easier to see in CodeView. *) pspSeg := GetPSP(); envSeg := LowLevel.PeekWord( pspSeg, 2CH ); (*Get segment address of the environment from PSP.*) ELSE errcode := FAPI.DOSGETENV(SYSTEM.ADR(envSeg), SYSTEM.ADR(cmdlineOffs)); (*Even though this is FAPI, it just doesn't seem to work under DOS. That's why we're doing it differently depending on the mode we're in. cmdlineOffs is telling us where the command line is in the environment segment, but we don't care about that now.*) END; RETURN envSeg; END EnvironmentSeg; PROCEDURE ReadEnvironment(name : ARRAY OF CHAR; VAR parameter : ARRAY OF CHAR); VAR bufch : CHAR; tmpcopy : ARRAY [0..255] OF CHAR; (*expanded from [0..80] on 11 Nov 86*) found : BOOLEAN; cmdlineOffs, pspSeg, errcode, EnvSeg, EnvNdx, cnt, EqSpot: CARDINAL; machineMode: SYSTEM.BYTE; BEGIN EnvSeg := EnvironmentSeg(); (* We'd like to call DOSSCANENV here, but it's not FAPI. *) EnvNdx := 0; found := FALSE; StrEdit.SetLength(parameter, 0); StrEdit.CAPstr( name ); REPEAT StrEdit.SetLength(tmpcopy, 0); bufch := LowLevel.PeekByte(EnvSeg,EnvNdx); WHILE bufch # 0C DO bufch := CAP(bufch); StrEdit.Append(tmpcopy, bufch); INC(EnvNdx); bufch := LowLevel.PeekByte(EnvSeg,EnvNdx); END; IF M2Strings.Pos(name,tmpcopy)=0 THEN EqSpot := M2Strings.Pos('=',tmpcopy); IF (EqSpot16) DO lasttry := try; try := lowtry + (try-lowtry) DIV 2; END; IF ((lasttry-try) > within) AND (try>16) THEN lowtry := try; try := try + (lasttry-try) DIV 2; ELSE EXIT; END; END; IF try<=16 THEN RETURN 0; ELSE RETURN try; END; END MemAvail; BEGIN Initialized := FALSE; Init(); END EnvironUtils.