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