home *** CD-ROM | disk | FTP | other *** search
- (*[76703,3015]
- EXEC.PAS 21-Jan-86 17305 345
-
- Keywords: MS-DOS PC-DOS EXECUTE SUBPROCESS CALL RUN COMMAND READ
- ENVIRONMENT STRING SET
-
- Version 1.6:
- o Call MS-DOS .COM or .EXE programs using the Exec function call (4Bh).
- o Call COMMAND.COM to execute .BAT files, internal DOS commands, .COM or
- .EXE files found in the PATH, allow redirection or piping, or give a
- DOS prompt.
- o Get the return codes from those programs.
- o Get a SET parameter from the MS-DOS environment.
- (Based on TURRUN.ASM in DL1, but in Pascal).
- REQUIRES DOS 2.0 or greater. 17394 bytes.
- Previous downloads: 1355
- - Bela Lubkin
- *)
-
- { EXEC.PAS version 1.6
- Copyright (C) 1986 by Bela Lubkin (1/21/86)
- Noncommercial use only EXCEPT with permission from Bela Lubkin; send
- EasyPlex to CompuServe ID 76703,3015 for permission.
-
- See "VERY IMPORTANT NOTES" below before using these functions. This is
- especially important if you are using Turbo version 1.0 or 2.0.
-
- 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
- -------------------
- Procedure FreeUpMemory;
- This procedure calls MS-DOS to free up memory that is not used by the
- running program. It is needed only under Turbo 1.0 or 2.0. It is
- commented out in this file. Uncomment it only if you are using a pre-
- 3.0 version of Turbo Pascal. It must be called once and ONLY ONCE
- before calling any of SubProcess, SubProcessViaCOMMAND, or Shell. It is
- a good idea to place this call early in the execution of the program.
-
- 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 function 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 3.0 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. Use Inline
- code or the MsDos procedure under Turbo 1.0 or 2.0.
-
- 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.
-
- If you are using Turbo 1.0 or 2.0, you must call FreeUpMemory once and ONLY
- ONCE before making any calls to SubProcess, SubProcessViaCOMMAND, or Shell.
- Uncomment the FreeUpMemory procedure, remove the Exit statement from
- SubProcess, and make sure you call FreeUpMemory before attempting to do any
- Exec calls!!
-
- Revision history
- ----------------
- Version 1.6 1/21/86 re-adds support for Turbo 1.0, 2.0 by providing the
- procedure FreeUpMemory. Adds the Shell function that was
- inadvertantly left out of 1.5.
- 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];
-
- Var
- _Exec_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;
- { NOTE: the above variable is referenced in an Inline statement. It MUST
- be a global variable (not a local variable or a typed constant)!! }
-
- (* THIS PROCEDURE MUST BE CALLED ONCE AND ONLY ONCE, BEFORE ANY CALLS TO THE
- SUBPROCESS PROCEDURES, AND ONLY IF TURBO 1.0 OR 2.0 IS BEING USED!!!!!!!!
- Uncomment it only if necessary.
-
- Procedure FreeUpMemory;
- { Paraphrases part of Turbo 3.0's startup code:
- (CS:[101h]+106h) is the address of the compiler Options.
- Options[6] is the code segment size the program (paragraphs).
- Options[8] is the data segment size.
- (CS+Options[6]+Options[8]) is the highwater mark of the program, sans
- stack/heap.
- CS:[2] is supplied by DOS: the number of paragraphs available to the
- program.
- (CS:[2]-High water mark) is the number of paragraphs available to the
- stack/heap.
- Options[0Ch] is the maximum stack/heap size needed by the program.
- The heap size is taken as the lesser of Options[0Ch] and
- (CS:[2]-highwater mark).
- The highwater mark including the stack/heap is the no-heap highwater
- mark + the calculated heap size.
- The size in paragraphs of the program, including code, data, stack and
- heap, is the full highwater mark - the original CS.
- DOS function 4Ah, Set memory block, is called to adjust the size of the
- program's memory block to the calculated size of the entire program. }
- Begin
- InLine($2E/$8B/$36/$01/$01/ { ADD SI,106h }
- $81/$C6/$06/$01/ { ADD SI,106h }
- $8C/$CB/ { MOV BX,CS }
- $2E/$03/$5C/$06/ { ADD BX,CS:[SI+6] }
- $2E/$03/$5C/$08/ { ADD BX,CS:[SI+8] }
- $2E/$8B/$16/$02/$00/ { MOV DX,CS:[2] }
- $29/$DA/ { SUB DX,BX }
- $2E/$3B/$54/$0C/ { CMP DX,CS:[SI+0Ch] }
- $72/$04/ { JB .1 }
- $2E/$8B/$54/$0C/ { MOV DX,CS:[SI+0Ch] }
- $8C/$C8/ { .1: MOV AX,CS }
- $8E/$C0/ { MOV ES,AX }
- $01/$D3/ { ADD BX,DX }
- $2B/$D8/ { SUB BX,AX }
- $B4/$4A/ { MOV AH,4Ah }
- $CD/$21); { INT 21h }
- End; *)
-
- Function SubProcess(CommandLine: _Exec_Str255): Integer;
- Const
- SSSave: Integer=0;
- SPSave: Integer=0;
-
- Var
- 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; {*}
- {*: these variables are accessed in an Inline statement; their
- declarations must not be changed }
-
- 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 _Exec_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(_Exec_Regs); { Create FCB 1 }
- FillChar(FCB2,Sizeof(FCB2),0);
- AX:=$2901;
- ES:=Seg(FCB2);
- DI:=Ofs(FCB2);
- MsDos(_Exec_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> }
- $A3/ _Exec_Regs ); { _Exec_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;
- Exit; { This line is here for one reason only: to cause compilation to
- fail under Turbo 1.0 or 2.0 and force you to read this comment.
- Go back and read the VERY IMPORTANT NOTES section. Then comment
- out this Exit, uncomment Procedure FreeUpMemory, and add a call to
- it to your code before attempting any calls to any of the Exec
- functions!! }
- 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 Shell: Integer;
- Begin
- Shell:=SubProcess(GetComSpec);
- End;
-
- Function SubProcessReturnCode: Integer;
- Begin
- _Exec_Regs.AH:=$4D;
- MsDos(_Exec_Regs);
- SubProcessReturnCode:=_Exec_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
- { FreeUpMemory; } { NECESSARY only for Turbo 1.0, 2.0 }
- WriteLn('Enter * to quit; ** to call a subsidiary command shell. Put a * before a');
- WriteLn('command to call it via COMMAND.COM.');
- Repeat
- Write('=->');
- ReadLn(Command);
- If Command='*' Then Halt
- Else If Command<>'' Then
- Begin
- If Command='**' Then
- Begin
- WriteLn('Type EXIT to return to Exec');
- I:=Shell;
- End
- Else 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.
- *)