g-tsang@gumby.UUCP (Michael H. Tsang) (02/14/86)
I have received some requests on posting the source of pushd and popd.
So, here they are!
DOSENV.I------------------------CUT HERE---------------------------------------
{ Please report any bugs or suggestions to the author: g-tsang@gumby.wisc.edu }
{ [DOSEnvLib v1.00 (c) 2.13.86] by Michael H. Tsang }
function GetDOSEnvSeg: integer;
var
SegPtr: integer;
begin
SegPtr := MemW[CSeg:$0016];
while MemW[SegPtr:$0016] <> SegPtr do { Trace back to root process }
SegPtr := MemW[SegPtr:$0016];
GetDOSEnvSeg := SegPtr + MemW[SegPtr-1:$0003] + 1 { Skip DOS program seg }
end; { GetDOSEnvSeg }
function StrEqual(Key: Str; DOSEnv, MemIndex: integer): boolean;
var
StrIndex: integer;
StillMatch: boolean;
begin
StillMatch := true;
StrIndex := 1;
while StillMatch and (StrIndex <= Length(Key)) do
if Mem[DOSEnv:MemIndex] = ord(Key[StrIndex]) then begin
MemIndex := MemIndex + 1;
StrIndex := StrIndex + 1
end else
StillMatch := false;
if StillMatch and (Mem[DOSEnv:MemIndex] = ord('=')) then
StrEqual := true
else
StrEqual := false
end; { StrEqual }
function GetDOSEnvir(Key: Str; DOSEnv: integer; var MemIndex: integer): Str;
function GetStr(Index: integer): Str;
var
TmpStr: Str;
begin
TmpStr := '';
while Mem[DOSEnv:Index] <> 0 do begin
TmpStr := TmpStr + chr(Mem[DOSEnv:Index]);
Index := Index + 1
end;
GetStr := TmpStr
end; { GetStr }
var
Found: boolean;
begin { GetDOSEnvir }
MemIndex := 0;
Found := false;
while (not Found) and (Mem[DOSEnv:MemIndex] <> 0) do
if StrEqual(Key, DOSEnv, MemIndex) then
Found := true
else begin { Skip this variable }
while Mem[DOSEnv:MemIndex] <> 0 do
MemIndex := MemIndex + 1;
MemIndex := MemIndex + 1
end;
if Found then
GetDOSEnvir := GetStr(MemIndex + Length(Key) + 1)
else
GetDOSEnvir := ''
end; { GetDOSEnvir }
function SetDOSEnvir(EnvVar, EnvStr: Str; DOSEnv: integer): boolean;
var
TmpStr: Str;
Index1, Index2: integer;
procedure WriteStr(S: Str);
var
Index: integer;
begin
for Index := 1 to Length(S) do begin
Mem[DOSEnv:Index1] := ord(S[Index]);
Index1 := Index1 + 1
end
end; { WriteStr }
begin { SetDOSEnvir }
TmpStr := GetDOSEnvir(EnvVar, DOSEnv, Index1); { Save the old string }
if TmpStr <> '' then begin { Variable was defined }
Index2 := Index1 + Length(EnvVar) + Length(TmpStr) + 2; { Point to next variable }
while Mem[DOSEnv:Index2] <> 0 do { Move following variables up }
repeat
Mem[DOSEnv:Index1] := Mem[DOSEnv:Index2];
Index1 := Index1 + 1;
Index2 := Index2 + 1
until Mem[DOSEnv:Index2-1] = 0
end;
if (Index1+Length(EnvVar)+Length(EnvStr)+3) <= (MemW[DOSEnv-1:$0003]*16) then begin
{ There is sufficient environment space }
if EnvStr <> '' then { Set the variable }
WriteStr(EnvVar + '=' + EnvStr + chr(0));
SetDOSEnvir := true
end else if TmpStr <> '' then begin { Restore old content of variable }
WriteStr(EnvVar + '=' + TmpStr + chr(0));
writeln(ProgramName, ': Insufficient environment space');
SetDOSEnvir := false
end;
Mem[DOSEnv:Index1] := 0
end; { SetDOSEnvir }
PUSHD.PAS---------------------------CUT HERE-----------------------------------
{ Please report any bugs or suggestions to the author: g-tsang@gumby.wisc.edu }
{$G512,P512}
program Pushd(input, output);
const
ProgramName = 'pushd';
Version = '[v2.30 (c) 2.13.86] by Michael H. Tsang';
StrLen = 255;
type
Str = string[StrLen];
var
StackStr: Str;
Depth, DOSEnv: integer;
Dirty: boolean;
{$I c:\tools\turbo\lib\dosenv.i}
function GetStack: boolean;
var
Index: integer;
TmpStr: Str;
begin
GetDir(0, StackStr);
TmpStr := GetDOSEnvir('DIRSTACK', DOSEnv, Index);
if (Length(StackStr) + Length(TmpStr)) >= StrLen then begin
writeln(ProgramName, ': Stack too large');
GetStack := false
end else begin
if TmpStr = '' then
Depth := 0
else begin
Depth := 1;
for Index := 1 to Length(TmpStr) do { Count depth }
if TmpStr[Index] = ';' then
Depth := Depth + 1;
StackStr := StackStr + ';' + TmpStr { Prepend current directory }
end;
GetStack := true
end
end; { GetStack }
procedure SwapStackTop;
var
TmpStr: Str;
Where: integer;
begin
if Depth = 0 then
writeln(ProgramName, ': No other directory')
else begin
Where := Pos(';', StackStr);
TmpStr := Copy(StackStr, 1, Where-1);
Delete(StackStr, 1, Where);
Where := Pos(';', StackStr);
if Where = 0 then
StackStr := StackStr + ';' + TmpStr
else
Insert(';'+TmpStr, StackStr, Where);
Dirty := true
end
end; { SwapStackTop }
procedure RotateStack(NumStr: Str);
var
Index, Cnt, Num, Result: integer;
TmpStr: Str;
begin
Val(Copy(NumStr, 2, Length(NumStr)-1), Num, Result);
if (Result <> 0) or (Num <= 0) then
writeln(ProgramName, ': ', NumStr, ': No such file or directory')
else begin
if Num > Depth then
writeln(ProgramName, ': Directory stack not that deep')
else begin
Index := 1;
for Cnt := 1 to Num do begin
while StackStr[Index] <> ';' do
Index := Index + 1;
Index := Index + 1
end;
TmpStr := Copy(StackStr, 1, Index-2);
Delete(StackStr, 1, Index-1);
StackStr := StackStr + ';' + TmpStr;
Dirty := true
end
end
end; { RotateStack }
procedure PushStack(ArgStr: Str);
var
Home: Str;
Index: integer;
begin
if ArgStr[1] = '~' then begin
Home := GetDOSEnvir('HOME', DOSEnv, Index);
if Home <> '' then begin
Delete(ArgStr, 1, 1);
Insert(Home, ArgStr, 1)
end
end;
if (Length(StackStr) + Length(ArgStr)) >= StrLen then
writeln(ProgramName, ': Insufficient stack space')
else begin
ArgStr := ArgStr + ';';
Insert(ArgStr, StackStr, 1);
Dirty := true
end
end; { PushStack }
procedure SaveStack;
var
TopStr, CDStr: Str;
Where: integer;
begin
GetDir(0, CDStr);
Where := Pos(';', StackStr);
if Where = 0 then begin { Isolate top of stack }
TopStr := StackStr;
StackStr := ''
end else begin
TopStr := Copy(StackStr, 1, Where-1);
Delete(StackStr, 1, Where)
end;
{$I-}
ChDir(TopStr);
{$I+}
if IOResult <> 0 then
writeln(ProgramName, ': ', TopStr, ': No such file or directory')
else
if SetDOSEnvir('DIRSTACK', StackStr, DOSEnv) then begin
GetDir(0, TopStr);
if StackStr = '' then
writeln(TopStr)
else
writeln(TopStr, ';', StackStr)
end else { Out of environment space }
ChDir(CDStr) { Restore previous directory }
end; { SaveStack }
var
Argc: integer;
ArgStr: Str;
begin { Pushd }
Argc := ParamCount;
if Argc > 1 then
writeln('Usage: ', ProgramName, ' [pathname | +n | -v]')
else begin
Dirty := false;
DOSEnv := GetDOSEnvSeg;
if GetStack then begin
if Argc = 0 then
SwapStackTop
else begin
ArgStr := ParamStr(1);
if ArgStr = '-v' then
writeln(ProgramName, ': ', Version)
else if ArgStr[1] = '+' then
RotateStack(ArgStr)
else
PushStack(ArgStr)
end;
if Dirty then
SaveStack
end
end
end. { Pushd }
POPD.PAS-----------------------------CUT HERE----------------------------------
{ Please report any bugs or suggestions to the author: g-tsang@gumby.wisc.edu }
{$G512,P512}
program Popd(input, output);
const
ProgramName = 'popd';
Version = '[v2.30 (c) 2.13.86] by Michael H. Tsang';
StrLen = 255;
type
Str = string[StrLen];
var
StackStr: Str;
Depth, DOSEnv: integer;
Dirty: boolean;
{$I c:\tools\turbo\lib\dosenv.i}
function GetStack: boolean;
var
Index: integer;
TmpStr: Str;
begin
GetDir(0, StackStr);
TmpStr := GetDOSEnvir('DIRSTACK', DOSEnv, Index);
if (Length(StackStr) + Length(TmpStr)) >= StrLen then begin
writeln(ProgramName, ': Stack too large');
GetStack := false
end else begin
if TmpStr = '' then
Depth := 0
else begin
Depth := 1;
for Index := 1 to Length(TmpStr) do
if TmpStr[Index] = ';' then
Depth := Depth + 1;
StackStr := StackStr + ';' + TmpStr
end;
GetStack := true
end
end; { GetStack }
procedure PopStack;
var
Where: integer;
begin
if Depth = 0 then
writeln(ProgramName, ': Directory stack empty')
else begin
Where := Pos(';', StackStr);
Delete(StackStr, 1, Where);
Dirty := true
end
end; { PopStack }
procedure DeleteStack(NumStr: Str);
var
Cnt, Num, Result, Index1, Index2: integer;
Found: boolean;
begin
Val(Copy(NumStr, 2, Length(NumStr)-1), Num, Result);
if (Result <> 0) or (Num <= 0) then
writeln(ProgramName, ': ', NumStr, ': Bad directory')
else begin
if Num > Depth then
writeln(ProgramName, ': Directory stack not that deep')
else begin
Index1 := 1;
for Cnt := 1 to Num do begin
while StackStr[Index1] <> ';' do
Index1 := Index1 + 1;
Index1 := Index1 + 1
end;
Index2 := Index1 - 1;
Found := false;
while not Found and (Index1 <= Length(StackStr)) do
if StackStr[Index1] <> ';' then
Index1 := Index1 + 1
else
Found := true;
Delete(StackStr, Index2, Index1-Index2);
Dirty := true
end
end
end; { DeleteStack }
procedure SaveStack;
var
TopStr, CDStr: Str;
Where: integer;
begin
GetDir(0, CDStr);
Where := Pos(';', StackStr);
if Where = 0 then begin
TopStr := StackStr;
StackStr := ''
end else begin
TopStr := Copy(StackStr, 1, Where-1);
Delete(StackStr, 1, Where)
end;
{$I-}
ChDir(TopStr);
{$I+}
if IOResult <> 0 then
writeln(ProgramName, ': ', TopStr, ': No such file or directory')
else
if SetDOSEnvir('DIRSTACK', StackStr, DOSEnv) then begin
GetDir(0, TopStr);
if StackStr = '' then
writeln(TopStr)
else
writeln(TopStr, ';', StackStr)
end else
ChDir(CDStr)
end; { SaveStack }
var
Argc: integer;
ArgStr: Str;
begin { Popd }
Argc := ParamCount;
if Argc > 1 then
writeln('Usage: ', ProgramName, ' [+n | -v]')
else begin
Dirty := false;
DOSEnv := GetDOSEnvSeg;
if GetStack then begin
if Argc = 0 then
PopStack
else begin
ArgStr := ParamStr(1);
if ArgStr = '-v' then
writeln(ProgramName, ': ', Version)
else if ArgStr[1] = '+' then
DeleteStack(ArgStr)
else
writeln(ProgramName, ': ', ArgStr, ': Bad directory')
end;
if Dirty then
SaveStack
end
end
end. { Popd }
--------------------------------------CUT HERE---------------------------------
Mike Tsang (g-tsang@gumby.wisc.edu)