pier@ur-tut.UUCP (Pierre Darmon) (12/17/85)
This file need to actually be called turborun.asm. Here's TurboRun.Asm: Page 60,132 Title TURBORUN a utility for Turbo Pascal, MS/PC-DOS v2.xx Name TurboRun ;************************************************************************ ;* * ;* T U R B O R U N * ;* Version 1.2 * ;* * ;* By John Cooper John Falconer * ;* (913) 262-8451 (415) 521-7245 * ;* CIS 74775,756 CIS 72435,1617 * ;* * ;* Update to Version 1.2 by * ;* * ;* Tom Devitt * ;* Pseudonym Software * ;* (818) 796-7933 * ;* * ;************************************************************************ Comment* Revision History Version 1.0 was successfully tested on 12/10/84. By John Cooper Updated to Version 1.0A on 12/22/84. By John Falconer 1. Changed ssmax from a constant to a code-base-relative value. This change allows Turborun to be used with different versions of Turbo Pascal. Although undocumented, the four versions of Turbo I tested all store their maximum stack segment size as a word located seven bytes ahead of the beginning of user code. 2. Added code to determine the length of the command line which is passed to the child process. Moved the child's command line starting point to PSP+081H as called for in the DOS manual (Ver 2.0 page E-6) and placed the length byte for the command line at PSP+080H. This allows the command line passed to the child to be used as a string with string[0] containing the valid length. Note that a carriage return is placed at the end of the passed command line but that it is not counted in the length. Note also that this change corrupts the CmdLine variable passed to Turborun by changing the last character of the file name to the length of the child's CmdLine. 3. Changed original code so that all characters on the command line are passed on to the child. This is as called for in the DOS manual. Previously the first terminator (usually a space) was skipped over. 4. Corrected a few minor documentation errors. Note: The EXEC call does not support IO-Redirection on the command line. * Page Comment * Updated to Version 1.0B January 10, 1985 By John Cooper 1. A note concerning the lack of IO-redirection support by the MS/PC DOS EXEC function call, the call which is at the heart of this program, was ammended, as it has been determined that, at least in the case of MS-DOS 2.11, EXEC does provide full IO-redirection, via the command line symbols "> < |", if the command processor is envolked ahead of the child. <Child> [FCB-1 [FCB-2]] >PIPEOUT <PIPEIN The above will NOT work, however, [path][drive]COMMAND.COM /C <Child> [FCB-1 [FCB-2]] >PIPEOUT <PIPEIN should work just fine. 2. Changed the way in which the program detects the end of the childs name, to include all filename separators, as listed on page 1-88 of MS-DOS v2.0 Programmer's Reference, except the back-slash (\) and colon (:). These two were excluded because the program needs to accept a full-path name, which could include these symbols. Pre- viously only a space or null was considered a terminator. This change was recommended but not implemented in version 1.0A. 3. Added notes on installation concerning the requirement, introduced by an enhancement made in 1.0A, that the external declaration of this program be the first in the Turbo source code. Also added some warnings and documentation notes. * Page Comment * Updated to Version 1.1 March 17, 1985 By John Falconer 1. A "bug" in the way memory allocation is calculated and set to protect Turbo's SSEG was fixed. The program is now known to function with such large applications as 1-2-3 and Dbase III. Updated to Version 1.2 on April 28, 1985 By Tom Devitt 1. Made Version 1.2 compatible with the 2.0 AND 3.0 versions of Turbo Pascal by modifying the method in which ssmax is located. Under 3.0 TP stores the maximum stack segment size 20 bytes ahead of the beginning of user code. However, both versions store this value at CS:[101H] + 112H. This change should make the placement of the EXTERNAL RUN proc unimportant. 2. Acknowledgement: I owe a debt to the guys at Pathfinder Software Inc., publishers of TurboLink. Although TL 2.0 contains a bug which makes it unusable on > 512k systems, I was able to discover the above fact by analysing their code. 3. With Turbo Pascal 2.0B, you must first compile in memory and only then switch over to the com option, limiting memory before the second compile. With Turbo Pascal 3.0B, you may skip the memory compile. * Page Comment* - - - W A R N I N G - - - Although every effort has been made, by the two authors, to ensure that this program will perform as specified, there are may be programs which will not function correctly when envoked from Turbo, via Turborun, but will do just fine if envoked from COMMAND.COM. An excellent example is WordStar(tm). In some, but not all, cases this can be solved by first envoking COMMAND.COM and then envoking the child from COMMAND.COM. Assume that there is a program, WORKING.COM, that will not work from Turborun but does work from DOS. The following command line might help; COMMAND.COM /c WORKING.COM This of course assume that there is not a shortage of memory of some other explainable problem. The switch, /c, is included to force COMMAND.COM to return control to the parent after the processing of its, COMMAND.COM's, command line. Installation Notes: The enhancement to provide for a version-independent SSMAX, provided by John F., has introduced the additional requirement that this external be the first code generating structute in the Turbo Pascal source code, i.e. make TurboRun the first procedure, following the Const, Type, and Var blocks, in the main program. Turborun assumes it is the first and can, therefore, find the SSMAX word exactly seven bytes prior to its own base address. Note: Under Version 1.2, the above requirement may be relaxed. - TD Memory Compiles. The use of this program in "memory mode" is not recom- mended. Turbo seems to dislike having its memory limited, which is required to run the child. It may work but it is, at best, risky! The prefered method is to do a memory-compile, if possible, then switch to Com and limit the Maximum Stack Size and compile again, this time producing a COM file. If compilation to memory is not possible, due to lack of memory or the use of Overlays, you MUST implement some sort of patch to work around Turbo Pascal 2.0B's known "bug" in its handling of externals greater that 128-bytes in length. The "bug" is easy to work around, by either loading the external at run-time(recommended) or converting it to an INLINE $Include file. Note: Above bug appears to have been fixed in Turbo Pascal 3.0B - TD * Page Comment * Limiting the Stack Segment for Turbo Pascal. If the Stack Size is not limited, at compile-time, then Turbo Pascal may want to consume all of the system's available RAM. Of course, that precludes the use of child processes because the BLOCK call will fail, due to a lack of resources. It is, therefore, recommended that you limit Maximum Stack Size to just enough memory to allow the Pascal program to operate, this will leave the balance of your system's resources available for child processes. Terminate But Stay Resident. Programs which use "Terminate but stay resident" or "Keep process" to terminate but keep itself in memory should not be run from Turborun. The reason is that will cause DOS to attempt to set the allocation block map to prevent overlaying of the child. If the system survives this, it still leave DOS in an unpredictable state. Exit codes. In order for the parent to correctly detect the reason the child terminated the child must pass that infomation back, so that the Get Return Code can find it. Many currently, available programs do not provide this and hence the code value passed back to RetCode may not reflect the actual reason the child was terminated. An example is COMMAND.COM. "BUGS". If you encounter difficulties using this program or you find "bugs" in it, please contact either author or the latest revisor. After this source code is assembled, linked, and converted to a COM file it should be included as an external procedure within the Turbo Pascal source file. The external should be of the form shown below. Procedure GoForIt(Var RetCode:Integer; Var Cmdline); External 'TurboRun.com'; Cmdline can be either type-CHAR or type-STRING. If the latter is used you should pass CmdLine[1] to skip the length byte. Format of CmdLine: path-name-to-child [<sp> First-FCB [<sp> Second-FCB [<sp> switchs and/or IO redirection]]] #0 Notice that the Cmdline to followed by a byte of 0, this is binary 0 not ASCII 0. <-- VERY IMPORTANT! * Page Comment * The variable, RetCode, will contain the return code from the child process. RetCode is actually used as two, seperate, byte-length variables. The table below explains how to interpret this variable in terms of its high and low bytes. High byte 0 : Normal Termination, No error 1 : Child was terminated via by CONTROL-C 2 : Child was aborted because of a DOS Hard Error 3 : Child used terminate-but-stay-resident (System needs to be rebooted) 4 : EXEC call failed. 8 : Memory allocation error, EXEC was not attempted In the cases of 0,1,2, and 3 the low byte has the value passed back by the child. Any of these values indicate that the EXEC call was successful. Programs which use terminate-but-stay- resident should not be called by the program. In the case of 4 the low byte has the reason the EXEC failed. 2 : The path specified was invalid or not found. 8 : There was not enough memory for the process to be created. 11 : The process was an EXE format file and contained information that was internally inconsistent. In the case of 8 the low byte has the reason the memory allocation request failed. 7 : The arena was trashed because a user program has changed memory that does not belong to it. System needs to be Rebooted. 8 : Insufficient memory. * Page Subttl Main Program ; ;------------------- E Q U A T E S -------------------- ; spsave equ cs:00fch ;Storage for SP register sssave equ cs:00feh ;Storage for SS register ; ;-------------------- M A C R O S --------------------- ; MsDos Macro function If function lt 256 mov ah,function Else mov ax,function EndIf int 21h EndM ; ; ;------------------ M A I N P R O G R A M ----------------- ; code segment para public 'CODE' assume cs:code,ds:nothing,es:code,ss:nothing org 00h run proc near call entry ;Find out where we were loaded ;There is no return from this CALL separate db ';,=+"[]><| ',9,0 ;Filename separators ;Excluding ":" and "\" which cannot appear in ;a filename but can appear in a pathname. child db 128 dup(?) ;Path to child (with filename extension) fcb1 db 16 dup(?) ;Optional fcb fcb2 db 16 dup(?) ;Optional fcb parablk dw 0,12 dup(?) ;Parameter block (DOS 2.0 Manual p. D-45) cmdstrt dw 0 ;Offset to first char in child's CmdLine ssmax dw 0 ;Storage for parent's maximum stack size, ;in paragraphs entry: pop bx ;Offset+3 sub bx,3 ;Actual offset address of RUN.COM pop dx ;Turbo(tm) return address pop si ;Offset to command string pop cx ;Segment address of command string push dx ;Restore turbo's RET address mov dx,si push ds push bp pushf push bx ;Save bx temporarily mov ax,112h ;Offest of ssmax mov bx,CS:[101H] ;pointer to user code add bx,ax ;bx = addr ssmax mov ax,cs:[bx] ;Move it to ax pop bx ;Recover bx mov [ssmax+bx],ax ;Save the max stack size for SETBLOCK call mov ds,cx ;Point to command string segment push cs ;Make ES=CS pop es mov di,offset child ;Child process path name add di,bx ;Relocation offset cld ;Force direction cmdlp: lodsb ;Get character push di ;Save DI mov cx,13 ;look for any of 13 filename separators mov di,offset separate add di,bx ;Relocation offset repnz scasb ;Look for match jz endstr ;Exit if a separator is found pop di ;Otherwise, retrieve DI and continue stosb ;Store byte jmp cmdlp ;Try next character endstr: pop di ;Retrieve DI mov [cmdstrt+bx],si ;Pointer to first char in child's CmdLine mov al,0 ;Put terminating 0 in child path stosb dec si ;Back up one for stosb dec si ;Back up one for the length byte ;ds:si point to the childs command line u1: mov [parablk+2+bx],si ;Store offset address inc si ;Start parsing at head of child's CmdLine mov cx,ds mov [parablk+4+bx],cx ;Store segment address mov di,offset fcb1 ;Setup to parse first filename add di,bx ;Relocation ;di has offset from cs to default FCB passed at 5Ch mov [parablk+6+bx],di MsDos 2901h ;Ignore leading separators mov di,offset fcb2 ;Parse second filename add di,bx ;Relocation ;di has offset from cs to default FCB passed at 6Ch mov [parablk+10+bx],di MsDos 2901h ; ;Place <cr> at end of CmdLine, calculate and store child's CmdLine length ; u2: cmp byte ptr ds:[si],0 ;Look for end of line jz u3 inc si jmp u2 u3: mov byte ptr ds:[si],13 mov ax,[cmdstrt+bx] ;Get pointer to first char in child's CmdLine xchg ax,si ;Swap it with current pointer dec si ;We don't include the <cr> in our length sub ax,si ;Calculate the length dec si ;Point to the length byte mov byte ptr ds:[si],al ;Store calculated length there mov cx,cs ;Setup segments in parameter block mov [parablk+8+bx],cx mov [parablk+12+bx],cx mov [parablk+bx],0 ;Pass environment to child, unchanged ;Now the childs parameter block is setup. ;All that remains is to allocate memory and go for it. push bx ;Save reloc register mov bx,[ssmax+bx] push cx mov cx,ss add bx,cx pop cx sub bx,cx MsDos 4ah ;Modify memory allocation jnc $+5 jmp alocer ;Allocation error, Exit pop bx ;Recover reloc register push bx ;Save a copy on stack mov dx,bx add bx,offset parablk mov [spsave],sp ;Save SP mov [sssave],ss ;Save SS push cs ;Point ds:sx to child pop ds add dx,offset child MsDos 4b00h ;Go for it cli ;Prevent interuption mov sp,[spsave] ;Recover SP mov ss,[sssave] ;Recover SS sti jnc $+5 jmp runerr ;Problems, Exit pop bx ;Get reloc register MsDos 4dh ;Get return code from child getbac: popf ;Turbo's Flags pop bp ;Turbo's BP pop ds ;Turbo's DS pop cx ;Return address pop di ;Offset to RC Variable pop es ;Segment of RC Variable mov es:[di],ax ;Store return code push cx ;Restore return address ret ;Back to Turbo alocer: pop bx ;Reloc register mov ah,8 ;Indicate Allocation error jmp getbac runerr: pop bx mov ah,4 ;Indicate RUN error jmp getbac run endp code ends end run ------- Pierre Darmon University of Rochester {allegra|decvax|seismo}!rochester!ur-tut!pier