home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / turbopas / env20.zip / ENVUNIT.PAS < prev   
Pascal/Delphi Source File  |  1988-09-19  |  16KB  |  608 lines

  1. unit EnvUnit; {             Version 2.0            88/09/19
  2.  
  3. Handy little routines to simplify using the environment string.
  4.  
  5. See the example program ENVTEST.PAS, for hints on how to use this unit.
  6.  
  7. MOST LIKELY TO BE USED:   1) FFind - search the path for a named file and
  8.                                      return the fully qualified file name
  9.                                      if it is found.
  10.  
  11.                           2) PathTo - search the path for a named file;
  12.                                       return the path to that file if found
  13.  
  14.                           3) ParamStr - the complete parameter string
  15.  
  16.  
  17. This program is hereby donated to the public domain. It may be freely copied,
  18. used & modified without charge or fee.
  19.  
  20. Author        :  Mike Babulic
  21.                  3827 Charleswood Dr. N.W.
  22.                  Calgary, Alberta
  23.                  CANADA
  24.                  T2L 2C7
  25. Compuserve ID :  72307,314
  26.  
  27. }
  28.  
  29.  
  30. interface
  31.  
  32. uses Dos;
  33.  
  34.  
  35. {$IFDEF VER40}   {These objects are already in TP Version 5's Dos Unit}
  36.                  {I've included them so you can upgrade gracefully}
  37.  
  38. type
  39.    PathStr = string[79];
  40.    DirStr  = string[67];
  41.    NameStr = string[8];
  42.    ExtStr  = string[4];
  43.  
  44. function DosVersion: word;  { lo = version (ex. 3);  hi = fraction (ex. .2) }
  45.  
  46. function EnvCount: integer;              {number of Environment Strings}
  47. function EnvStr(Index:integer): string;  {get Env. String number index}
  48. function GetEnv(EnvVar:string): string;  {get Env. String named by EnvVar}
  49.  
  50. function FExpand(Path:PathStr):PathStr;
  51.   {expand the path to a fully qualified file name}
  52. function FSearch(Path:PathStr;DirList:string):PathStr;
  53.    {Search DirList (paths separated by ";") for Path & return full name of
  54.     this file}
  55. procedure FSplit(Path:PathStr; var Dir:DirStr; var Name:NameStr; var Ext:ExtStr);
  56. {$ENDIF}
  57.  
  58.  
  59.   var   MyPath : string;        {Path & Name of the running program}
  60.         MyDir  : DirStr;
  61.         MyName : NameStr;
  62.         MyExt  : ExtStr;
  63.  
  64.  
  65.   function DOS_Version: integer;
  66.       {Returns the version of DOS being used (ex. 302 is DOS 3.2)}
  67.  
  68.  
  69.   function ParamString: String;
  70.       {Returns the complete parameter string}
  71.  
  72.   function EnvStrPtr:Pointer;
  73.       {Point to environment strings}
  74.  
  75.  
  76.   var PSP : word;  {Program Segment Prefix;  initially = PrefixSeg}
  77.  
  78.   function ProgPath: PathStr;    {Path to program owning current PSP}
  79.   function ProgDir:  DirStr;        {Directory of program owning current PSP}
  80.   function ProgName: NameStr;       {Name of program owning current PSP}
  81.   function ProgExt:  ExtStr;        {Extension of program owning current PSP}
  82.  
  83.   procedure UseMyPSP;
  84.       {Use the program's PSP to find the environment}
  85.   procedure UseParentPSP;
  86.       {Use the parent of the current PSP to find the environment}
  87.   procedure UseRootPSP;
  88.       {Use the parent of the current PSP to find the environment}
  89.  
  90.  
  91.   function FirstEnv:String;
  92.       {Get the First Environment string}
  93.   function NextEnv:String;
  94.       {Get the Next Environment string}
  95.   function EOEnv:Boolean;
  96.      {True if End Of Environment}
  97.  
  98.  
  99.   function FirstNamed(name,delim:String):String;
  100.      {Get the first string in an the named environment specification
  101.          eg. If name = 'PATH' and delim = ';' then get the first path string
  102.              "Path" strings are delimited by semicolins: ";" }
  103.   function NextNamed:String;
  104.      {Get the next string in an environment specification}
  105.   function EONamed:Boolean;
  106.      {True if end of environment specification}
  107.  
  108.  
  109.   function FirstPath:String;
  110.      {Almost the same as Firstnamed('PATH',';'), but appends a '\' to the
  111.       string if needed}
  112.   function NextPath:String;
  113.  
  114.  
  115.   function PathTo(filename:string):string;
  116.      {Searches the environment PATH and returns a path to the named file.
  117.         Check the current directory,
  118.         then search the environment PATH,
  119.         then check the directory containing the calling program (MyDir).
  120.         If the file is still not found, return a null string ('')}
  121.  
  122.   function FFind(filename:string):string;
  123.      {Find the File called "fileneme".
  124.         Check the current directory,
  125.         then search the environment PATH,
  126.         then check the directory containing the calling program (MyDir).
  127.         - if "filename" is found return the fully qualified file name.
  128.         - if "filename" is NOT found then return a PERIOD (".")
  129.           - a period is returned because if you write something like:
  130.                 Assign(aFile,FFind('MISSING.TXT'));
  131.                 Reset(aFile);
  132.             and FFind returned '' when it failed then aFile would be assigned
  133.             to the standard INPUT file (usually the keyboard)! }
  134.  
  135. {misc}
  136.   function FileExists(name:string):Boolean;      {True if named file exists}
  137.   procedure PtrInc(var p:Pointer; n: Longint);   {Increment pointer by n}
  138.  
  139.  
  140. {----------------------------------------------------------------------------}
  141.  
  142. implementation
  143.  
  144.  
  145.   procedure PtrInc(var p:Pointer; n: Longint);   {Increment pointer by n}
  146.     type pointr = record  lo,hi: word  end;
  147.     var
  148.        pt : pointr   absolute  p;
  149.        c  : pointr   absolute  n;
  150.     begin
  151.       n := pt.lo + n;
  152.       pt.hi := pt.hi + n shr 4;
  153.       pt.lo := c.lo and $F;
  154.     end;
  155.  
  156.  
  157. {-----------------------------------------------------------------------------}
  158.  
  159.  
  160.  
  161.   type WordP = ^word;
  162.  
  163.   function EnvStrPtr:Pointer;
  164.     begin
  165.       EnvStrPtr := Ptr(WordP(Ptr(PSP,$2C))^,0);
  166.     end;
  167.  
  168.   procedure UseMyPSP;
  169.     begin
  170.       PSP := PrefixSeg;
  171.     end;
  172.  
  173.   Procedure UseParentPSP;
  174.     begin
  175.       PSP := WordP(Ptr(PSP,$16))^;
  176.     end;
  177.  
  178.   Procedure UseRootPSP;
  179.     var oldPSP : word;
  180.     begin
  181.       repeat
  182.         oldPSP := PSP;
  183.         UseParentPSP;
  184.       until PSP=oldPSP;
  185.     end;
  186.  
  187.  
  188. {-----------------------------------------------------------------------------}
  189.  
  190.   Type ASCIIz = array [0..127] of char;
  191.        ASCIIptr = ^ASCIIz;
  192.  
  193.   function StrZ(var c:ASCIIz):string;
  194.     label done;
  195.     var i: integer;
  196.     begin
  197.       for i := 0 to 127 do begin
  198.        if c[i]=#0 then goto done;
  199.         StrZ[i+1] := c[i];
  200.       end;
  201.       i := 128;
  202.       done: StrZ[0] := chr(i);
  203.     end;
  204.  
  205.   function ToDelim(d:string; var s:string):integer;
  206.     var i:integer;
  207.     begin
  208.       i := pos(d,s);    {length to first delimiter}
  209.       if i>0 then
  210.         s[0] := chr(i-1)
  211.       else
  212.         i := length(s);
  213.       ToDelim := i;
  214.     end;
  215.  
  216.  
  217. {----------------------------------------------------------------------------}
  218.  
  219.  
  220. function ParamString: String;
  221.   type StrPtr = ^String;
  222.   begin
  223.     ParamString := StrPtr(Ptr(PrefixSeg,$80))^;
  224.   end;
  225.  
  226.  
  227. {----------------------------------------------------------------------------}
  228.  
  229.  
  230.   var EnvPtr : ASCIIptr;
  231.  
  232.   function FirstEnv:String;
  233.     var s: string[255];
  234.         i: integer;
  235.     begin
  236.       EnvPtr := EnvStrPtr;
  237.       FirstEnv := NextEnv;
  238.     end;
  239.  
  240.   function NextEnv:String;
  241.     var s: string;
  242.         i: integer;
  243.     begin
  244.       if EOEnv then
  245.         NextEnv := ''
  246.       else begin
  247.         s := StrZ(EnvPtr^);
  248.         i := ToDelim(#0,s);
  249.         PtrInc(Pointer(EnvPtr),i+1);
  250.         NextEnv := s;
  251.       end;
  252.     end;
  253.  
  254. procedure SkipEnv;
  255.   var i : integer;
  256.   begin
  257.     for i := 1 to MaxInt do
  258.       if EnvPtr^[i]=#0 then begin
  259.         PtrInc(Pointer(EnvPtr),i+1);
  260.         exit
  261.       end;
  262.   end;
  263.  
  264.    function EOEnv:Boolean;
  265.      begin
  266.        EOEnv := (EnvPtr^[0]=#0);
  267.      end;
  268.  
  269.  
  270. {----------------------------------------------------------------------------}
  271.  
  272.  
  273.   var namePtr : ASCIIptr;
  274.       dummy  : LongInt;
  275.       namedDelim : string;
  276.  
  277.   function EONamed:Boolean;
  278.     begin
  279.       EONamed := (namePtr^[0]=#0);
  280.     end;
  281.  
  282.   function FirstNamed(name,delim:String):string;
  283.     var
  284.         s: string;
  285.         i: integer;
  286.     begin
  287.       for i := 1 to length(name) do name[i] := upcase(name[i]);
  288.       name := name+'=';
  289.       FirstNamed := '';
  290.       namePtr := EnvStrPtr;
  291.       namedDelim := delim;
  292.       while namePtr^[0]<>#0 do begin
  293.         s := StrZ(namePtr^);
  294.         if (length(s)>=length(name)) and (name=copy(s,1,length(name))) then begin
  295.           i := Pos('=',s);  {skip past the '='}
  296.           PtrInc(Pointer(namePtr),i);
  297.           s := StrZ(namePtr^);
  298.           i := ToDelim(NamedDelim,s);
  299.           PtrInc(Pointer(namePtr),i);
  300.           FirstNamed := s;
  301.           Exit;
  302.           end
  303.         else
  304.           PtrInc(Pointer(namePtr),length(s)+1);
  305.       end;
  306.     end;
  307.  
  308.   function NextNamed:string;
  309.     var
  310.         s: string;
  311.         i: integer;
  312.     begin
  313.       if EONamed then begin
  314.         NextNamed := '';
  315.         end
  316.       else begin
  317.         s := StrZ(namePtr^);
  318.         i := ToDelim(NamedDelim,s);
  319.         PtrInc(Pointer(namePtr),i);
  320.         NextNamed := s;
  321.       end;
  322.     end;
  323.  
  324. {----------------------------------------------------------------------------}
  325.  
  326.   function DirDelim(s:String):String;
  327.     var i: integer;
  328.     begin
  329.       DirDelim := '';
  330.       i := length(s);
  331.       while (i>0) and (s[i]=' ') do i := pred(i);
  332.       if i<=0 then exit;
  333.       s[0] := chr(i);
  334.       if not (s[i] IN [':','\']) then  s := s + '\';
  335.       DirDelim := s;
  336.     end;
  337.  
  338.   function FirstPath: String;
  339.     begin
  340.       FirstPath := DirDelim(FirstNamed('PATH',';'));
  341.     end;
  342.  
  343.   function NextPath: String;
  344.     begin
  345.       NextPath := DirDelim(NextNamed);
  346.     end;
  347.  
  348.  
  349.   function PathTo(filename:string):string;
  350.     var path: string;
  351.         found: boolean;
  352.     begin
  353.       PathTo := '';
  354.       if filename<>'' then begin
  355.         found := FALSE;
  356.         if FileExists(filename) then begin   {Check Current Directory}
  357.           GetDir(0,path);
  358.           path := DirDelim(path);
  359.           found := FileExists(path+filename);
  360.         end;
  361.         if not found then begin              {Check the Path}
  362.           path  := FirstPath;
  363.           found := FileExists(path+filename);
  364.           while not (EONamed or found) do begin
  365.             path  := NextPath;
  366.             found := FileExists(path+filename);
  367.           end;
  368.         end;
  369.         if not found then begin               {Check the Program's Directory}
  370.           found := FileExists(MyDir+filename);
  371.           if found then path := MyDir;
  372.         end;
  373.         if found then
  374.           PathTo := path;
  375.       end;
  376.     end;
  377.  
  378.   function FFind(filename:string):string;
  379.     var p : string;
  380.     begin
  381.       p := PathTo(filename);
  382.       if p<>'' then
  383.         FFind := FExpand(p+filename)
  384.       else
  385.         FFind := '.';
  386.     end;
  387.  
  388.  
  389.  
  390. {-----------------------------------------------------------------------------}
  391.  
  392.   function FileExists(name:string):Boolean;
  393.     var s : SearchRec;
  394.     begin
  395.       FindFirst(Name,0,s);
  396.       FileExists := (DosError=0);
  397.     end;
  398.  
  399.  
  400. {-----------------------------------------------------------------------------}
  401.  
  402.  
  403.  
  404.   function DOS_Version: integer;
  405.       {Returns the version of DOS being used}
  406.     var r : registers;
  407.     begin
  408.       r.ax := $3000;
  409.       MsDos(r);
  410.       with r do
  411.         DOS_Version := al * 100 + ah
  412.     end;
  413.  
  414.  
  415. {-----------------------------------------------------------------------------}
  416.  
  417.   var
  418.       pPath : string;
  419.       pDir  : DirStr;
  420.       pName : NameStr;
  421.       pExt  : ExtStr;
  422.  
  423.   procedure GetPName;
  424.     var
  425.       c : ^char;
  426.       i : word;
  427.     begin
  428.       if DOS_Version<300 then begin {Only for DOS 3.x and greater}
  429.         pPath := '';
  430.         pName := '';
  431.        end
  432.       else begin
  433.         c := EnvStrPtr;
  434.         {Skip to the end of the Environment}
  435.           repeat
  436.             while c^<>#0 do
  437.               PtrInc(pointer(c),1);
  438.             PtrInc(pointer(c),1);
  439.           until c^=#0;
  440.           PtrInc(Pointer(c),3);
  441.         pPath := FExpand(StrZ(AsciiPtr(c)^));
  442.         FSplit(pPath,pDir,pName,pExt);
  443.       end;
  444.     end;
  445.  
  446.  
  447.  
  448.   function ProgPath: PathStr;    {Path to program owning current PSP}
  449.     begin
  450.       GetPName;  ProgPath := pPath;
  451.     end;
  452.  
  453.   function ProgDir:  DirStr;        {Directory of program owning current PSP}
  454.     begin
  455.       GetPName;  ProgDir := pDir;
  456.     end;
  457.  
  458.   function ProgName: NameStr;       {Name of program owning current PSP}
  459.     begin
  460.       GetPName;  ProgName := pName;
  461.     end;
  462.  
  463.   function ProgExt:  ExtStr;        {Extension of program owning current PSP}
  464.     begin
  465.       GetPName;  ProgExt := pExt;
  466.     end;
  467.  
  468.  
  469. {-----------------------------------------------------------------------------}
  470.  
  471. {$IFDEF VER40}  {These objects are already in TP Version 5's Dos Unit}
  472.  
  473.  
  474. function DosVersion: word;  { lo = version (ex. 3);  hi = fraction (ex. .2) }
  475.     var r : registers;
  476.     begin
  477.       r.ax := $3000;
  478.       MsDos(r);
  479.       DOSVersion := r.ax;
  480.     end;
  481.  
  482.  
  483. function EnvCount: integer;              {number of Environment Strings}
  484.   var i: integer;
  485.   begin
  486.     UseMyPSP;
  487.     EnvPtr := EnvStrPtr;
  488.     i := 0;
  489.     while not EoEnv do begin
  490.       SkipEnv;
  491.       i := succ(i);
  492.     end;
  493.     EnvCount := i;
  494.   end;
  495.  
  496.  
  497. function EnvStr(Index:integer): string;  {get Env. String number index}
  498.   begin
  499.     UseMyPSP;
  500.     EnvPtr := EnvStrPtr;
  501.     while (index>1) and not EoEnv do begin
  502.       SkipEnv;
  503.       index := pred(index);
  504.     end;
  505.     if index = 1 then
  506.       EnvStr := NextEnv
  507.     else
  508.       EnvStr := '';
  509.   end;
  510.  
  511.  
  512. function GetEnv(EnvVar:string): string;  {get Env. String named by EnvVar}
  513.   begin
  514.     GetEnv := FirstNamed(EnvVar,#0);
  515.   end;
  516.  
  517.  
  518. function FExpand(Path:PathStr):PathStr;
  519.   var
  520.     i : integer;
  521.     old: PathStr;
  522.   begin
  523.     FSplit(path,pDir,pName,pExt);
  524.     if length(pDir)=0 then
  525.       GetDir(0,pDir)
  526.     else begin
  527.       if pDir[length(pDir)]='\' then  pDir[0] := chr(length(pDir)-1);
  528.       GetDir(0,old);
  529.       ChDir(pDir);
  530.       GetDir(0,pDir);
  531.       ChDir(old);
  532.     end;
  533.     path := pName+pExt;
  534.     for i := 1 to length(path) do path[i] := UpCase(path[i]);
  535.     FExpand := pDir+'\'+path;
  536.   end;
  537.  
  538.  
  539.   function FSearch(Path:PathStr;DirList:string):PathStr;
  540.     var dir: string;
  541.         i: integer;
  542.         found: boolean;
  543.     procedure NextDir;
  544.       var j : integer;
  545.       begin
  546.         i := succ(i);  j := i;
  547.         while (j<length(DirList)) and (DirList[j]<>';') do j := succ(j);
  548.         Dir := DirDelim(Copy(Dirlist,i,j-i))+Path;
  549.         i := j;
  550.       end;
  551.     begin
  552.       FSearch := '';
  553.       if Path<>'' then begin
  554.         found := FileExists(path);       {Check Current Directory}
  555.         if Found then
  556.           Dir := Path
  557.         else begin                       {Check DirList}
  558.           i := 0;
  559.           repeat
  560.             NextDir;
  561.             found := FileExists(Dir);
  562.           until (i>=length(DirList)) or found;
  563.         end;
  564.         if found then
  565.           FSearch := Dir;
  566.       end;
  567.     end;
  568.  
  569.  
  570. procedure FSplit(Path:PathStr; var Dir:DirStr; var Name:NameStr; var Ext:ExtStr);
  571.   var i,j : integer;
  572.       done : boolean;
  573.   begin
  574.     Dir  := '';  Name := '';  Ext := '';
  575.     if Path='' then exit;
  576.     if Path[length(Path)]='.' then begin
  577.       Dir := Path;
  578.       if length(Path)=1 then exit;
  579.       if Path[length(Path)-1] in ['.','\'] then exit;
  580.       Dir := '';
  581.     end;
  582.     i := length(Path);  j := 0;  done := FALSE;
  583.     while (i>0) and (j<sizeof(Ext)) and not done do begin
  584.       done := (Path[i]='.');
  585.       if done then
  586.         Ext := Copy(Path,i,j+1);
  587.       j := succ(j);
  588.       i := pred(i);
  589.     end;
  590.     i := length(Path) - length(Ext);  j := i;
  591.     while (i>0) and not (Path[i] in [':','\']) do  i := pred(i);
  592.     Name := Copy(Path,i+1,j-i);
  593.     Dir := Copy(Path,1,i);
  594.   end;
  595. {$ENDIF}
  596.  
  597.  
  598. {-----------------------------------------------------------------------------}
  599.  
  600.   begin
  601.     UseMyPSP;
  602.     EnvPtr := EnvStrPtr;
  603.     dummy := 0;
  604.     namePtr := @dummy;
  605.     GetPName;
  606.     MyPath := pPath;
  607.     MyDir := pDir;  MyName := pName;  MyExt := pExt;
  608.   end.