home *** CD-ROM | disk | FTP | other *** search
- {**************************************************************************
- * MEMU - utility unit for TSR Utilities. *
- * Copyright (c) 1991 Kim Kokkonen, TurboPower Software. *
- * May be freely distributed and used but not sold except by permission. *
- * *
- * Version 3.0 9/24/91 *
- * first release *
- * Version 3.1 11/4/91 *
- * update for new WATCH identification behavior *
- * update HasEnvironment for programs that shrink env size to 0 *
- * Version 3.2 11/22/91 *
- * add FindHiMemStart function to generalize high memory access *
- * modify FindTheBlocks for new high memory approach *
- * add MergeHiMemBlocks procedure to merge memory blocks in hi mem *
- * add ValidPsp function to determine whether a Psp still exists *
- * Version 3.3 1/8/92 *
- * add NextArg function to parse command lines more flexibly *
- * Version 3.4 2/14/92 *
- * change NextArg to ignore embedded '-' *
- * change FindTheBlocks to support new /L switches in MAPMEM, DISABLE *
- * change StripNonAscii to allow European accented characters *
- ***************************************************************************}
-
- {$R-,S-,I-,V-,B-,F-,A-,E-,N-,G-,X-}
-
- unit MemU;
- {-Miscellaneous memory functions needed for TSR Utilities}
-
- interface
-
- const
- {!!!!!! Following may change when WATCH reassembled. Check WATCH.MAP !!!!!}
- ChangeVectors = $320;
- OrigVectors = $720;
-
- {Offsets into resident copy of WATCH.COM for data storage}
- WatchOfs = $80; {Location of length of command line}
- WatchOffset = $81; {Location of start of command line}
- NextChange = $104; {Data structures within WATCH}
- WatchId = 'TSR WATCHER'; {ID placed in WATCH command line}
- MaxChanges = 128; {Maximum number of vector changes stored in WATCH}
-
- Version = '3.4'; {TSR Utilities version number}
- MarkID = 'MM3.4 TSR'; {Marking string for TSR MARK}
- FmarkID = 'FM3.4 TSR'; {Marking string for TSR file mark}
- NmarkID = 'MN3.4 TSR'; {Marking string for TSR file mark}
- NetMarkID = 'MN34'; {ID at start of net mark file}
-
- {Offsets into resident mark copies for id strings}
- MarkOffset = $103; {Where markID is found in MARK TSR}
- FmarkOffset = $60; {Where FmarkID is found in FMARK TSR}
- NmarkOffset = $60; {Where NmarkID is found in FMARK TSR}
-
- {Offsets into resident copy of MARK for data storage}
- VectorOffset = $120; {Where vector table is stored}
- EGAsavOffset = $520; {Where the EGA save save is stored}
- IntComOffset = $528; {Where the interapps comm area is stored}
- ParentOffset = $538; {(TER) Where parent's PSP segment is stored}
- ParLenOffset = $53A; {Where parent's PSP mcb length is stored}
- EMScntOffset = $53C; {Where count of EMS active pages is stored}
- EMSmapOffset = $53E; {Where the page map is stored}
-
- const
- MaxBlocks = 256; {Max number of DOS allocation blocks supported}
-
- ProtectChar = '!'; {Marks whose name begins with this will be
- released ONLY if an exact name match occurs}
-
- const
- RBR = 0; {Receiver buffer register offset}
- THR = 0; {Transmitter buffer register offset}
- BRL = 0; {Baud rate low}
- BRH = 1; {Baud rate high}
- IER = 1; {Interrupt enable register}
- IIR = 2; {Interrupt identification register}
- LCR = 3; {Line control register}
- MCR = 4; {Modem control register}
- LSR = 5; {Line status register}
- MSR = 6; {Modem status register}
-
- type
- OS =
- record
- O, S : Word;
- end;
-
- StringPtr = ^String;
-
- NameArray = array[1..8] of Char;
-
- McbPtr = ^Mcb;
- Mcb =
- record
- Id : Char;
- Psp : Word;
- Len : Word;
- Unused : array[1..3] of Byte;
- Name : NameArray;
- end;
-
- Block =
- record {Store info about each memory block}
- mcb : Word;
- psp : Word;
- releaseIt : Boolean;
- end;
-
- BlockType = 0..MaxBlocks;
- BlockArray = array[1..MaxBlocks] of Block;
-
- McbGroup =
- record
- Count : Word;
- Mcbs : array[1..MaxBlocks] of
- record
- mcb : Word;
- psp : Word;
- end;
- end;
-
- ChangeBlock =
- record {Store info about each vector takeover}
- VecNum : byte;
- case ID : byte of
- 0, 1 : (VecOfs, VecSeg : Word);
- 2 : (SaveCode : array[1..6] of byte);
- $FF : (PspAdd : Word);
- end;
- {
- ID is interpreted as follows:
- 00 = ChangeBlock holds the new pointer for vector vecnum
- 01 = ChangeBlock holds pointer for vecnum but the block is disabled
- 02 = ChangeBlock holds the code underneath the vector patch
- FF = ChangeBlock holds the segment of a new PSP
- }
- ChangeArray = array[0..MaxChanges] of ChangeBlock;
-
- {Structure of a device driver header}
- DeviceHeader =
- record
- NextHeaderOffset : Word; {Offset address of next device in chain}
- NextHeaderSegment : Word; {Segment address of next device in chain}
- Attributes : Word; {Device attributes}
- StrategyEntPt : Word; {Offset in current segment - strategy}
- InterruptEntPt : Word; {Offset in current segment - interrupt}
- DeviceName : array[1..8] of Char; {Name of the device}
- end;
- DeviceHeaderPtr = ^DeviceHeader;
- DeviceArray = array[1..256] of DeviceHeaderPtr;
-
- FileRec =
- record
- OpenCnt : Word;
- OpenMode : Word;
- Attribute : Byte;
- Unknown1 : Word;
- DCB : Pointer;
- InitCluster : Word;
- Time : Word;
- Date : Word;
- Size : LongInt;
- Pos : LongInt;
- BeginCluster : Word;
- CurCluster : Word;
- Block : Word;
- Unknown2 : Byte; {Varies with DOS version beyond here}
- Name : array[0..7] of Char;
- Ext : array[0..2] of Char;
- Unknown3 : array[0..5] of Byte;
- Owner : Word;
- Unknown4 : Word;
- end;
-
- SftRecPtr = ^SftRec;
- SftRec =
- record
- Next : SftRecPtr;
- Count : Word;
- Files : array[1..255] of FileRec;
- end;
-
- DosRec =
- record
- McbSeg : Word;
- FirstDPB : Pointer;
- FirstSFT : SftRecPtr;
- ClockDriver : Pointer;
- ConDriver : Pointer;
- MaxBlockBytes : Word;
- CachePtr : Pointer;
- DriveTable : Pointer;
- FcbTable : Pointer;
- ProtectedFcbCount : Word;
- BlockDevices : Byte;
- LastDrive : Byte;
- NullDevice : DeviceHeader;
- JoinedDrives : Byte; {Following valid DOS 4.0 or later}
- SpecialProgOfs : Word;
- IFSPtr : Pointer;
- IFSList : Pointer;
- BuffersX : Word;
- BuffersY : Word;
- BootDrive : Byte;
- Unknown1 : Byte;
- ExtMemSize : Word;
- end;
- DosRecPtr = ^DosRec;
-
- ComRec = {State of the communications system}
- record
- Base : Word;
- IERReg : Byte;
- LCRReg : Byte;
- MCRReg : Byte;
- BRLReg : Byte;
- BRHReg : Byte;
- end;
- ComArray = array[1..2] of ComRec;
-
- const
- Digits : array[0..$F] of Char = '0123456789ABCDEF';
- DosDelimSet : set of Char = ['\', ':', #0];
-
- var
- DosVM : Byte; {Minor DOS version number}
- DosV : Byte; {Major DOS version number}
- DosVT : Word absolute DosVM; {Combined version number}
- DosList : Pointer; {Pointer to DOS list of lists}
- Mcb1 : McbPtr; {First MCB in system}
-
- function GetDosListPtr : Pointer;
- {-Return address of DOS list of lists}
-
- function GetUmbLinkStatus : Boolean;
- {-Return status of DOS 5 upper memory block link}
-
- function SetUmbLinkStatus(On : Boolean) : Word;
- {-Change state of DOS 5 upper memory block link}
-
- function DosVersion : Word;
- {-Return DOS version number with high byte = major version number}
-
- function TopOfMemSeg : Word;
- {-Return segment of top of normal memory}
-
- function FindHiMemStart : word;
- {-Return segment of first mcb in high memory, 0 if none}
-
- procedure MergeHiMemBlocks(HiMemSeg : Word);
- {-Merge adjacent blocks in high memory, starting with HiMemSeg}
-
- function HexB(B : Byte) : String;
- {-Return hex string for byte}
-
- function HexW(W : Word) : String;
- {-Return hex string for word}
-
- function HexPtr(P : Pointer) : string;
- {-Return hex string for pointer}
-
- function StUpcase(S : String) : String;
- {-Return the uppercase string}
-
- function JustFilename(PathName : String) : String;
- {-Return just the filename of a pathname}
-
- function JustName(PathName : String) : String;
- {-Return just the name (no extension, no path) of a pathname}
-
- function Extend(S : String; Len : Byte) : String;
- {-Truncate or pad S to length Len}
-
- function SmartExtend(S : String; Len : Byte) : String;
- {-Truncate or pad S to length Len; end with '...' if truncated}
-
- function Asc2Str(Name : NameArray) : String;
- {-Convert array[1..8] of char to string}
-
- procedure StripNonAscii(var S : String);
- {-Return an empty string if input contains non-ASCII characters}
-
- function CommaIze(L : LongInt; Width : Byte) : String;
- {-Convert L to a string and add commas for thousands}
-
- function HasEnvironment(HiMemSeg : Word; M : McbPtr) : Boolean;
- {-Return True if M has an associated environment block}
-
- function ValidPsp(HiMemSeg, PspSeg, PspLen : Word) : Boolean;
- {-Return True if PspSeg is a valid, existing Psp}
-
- function NameFromEnv(M : McbPtr) : String;
- {-Return M's name from its environment (already known to exist)}
-
- function NameFromMcb(M : McbPtr) : String;
- {-Return name from the Mcb (DOS 4+ only)}
-
- function MasterCommandSeg : Word;
- {-Return PSP segment of master COMMAND.COM}
-
- function WatchPspSeg : Word;
- {-Find copy of WATCH.COM in memory, returning its PSP segment or 0}
-
- procedure FindTheBlocks(UseLoMem : Boolean;
- HiMemSeg : Word;
- var Blocks : BlockArray;
- var BlockMax : BlockType;
- var StartMcb : Word;
- var CommandSeg : Word);
- {-Scan memory for the allocated memory blocks}
-
- procedure StuffKey(W : Word);
- {-Stuff one key into the keyboard buffer}
-
- procedure StuffKeys(Keys : string; ClearFirst : Boolean);
- {-Stuff up to 16 keys into keyboard buffer}
-
- function ExistFile(path : String) : Boolean;
- {-Return true if file exists}
-
- function NextArg(S : String; var SPos : Word) : String;
- {-Return next argument beginning at SPos in S.
- Increment SPos to point past the argument.
- Arguments are delimited by white space, and '/'.}
-
- procedure IntsOff;
- {-Turn off CPU interrupts}
- inline($FA);
-
- procedure IntsOn;
- {-Turn on CPU interrupts}
- inline($FB);
-
- procedure NullJump;
- {-Slight delay}
- inline($EB/$00);
-
- {=======================================================================}
-
- implementation
-
- uses
- xms;
-
- function GetDosListPtr : Pointer; Assembler;
- {-Return address of DOS list of lists}
- asm
- mov ah,$52
- int $21
- mov dx,es
- mov ax,bx
- end;
-
- function GetUmbLinkStatus : Boolean; Assembler;
- {-Return status of DOS 5 upper memory block link}
- asm
- mov ax,$5802
- int $21
- end;
-
- function SetUmbLinkStatus(On : Boolean) : Word; Assembler;
- {-Change state of DOS 5 upper memory block link}
- asm
- mov ax,$5803
- mov bl,On
- xor bh,bh
- int $21
- jc @1
- xor ax,ax
- @1:
- end;
-
- function DosVersion : Word; Assembler;
- {-Return major DOS version number}
- asm
- mov ah,$30
- int $21
- xchg ah,al
- end;
-
- function TopOfMemSeg : Word;
- {-Return segment of top of memory}
- var
- KBRAM : Word;
- begin
- asm
- int $12
- mov KBRAM,ax
- end;
- TopOfMemSeg := KBRAM shl 6;
- end;
-
- function FindHiMemStart : word;
- {-Return segment of first mcb in high memory}
- var
- Segment : word;
- Size : word;
- Mseg : word;
- M : mcbptr;
- N : mcbptr;
- Status : byte;
- Done : boolean;
- Invalid : boolean;
- begin
- {assume failure}
- FindHiMemStart := 0;
-
- {assure XMS driver installed}
- if not XmsInstalled then
- Exit;
-
- {look for umbs}
- Status := AllocateUmbMem($FFFF, Segment, Size);
- case status of
- $B0, $B1 : ; {UMBs are possible, but not to allocate $FFFF paragraphs}
- else
- Exit; {UMBs are not possible}
- end;
-
- {find the starting umb}
- Mseg := TopOfMemSeg;
- Done := False;
- repeat
- M := Ptr(Mseg, 0);
- case M^.Id of
- 'M' {, 'Z'} : {There must be at least 2 mcbs in high memory}
- begin
- {determine whether this is a valid chain of mcbs}
- N := M;
- Invalid := False;
- repeat
- case N^.Id of
- 'M' :
- if $FFFE-N^.Len >= OS(N).S then
- {next mcb won't land beyond $FFFF}
- N := Ptr(OS(N).S+N^.Len+1, 0)
- else
- Invalid := true;
- 'Z' :
- begin
- {found end of chain starting at M}
- FindHiMemStart := Mseg;
- Done := True;
- end;
- else
- Invalid := True;
- end;
- until Done or Invalid;
- end;
- end;
- if Mseg < $FFFF then
- inc(Mseg)
- else
- Done := True;
- until Done;
- end;
-
- procedure MergeHiMemBlocks(HiMemSeg : Word);
- {-Merge adjacent blocks in high memory, starting with HiMemSeg}
- var
- M : McbPtr;
- N : McbPtr;
- Done : Boolean;
- begin
- if HiMemSeg = 0 then
- Exit;
- M := Ptr(HiMemSeg, 0);
- Done := False;
- repeat
- Done := (M^.Id = 'Z');
- if not Done then begin
- N := Ptr(OS(M).S+M^.Len+1, 0);
- if (M^.Psp = 0) and (N^.Psp = 0) then begin
- {This block and the next are both free}
- inc(M^.Len, N^.Len+1);
- M^.Id := N^.Id;
- end else
- M := N;
- end;
- until Done;
- end;
-
- function HexB(B : Byte) : String;
- {-Return hex string for byte}
- begin
- HexB[0] := #2;
- HexB[1] := Digits[B shr 4];
- HexB[2] := Digits[B and $F];
- end;
-
- function HexW(W : Word) : String;
- {-Return hex string for word}
- begin
- HexW[0] := #4;
- HexW[1] := Digits[Hi(W) shr 4];
- HexW[2] := Digits[Hi(W) and $F];
- HexW[3] := Digits[Lo(W) shr 4];
- HexW[4] := Digits[Lo(W) and $F];
- end;
-
- function HexPtr(P : Pointer) : string;
- {-Return hex string for pointer}
- begin
- HexPtr := HexW(OS(P).S)+':'+HexW(OS(P).O);
- end;
-
- function StUpcase(s : String) : String;
- {-Return the uppercase string}
- var
- i : Byte;
- begin
- for i := 1 to Length(s) do
- s[i] := UpCase(s[i]);
- StUpcase := s;
- end;
-
- function JustFilename(PathName : String) : String;
- {-Return just the filename of a pathname}
- var
- I : Word;
- begin
- I := Word(Length(PathName))+1;
- repeat
- Dec(I);
- until (PathName[I] in DosDelimSet) or (I = 0);
- JustFilename := Copy(PathName, I+1, 64);
- end;
-
- function JustName(PathName : String) : String;
- {-Return just the name (no extension, no path) of a pathname}
- var
- DotPos : Byte;
- begin
- PathName := JustFilename(PathName);
- DotPos := Pos('.', PathName);
- if DotPos > 0 then
- PathName := Copy(PathName, 1, DotPos-1);
- JustName := PathName;
- end;
-
- function Extend(S : String; Len : Byte) : String;
- {-Truncate or pad S to length Len}
- begin
- if Length(S) < Len then
- FillChar(S[Length(S)+1], Len-Length(S), ' ');
- S[0] := Char(Len);
- Extend := S;
- end;
-
- function SmartExtend(S : String; Len : Byte) : String;
- {-Truncate or pad S to length Len; end with '...' if truncated}
- begin
- if Length(S) > Len then
- SmartExtend := copy(S, 1, Len-3)+'...'
- else
- SmartExtend := Extend(S, Len);
- end;
-
- function Asc2Str(Name : NameArray) : String;
- {-Convert array[1..8] of char to string}
- var
- I : Integer;
- begin
- I := 1;
- while (I <= 8) and (Name[I] <> #0) and (Name[I] <> ' ') do begin
- Asc2Str[I] := Name[I];
- Inc(I);
- end;
- Asc2Str[0] := Char(I-1);
- end;
-
- procedure StripNonAscii(var S : String);
- {-Return an empty string if input contains non-ASCII characters}
- var
- I : Integer;
- Ok : Boolean;
- begin
- Ok := True;
- I := 1;
- while Ok and (I <= Length(S)) do begin
- case S[I] of
- #0..#31, #127, #166..#255 : Ok := False;
- end;
- Inc(I);
- end;
- if not Ok then
- S := '';
- end;
-
- function CommaIze(L : LongInt; Width : Byte) : String;
- {-Convert L to a string and add commas for thousands}
- var
- I : Word;
- Len : Word;
- S : String[19];
- begin
- Str(L, S);
- Len := Length(S);
- I := Len;
- while I > 1 do begin
- if (Len+1-I) mod 3 = 0 then
- insert(',', S, I);
- dec(I);
- end;
- while Length(S) < Width do
- insert(' ', S, 1);
- CommaIze := S;
- end;
-
- function HasEnvironment(HiMemSeg : Word; M : McbPtr) : Boolean;
- {-Return True if M has an associated environment block}
- var
- EnvSeg : Word;
-
- function HasEnv(Start : McbPtr) : Boolean;
- var
- N : McbPtr;
- Done : Boolean;
- begin
- N := Start;
- repeat
- if (N^.Psp = M^.Psp) and (N^.Len > 0) and (EnvSeg = OS(N).S+1) then begin
- HasEnv := True;
- Exit;
- end;
- Done := (N^.Id = 'Z');
- N := Ptr(OS(N).S+N^.Len+1, 0);
- until Done;
- HasEnv := False;
- end;
-
- begin
- EnvSeg := MemW[M^.Psp:$2C];
- if HasEnv(Mcb1) then
- HasEnvironment := True
- else if (HiMemSeg <> 0) and HasEnv(Ptr(HiMemSeg, 0)) then
- HasEnvironment := True
- else
- HasEnvironment := False;
- end;
-
- function ValidPsp(HiMemSeg, PspSeg, PspLen : Word) : Boolean;
- {-Return True if PspSeg is a valid, existing Psp}
-
- function ValidP(Start : McbPtr) : Boolean;
- var
- N : McbPtr;
- Done : Boolean;
- begin
- N := Start;
- repeat
- if (N^.Psp = PspSeg) and (N^.Len = PspLen) then begin
- ValidP := True;
- Exit;
- end;
- Done := (N^.Id = 'Z');
- N := Ptr(OS(N).S+N^.Len+1, 0);
- until Done;
- ValidP := False;
- end;
-
- begin
- if ValidP(Mcb1) then
- ValidPsp := True
- else if (HiMemSeg <> 0) and ValidP(Ptr(HiMemSeg, 0)) then
- ValidPsp := True
- else
- ValidPsp := False;
- end;
-
- function NameFromEnv(M : McbPtr) : String;
- {-Return M's name from its environment (already known to exist)}
- type
- CharArray = array[0..32767] of Char;
- CharArrayPtr = ^CharArray;
- var
- E : Word;
- Eptr : CharArrayPtr;
- Name : String[79];
- Nlen : Byte absolute Name;
- begin
- Eptr := Ptr(MemW[M^.Psp:$2C], 0);
- E := 0;
- repeat
- if Eptr^[E] = #0 then begin
- Inc(E);
- if Eptr^[E] = #0 then begin
- {found end of environment}
- Inc(E, 3);
- Nlen := 0;
- while (Nlen < 63) and (Eptr^[E] <> #0) do begin
- Inc(Nlen);
- Name[Nlen] := Eptr^[E];
- Inc(E);
- end;
- StripNonAscii(Name);
- NameFromEnv := JustName(Name);
- Exit;
- end;
- end;
- Inc(E);
- until (E > 32767);
- NameFromEnv := '';
- end;
-
- function NameFromMcb(M : McbPtr) : String;
- {-Return name from the Mcb (DOS 4+ only)}
- var
- Name : String[79];
- begin
- Name := Asc2Str(M^.Name);
- StripNonAscii(Name);
- NameFromMcb := Name;
- end;
-
- function MasterCommandSeg : Word;
- {-Return PSP segment of master COMMAND.COM}
- var
- curmcb : mcbptr;
- mseg : word;
- par : word;
- begin
- {First block}
- curmcb := mcb1;
- repeat
- curmcb := ptr(OS(curmcb).s+curmcb^.len+1, 0);
- par := memw[curmcb^.psp:$16];
- mseg := OS(curmcb).s;
- if (par = curmcb^.psp) and (mseg+1 = curmcb^.psp) then begin
- MasterCommandSeg := curmcb^.psp;
- exit;
- end;
- until curmcb^.id = 'Z';
- MasterCommandSeg := 0;
- end;
-
- function WatchPspSeg : Word; assembler;
- {-Find copy of WATCH.COM in memory, returning its PSP segment or zero}
- asm
- mov ax,$7761 {id call to WATCH}
- int $21
- jc @1
- cmp ax,$6177 {WATCH flips ah and al if installed}
- jne @1
- mov ax,bx {WATCH returns its own CS in BX}
- jmp @2
- @1: xor ax,ax {not installed}
- @2:
- end;
-
- procedure FindTheBlocks(UseLoMem : Boolean;
- HiMemSeg : Word;
- var Blocks : BlockArray;
- var BlockMax : BlockType;
- var StartMcb : Word;
- var CommandSeg : Word);
- {-Scan memory for the allocated memory blocks}
- const
- MidBlockID = $4D; {Byte DOS uses to identify part of MCB chain}
- EndBlockID = $5A; {Byte DOS uses to identify last block of MCB chain}
- var
- mcbSeg : Word; {Segment address of current MCB}
- nextSeg : Word; {Computed segment address for the next MCB}
- gotFirst : Boolean; {True after first MCB is found}
- gotLast : Boolean; {True after last MCB is found}
- idbyte : Byte; {Byte that DOS uses to identify an MCB}
-
- procedure StoreTheBlock(SaveBlock : Boolean;
- var mcbSeg, nextSeg : Word;
- var gotFirst, gotLast : Boolean);
- {-Store information regarding the memory block}
- var
- nextID : Byte;
- PspAdd : Word; {Segment address of the current PSP}
- mcbLen : Word; {Size of the current memory block in paragraphs}
-
- begin
-
- PspAdd := MemW[mcbSeg:1]; {Address of program segment prefix for MCB}
- mcbLen := MemW[mcbSeg:3]; {Size of the MCB in paragraphs}
- nextSeg := Succ(mcbSeg+mcbLen); {Where the next MCB should be}
- nextID := Mem[nextSeg:0];
-
- if gotLast or (nextID = EndBlockID) or (nextID = MidBlockID) then begin
- if BlockMax < MaxBlocks then begin
- gotFirst := True;
- if SaveBlock then begin
- inc(BlockMax);
- with Blocks[BlockMax] do begin
- mcb := mcbSeg;
- psp := PspAdd;
- end;
- end;
- end;
- {Store master COMMAND.COM segment}
- if CommandSeg = 0 then
- if (McbSeg+1 = PspAdd) and (MemW[PspAdd:$16] = PspAdd) then
- CommandSeg := PspAdd;
- end;
- end;
-
- procedure ScanBlocks(SaveBlock : Boolean);
- {-Scan memory until ending block is found}
- begin
- repeat
- idbyte := Mem[mcbSeg:0];
- if idbyte = MidBlockID then begin
- StoreTheBlock(SaveBlock, mcbSeg, nextSeg, gotFirst, gotLast);
- if gotFirst then
- mcbSeg := nextSeg
- else
- inc(mcbSeg);
- end else if gotFirst and (idbyte = EndBlockID) then begin
- gotLast := True;
- StoreTheBlock(SaveBlock, mcbSeg, nextSeg, gotFirst, gotLast);
- end else
- {Start block was invalid}
- gotLast := True;
- until gotLast;
- end;
-
- begin
- BlockMax := 0;
- CommandSeg := 0;
- StartMCB := OS(MCB1).S;
-
- mcbSeg := StartMCB;
- gotFirst := False;
- gotLast := False;
- ScanBlocks(UseLoMem);
-
- if HiMemSeg <> 0 then begin
- mcbSeg := HiMemSeg;
- gotFirst := False;
- gotLast := False;
- ScanBlocks(True);
- end;
- end;
-
- const
- KbdStart = $1E;
- KbdEnd = $3C;
- var
- KbdHead : Word absolute $40 : $1A;
- KbdTail : Word absolute $40 : $1C;
-
- procedure StuffKey(W : Word);
- {-Stuff one key into the keyboard buffer}
- var
- SaveKbdTail : Word;
- begin
- SaveKbdTail := KbdTail;
- if KbdTail = KbdEnd then
- KbdTail := KbdStart
- else
- Inc(KbdTail, 2);
- if KbdTail = KbdHead then
- KbdTail := SaveKbdTail
- else
- MemW[$40:SaveKbdTail] := W;
- end;
-
- procedure StuffKeys(Keys : string; ClearFirst : Boolean);
- {-Stuff up to 16 keys into keyboard buffer}
- var
- Len : Byte;
- I : Byte;
- begin
- if ClearFirst then
- KbdTail := KbdHead;
- Len := Length(Keys);
- if Len > 16 then
- Len := 16;
- for I := 1 to Length(Keys) do
- StuffKey(Ord(Keys[I]));
- end;
-
- function ExistFile(path : String) : Boolean;
- {-Return true if file exists}
- var
- F : file;
- begin
- Assign(F, path);
- Reset(F);
- if IoResult = 0 then begin
- ExistFile := True;
- Close(F);
- end else
- ExistFile := False;
- end;
-
- function NextArg(S : String; var SPos : Word) : String;
- {-Return next argument beginning at SPos in S.
- Increment SPos to point past the argument.
- Arguments are delimited by white space and '/'}
- var
- Start : Word;
-
- function Delimiter(Ch : Char) : Boolean;
- begin
- case Ch of
- #0..' ', '/' : Delimiter := True;
- else
- Delimiter := False;
- end;
- end;
-
- begin
- {Skip leading white space}
- while (SPos <= Length(S)) and (S[SPos] <= ' ') do
- inc(SPos);
-
- {Exit if beyond end of string}
- if SPos > Length(S) then begin
- NextArg := '';
- Exit;
- end;
-
- {Find end of this argument}
- Start := SPos;
- inc(SPos);
- while (SPos <= Length(S)) and not Delimiter(S[Spos]) do
- inc(SPos);
-
- {Return the string}
- NextArg := Copy(S, Start, SPos-Start);
- end;
-
- begin
- DosVT := DosVersion;
- DosList := GetDosListPtr; {pointer to dos list of lists}
- Mcb1 := Ptr(MemW[OS(DosList).S:OS(DosList).O-2], 0); {first Mcb}
- end.
-