home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / environ / setpath.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-04-28  |  7.9 KB  |  202 lines

  1. program SetPath;
  2.  
  3. {                Program: SetPath
  4.                   Author: David Dubois
  5.                           Zelkop Software
  6.                           Halifax, N.S.
  7.     CompuServe User I.D.: 71401,747
  8.                     Date: 1988.04.27
  9.  
  10.     I hereby dedicate this knowledge to the public domain. Feel free to use
  11.     it, but if you do, please mention my name. There are no guarantees, and
  12.     in fact, I wouldn't bet a dollar that it will work every time.
  13.  
  14.     I just figured this all out in the last couple of hours, so please
  15.     excuse the sparse documentation. I hope to upload something more
  16.     concrete in the near future.
  17.  
  18.     This program shows how to find the global MS-DOS enviroment.
  19.  
  20.     As an example, this program will update the PATH= string in the global
  21.     enviroment to the string passed as a parameter.
  22.  
  23.     On normal circumstances, a program can only work with its own copy of
  24.     the DOS enviroment. The purpose of this program is to break that
  25.     barrier.
  26.  
  27.     THINGS YOU MAY NOT HAVE KNOWN
  28.  
  29.     Every program that is run gets its own Program Segment Prefix (PSP).
  30.     This is an area of memory that COMMAND.COM uses to communicate
  31.     information to the program. For example, one such bit of information is
  32.     the segment address of the program's copy of the enviroment.
  33.  
  34.     At offset $16 of the PSP you can find the segment address of the parent
  35.     program's PSP.
  36.  
  37.     In COMMAND.COM's PSP, this segment actually points to itself.
  38.  
  39.     Therefore, we can find COMMAND.COM's PSP by tracing the line back,
  40.     until we get to a program whose PSP's parent is itself.
  41.  
  42.     "Aha!", you say, "so we just look at COMMAND.COM's PSP to see where its
  43.     enviroment is." Sorry, it's not that simple. Understandably,
  44.     COMMAND.COM treats its own PSP a little differently than its
  45.     children's. Particularly, where usually one can find the segment
  46.     address of the enviroment, one instead finds zeros. Hmmm ...
  47.  
  48.     Here comes the shaky part:
  49.  
  50.     The thing to realize, is since the size of the enviroment is not set in
  51.     stone, COMMAND.COM has to dynamically allocate the memory for it. This
  52.     is done with the standard DOS memory allocation calls. Therefore,
  53.     somewhere, nearby, there must be memory allocation block with the
  54.     global enviroment in it. (This is shaky logic step #1).
  55.  
  56.     A memory allocation block starts on a segment boundary. The first byte
  57.     is either a $4D (letter M) or a $5A (letter Z). It will be $5A only if
  58.     this is the last memory that has been allocated. In this program I have
  59.     assumed that the block we're looking for won't be the last. (That is
  60.     shaky logic step #2.) The next two bytes are the segment of the PSP
  61.     that allocated the memory. This we are pretty sure we know. The next
  62.     two bytes are a bonus: a word describing the number of paragraphs that
  63.     were allocated. If we can find what we are looking for, this should be
  64.     the size of the enviroment.
  65.  
  66.     Let's look for such a block. Starting at COMMAND.COM's PSP segment, we
  67.     look through segment boundaries until we find a match. We will assume
  68.     that such a block will be found. (Shaky logic step #3) Even, worse we
  69.     will assume that the first such block we find is the enviroment block.
  70.     (Finally, shaky logic step #4).
  71.  
  72.     Assuming that the great spirit of PC-dom is working in our favor today,
  73.     and all of these assumptions turn out to be true, we are all set. The
  74.     enviroment itself starts at the next segment boundary (as is the nature
  75.     of DOS allocated memory blocks) and we know the size of the enviroment.
  76.     Now we can have our way.
  77.  
  78.     REPLACING THE PATH
  79.  
  80.     This part was written in hurry. I was anxious to share the information
  81.     so far described with all our friends. I haven't put in proper checks
  82.     to make sure that overflow does not occur. If that happens, some of the
  83.     strings will become truncated, but I don't think smoke will start
  84.     coming out the back of the machine. Perhaps in the near future I will
  85.     clean it up and release a new version. I won't go too deeply into an
  86.     explanation.
  87.  
  88.     Essentially it starts with a blank, NewEnv, the same size as the old
  89.     enviroment. It copies in the new PATH, then it copies the old
  90.     enviroment, filtering out any old PATH. Then fills the rest, if any
  91.     with zeros. I added two zeros onto the end as a safety measure. Then
  92.     copy the new over the old.
  93.  
  94.     COMMENTS, SUGGESTIONS, CURSES
  95.  
  96.     That this works at all is based on experimental, rather than properly
  97.     documented, evidence. There are no guarantees. But then, its free.
  98.  
  99.     I'm open to any comments or suggestions that anyone out there might
  100.     have. Specifically, I'd be interested to know if it works on your
  101.     machine, or if it doesn't work on your machine. If it doesn't work, can
  102.     you find an alternate solution for your machine, or find out what,
  103.     specifically, is wrong with my assumptions? Can anyone out there find
  104.     any documentation that would guarantee my assumptions are true? Can any
  105.     of you prove Fermat's last conjecture?
  106.  
  107.     You can write me at
  108.  
  109.                         David Dubois
  110.                         Zelkop Software
  111.                         P.O. Box 5177
  112.                         Armdale, N.S.
  113.                         Canada
  114.                         B3L 4M7
  115.  
  116.     or you if you're on CompuServe you can EasyPlex me at 71401,747, or
  117.     leave a message on the Borland's Programmer A Forum (GO BPROGA). }
  118.  
  119. type
  120.   EnvType = array [ 1 .. 32768 ] of char;
  121.   EnvPtr  = ^ EnvType;
  122. var
  123.   Env   : EnvPtr;
  124.   Bytes : word;
  125.  
  126.   procedure FindEnvironment;
  127.   var
  128.     CommandSeg : word;
  129.     TempSeg    : word;
  130.     BlockSeg   : word;
  131.   begin
  132.     TempSeg := PrefixSeg;                   { Trace the PSP's    }
  133.     repeat                                  { back into previous }
  134.       CommandSeg := TempSeg;                { generations        }
  135.       TempSeg := memw [ TempSeg : $16 ];
  136.     until CommandSeg = TempSeg;
  137.  
  138.     BlockSeg := CommandSeg;                           { Look for         }
  139.     repeat                                            { allocation block }
  140.       inc ( BlockSeg );
  141.     until     ( mem  [ BlockSeg : 0 ] = $4D        )
  142.           and ( memw [ BlockSeg : 1 ] = CommandSeg );
  143.  
  144.     Env := ptr ( succ ( BlockSeg ), 0 );   { pointer to enviroment }
  145.     Bytes := 16 * memw [ BlockSeg : 3 ];   { size of enviroment in bytes }
  146.   end;
  147.  
  148.   procedure ReplacePath ( NewPath : string );
  149.   var
  150.     NewEnv   : EnvPtr;
  151.     OldOfs   : word;
  152.     NewOfs   : word;
  153.     I        : word;
  154.   begin
  155.     getmem ( NewEnv, Bytes );   { make place to copy }
  156.  
  157.     OldOfs := 1;
  158.     NewOfs := 1;
  159.  
  160.     for I := 1 to length ( NewPath ) do             { uppercaserize }
  161.       NewPath [ I ] := upcase ( NewPath [ I ] );
  162.     NewPath := 'PATH=' + NewPath + #0;               { store new path }
  163.     for I := 1 to length ( NewPath ) do
  164.       begin
  165.         NewEnv ^ [ NewOfs ] := NewPath [ I ];
  166.         inc ( NewOfs );
  167.       end;
  168.  
  169.     while ( NewOfs <= Bytes ) and ( OldOfs <= Bytes ) do   { copy rest }
  170.       if     ( Env ^ [ OldOfs     ] = 'P' )
  171.          and ( Env ^ [ OldOfs + 1 ] = 'A' )
  172.          and ( Env ^ [ OldOfs + 2 ] = 'T' )         { filter out }
  173.          and ( Env ^ [ OldOfs + 3 ] = 'H' )         { old path   }
  174.          and ( Env ^ [ OldOfs + 4 ] = '=' ) then
  175.         begin
  176.           while Env ^ [ OldOfs ] <> #0 do
  177.             inc ( OldOfs );
  178.           inc ( OldOfs );
  179.         end
  180.       else
  181.         begin
  182.           NewEnv ^ [ NewOfs ] := Env ^ [ OldOfs ];    { moving }
  183.           inc ( NewOfs );
  184.           inc ( OldOfs );
  185.         end;
  186.  
  187.     while NewOfs <= Bytes do
  188.       begin
  189.         NewEnv ^ [ NewOfs ] := #0;             { fill rest }
  190.         inc ( NewOfs );
  191.       end;
  192.  
  193.     NewEnv ^ [ Bytes - 1 ] := #0;           { safety }
  194.     NewEnv ^ [ Bytes ] := #0;
  195.  
  196.     move ( NewEnv ^, Env ^, Bytes );       { do it }
  197.   end;
  198.  
  199. begin
  200.   FindEnvironment;
  201.   ReplacePath ( paramstr ( 1 ) );
  202. end.