home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 31 / CDASC_31_1996_juillet_aout.iso / internet / rnr214.zip / EXEC.PAS < prev    next >
Pascal/Delphi Source File  |  1994-11-20  |  16KB  |  590 lines

  1. {alpha3: russell has modified this unit to work with tp4 -- see the original}
  2.  
  3. Unit exec;
  4. {
  5.    EXEC function with memory swap.
  6.    Needs Assembler file 'spawn.asm'.
  7.  
  8. Public domain software by
  9.  
  10.         Thomas Wagner
  11.         Ferrari electronic GmbH
  12.         Beusselstrasse 27
  13.         D-1000 Berlin 21
  14.         West Germany
  15.  
  16.         BIXname: twagner
  17. }
  18.  
  19. Interface
  20.  
  21. {alpha3: russell added tp4exec and genericf}
  22.  
  23. Uses
  24.   Dos,tp4exec,genericf;
  25.  
  26. type
  27.     filename = pathstr;
  28.     string128 = string [128];
  29.  
  30.  
  31. function do_exec (xfn: filename; pars: string128; spwn: integer;
  32.                   needed: word; newenv: boolean): integer;
  33.  
  34.    { The EXEC function.
  35.  
  36.       Parameters:    xfn   is a string containing the name of the file
  37.                            to be executed. If the string is empty,
  38.                            the COMSPEC environment variable is used to
  39.                            load a copy of COMMAND.COM or its equivalent.
  40.                            If the filename does not include a path, the
  41.                            current PATH is searched after the default.
  42.                            If the filename does not include an extension,
  43.                            the path is scanned for a COM or EXE file in
  44.                            that order.
  45.  
  46.                      pars  The program parameters.
  47.  
  48.                      spwn  If 1, the function will return, if necessary
  49.                            after swapping the memory image. 
  50.                            If -1, EMS will not be used during swapping.
  51.                            If 0, the function will terminate after the 
  52.                            EXECed program returns. 
  53.                            NOTE: If the program file is
  54.                            not found, the function will always return
  55.                            with the appropriate error code, even if 
  56.                            'spwn' is 0.
  57.  
  58.                      needed   The memory needed for the program in 
  59.                            paragraphs. If not enough memory is free, the
  60.                            program will be swapped out. Use 0 to never
  61.                            swap, $ffff to always swap. If 'spwn' is false,
  62.                            this parameter is irrelevant.
  63.  
  64.                      newenv   If this parameter is FALSE, the environment
  65.                            of the spawned program is a copy of the parent's
  66.                            environment. If it is TRUE, a new environment
  67.                            is created which includes the modifications from
  68.                            previous 'putenv' calls.
  69.  
  70.       Return value:
  71.                            $0000..00FF: The EXECed Program's return code
  72.                            (0..255 decimal)
  73.                            $0100:       Error writing swap file
  74.                            (256 decimal)
  75.                            $0200:       Program file not found
  76.                            (512 decimal)
  77.                            $03xx:       DOS-error-code xx calling EXEC
  78.                            (768..1023 decimal)
  79.                            $0400:       Error allocating environment buffer
  80.                            (1024 decimal)
  81. }
  82.  
  83.  
  84. procedure putenv (envvar: string);
  85. {  Adds a string to the environment. Note that the change to the 
  86.    environment is valid for an exec'ed process only, and only if you
  87.    set the 'newenv' parameter in do_exec to TRUE. }
  88.  
  89.  
  90. function envcount: integer;
  91. function envstr (index: integer): string;
  92. function getenv (envvar: string): string;
  93.  
  94. { Replacement functions for the environment handling functions in the
  95.   DOS unit. All three functions work exactly like their DOS-unit 
  96.   counterparts, except that they recognize the changes to the child
  97.   environment produced by 'putenv'. }
  98.  
  99.  
  100.  
  101. {===========================================================================}
  102.  
  103. Implementation
  104.  
  105. const
  106.    swap_filename = '$$AAAAAA.AAA';
  107.  
  108.     m_swapping        = $01;
  109.     m_use_ems        = $02;
  110.     m_creat_temp    = $04;
  111.     m_exec            = $80;
  112.  
  113. type
  114.    stringptr = ^string;
  115.    stringarray = array [0..10000] of stringptr;
  116.    stringarrptr = ^stringarray;
  117.    bytearray = array [0..30000] of byte;
  118.    bytearrayptr = ^bytearray;
  119.  
  120. var
  121.    envptr: stringarrptr;   { Pointer to the changed environment }
  122.    envcnt: integer;        { Count of environment strings }
  123.  
  124.  
  125. function do_spawn (method: byte;
  126.                    var swapfn; var xeqfn; var cmdtail; envlen: word;
  127.                    var env): integer; external;
  128.  
  129. {alpha3: russell changed spawn to spawnpn}
  130. {$L spawnpn}
  131.  
  132.  
  133. { Environment routines }
  134.  
  135. function envcount: integer;
  136.  
  137.    { Returns count of strings in environment. }
  138.  
  139.    var
  140.       cnt: integer;
  141.    begin
  142.    if envptr = nil { If not yet changed }
  143. {alpha3: russell changed dos.* to tp4exec.*}
  144.       then envcount := tp4exec.envcount
  145.       else envcount := envcnt;
  146.    end;
  147.  
  148.  
  149. function envstr (index: integer): string;
  150.  
  151.    { Returns environment string 'index' }
  152.  
  153.    begin
  154.    if envptr = nil { If not yet changed }
  155. {alpha3: russell changed dos.* to tp4exec.*}
  156.       then envstr := tp4exec.envstr (index)
  157.       else if (index <= 0) or (index >= envcnt)
  158.       then envstr := ''
  159.       else if envptr^ [index - 1] = nil
  160.       then envstr := ''
  161.       else envstr := envptr^ [index - 1]^;
  162.    end;
  163.  
  164.  
  165. function name_eq (var n1, n2: string): boolean;
  166.  
  167.    { Compares search string 'n1' with environment string 'n2'.
  168.      Case is insignificant. }
  169.  
  170.    var
  171.       i: integer;
  172.       eq: boolean;
  173.    begin
  174.    i := 1;
  175.    eq := false;
  176.    while (i <= length (n1)) and (i <= length (n2)) and
  177.          (upcase (n1 [i]) = upcase (n2 [i])) do
  178.       i := i + 1;
  179.    name_eq := (i > length (n1)) and (i <= length (n2)) and (n2 [i] = '=');
  180.    end;
  181.  
  182.  
  183. function searchenv (var str: string): integer;
  184.  
  185.    { Search for environment string, returns index in 'envptr' array.
  186.      Assumes 'envptr' is not NIL. }
  187.  
  188.    var
  189.       idx: integer;
  190.       found: boolean;
  191.    begin
  192.    idx := 0;
  193.    found := false;
  194.  
  195.    while (idx < envcnt) and not found do
  196.       begin
  197.       if envptr^ [idx] <> nil
  198.          then found := name_eq (str, envptr^ [idx]^);
  199.       idx := idx + 1;
  200.       end;
  201.    if not found
  202.       then searchenv := -1
  203.       else searchenv := idx - 1;
  204.    end;
  205.  
  206.  
  207. function getenv (envvar: string): string;
  208.  
  209.    { Returns value of environment string specified by name. }
  210.  
  211.    var
  212.       strp: stringptr;
  213.       eq: integer;
  214.    begin
  215.    if envptr = nil { If not yet changed }
  216. {alpha3: russell changed dos.* to tp4exec.*}
  217.       then getenv := tp4exec.getenv (envvar)
  218.       else begin
  219.       eq := searchenv (envvar);
  220.       if eq < 0
  221.          then getenv := ''
  222.          else begin
  223.          strp := envptr^ [eq];
  224.          eq := pos ('=', strp^);
  225.          getenv := copy (strp^, eq + 1, length (strp^) - eq);
  226.          end;
  227.       end;
  228.    end;
  229.  
  230.  
  231. procedure init_envptr;
  232.  
  233.    { Initialise 'envptr' array. Called when 'putenv' is used for the 
  234.      first time. Copies all environment strings into heap storage,
  235.      and builds an array of pointers to this strings. }
  236.  
  237.    var
  238.       i: integer;
  239.       str: string [255];
  240.    begin
  241. {alpha3: russell changed dos.* to tp4exec.*}
  242.    envcnt := tp4exec.envcount;
  243.    getmem (envptr, envcnt * sizeof (stringptr));
  244.    if envptr = nil
  245.       then exit;
  246.    for i := 0 to envcnt - 1 do
  247.       begin
  248. {alpha3: russell changed dos.* to tp4exec.*}
  249.       str := tp4exec.envstr (i + 1);
  250.       getmem (envptr^ [i], length (str) + 1);
  251.       if envptr^ [i] <> nil
  252.          then envptr^ [i]^ := str;
  253.       end;
  254.    end;
  255.  
  256.  
  257. procedure putenv (envvar: string);
  258.  
  259.    { Adds the string 'envvar' to the environment, or changes the
  260.      environment string if the name is already present. }
  261.  
  262.    var
  263.       idx, eq: integer;
  264.       help: stringarrptr;
  265.    begin
  266.    if envptr = nil
  267.       then init_envptr;
  268.    if envptr = nil
  269.       then exit;
  270.  
  271.    eq := pos ('=', envvar);
  272.    if eq = 0
  273.       then exit;
  274.    for idx := 1 to eq do
  275.       envvar [idx] := upcase (envvar [idx]);
  276.  
  277.    idx := searchenv (envvar);
  278.    if idx >= 0
  279.       then begin
  280.       freemem (envptr^ [idx], length (envptr^ [idx]^) + 1);
  281.  
  282.       if eq >= length (envvar)
  283.          then envptr^ [idx] := nil
  284.          else begin
  285.          getmem (envptr^ [idx], length (envvar) + 1);
  286.          if envptr^ [idx] <> nil
  287.             then envptr^ [idx]^ := envvar;
  288.          end;
  289.       end
  290.       else if eq < length (envvar)
  291.       then begin
  292.       getmem (help, (envcnt + 1) * sizeof (stringptr));
  293.       if help = nil
  294.          then exit;
  295.       move (envptr^, help^, envcnt * sizeof (stringptr));
  296.       freemem (envptr, envcnt * sizeof (stringptr));
  297.       envptr := help;
  298.       getmem (envptr^ [envcnt], length (envvar) + 1);
  299.       if envptr^ [envcnt] <> nil
  300.          then envptr^ [envcnt]^ := envvar;
  301.       envcnt := envcnt + 1;
  302.       end;
  303.    end;
  304.  
  305.  
  306.  
  307. { Routines to search for files }
  308.  
  309.  
  310. function exists (fn: filename): boolean;
  311.    
  312.    { Returns TRUE if a file with name 'fn' exists. }
  313.  
  314.    var
  315.       s: searchrec;
  316.    begin
  317.    findfirst (fn, readonly or hidden or sysfile or archive, s);
  318.    exists := doserror = 0;
  319.    end { exists };
  320.  
  321.  
  322. function tryext (var fn: filename): boolean;
  323.  
  324.    { Try '.COM' and '.EXE' on current filename, modify filename if found. }
  325.  
  326.    var
  327.       found: boolean;
  328.    begin
  329.    found := exists (fn + '.COM');
  330.    if found
  331.       then fn := fn + '.COM'
  332.       else begin
  333.       found := exists (fn + '.EXE');
  334.       if found
  335.          then fn := fn + '.EXE'
  336.       end;
  337.    tryext := found;
  338.    end;
  339.  
  340.  
  341.  
  342. function findfile (var fn: filename): boolean;
  343.  
  344.    { Try to find the file 'fn' in the current path. Modifies the filename
  345.      accordingly. }
  346.  
  347.    var
  348.       path: string [255];
  349.       prfx: filename;
  350.       i, j: integer;
  351.       ext, found: boolean;
  352.    begin
  353.    if fn = ''
  354.       then fn := getenv ('COMSPEC');
  355.  
  356.    i := pos ('\', fn);
  357.    j := pos ('.', fn);
  358.    if (j < i) and (j > 0)
  359.       then begin
  360.       j := i;
  361.       while (j <= length (fn)) and (fn [j] <> '.') do
  362.          j := j + 1;
  363.       end;
  364.    if (j > 0) and (j = length (fn))
  365.       then fn [0] := pred (fn [0]);
  366.  
  367.    ext := (j > 0) and (j < length (fn));
  368.  
  369.    if (ext)
  370.       then found := exists (fn)
  371.       else found := tryext (fn);
  372.  
  373.    if not found and (i = 0)
  374.       then begin
  375.       path := getenv ('PATH');
  376.       i := 1;
  377.       while i <= length (path) do
  378.          begin
  379.          j := 0;
  380.          while (path [i] <> ';') and (i <= length (path)) do
  381.             begin
  382.             j := j + 1;
  383.             prfx [j] := path [i];
  384.             i := i + 1;
  385.             end;
  386.          i := i + 1;
  387.          if (j > 0)
  388.             then begin
  389.             j := j + 1;
  390.             prfx [j] := '\';
  391.             prfx [0] := chr (j);
  392.             prfx := prfx + fn;
  393.             if ext
  394.                then found := exists (prfx)
  395.                else found := tryext (prfx);
  396.             if found
  397.                then begin
  398.                fn := prfx;
  399.                i := 999;
  400.                end;
  401.             end;
  402.          end;
  403.       end;
  404.    findfile := found;
  405.    end; { findfile }
  406.  
  407.  
  408. procedure tempdir (var outfn: filename);
  409.  
  410.    { Set temporary file path.
  411.      Read "TMP/TEMP" environment. If empty or invalid, clear path.
  412.      If TEMP is drive or drive+backslash only, return TEMP.
  413.      Otherwise check if given path is a valid directory.
  414.      If so, add a backslash, else clear path.
  415.    }
  416.    var
  417.       drive: string [2];
  418.       dir: dirstr;
  419.       name: namestr;
  420.       ext: extstr;
  421.       f: file;
  422.       attr: word;
  423.       regs: registers;
  424.  
  425.    begin
  426.    outfn := getenv ('TMP');
  427.    if outfn = ''
  428.       then outfn := getenv ('TEMP');
  429.  
  430.    if outfn = ''
  431.       then exit;
  432.  
  433.    if outfn [length (outfn)] in ['\', '/']
  434.       then dec (outfn [0]);
  435.  
  436.    fsplit (outfn, dir, name, ext);
  437.    drive := '';
  438.    if length (dir) > 1
  439.       then if dir [2] = ':'
  440.          then begin
  441.          drive := dir [1] + ':';
  442.          delete (dir, 1, 2);
  443.          end;
  444.  
  445.    if drive <> ''
  446.       then begin
  447.       regs.ah := $1c;
  448.       regs.dl := ord (upcase (drive [1])) - ord ('A') + 1;
  449.       msdos (regs);
  450.       if regs.al = $ff
  451.          then begin
  452.          outfn := '';
  453.          exit;
  454.          end;
  455.       end;
  456.  
  457.    if name = ''
  458.       then begin
  459.       if dir <> ''
  460.          then outfn := ''
  461.          else outfn := drive + '\';
  462.       exit;
  463.       end;
  464.  
  465.    assign (f, outfn);
  466.    getfattr (f, attr);
  467.    if (doserror <> 0) or 
  468.       ((attr and directory) = 0) or 
  469.       ((attr and readonly) <> 0)
  470.       then outfn := ''
  471.       else outfn := outfn + '\';
  472.    end;
  473.  
  474.  
  475. function do_exec (xfn: filename; pars: string128; spwn: integer;
  476.                   needed: word; newenv: boolean): integer;
  477.    var
  478.       swapfn: filename;
  479.       avail: word;
  480.       regs: registers;
  481.       envlen, einx: word;
  482.       idx, len: integer;
  483.       envp: bytearrayptr;
  484.       method: byte;
  485.    begin
  486.  
  487.    { First, check if the file to execute exists. }
  488.  
  489.    if not findfile (xfn)
  490.       then begin
  491.       do_exec := $200;
  492.       exit;
  493.       end;
  494.  
  495.    { Now create a copy of the environment if the user wants it, and
  496.      if the environment has been changed. }
  497.  
  498.    envlen := 0;
  499.    if newenv and (envptr <> nil)
  500.       then begin
  501.       for idx := 0 to envcnt - 1 do
  502.          envlen := envlen + length (envptr^ [idx]^) + 1;
  503.       if envlen > 0
  504.          then begin
  505.          envlen := envlen + 1;
  506.          getmem (envp, envlen);
  507.          if envp = nil
  508.             then begin
  509.             do_exec := $400;
  510.             exit;
  511.             end;
  512.          einx := 0;
  513.          for idx := 0 to envcnt - 1 do
  514.             begin
  515.             len := length (envptr^ [idx]^);
  516.             move (envptr^ [idx]^ [1], envp^ [einx], len);
  517.             envp^ [einx + len] := 0;
  518.             einx := einx + len + 1;
  519.             end;
  520.          envp^ [einx] := 0;
  521.          end;
  522.       end;
  523.  
  524.    if spwn = 0
  525.       then method := m_exec    { Mark 'EXEC' function }
  526.       else begin
  527.  
  528.       { Determine amount of free memory }
  529.       with regs do
  530.          begin
  531.          ax := $4800;
  532.          bx := $ffff;
  533.          msdos (regs);
  534.          avail := regs.bx;
  535.          end;
  536.  
  537.       { No swapping if available memory > needed }
  538.  
  539.       if needed < avail
  540.          then method := 0
  541.          else begin
  542.  
  543.          { Swapping necessary, use 'TMP' or 'TEMP' environment variable
  544.            to determine swap file path if defined. }
  545.  
  546.          if spwn < 0
  547.             then method := m_swapping
  548.             else method := m_swapping or m_use_ems;
  549.  
  550.          tempdir (swapfn);
  551.  
  552.             if (dosversion and $ff) >= 3
  553.                 then method := method or m_creat_temp
  554.                 else begin
  555.                 swapfn := swapfn + swap_filename;
  556.              len := length (swapfn);
  557.              while exists (swapfn) do
  558.                 begin
  559.                 if (swapfn [len] >= 'Z')
  560.                    then len := len - 1;
  561.                 if (swapfn [len] = '.')
  562.                    then len := len - 1;
  563.                 swapfn [len] := succ (swapfn [len]);
  564.                 end;
  565.                 end;
  566.          swapfn [length (swapfn) + 1] := #0;
  567.          end;
  568.       end;
  569.  
  570.    { All set up, ready to go. }
  571.  
  572.    swapvectors;
  573.    do_exec := do_spawn (method, swapfn, xfn, pars, envlen, envp^);
  574.    swapvectors;
  575.  
  576.    { Free the environment buffer if it was allocated. }
  577.  
  578.    if envlen > 0
  579.       then freemem (envp, envlen);
  580.    end;
  581.  
  582.  
  583. { Initialisation for environment processing }
  584.  
  585. Begin
  586. envptr := nil;
  587. envcnt := 0;
  588. End.
  589.  
  590.