home *** CD-ROM | disk | FTP | other *** search
- { EXEC.PAS version 1.5
- Copyright (C) 1986 by Bela Lubkin (1/14/86)
- Noncommercial use only EXCEPT with permission from Bela Lubkin; send
- EasyPlex to ID 76703,3015 for permission.
-
- See "VERY IMPORTANT NOTES" below before using these functions.
- REQUIRES Turbo Pascal version 3.0 (may work with later versions, when they
- appear)
-
- Allows you to
- o Call MS-DOS programs
- o Get the return codes from those programs
- o Get strings from the MS-DOS environment
-
- Calling information
- -------------------
- Function SubProcess(CommandLine: _Exec_Str255): Integer;
- Calls an executable image (.COM or .EXE file) using MS-DOS function
- 4Bh, Exec. The parameter CommandLine must contain both the name of the
- program to run and the arguments to be passed to it, seperated by a
- space. Path searching and other amenities are not performed; the passed
- in name must be specific enough to allow the file to be found, i.e.
- 'CHKDSK' will NOT work. At least 'CHKDSK.COM' must be specified, and a
- drive and path name will help even more. For example,
- 'C:\SYSTEM\CHKDSK.COM'
- 'A:\WS.COM DOCUMENT.1'
- 'C:\DOS\LINK.EXE TEST;'
- 'D:\ASSEM\MASM.EXE PROG1 PROG1.OBJ NUL PROG1.MAP'
- 'C:\COMMAND.COM /C COPY *.* B:\BACKUP >FILESCOP.IED'
- The last example uses COMMAND.COM to invoke a DOS internal command and
- to perform redirection. Only with the use of COMMAND.COM can the
- following be done: redirection; piping; path searching; searching for
- the extension of a program (.COM, .EXE, or .BAT); batch files; and
- internal DOS commands.
- Because the COMMAND-assisted Exec function is so useful, a seperate
- function, SubProcessViaCOMMAND, is provided for that purpose.
- The integer return value of SubProcess is the error value returned by
- DOS on completion of the Exec call. If it is nonzero, the call failed.
- Here is a list of likely error values:
- 0: Success
- 2: File/path not found
- 3: Path not found
- 4: Too many files open (no handles left)
- 5: Access denied
- 8: Not enough memory to load program
- 10: Illegal environment (greater than 32K)
- 11: Illegal .EXE file format
- 32: Sharing violation
- 33: Lock violation
- If you get any other result, consult an MS-DOS Technical Reference
- manual.
-
- Function GetEnvStr(SearchString: _Exec_Str255): _Exec_Str255;
- Gets a string from the MS-DOS environment. The parameter SearchString
- specifies the desired environment string. The function result returns
- the value of that string from the environment. If the string is not
- found, a null string is returned. SearchString may have one special
- value, '='. This returns garbage under MS-DOS 2.x. Under MS-DOS 3.x,
- it returns the pathname under which the currently running program was
- invoked. Examples:
- GetEnvStr('COMSPEC') might = 'C:\COMMAND.COM'
- GetEnvStr('PROMPT') might = '$p $g'
- GetEnvStr('REFLEX') might = 'Herc'
- GetEnvStr('=') might = 'C:\TURBO\exectest.COM'
- Only an exact match will succeed; case IS significant. Do not include
- an equal sign in the search string (GetEnvStr('COMSPEC=') will fail).
- Note: if you are wondering why there is no SetEnvStr procedure, read
- an MS-DOS Technical Reference manual.
-
- Function GetComSpec: _Exec_Str66;
- This is a special case of GetEnvStr and simply returns the COMSPEC
- environment string. It is included for compatability with previous
- EXEC.PAS versions.
-
- Function SubProcessViaCOMMAND(CommandLine: _Exec_Str255): Integer;
- This is a special case of SubProcess. The CommandLine is passed to
- COMMAND.COM, which does all further processing. Command lines invoked
- via this procedure can do redirection and piping; undergo the normal DOS
- PATH search; may be batch files; and may be internal DOS commands such
- as COPY and RENAME.
- Disadvantages of this approach are: a copy of COMMAND.COM must be
- present (not always true on a floppy-based system); a slight time and
- memory penalty is involved due to the loading of an extra copy of
- COMMAND.COM (about 3K under DOS 3.1); the subprocess return code
- (Errorlevel) is lost. In most cases the benefits will outweight the
- disadvantages.
- The integer return code is the same as for SubProcess.
- Note: you may be wondering why there is not
-
- Function Shell: Integer;
- This is a special case of SubProcess. It gives a DOS prompt to the
- user. Typing EXIT returns to the Turbo program. The integer return
- code is the same as for SubProcess.
-
- Function SubProcessReturnCode: Integer;
- This function calls MS-DOS function 4Dh, Get Return Code of a
- Sub-process. The integer return value is the return code set by the
- last subprocess you called. Like Turbo's IOResult, SubProcessReturnCode
- is only valid once after a SubProcess call, reverting to 0 on successive
- calls. The return code obtained after using SubProcessViaCOMMAND or
- Shell is the code returned by COMMAND.COM, not by any other program, and
- is not likely to be useful.
- Note: Turbo programs can set the return code by using the Halt
- procedure with a parameter, e.g. Halt(20);. Other languages can call
- DOS function 4Ch (Terminate) with the return code in AL.
-
- VERY IMPORTANT NOTES
- --------------------
- The Exec calls (SubProcess, SubProcessViaCOMMAND, Shell) will not work
- unless you restrict Turbo's heap. To do this, lower "mAximum dynamic free
- memory" on the compiler Options menu to a reasonable value. What is
- reasonable depends on your program's use of the heap and the stack, and must
- be determined by you. If you use neither the heap nor recursion, as low as
- 400h (16K bytes) is probably more than enough.
-
- The Exec calls CANNOT be called from within the interactive Turbo compiler
- system. They can only be called from .COM or .CHN files running outside of
- the Turbo environment.
-
- Revision history
- ----------------
- Version 1.5 1/14/86 fixes the memory freeing bug by removing support for
- Turbo 2.0. String types changed to minimize chances of
- collision. General environment support added. Explicit calls
- for Exec-via-COMMAND.COM and Exec-to-DOS-prompt added. Support
- for getting the subprocess return code added. Major
- documentation overhaul. NOW REQUIRES TURBO 3.0!
- (Thanks to Stu Fuller 76703,501 for pointing out how easy it
- was to add full environment support).
- Version 1.4 attempts to fix a bug in the freeing of memory before the
- Exec call.
- Version 1.3 works with MS-DOS 2.0 and up, TURBO PASCAL version 1.0 and up.
- Version 1.2 had a subtle but dangerous bug: I set a variable that was
- addressed relative to BP, using a destroyed BP!
- Version 1.1 didn't work with Turbo 2.0 because I used Turbo 3.0 features
- Version 1.0 only worked with DOS 3.0 due to a subtle bug in DOS 2.x
-
- - Bela Lubkin
- CompuServe 76703,3015
- }
-
- Type
- _Exec_Str66=String[66];
- _Exec_Str255=String[255];
-
- Function SubProcess(CommandLine: _Exec_Str255): Integer;
- Const
- SSSave: Integer=0;
- SPSave: Integer=0;
-
- Var
- Regs: Record Case Integer Of
- 1: (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: Integer);
- 2: (AL,AH,BL,BH,CL,CH,DL,DH: Byte);
- End;
- FCB1,FCB2: Array [0..36] Of Byte;
- PathName: _Exec_Str66;
- CommandTail: _Exec_Str255;
- ParmTable: Record
- EnvSeg: Integer;
- ComLin: ^Integer;
- FCB1Pr: ^Integer;
- FCB2Pr: ^Integer;
- End;
- RegsFlags: Integer;
-
- Begin
- If Pos(' ',CommandLine)=0 Then
- Begin
- PathName:=CommandLine+#0;
- CommandTail:=^M;
- End
- Else
- Begin
- PathName:=Copy(CommandLine,1,Pred(Pos(' ',CommandLine)))+#0;
- CommandTail:=Copy(CommandLine,Pos(' ',CommandLine),255)+^M;
- End;
- CommandTail[0]:=Pred(CommandTail[0]);
- With Regs Do
- Begin
- FillChar(FCB1,Sizeof(FCB1),0);
- AX:=$2901;
- DS:=Seg(CommandTail[1]);
- SI:=Ofs(CommandTail[1]);
- ES:=Seg(FCB1);
- DI:=Ofs(FCB1);
- MsDos(Regs); { Create FCB 1 }
- FillChar(FCB2,Sizeof(FCB2),0);
- AX:=$2901;
- ES:=Seg(FCB2);
- DI:=Ofs(FCB2);
- MsDos(Regs); { Create FCB 2 }
- With ParmTable Do
- Begin
- EnvSeg:=MemW[CSeg:$002C];
- ComLin:=Addr(CommandTail);
- FCB1Pr:=Addr(FCB1);
- FCB2Pr:=Addr(FCB2);
- End;
- InLine($8D/$96/ PathName /$42/ { <DX>:=Ofs(PathName[1]); }
- $8D/$9E/ ParmTable / { <BX>:=Ofs(ParmTable); }
- $B8/$00/$4B/ { <AX>:=$4B00; }
- $1E/$55/ { Save <DS>, <BP> }
- $16/$1F/ { <DS>:=Seg(PathName[1]); }
- $16/$07/ { <ES>:=Seg(ParmTable); }
- $2E/$8C/$16/ SSSave / { Save <SS> in SSSave }
- $2E/$89/$26/ SPSave / { Save <SP> in SPSave }
- $FA/ { Disable interrupts }
- $CD/$21/ { Call MS-DOS }
- $FA/ { Disable interrupts }
- $2E/$8B/$26/ SPSave / { Restore <SP> }
- $2E/$8E/$16/ SSSave / { Restore <SS> }
- $FB/ { Enable interrupts }
- $5D/$1F/ { Restore <BP>,<DS> }
- $9C/$8F/$86/ RegsFlags / { Flags:=<CPU flags> }
- $89/$86/ Regs ); { Regs.AX:=<AX>; }
- { The messing around with SS and SP is necessary because under DOS 2.x,
- after returning from an EXEC call, ALL registers are destroyed except
- CS and IP! I wish I'd known that before I released this package the
- first time... }
- If (RegsFlags And 1)<>0 Then SubProcess:=AX
- Else SubProcess:=0;
- End;
- End;
-
- Function GetEnvStr(SearchString: _Exec_Str255): _Exec_Str255;
- Type
- Env=Array [0..32767] Of Char;
- Var
- EPtr: ^Env;
- EStr: _Exec_Str255;
- Done: Boolean;
- I: Integer;
-
- Begin
- GetEnvStr:='';
- If SearchString<>'' Then
- Begin
- EPtr:=Ptr(MemW[CSeg:$002C],0);
- I:=0;
- SearchString:=SearchString+'=';
- Done:=False;
- EStr:='';
- Repeat
- If EPtr^[I]=#0 Then
- Begin
- If EPtr^[Succ(I)]=#0 Then
- Begin
- Done:=True;
- If SearchString='==' Then
- Begin
- EStr:='';
- I:=I+4;
- While EPtr^[I]<>#0 Do
- Begin
- EStr:=EStr+EPtr^[I];
- I:=Succ(I);
- End;
- GetEnvStr:=EStr;
- End;
- End;
- If Copy(EStr,1,Length(SearchString))=SearchString Then
- Begin
- GetEnvStr:=Copy(EStr,Succ(Length(SearchString)),255);
- Done:=True;
- End;
- EStr:='';
- End
- Else EStr:=EStr+EPtr^[I];
- I:=Succ(I);
- Until Done;
- End;
- End;
-
- Function GetComSpec: _Exec_Str66;
- Begin
- GetComSpec:=GetEnvStr('COMSPEC');
- End;
-
- Function SubProcessViaCOMMAND(CommandLine: _Exec_Str255): Integer;
- Begin
- SubProcessViaCOMMAND:=SubProcess(GetComSpec+' /C '+CommandLine);
- End;
-
- Function SubProcessReturnCode: Integer;
- Var
- Regs: Record Case Integer Of
- 1: (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: Integer);
- 2: (AL,AH,BL,BH,CL,CH,DL,DH: Byte);
- End;
- Begin
- Regs.AH:=$4D;
- MsDos(Regs);
- SubProcessReturnCode:=Regs.AX;
- End;
-
- { Example program. Set both mInimum and mAximum free dynamic memory to 100
- and compile this to a .COM file. Delete the next line to enable: }
- (*
-
- Var Command: _Exec_Str255;
- I: Integer;
-
- Begin
- WriteLn('Enter a * to quit; put a * before a command to use COMMAND.COM.');
- Repeat
- Write('=->');
- ReadLn(Command);
- If Command='*' Then Halt;
- If Command<>'' Then
- Begin
- If Command[1]='*' Then
- I:=SubProcessViaCOMMAND(Copy(Command,2,255))
- Else I:=SubProcess(Command);
- If I<>0 Then WriteLn('Error - ',I);
- WriteLn('Return code = ',SubProcessReturnCode);
- End;
- Until False;
- End.
- *)