/úGETENV DEF»kGETENV MAC¼ÕGETENV MCDzçGETENV SYMœ7M2Z3INS1MODQó·READ ME r·qTESTPROGMODoS:DEFINITION MODULE GetEnv; FROM SYSTEM IMPORT ADDRESS; (* Returns ZCPR3/ZCPR3.3 Environment descriptor address if the TM2 program *) (* has been installed by INSTM2Z3 for either of these OS's, other choice *) (* is installation (by INSTM2Z3) for CP/M, in which case "a" is NIL and n *) (* is a 16 char max string which may be used as a file name *) PROCEDURE GetEnv (VAR a : ADDRESS; VAR n : ARRAY OF CHAR); END GetEnv. ; Procedure to return environment descriptor address and a 16 (max) char ; file name to caller. This works in conjunction with the INSTM2Z3 ; program which searches a TM2 generated .COM file for the marker "Z3.3ENV" ; near the end of this procedure and patches this routine as follows: ; The EnvAdr: location and the FilNam: buffer will be patched to 0h ; and the name of a file (TCAP?) if the installation is for CP/M. ; If for ZCPR3 the EnvAdr: location will be patched to the value specified by ; an .ENV file and the FilNam: location will be null. If for ZCPR 3.3, ; FilNam: will be patched to null and the code at the end of this procedure ; will be patched so that register HL (set to point to environment descriptor ; by the ZCPR3.3 loader) will be saved in EnvAdr: before any thing else is ; done and control will return to the TM2 main program to continue the ; initialization of the TM2 .COM program. ; ; By this process a TM2 program can be installed at the binary level and ; gain access to ZCPR3/ZCPR3.3 services. It was intended that in a CP/M ; environment the FilNam: would be used to give the TM2 program access to ; a ZCPR style TCAP file but, in fact, the file name can be used for any ; desired purpose. ; ; FilNam: is large enough (16 char) to accommodate the DU:FILENAME.EXT ; form of file names ; PUBLIC GetEnv GetEnv: POP IY ; save return address POP DE ; array size POP HL ; address of array POP IX ; address of Environment descriptor param PUSH IY ; restore return address LD B, E ; B = Array size; LD A, 0 PUSH HL ; save copy of HL L1: LD (HL), A ; set array to nulls DJNZ L1 LD A, E CP 16 ; test array size JR NC, L2 ; if actual size >= 16 LD B, 16 ; use size of 16 JR L3 L2: LD B, E ; else use actual size L3: LD HL, FilNam ; HL -> source POP DE ; DE -> dest (array address) LDIR ; send file name to caller LD HL, (EnvAdr) ; HL = Environment descriptor address LD (IX), L ; return the environment descriptor to caller LD (IX + 1), H RET ; NOTICE: Modification of the code beyond this point may mean that the ; program INSTM2Z3 will no longer patch it properly!!! DB 'Z3.3ENV' ; ID marker for INSTM2Z3 program EnvAdr: DW 0FE00h ; buffer for environment descriptor address FilNam: DB 0,0,0,0,0,0,0,0 ; file name storage DB 0,0,0,0,0,0,0,0 DB 0 ; marker used by INSTM2Z3. 0 = CP/M, ; 1 = ZCPR3, 2 = ZCPR3.3 LD (EnvAdr), HL ; come here from entry to TM2 program installed ; for ZCPR3.3 only and save HL JP 0 ; return to TM2 program (patched to proper ; address) END  ðA   ADDRESSGetEnvanëÉiÍq‡ÃýáÑáÝáýåC>åwý{þ0C!:Ñí°*8ÝuÝtÉZ3.3ENVþ"8ñÿ¬ÿGETENV ðSe"(LÙ(***************************************************************) (* Copyright 1987 by Edward Jackson. This program is released *) (* into the public domain and may be freely distributed by *) (* others in commercial or non-comercial situations provided *) (* proper credit is given to the author. *) (* *) (* M2Z3INS version 1. *) (* *) (* This program "installs" Turbo Modula2 programs which have *) (* been linked into .COM files in a ZCPR3 environment, ZCPR3.3 *) (* environment, or CP/M environment. This is accomplished by *) (* patching the GetEnv procedure which MUST be included in the *) (* root segment of the TM2 .COM file. A subsequent call to *) (* this procedure will return the address of the resident *) (* environment descriptor or, for CP/M, a NIL address and a *) (* string of up to 16 characters. The string is intended to *) (* be used as a file name for TCAP information but can be used *) (* for any other purpose desired. *) (* *) (* In a ZCPR3 environment the address of the environment *) (* descriptor is obtained from the *.ENV file that is peculiar *) (* to the target system. *) (* *) (* In a ZCPR3.3 environment the address of the environment *) (* descriptor is placed in register HL by the loader after *) (* loading the .COM file. The .COM file is patched by this *) (* installation program so that register HL is saved in the *) (* GetEnv procedure. *) (* *) (* In a CP/M environment there is no environment descriptor *) (* so this instalation program patches the environment des- *) (* criptor address to NIL and the 16 char string to the value *) (* specified at installation time. *) (* *) (* NOTES: Where an environment descriptor is available, the *) (* 16 char string is empty. *) (* *) (* Since many ZCPR systems place the environmen des- *) (* criptor at 0FE00h, this is used as the default *) (* value in GetEnv. *) (* *) (* Special thanks to Steve Cohen for sugesting the basic *) (* approach. *) (***************************************************************) MODULE M2Z3INS1; FROM STORAGE IMPORT ALLOCATE; FROM InOut IMPORT WriteHex; FROM SYSTEM IMPORT ADDRESS, FILL, ADR; FROM ComLine IMPORT PromptFor; FROM Files IMPORT FILE, ReadBytes, ReadByte, WriteBytes, WriteByte, SetPos, NextPos, Open, Close, EOF; FROM Strings IMPORT Append, Pos, Length, CAPS, Delete; FROM Terminal IMPORT ReadChar; CONST Version = 1; (* Version number *) EXCEPTION FileErr; TYPE SysType = (CPM, Z3, Z33); VAR EnvName, Tm2Name : ARRAY [0..15] OF CHAR; TCAPName : ARRAY [0..15] OF CHAR; Environment, Tm2File : FILE; EnvAdr : POINTER TO ADDRESS; InstallType : CHAR; Nbytes, i : CARDINAL; TestStr, Target : ARRAY [0..6] OF CHAR; Switch : SysType; OK : BOOLEAN; c : CHAR; C : ARRAY [0..0] OF CHAR; SwitchStr : ARRAY [0..2] OF CHAR; EnvAdrLoc, JmpBackLoc, TCAPFNLoc, InstallTypeLoc : LONGINT; JmpToAdr, JmpBackAdr : POINTER TO CARDINAL; BEGIN (* Sign on legend *) FOR i := 1 TO 24 DO WRITELN (); END; WRITELN (' TM2/ZCPR3 Installation Program'); WRITELN (' Copyright 1987 by Edward Jackson, Gilroy, CA'); WRITELN (' Released into the Public Domain by the Author'); WRITELN (); WRITELN ('Version ', Version:1); WRITELN (); WRITELN (' Patches .COM files generated by Turbo Modula2 so that the'); WRITELN (' address of the resident environment descriptor is available'); WRITELN (' for use by the program in a ZCPR3 or ZCPR3.3 system. For'); WRITELN (' CP/M systems, a 16 char file name is patched in for use as'); WRITELN (' desired.'); WRITELN (); WRITELN (' Press any key to continue... '); WRITELN (); WRITELN (); WRITELN (); WRITELN (); ReadChar (c); NEW (EnvAdr); NEW (JmpToAdr); NEW (JmpBackAdr); (* Get target system type *) PromptFor ("Patch for CP/M, ZCPR3 or ZCPR3.3? [C, 3 or 3.3] ", SwitchStr); IF SwitchStr = "C" THEN Switch := CPM; ELSIF SwitchStr = "3" THEN Switch := Z3; ELSIF SwitchStr = "3.3" THEN Switch := Z33; ELSE WRITELN ("Invalid system designation!"); HALT; END; FILL (ADR (TCAPName), 16, 0); (* get the arguments required for the target system type *) IF Switch = Z3 THEN PromptFor ("Enter name of Environment Descriptor File: ", EnvName); PromptFor ('Enter name of TM2 "COM" file to be installed: ', Tm2Name); CAPS (EnvName); ELSIF Switch = CPM THEN PromptFor ('Enter 16 character name of TCAP file: ', TCAPName); CAPS (TCAPName); PromptFor ('Enter name of TM2 "COM" file to be installed: ', Tm2Name); ELSE PromptFor ('Enter name of TM2 "COM" file to be installed: ', Tm2Name); END; (* do some error checking on the arguments *) CAPS (Tm2Name); IF Pos (".COM", Tm2Name) <> (Length (Tm2Name) - 4) THEN WRITELN ('Can only install "COM" files.'); HALT; END; IF Switch = Z3 THEN OK := Open (Environment, EnvName); IF NOT OK THEN WRITELN ("Can't find environment file!"); HALT; END; END; OK := Open (Tm2File, Tm2Name); IF NOT OK THEN WRITELN ("Can't find TM2 file!"); HALT; END; (* Search for "Z3.3ENV" string in the .COM file *) (* It is embedded in the GetEnv procedure *) SetPos (Tm2File, 7000L); (* start near end of TM2 Run Time routines *) TestStr := ''; Target := 'Z3.3ENV'; LOOP IF EOF (Tm2File) THEN (* "Z3.3ENV" not found *) WRITELN ("Can't install this program"); Close (Tm2File); HALT; END; (* Read a char at a time and add to test string. If test string length > 0 *) (* and a partial match is not found at front of string, discard the first *) (* char in test string and continue. EXIT Loop when test string = *) (* "Z3.3ENV" *) ReadByte (Tm2File, c); C [0] := c; Append (C, TestStr); WHILE (Length (TestStr) > 0) AND (Pos (TestStr, Target) <> 0) DO Delete (TestStr, 0, 1); END; IF TestStr = Target THEN EXIT; END END; (* record important locations in Tm2File *) EnvAdrLoc := NextPos (Tm2File); JmpToAdr^ := CARD (EnvAdrLoc) + 19 + 256; (* corrected for load at 100h *) JmpBackLoc := EnvAdrLoc + 23L; InstallTypeLoc := EnvAdrLoc + 18L; TCAPFNLoc := EnvAdrLoc + 2L; (* save current jumpback address *) SetPos (Tm2File, JmpBackLoc); Nbytes := ReadBytes (Tm2File, JmpBackAdr, 2); IF Nbytes <> 2 THEN RAISE FileErr; END; (* Get current installation type (0 = CPM, 1 = ZCPR3, 2 = ZCPR3.3) *) SetPos (Tm2File, InstallTypeLoc); ReadByte (Tm2File, InstallType); (* If current install type ZCPR3.3 then must unpatch first *) IF InstallType = 2C THEN SetPos (Tm2File, 1L); WriteBytes (Tm2File, JmpBackAdr, 2); END; (* Always set the TCAP File name buffer with nulls if target not CP/M *) SetPos (Tm2File, TCAPFNLoc); WriteBytes (Tm2File, ADR (TCAPName), 16); (* If target is ZCPR3 Get Environment descriptor address from *.ENV file *) IF Switch = Z3 THEN SetPos (Environment, 27L); Nbytes := ReadBytes (Environment, EnvAdr, 2); Close (Environment); IF Nbytes <> 2 THEN RAISE FileErr; END; WRITE ('Environment Descriptor Address is: '); WriteHex (CARDINAL (EnvAdr^), 0); WRITELN (); (* Patch the .COM file for target system = ZCPR3 *) SetPos (Tm2File, EnvAdrLoc); WriteBytes (Tm2File, EnvAdr, 2); InstallType := CHR (ORD (Switch)); (* Mark as installed for ZCPR3 *) SetPos (Tm2File, InstallTypeLoc); WriteByte (Tm2File, InstallType); ELSIF Switch = CPM THEN EnvAdr^ := 0; (* Patch the .COM file for target system = CP/M *) SetPos (Tm2File, EnvAdrLoc); WriteBytes (Tm2File, EnvAdr, 2); InstallType := CHR (ORD (Switch)); (* Mark as installed for CP/M *) SetPos (Tm2File, InstallTypeLoc); WriteByte (Tm2File, InstallType); ELSE (* Patch the .COM file for target system = ZCPR3.3 *) SetPos (Tm2File, 1L); Nbytes := ReadBytes (Tm2File, JmpBackAdr, 2); IF Nbytes <> 2 THEN RAISE FileErr; END; SetPos (Tm2File, InstallTypeLoc); (* mark target system type *) InstallType := CHR (ORD (Switch)); WriteByte (Tm2File, InstallType); SetPos (Tm2File, 1L); WriteBytes (Tm2File, JmpToAdr, 2); (* Patch to code that saves HL *) SetPos (Tm2File, JmpBackLoc); WriteBytes (Tm2File, JmpBackAdr, 2); (* Patch return Tm2 Init code *) WRITELN (); WRITELN (Tm2Name, ' is now patched so that the Environment Descriptor'); WRITELN ('will be saved inside the GetEnv procedure when the file is'); WRITELN ('loaded by ZCPR3.3'); END; Close (Tm2File); WRITELN (); WRITELN ('Installation complete.'); EXCEPTION | FileErr : Close (Tm2File); WRITELN ('Error reading Tm2 file'); HALT; END M2Z3INS1. MODULE TESTPROG; FROM InOut IMPORT WriteHex; FROM SYSTEM IMPORT ADR, ADDRESS; FROM GetEnv IMPORT GetEnv; VAR a : ADDRESS; n : ARRAY [0..15] OF CHAR; BEGIN GetEnv (a, n); WriteHex (CARDINAL (a), 6); WRITELN (); WRITELN ('/', n, '/'); END TESTPROG. The program M2Z3INS1 is an installation program whose purpose is to make the ZCPR environment descriptor address available inside a Turbo Modula2 program. In ZCPR3.3 systems the TM2 program becomes self adapting... that is, after installing it with the M2Z3INS1 program it can be moved to any ZCPR3.3 system and it will correctly find the environment descriptor. In ZCPR3 systems the TM2 program must be reinstalled if moved to another computer to guarantee that it will correctly find the environment descriptor. In CP/M systems there is, of course, no environment descriptor but the installation program permits installing a 16 char string in the TM2 program. The intended use of the string is to install the name of a file containing system environment info (TCAP?) but it's use is not restricted. The system works by searching the TM2 .COM file 1 char at a time for a unique marker (don't be surprised if it takes rather a long time on floppy disks!). Just after the marker the .COM file is patched to insert the address of the resident environment descriptor and a 16 char array. Thanks to Steve Cohen for suggesting the basic approach! To use the installation program you MUST include the GetEnv procedure in your TM2 code. Compile the code and link it into a .COM file. After the installation process a call to GetEnv will return the address of the environment descriptor and the 16 char string. I'm working on a procedure to extract the addresses of things in the environment descriptor by it isn't quite complete yet. Perhaps one of you out there in "Z Country" will tackle a procedure to translate named directories to the DU: form and vice versa! Ed Jackson 10/20/87