spawn.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 460 行

C
460
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include "vi.h"
#include "fcbmem.h"

void ResetSpawnScreen( void )
{
}

#if !defined(__386__)
static long minMemoryLeft;
static int chkSwapSize;

#include "tinyio.h"
static char *fullName;

typedef enum {
    IN_EMS,
    IN_XMS,
    ON_DISK
} where;

typedef struct {
    unsigned short      envp;
    void                far *cmdline;
    void                far *fcb1;
    void                far *fcb2;
} exec_block;

typedef char _fcb[16];

typedef struct {
    char        chain;  /* 'M' memory block, 'Z' is last in chain */
    unsigned    owner;  /* 0x0000 ==> free, otherwise psp address */
    unsigned    size;   /* in paragraphs, not including header  */
} dos_mem_block;

#define MEMORY_BLOCK 'M'
#define END_OF_CHAIN 'Z'
#define NEXT_BLOCK( curr )  MK_FP( (FP_SEG( curr ) + (curr)->size + 1), 0 )
#define PUT_ITEM( item ) (TinyWrite( hdl, &(item), \
                         sizeof( item ) ) == sizeof( item ))

static dos_mem_block saveMem;
static dos_mem_block *savePtrMem;
static dos_mem_block *savePtrChk;

static unsigned long fileHandle;
static unsigned short *xSize;
static long *xHandle;
static unsigned short currMem;
static where isWhere;

static void memGiveBack( void (*rtn)( long ) )
{
    int i;

    for( i=0;i<chkSwapSize;i++ ) {
        rtn( xHandle[i] );
    }

} /* memGiveBack */

static void memBlockWrite( void (*rtn)(long, void*, unsigned),
                           char *buff, unsigned *size )
{
    unsigned    bytes;

    if( (*size) >= 0x0200 ) {
        (*size) = 0x0200;
    }
    bytes = (*size) << 4;
    rtn( xHandle[ currMem ], buff, bytes );
    xSize[ currMem ] = bytes;
    currMem++;

} /* memBlockWrite */

static int memBlockRead( void (*rtn)(long, void*, unsigned), void **buff )
{
    rtn( xHandle[ currMem ], *buff, xSize[ currMem ] );
    (*buff) = MK_FP( FP_SEG( (*buff) ) + 0x200, 0 );
    if( xSize[ currMem ] < MAX_IO_BUFFER ) {
        return( FALSE );
    }
    currMem++;
    return( TRUE );

} /* memBlockRead */

static void cleanUp( void )
{

    switch( isWhere ) {
    case ON_DISK:
        TinyClose( fileHandle );
        TinyDelete( fullName );
        break;
#ifndef NOXMS
    case IN_XMS:
        memGiveBack( &GiveBackXMSBlock );
        break;
#endif
#ifndef NOEMS
    case IN_EMS:
        memGiveBack( &GiveBackEMSBlock );
        break;
#endif
    }

} /* cleanUp */

/*
 * chkWrite - write checkpoint data
 */
static bool chkWrite( void *buff, unsigned *size )
{
    unsigned    bytes;

    switch( isWhere ) {
    case ON_DISK:
        if( (*size) >= 0x1000 ) {
            (*size) = 0x0800;
        }
        bytes = (*size) << 4;
        if( TinyWrite( fileHandle, buff, bytes) != bytes ) {
            return( FALSE );
        }
        return( TRUE );
#ifndef NOEMS
    case IN_EMS:
        memBlockWrite( &EMSBlockWrite, buff, size );
        return( TRUE );
#endif
#ifndef NOXMS
    case IN_XMS:
        memBlockWrite( &XMSBlockWrite, buff, size );
        return( TRUE );
#endif
    }

} /* chkWrite */

/*
 * chkRead - read checkpoint "file"
 */
static bool chkRead( void **buff )
{

    switch( isWhere ) {
    case ON_DISK:
        if( TinyRead( fileHandle, *buff, 0x8000 ) == 0x8000 ) {
            (*buff) = MK_FP( FP_SEG( (*buff) ) + 0x800, 0 );
            return( TRUE );
        }
        return( FALSE );
#ifndef NOEMS
    case IN_EMS:
        return( memBlockRead( EMSBlockRead, buff ) );
#endif
#ifndef NOXMS
    case IN_XMS:
        return( memBlockRead( XMSBlockRead, buff ) );
#endif
    }

} /* chkRead */

/*
 * chkOpen - re-open a checkpoint file
 */
static bool chkOpen( void )
{
    tiny_ret_t  ret;

    switch( isWhere ) {
    case ON_DISK:
        ret = TinyOpen( fullName, TIO_READ );
        if( ret < 0 ) {
            return( FALSE );
        }
        fileHandle = ret;
        break;
#ifndef NOEMS
    case IN_EMS:
        currMem = 0;
        break;
#endif
#ifndef NOXMS
    case IN_XMS:
        currMem = 0;
        break;
#endif
    }
    return( TRUE );

} /* chkOpen */

/*
 * chkClose
 */
static void chkClose( void )
{
    switch( isWhere ) {
    case ON_DISK:
        TinyClose( fileHandle );
        break;
    }

} /* chkClose */

/*
 * checkPointMem - checkpoint up to max bytes of memory
 */
static bool checkPointMem( unsigned max )
{
    dos_mem_block       *mem,*start,*end,*next,*chk;
    unsigned            size,psp;

    if( max == 0 ) {
        return( FALSE );
    }
    psp = TinyGetPSP();
    start = MK_FP( psp - 1, 0 );
    if( start->chain == END_OF_CHAIN ) {
        return( FALSE );
    }
    start = NEXT_BLOCK( start );
    mem = start;
    for( ;; ) {
        if( mem->owner == 0 && mem->size >= max ) {
            return( FALSE );
        }
        if( mem->chain == END_OF_CHAIN ) {
            break;
        }
        mem = NEXT_BLOCK( mem );
    }
    end = NEXT_BLOCK( mem );
    size = FP_SEG( end ) - FP_SEG( start );
    if( size < 0x100 ) {
        return( FALSE );
    }

    if( size > max ) {
        size = max;
    }
    chk = MK_FP( FP_SEG( end ) - size - 1, 0 );
    mem = start;
    for( ;; ) {
        next = NEXT_BLOCK( mem );
        if( FP_SEG( next ) > FP_SEG( chk ) ) {
            break;
        }
        mem = next;
    }

    savePtrMem = mem;
    memcpy( &saveMem, mem, sizeof( dos_mem_block ) );
    savePtrChk = chk;

    next = chk;
    while( FP_SEG( next ) < FP_SEG( end ) ) {
        size = FP_SEG( end ) - FP_SEG( next );
        if( !chkWrite( next, &size ) ) {
            cleanUp();
            return( FALSE );
        }
        next = MK_FP( FP_SEG( next ) + size, 0 );
    }
    chkClose();
    mem->chain = MEMORY_BLOCK;
    mem->size = FP_SEG( chk ) - FP_SEG( mem ) - 1;
    chk->size = FP_SEG( end ) - FP_SEG( chk ) - 1;
    chk->chain = END_OF_CHAIN;
    chk->owner = 0;
    return( TRUE );
}


static void CheckPointRestore( void )
{
    dos_mem_block       *chk;

    if( !chkOpen() ) {
        return;
    }

    chk = savePtrMem;
    memcpy( chk, &saveMem, sizeof( dos_mem_block ) );
    chk = savePtrChk;

    while( chkRead( &chk ) );
    cleanUp();
}

extern int DoSpawn( void *, void * );
#pragma aux DoSpawn = \
        "push   ds" \
        "push   es" \
        "push   si" \
        "push   di" \
        "mov    ds,dx"  /*  exe segment */ \
        "mov    dx,ax"  /*  exe offset */ \
        "mov    es,cx"  /*  parm block segment (offset in bx already) */ \
        "mov    ax,4b00h"  /*  exec process */ \
        "int    21h" \
        "jc     rcisright" \
        "mov    ax,4d00h" \
        "int    21h" \
        "xor    ah,ah" \
        "rcisright:" \
        "pop    di" \
        "pop    si" \
        "pop    es" \
        "pop    ds" \
        parm [dx ax] [cx bx] value[ax];

extern int GetFcb( void *, void * );
#pragma aux GetFcb = \
        "push   ds" \
        "push   es" \
        "push   si" \
        "push   di" \
        "mov    ds,dx" /*  exe segment */ \
        "mov    si,ax" /*  exe offset */ \
        "mov    es,cx" /*  parm block segment (offset in bx already) */ \
        "mov    di,bx" \
        "mov    ax,2901h" /*  parse filename/get fcb */ \
        "int    21h" \
        "pop    di" \
        "pop    si" \
        "pop    es" \
        "pop    ds" \
        parm [dx ax] [cx bx] value[ax];

int MySpawn( char *cmd )
{
    bool        cp;
    int         rc;
    exec_block  exeparm;
    _fcb        fcb1,fcb2;
    cmd_struct  cmds;
    char        path[_MAX_PATH],file[_MAX_PATH];
    tiny_ret_t  ret;
    int         i;
    char        chkfname[L_tmpnam];

    minMemoryLeft = MaxMemFree & ~((long)MAX_IO_BUFFER-1);
    chkSwapSize = 1+(unsigned short)
        ((( minMemoryLeft + ((long)MAX_IO_BUFFER-1) ) & ~((long)MAX_IO_BUFFER-1)) /
                (long)MAX_IO_BUFFER);

    /*
     * set up checkpoint file stuff:
     */
#ifndef NOEMS
    if( !EMSBlockTest( chkSwapSize ) ) {
        xHandle = alloca( chkSwapSize * sizeof( long ) );
        xSize = alloca( chkSwapSize * sizeof( short ) );
        for( i=0;i<chkSwapSize;i++ ) {
            EMSGetBlock( &xHandle[i] );
        }
        isWhere = IN_EMS;
        currMem = 0;
        goto evil_goto;
    }
#endif
#ifndef NOXMS
    if( !XMSBlockTest( chkSwapSize ) ) {
        xHandle = alloca( chkSwapSize * sizeof( long ) );
        xSize = alloca( chkSwapSize * sizeof( short ) );
        for( i=0;i<chkSwapSize;i++ ) {
            XMSGetBlock( &xHandle[i] );
        }
        isWhere = IN_XMS;
        currMem = 0;
        goto evil_goto;
    }
#endif
    file[0] = 0;
    tmpnam( chkfname );
    StrMerge( 3, file, TmpDir, FILE_SEP_STR, chkfname );
    fullName = file;
    ret = TinyCreate( fullName, TIO_NORMAL );
    if( ret < 0 ) {
        return( 0 );
    }
    fileHandle = ret;
    isWhere = ON_DISK;

    /*
     * build command line
     */
evil_goto:
    GetSpawnCommandLine( path, cmd, &cmds );

    /*
     * set up parm block
     */
    exeparm.envp = 0;
    exeparm.cmdline = &cmds;
    exeparm.fcb1 = fcb1;
    exeparm.fcb2 = fcb2;
    GetFcb( &cmds.cmd, &fcb1 );
    GetFcb( &cmds.cmd, &fcb2 );

    /*
     * spawn the command
     */
    cp = checkPointMem( minMemoryLeft/16 );
    rc = DoSpawn( path, &exeparm );
    if( cp ) {
        CheckPointRestore();
    }

    return( rc );
}
#else
int MySpawn( char *cmd )
{
    return( system( cmd ) );
}
#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?