[net.sources] Turbo Pascal Dos Shell. Turbopush.asm file.

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