⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 task.c

📁 开源DOS的C代码源程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************/
/*                                                              */
/*                           task.c                             */
/*                                                              */
/*                 Task Manager for DOS Processes               */
/*                                                              */
/*                      Copyright (c) 1995                      */
/*                      Pasquale J. Villani                     */
/*                      All Rights Reserved                     */
/*                                                              */
/* This file is part of DOS-C.                                  */
/*                                                              */
/* DOS-C is free software; you can redistribute it and/or       */
/* modify it under the terms of the GNU General Public License  */
/* as published by the Free Software Foundation; either version */
/* 2, or (at your option) any later version.                    */
/*                                                              */
/* DOS-C is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of   */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See    */
/* the GNU General Public License for more details.             */
/*                                                              */
/* You should have received a copy of the GNU General Public    */
/* License along with DOS-C; see the file COPYING.  If not,     */
/* write to the Free Software Foundation, 675 Mass Ave,         */
/* Cambridge, MA 02139, USA.                                    */
/****************************************************************/

#include "portab.h"
#include "globals.h"

#ifdef VERSION_STRINGS
static BYTE *RcsId =
    "$Id: task.c,v 1.44 2004/05/10 20:49:37 bartoldeman Exp $";
#endif

#define toupper(c)	((c) >= 'a' && (c) <= 'z' ? (c) + ('A' - 'a') : (c))

#define LOADNGO 0
#define LOAD    1
#define OVERLAY 3

#define LOAD_HIGH 0x80

/* static exe_header ExeHeader;
                           to save some bytes, both static and on stack,
                           we recycle SecPathBuffer                 TE */

#define ExeHeader (*(exe_header *)(SecPathName + 0))
#define TempExeBlock (*(exec_blk *)(SecPathName + sizeof(exe_header)))
#define Shell (SecPathName + sizeof(exe_header) + sizeof(exec_blk))

#ifdef __TURBOC__ /* this is a Borlandism and doesn't work elsewhere */
 #if sizeof(SecPathName) < sizeof(exe_header) + sizeof(exec_blk) + NAMEMAX
  #error No room in SecPathName to be recycled!
 #endif
#endif

#define CHUNK 32256
#define MAXENV 32768u
#define ENV_KEEPFREE 83         /* keep unallocated by environment variables */
        /* The '65' added to nEnvSize does not cover the additional stuff:
           + 2 bytes: number of strings
           + 80 bytes: maximum absolute filename
           + 1 byte: '\0'
           -- 1999/04/21 ska */

intvec getvec(unsigned char intno)
{
  intvec iv;
  disable();
  iv = *(intvec FAR *)MK_FP(0,4 * (intno));
  enable();
  return iv;
}

void setvec(unsigned char intno, intvec vector)
{
  disable();
  *(intvec FAR *)MK_FP(0,4 * intno) = vector;
  enable();
}

ULONG SftGetFsize(int sft_idx)
{
  sft FAR *s = idx_to_sft(sft_idx);

  /* Get the SFT block that contains the SFT      */
  if (FP_OFF(s) == (size_t) -1)
    return DE_INVLDHNDL;

  /* If SFT entry refers to a device, return the date and time of opening */
  if (s->sft_flags & (SFT_FDEVICE | SFT_FSHARED))
  {
    return s->sft_size;
  }

  /* call file system handler                     */
  return dos_getfsize(s->sft_status);
}

STATIC COUNT ChildEnv(exec_blk * exp, UWORD * pChildEnvSeg, char far * pathname)
{
  BYTE FAR *pSrc;
  BYTE FAR *pDest;
  UWORD nEnvSize;
  COUNT RetCode;
/*  UWORD MaxEnvSize;                                                                                                                                           not used -- 1999/04/21 ska */
  psp FAR *ppsp = MK_FP(cu_psp, 0);

  /* create a new environment for the process             */
  /* copy parent's environment if exec.env_seg == 0       */

  pSrc = exp->exec.env_seg ?
      MK_FP(exp->exec.env_seg, 0) : MK_FP(ppsp->ps_environ, 0);

#if 0
  /* Every process requires an environment because of argv[0]
     -- 1999/04/21 ska */
  */if (!pSrc)                  /* no environment to copy */
  {
    *pChildEnvSeg = 0;
    return SUCCESS;
  }
#endif

  nEnvSize = 1;
  /* This loop had not counted the very last '\0'
     -- 1999/04/21 ska */
  if (pSrc)
  {                             /* if no environment is available, one byte is required */

    for (nEnvSize = 0;; nEnvSize++)
    {
      /* Test env size and abort if greater than max          */
      if (nEnvSize >= MAXENV - ENV_KEEPFREE)
        return DE_INVLDENV;

      if (*(UWORD FAR *) (pSrc + nEnvSize) == 0)
        break;
    }
    nEnvSize += 2;              /* account for trailing \0\0 */
  }

  /* allocate enough space for env + path                 */
  if ((RetCode = DosMemAlloc((nEnvSize + ENV_KEEPFREE + 15)/16,
                             mem_access_mode, pChildEnvSeg,
                             NULL /*(UWORD FAR *) MaxEnvSize ska */ )) < 0)
    return RetCode;
  pDest = MK_FP(*pChildEnvSeg + 1, 0);

  /* fill the new env and inform the process of its       */
  /* location throught the psp                            */

  /* copy the environment */
  if (pSrc)
  {
    fmemcpy(pDest, pSrc, nEnvSize);
    pDest += nEnvSize;
  }
  else
    *pDest++ = '\0';            /* create an empty environment */

  /* initialize 'extra strings' count */
  *((UWORD FAR *) pDest) = 1;
  pDest += sizeof(UWORD) / sizeof(BYTE);

  /* copy complete pathname */
  if ((RetCode = truename(pathname, PriPathName, CDS_MODE_SKIP_PHYSICAL)) < SUCCESS)
  {
    return RetCode;
  }
  fstrcpy(pDest, PriPathName);

  /* Theoretically one could either:
     + resize the already allocated block to best-fit behind the pathname, or
     + generate the filename into a temporary buffer to allocate only the
     minimum required environment -- 1999/04/21 ska */

  return SUCCESS;
}

/* The following code is 8086 dependant                         */
void new_psp(seg para, seg cur_psp)
{
  psp FAR *p = MK_FP(para, 0);

  fmemcpy(p, MK_FP(cur_psp, 0), sizeof(psp));

  /* terminate address                                    */
  p->ps_isv22 = getvec(0x22);
  /* break address                                        */
  p->ps_isv23 = getvec(0x23);
  /* critical error address                               */
  p->ps_isv24 = getvec(0x24);
  /* parent psp segment set to 0 (see RBIL int21/ah=26)   */
  p->ps_parent = 0;
}

void child_psp(seg para, seg cur_psp, int psize)
{
  psp FAR *p = MK_FP(para, 0);
  psp FAR *q = MK_FP(cur_psp, 0);
  int i;

  new_psp(para, cur_psp);

  /* Now for parent-child relationships                   */
  /* parent psp segment                                   */
  p->ps_parent = cu_psp;
  /* previous psp pointer                                 */
  p->ps_prevpsp = q;

  /* Environment and memory useage parameters             */
  /* memory size in paragraphs                            */
  p->ps_size = psize;

  /* File System parameters                               */
  /* maximum open files                                   */
  p->ps_maxfiles = 20;
  fmemset(p->ps_files, 0xff, 20);

  /* open file table pointer                              */
  p->ps_filetab = p->ps_files;

  /* clone the file table -- 0xff is unused               */
  for (i = 0; i < 20; i++)
    if (CloneHandle(i) >= 0)
      p->ps_files[i] = q->ps_filetab[i];

  /* first command line argument                          */
  p->ps_fcb1.fcb_drive = 0;
  fmemset(p->ps_fcb1.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE);
  /* second command line argument                         */
  p->ps_fcb2.fcb_drive = 0;
  fmemset(p->ps_fcb2.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE);

  /* local command line                                   */
  p->ps_cmd.ctCount = 0;
  p->ps_cmd.ctBuffer[0] = 0xd; /* command tail            */
}

STATIC UBYTE chkdrv(unsigned drive) /* from FCB: 0 = default, 1 = A:, ... */
{
  if (drive)
    drive--; /* 0 = A:, 1 = B:, ... */
  else
    drive = default_drive;
  return get_cds(drive) ? 0 : 0xff; /* return 0 if drive is valid, else 0xff */
}

STATIC UWORD patchPSP(UWORD pspseg, UWORD envseg, exec_blk FAR * exb,
                      BYTE FAR * fnam)
{
  psp FAR *psp;
  mcb FAR *pspmcb;
  int i;
  BYTE FAR *np;

  pspmcb = MK_FP(pspseg, 0);
  ++pspseg;
  psp = MK_FP(pspseg, 0);

  /* complete the psp by adding the command line and FCBs     */
  fmemcpy(&psp->ps_cmd, exb->exec.cmd_line, sizeof(CommandTail));
  if (FP_OFF(exb->exec.fcb_1) != 0xffff)
  {
    fmemcpy(&psp->ps_fcb1, exb->exec.fcb_1, 16);
    fmemcpy(&psp->ps_fcb2, exb->exec.fcb_2, 16);
  }

  /* identify the mcb as this functions'                  */
  pspmcb->m_psp = pspseg;
  /* Patch in environment segment, if present, also adjust its MCB */
  if (envseg)
  {
    ((mcb FAR *) MK_FP(envseg, 0))->m_psp = pspseg;
    envseg++;
  }
  psp->ps_environ = envseg;

  /* use the file name less extension - left adjusted and */
  np = fnam;
  for (;;)
  {
    switch (*fnam++)
    {
      case '\0':
        goto set_name;
      case ':':
      case '/':
      case '\\':
        np = fnam;
    }
  }
set_name:
  for (i = 0; i < 8 && np[i] != '.' && np[i] != '\0'; i++)
  {
    pspmcb->m_name[i] = toupper(np[i]);
  }
  if (i < 8)
    pspmcb->m_name[i] = '\0';

  /* return value: AX value to be passed based on FCB values */
  return chkdrv(psp->ps_fcb1.fcb_drive) |
    (chkdrv(psp->ps_fcb2.fcb_drive) << 8);
}

int load_transfer(UWORD ds, exec_blk *exp, UWORD fcbcode, COUNT mode)
{
  psp FAR *p = MK_FP(ds, 0);
  psp FAR *q = MK_FP(cu_psp, 0);
  
  /* Transfer control to the executable                   */
  p->ps_parent = cu_psp;
  p->ps_prevpsp = q;
  q->ps_stack = (BYTE FAR *)user_r;
  user_r->FLAGS &= ~FLG_CARRY;
  
  cu_psp = ds;
  /* process dta                                          */
  dta = &p->ps_cmd;
  
  if (mode == LOADNGO)
  {
    iregs FAR *irp;
    
    /* build the user area on the stack                     */
    irp = (iregs FAR *)(exp->exec.stack - sizeof(iregs));
    
    /* start allocating REGs (as in MS-DOS - some demos expect them so --LG) */
    /* see http://www.beroset.com/asm/showregs.asm */
    irp->DX = irp->ES = irp->DS = ds;
    irp->CS = FP_SEG(exp->exec.start_addr);
    irp->SI = irp->IP = FP_OFF(exp->exec.start_addr);
    irp->DI = FP_OFF(exp->exec.stack);
    irp->BP = 0x91e; /* this is more or less random but some programs
                        expect 0x9 in the high byte of BP!! */
    irp->AX = irp->BX = fcbcode;
    irp->CX = 0xFF;
    irp->FLAGS = 0x200;
    
    if (InDOS)
      --InDOS;
    exec_user(irp, 1);
    
    /* We should never be here          
       fatal("KERNEL RETURNED!!!");                    */
  }
  /* mode == LOAD */
  exp->exec.stack -= 2;
  *((UWORD FAR *)(exp->exec.stack)) = fcbcode;
  return SUCCESS;
}

/* Now find out how many paragraphs are available
   considering a threshold, trying HIGH then LOW */
STATIC int ExecMemLargest(UWORD *asize, UWORD threshold)
{
  int rc;
  if (mem_access_mode & 0x80)
  {
    mem_access_mode &= ~0x80;
    mem_access_mode |= 0x40;
    rc = DosMemLargest(asize);
    mem_access_mode &= ~0x40;
    /* less memory than the .COM/.EXE file has:
       try low memory first */
    if (rc != SUCCESS || *asize < threshold)
      rc = DosMemLargest(asize);
    mem_access_mode |= 0x80;
  }
  else
    rc = DosMemLargest(asize);
  return (*asize < threshold ? DE_NOMEM : rc);
}

STATIC int ExecMemAlloc(UWORD size, seg *para, UWORD *asize)
{
  /* We can still get an error on first fit if the above  */
  /* returned size was a best fit case                    */
  /* ModeLoadHigh = 80 = try high, then low               */
  int rc = DosMemAlloc(size, mem_access_mode, para, asize);

  if (rc != SUCCESS)
  {
    if (rc == DE_NOMEM)
    {
      rc = DosMemAlloc(0, LARGEST, para, asize);
      if ((mem_access_mode & 0x80) && (rc != SUCCESS))
      {
        mem_access_mode &= ~0x80;
        rc = DosMemAlloc(0, LARGEST, para, asize);
        mem_access_mode |= 0x80;
      }
    }
  }
  else
  {
    /* with no error, we got exactly what we asked for      */
    *asize = size;
  }

  /* This should never happen, but ... */
  if (rc == SUCCESS && *asize < size)
  {
    DosMemFree(*para);
    return DE_NOMEM;
  }
  return rc;
}

COUNT DosComLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd)
{
  UWORD mem;
  UWORD env, asize = 0;
  
  {
    UWORD com_size;
    {
      ULONG com_size_long = SftGetFsize(fd);
      /* maximally 64k - 256 bytes stack -
         256 bytes psp */
      com_size = ((UWORD)min(com_size_long, 0xfe00u) >> 4) + 0x10;
    }

    if ((mode & 0x7f) != OVERLAY)

⌨️ 快捷键说明

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