home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / t_power / tpenv.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-11-14  |  14.8 KB  |  590 lines

  1. {$R-,S-,V-,I-,B-,F-}
  2.  
  3. {Disable the following define if you don't have Turbo Professional}
  4. {$DEFINE UseTpro}
  5.  
  6. {*********************************************************}
  7. {*                    TPENV.PAS 1.02                     *}
  8. {*                by TurboPower Software                 *}
  9. {*********************************************************}
  10.  
  11. {
  12.   Version 1.01 11/7/88
  13.     Find master environment in DOS 3.3 and 4.0
  14.   Version 1.02 11/14/88
  15.     Correctly find master environment when run
  16.       within AUTOEXEC.BAT
  17. }
  18.  
  19. unit TpEnv;
  20.   {-Manipulate the environment}
  21.  
  22. interface
  23.  
  24.   {$IFDEF UseTpro}
  25. uses
  26.   TpString,
  27.   TpDos;
  28.   {$ENDIF}
  29.  
  30. type
  31.   EnvArray = array[0..32767] of Char;
  32.   EnvArrayPtr = ^EnvArray;
  33.   EnvRec =
  34.     record
  35.       EnvSeg : Word;              {Segment of the environment}
  36.       EnvLen : Word;              {Usable length of the environment}
  37.       EnvPtr : Pointer;           {Nil except when allocated on heap}
  38.     end;
  39.  
  40. const
  41.   ShellUserProc : Pointer = nil;  {Put address of ExecDos user proc here if desired}
  42.  
  43. procedure MasterEnv(var Env : EnvRec);
  44.   {-Return master environment record}
  45.  
  46. procedure CurrentEnv(var Env : EnvRec);
  47.   {-Return current environment record}
  48.  
  49. procedure NewEnv(var Env : EnvRec; Size : Word);
  50.   {-Allocate a new environment on the heap}
  51.  
  52. procedure DisposeEnv(var Env : EnvRec);
  53.   {-Deallocate an environment previously allocated on heap}
  54.  
  55. procedure SetCurrentEnv(Env : EnvRec);
  56.   {-Specify a different environment for the current program}
  57.  
  58. procedure CopyEnv(Src, Dest : EnvRec);
  59.   {-Copy contents of Src environment to Dest environment}
  60.  
  61. function EnvFree(Env : EnvRec) : Word;
  62.   {-Return bytes free in environment}
  63.  
  64. function GetEnvStr(Env : EnvRec; Search : string) : string;
  65.   {-Return a string from the environment}
  66.  
  67. function SetEnvStr(Env : EnvRec; Search, Value : string) : Boolean;
  68.   {-Set environment string, returning true if successful}
  69.  
  70. procedure DumpEnv(Env : EnvRec);
  71.   {-Dump the environment to StdOut}
  72.  
  73. function ProgramStr : string;
  74.   {-Return the complete path to the current program, '' if DOS < 3.0}
  75.  
  76. function SetProgramStr(Env : EnvRec; Path : string) : Boolean;
  77.   {-Add a program name to the end of an environment if sufficient space}
  78.  
  79.   {$IFDEF UseTpro}
  80. function ShellWithPrompt(Prompt : string) : Integer;
  81.   {-Shell to DOS with a new prompt}
  82.   {$ENDIF}
  83.  
  84.   {===============================================================}
  85.  
  86. implementation
  87.  
  88. type
  89.   SO =
  90.     record
  91.       O : Word;
  92.       S : Word;
  93.     end;
  94.  
  95.   procedure ClearEnvRec(var Env : EnvRec);
  96.     {-Initialize an environment record}
  97.   begin
  98.     FillChar(Env, SizeOf(Env), 0);
  99.   end;
  100.  
  101.   procedure MasterEnv(var Env : EnvRec);
  102.     {-Return master environment record}
  103.   var
  104.     Owner : Word;
  105.     Mcb : Word;
  106.     Eseg : Word;
  107.     Done : Boolean;
  108.   begin
  109.     with Env do begin
  110.       ClearEnvRec(Env);
  111.  
  112.       {Interrupt $2E points into COMMAND.COM}
  113.       Owner := MemW[0:(2+4*$2E)];
  114.  
  115.       {Mcb points to memory control block for COMMAND}
  116.       Mcb := Owner-1;
  117.       if (Mem[Mcb:0] <> Byte('M')) or (MemW[Mcb:1] <> Owner) then
  118.         Exit;
  119.  
  120.       {Read segment of environment from PSP of COMMAND}
  121.       Eseg := MemW[Owner:$2C];
  122.  
  123.       {Earlier versions of DOS don't store environment segment there}
  124.       if Eseg = 0 then begin
  125.         {Master environment is next block past COMMAND}
  126.         Mcb := Owner+MemW[Mcb:3];
  127.         if (Mem[Mcb:0] <> Byte('M')) or (MemW[Mcb:1] <> Owner) then
  128.           {Not the right memory control block}
  129.           Exit;
  130.         Eseg := Mcb+1;
  131.       end else
  132.         Mcb := Eseg-1;
  133.  
  134.       {Return segment and length of environment}
  135.       EnvSeg := Eseg;
  136.       EnvLen := MemW[Mcb:3] shl 4;
  137.     end;
  138.   end;
  139.  
  140.   procedure CurrentEnv(var Env : EnvRec);
  141.     {-Return current environment record}
  142.   var
  143.     ESeg : Word;
  144.     Mcb : Word;
  145.   begin
  146.     with Env do begin
  147.       ClearEnvRec(Env);
  148.       ESeg := MemW[PrefixSeg:$2C];
  149.       Mcb := ESeg-1;
  150.       if (Mem[Mcb:0] <> Byte('M')) or (MemW[Mcb:1] <> PrefixSeg) then
  151.         Exit;
  152.       EnvSeg := ESeg;
  153.       EnvLen := MemW[Mcb:3] shl 4;
  154.     end;
  155.   end;
  156.  
  157.   procedure NewEnv(var Env : EnvRec; Size : Word);
  158.     {-Allocate a new environment (on the heap)}
  159.   var
  160.     Mcb : Word;
  161.   begin
  162.     with Env do
  163.       if MaxAvail < Size+31 then
  164.         {Insufficient space}
  165.         ClearEnvRec(Env)
  166.       else begin
  167.         {31 extra bytes for paragraph alignment, fake MCB}
  168.         GetMem(EnvPtr, Size+31);
  169.         EnvSeg := SO(EnvPtr).S+1;
  170.         if SO(EnvPtr).O <> 0 then
  171.           Inc(EnvSeg);
  172.         EnvLen := Size;
  173.         {Fill it with nulls}
  174.         FillChar(EnvPtr^, Size+31, 0);
  175.         {Make a fake MCB below it}
  176.         Mcb := EnvSeg-1;
  177.         Mem[Mcb:0] := Byte('M');
  178.         MemW[Mcb:1] := PrefixSeg;
  179.         MemW[Mcb:3] := (Size+15) shr 4;
  180.       end;
  181.   end;
  182.  
  183.   procedure DisposeEnv(var Env : EnvRec);
  184.     {-Deallocate an environment previously allocated on heap}
  185.   begin
  186.     with Env do
  187.       if EnvPtr <> nil then begin
  188.         FreeMem(EnvPtr, EnvLen+31);
  189.         ClearEnvRec(Env);
  190.       end;
  191.   end;
  192.  
  193.   procedure SetCurrentEnv(Env : EnvRec);
  194.     {-Specify a different environment for the current program}
  195.   begin
  196.     with Env do
  197.       if EnvSeg <> 0 then
  198.         MemW[PrefixSeg:$2C] := EnvSeg;
  199.   end;
  200.  
  201.   procedure CopyEnv(Src, Dest : EnvRec);
  202.     {-Copy contents of Src environment to Dest environment}
  203.   var
  204.     Size : Word;
  205.     SPtr : EnvArrayPtr;
  206.     DPtr : EnvArrayPtr;
  207.   begin
  208.     if (Src.EnvSeg = 0) or (Dest.EnvSeg = 0) then
  209.       Exit;
  210.  
  211.     if Src.EnvLen <= Dest.EnvLen then
  212.       {Space for the whole thing}
  213.       Size := Src.EnvLen
  214.     else
  215.       {Take what fits}
  216.       Size := Dest.EnvLen-1;
  217.  
  218.     SPtr := Ptr(Src.EnvSeg, 0);
  219.     DPtr := Ptr(Dest.EnvSeg, 0);
  220.     Move(SPtr^, DPtr^, Size);
  221.     FillChar(DPtr^[Size], Dest.EnvLen-Size, 0);
  222.   end;
  223.  
  224.   procedure SkipAsciiZ(EPtr : EnvArrayPtr; var EOfs : Word);
  225.     {-Skip to end of current AsciiZ string}
  226.   begin
  227.     while EPtr^[EOfs] <> #0 do
  228.       Inc(EOfs);
  229.   end;
  230.  
  231.   function EnvNext(EPtr : EnvArrayPtr) : Word;
  232.     {-Return the next available location in environment at EPtr^}
  233.   var
  234.     EOfs : Word;
  235.   begin
  236.     EOfs := 0;
  237.     if EPtr <> nil then begin
  238.       while EPtr^[EOfs] <> #0 do begin
  239.         SkipAsciiZ(EPtr, EOfs);
  240.         Inc(EOfs);
  241.       end;
  242.     end;
  243.     EnvNext := EOfs;
  244.   end;
  245.  
  246.   function EnvFree(Env : EnvRec) : Word;
  247.     {-Return bytes free in environment}
  248.   begin
  249.     with Env do
  250.       if EnvSeg <> 0 then
  251.         EnvFree := EnvLen-EnvNext(Ptr(EnvSeg, 0))-1
  252.       else
  253.         EnvFree := 0;
  254.   end;
  255.  
  256.   {$IFNDEF UseTpro}
  257.   function StUpcase(S : string) : string;
  258.     {-Uppercase a string}
  259.   var
  260.     SLen : byte absolute S;
  261.     I : Integer;
  262.   begin
  263.     for I := 1 to SLen do
  264.       S[I] := UpCase(S[I]);
  265.     StUpcase := S;
  266.   end;
  267.   {$ENDIF}
  268.  
  269.   function SearchEnv(EPtr : EnvArrayPtr;
  270.                      var Search : string) : Word;
  271.     {-Return the position of Search in environment, or $FFFF if not found.
  272.       Prior to calling SearchEnv, assure that
  273.         EPtr is not nil,
  274.         Search is not empty
  275.     }
  276.   var
  277.     SLen : Byte absolute Search;
  278.     EOfs : Word;
  279.     MOfs : Word;
  280.     SOfs : Word;
  281.     Match : Boolean;
  282.   begin
  283.     {Force upper case search}
  284.     Search := StUpcase(Search);
  285.  
  286.     {Assure search string ends in =}
  287.     if Search[SLen] <> '=' then begin
  288.       Inc(SLen);
  289.       Search[SLen] := '=';
  290.     end;
  291.  
  292.     EOfs := 0;
  293.     while EPtr^[EOfs] <> #0 do begin
  294.       {At the start of a new environment element}
  295.       SOfs := 1;
  296.       MOfs := EOfs;
  297.       repeat
  298.         Match := (EPtr^[EOfs] = Search[SOfs]);
  299.         if Match then begin
  300.           Inc(EOfs);
  301.           Inc(SOfs);
  302.         end;
  303.       until not Match or (SOfs > SLen);
  304.  
  305.       if Match then begin
  306.         {Found a match, return index of start of match}
  307.         SearchEnv := MOfs;
  308.         Exit;
  309.       end;
  310.  
  311.       {Skip to end of this environment string}
  312.       SkipAsciiZ(EPtr, EOfs);
  313.  
  314.       {Skip to start of next environment string}
  315.       Inc(EOfs);
  316.     end;
  317.  
  318.     {No match}
  319.     SearchEnv := $FFFF;
  320.   end;
  321.  
  322.   procedure GetAsciiZ(EPtr : EnvArrayPtr; var EOfs : Word; var EStr : string);
  323.     {-Collect AsciiZ string starting at EPtr^[EOfs]}
  324.   var
  325.     ELen : Byte absolute EStr;
  326.   begin
  327.     ELen := 0;
  328.     while (EPtr^[EOfs] <> #0) and (ELen < 255) do begin
  329.       Inc(ELen);
  330.       EStr[ELen] := EPtr^[EOfs];
  331.       Inc(EOfs);
  332.     end;
  333.   end;
  334.  
  335.   function GetEnvStr(Env : EnvRec; Search : string) : string;
  336.     {-Return a string from the environment}
  337.   var
  338.     SLen : Byte absolute Search;
  339.     EPtr : EnvArrayPtr;
  340.     EOfs : Word;
  341.     EStr : string;
  342.     ELen : Byte absolute EStr;
  343.   begin
  344.     with Env do begin
  345.       ELen := 0;
  346.       if (EnvSeg <> 0) and (SLen <> 0) then begin
  347.         {Find the search string}
  348.         EPtr := Ptr(EnvSeg, 0);
  349.         EOfs := SearchEnv(EPtr, Search);
  350.         if EOfs <> $FFFF then begin
  351.           {Skip over the search string}
  352.           Inc(EOfs, SLen);
  353.           {Build the result string}
  354.           GetAsciiZ(EPtr, EOfs, EStr);
  355.         end;
  356.       end;
  357.       GetEnvStr := EStr;
  358.     end;
  359.   end;
  360.  
  361.   function SetEnvStr(Env : EnvRec; Search, Value : string) : Boolean;
  362.     {-Set environment string, returning true if successful}
  363.   var
  364.     SLen : Byte absolute Search;
  365.     VLen : Byte absolute Value;
  366.     EPtr : EnvArrayPtr;
  367.     ENext : Word;
  368.     EOfs : Word;
  369.     MOfs : Word;
  370.     OldLen : Word;
  371.     NewLen : Word;
  372.     NulLen : Word;
  373.   begin
  374.     with Env do begin
  375.       SetEnvStr := False;
  376.       if (EnvSeg = 0) or (SLen = 0) then
  377.         Exit;
  378.       EPtr := Ptr(EnvSeg, 0);
  379.  
  380.       {Find the search string}
  381.       EOfs := SearchEnv(EPtr, Search);
  382.  
  383.       {Get the index of the next available environment location}
  384.       ENext := EnvNext(EPtr);
  385.  
  386.       {Get total length of new environment string}
  387.       NewLen := SLen+VLen;
  388.  
  389.       if EOfs <> $FFFF then begin
  390.         {Search string exists}
  391.         MOfs := EOfs+SLen;
  392.         {Scan to end of string}
  393.         SkipAsciiZ(EPtr, MOfs);
  394.         OldLen := MOfs-EOfs;
  395.         {No extra nulls to add}
  396.         NulLen := 0;
  397.       end else begin
  398.         OldLen := 0;
  399.         {One extra null to add}
  400.         NulLen := 1;
  401.       end;
  402.  
  403.       if VLen <> 0 then
  404.         {Not a pure deletion}
  405.         if ENext+NewLen+NulLen >= EnvLen+OldLen then
  406.           {New string won't fit}
  407.           Exit;
  408.  
  409.       if OldLen <> 0 then begin
  410.         {Overwrite previous environment string}
  411.         Move(EPtr^[MOfs+1], EPtr^[EOfs], ENext-MOfs-1);
  412.         {More space free now}
  413.         Dec(ENext, OldLen+1);
  414.       end;
  415.  
  416.       {Append new string}
  417.       if VLen <> 0 then begin
  418.         Move(Search[1], EPtr^[ENext], SLen);
  419.         Inc(ENext, SLen);
  420.         Move(Value[1], EPtr^[ENext], VLen);
  421.         Inc(ENext, VLen);
  422.       end;
  423.  
  424.       {Clear out the rest of the environment}
  425.       FillChar(EPtr^[ENext], EnvLen-ENext, 0);
  426.  
  427.       SetEnvStr := True;
  428.     end;
  429.   end;
  430.  
  431.   procedure DumpEnv(Env : EnvRec);
  432.     {-Dump the environment to StdOut}
  433.   var
  434.     EOfs : Word;
  435.     EPtr : EnvArrayPtr;
  436.   begin
  437.     with Env do begin
  438.       if EnvSeg = 0 then
  439.         Exit;
  440.       EPtr := Ptr(EnvSeg, 0);
  441.       EOfs := 0;
  442.       WriteLn;
  443.       while EPtr^[EOfs] <> #0 do begin
  444.         while EPtr^[EOfs] <> #0 do begin
  445.           Write(EPtr^[EOfs]);
  446.           Inc(EOfs);
  447.         end;
  448.         WriteLn;
  449.         Inc(EOfs);
  450.       end;
  451.       WriteLn('Bytes free: ', EnvFree(Env));
  452.     end;
  453.   end;
  454.  
  455.   function DosVersion : Word;
  456.     {-Return the DOS version, major part in AX}
  457.   inline(
  458.          $B4/$30/                 {mov ah,$30}
  459.          $CD/$21/                 {int $21}
  460.          $86/$C4);                {xchg ah,al}
  461.  
  462.   function ProgramStr : string;
  463.     {-Return the name of the current program, '' if DOS < 3.0}
  464.   var
  465.     EOfs : Word;
  466.     Env : EnvRec;
  467.     EPtr : EnvArrayPtr;
  468.     PStr : string;
  469.   begin
  470.     ProgramStr := '';
  471.     if DosVersion < $0300 then
  472.       Exit;
  473.     CurrentEnv(Env);
  474.     if Env.EnvSeg = 0 then
  475.       Exit;
  476.     {Find the end of the current environment}
  477.     EPtr := Ptr(Env.EnvSeg, 0);
  478.     EOfs := EnvNext(EPtr);
  479.     {Skip to start of path name}
  480.     Inc(EOfs, 3);
  481.     {Collect the path name}
  482.     GetAsciiZ(EPtr, EOfs, PStr);
  483.     ProgramStr := PStr;
  484.   end;
  485.  
  486.   function SetProgramStr(Env : EnvRec; Path : string) : Boolean;
  487.     {-Add a program name to the end of an environment if sufficient space}
  488.   var
  489.     PLen : Byte absolute Path;
  490.     EOfs : Word;
  491.     Numb : Word;
  492.     EPtr : EnvArrayPtr;
  493.   begin
  494.     SetProgramStr := False;
  495.     with Env do begin
  496.       if EnvSeg = 0 then
  497.         Exit;
  498.       {Find the end of the current environment}
  499.       EPtr := Ptr(EnvSeg, 0);
  500.       EOfs := EnvNext(EPtr);
  501.       {Assure space for path}
  502.       if EnvLen < PLen+EOfs+4 then
  503.         Exit;
  504.       {Put in the count field}
  505.       Inc(EOfs);
  506.       Numb := 1;
  507.       Move(Numb, EPtr^[EOfs], 2);
  508.       {Skip to start of path name}
  509.       Inc(EOfs, 2);
  510.       {Move the path into place}
  511.       Path := StUpcase(Path);
  512.       Move(Path[1], EPtr^[EOfs], PLen);
  513.       {Null terminate}
  514.       Inc(EOfs, PLen);
  515.       EPtr^[EOfs] := #0;
  516.       SetProgramStr := True;
  517.     end;
  518.   end;
  519.  
  520.   {$IFDEF UseTpro}
  521.   function ShellWithPrompt(Prompt : string) : Integer;
  522.     {-Shell to DOS with a new prompt}
  523.   const
  524.     PromptStr : string[7] = 'PROMPT=';
  525.   var
  526.     PLen : Byte absolute Prompt;
  527.     NSize : Word;
  528.     Status : Integer;
  529.     CE : EnvRec;
  530.     NE : EnvRec;
  531.     OldP : string;
  532.     OldPLen : Byte absolute OldP;
  533.   begin
  534.     {Point to current environment}
  535.     CurrentEnv(CE);
  536.     if CE.EnvSeg = 0 then begin
  537.       {Error getting environment}
  538.       ShellWithPrompt := -5;
  539.       Exit;
  540.     end;
  541.  
  542.     {Compute size of new environment}
  543.     OldP := GetEnvStr(CE, PromptStr);
  544.     NSize := CE.EnvLen;
  545.     if OldPLen < PLen then
  546.       Inc(NSize, PLen-OldPLen);
  547.  
  548.     {Allocate and initialize a new environment}
  549.     NewEnv(NE, NSize);
  550.     if NE.EnvSeg = 0 then begin
  551.       {Insufficient memory for new environment}
  552.       ShellWithPrompt := -6;
  553.       Exit;
  554.     end;
  555.     CopyEnv(CE, NE);
  556.  
  557.     {Get the program name from the current environment}
  558.     OldP := ProgramStr;
  559.  
  560.     {Set the new prompt string}
  561.     if not SetEnvStr(NE, PromptStr, Prompt) then begin
  562.       {Program error, should have enough space}
  563.       ShellWithPrompt := -7;
  564.       Exit;
  565.     end;
  566.  
  567.     {Transfer program name to new environment if possible}
  568.     if not SetProgramStr(NE, OldP) then
  569.       ;
  570.  
  571.     {Point to new environment}
  572.     SetCurrentEnv(NE);
  573.  
  574.     {Shell to DOS with new prompt in place}
  575.     Status := ExecDos('', True, ShellUserProc);
  576.  
  577.     {Restore previous environment}
  578.     SetCurrentEnv(CE);
  579.  
  580.     {Release the heap space}
  581.     if Status >= 0 then
  582.       DisposeEnv(NE);
  583.  
  584.     {Return exec status}
  585.     ShellWithPrompt := Status;
  586.   end;
  587.   {$ENDIF}
  588.  
  589. end.
  590.