2000-05-06 21:34:20 +02:00
|
|
|
/****************************************************************/
|
|
|
|
/* */
|
|
|
|
/* 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
|
2001-11-18 15:01:12 +01:00
|
|
|
static BYTE *RcsId =
|
|
|
|
"$Id$";
|
2000-05-06 21:34:20 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define LOADNGO 0
|
|
|
|
#define LOAD 1
|
|
|
|
#define OVERLAY 3
|
|
|
|
|
2001-03-30 21:30:06 +02:00
|
|
|
#define LOAD_HIGH 0x80
|
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
/* 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)))
|
2004-03-07 13:19:43 +01:00
|
|
|
#define Shell (SecPathName + sizeof(exe_header) + sizeof(exec_blk))
|
2004-07-09 04:16:31 +02:00
|
|
|
#define sizeofShell (sizeof SecPathName - sizeof(exe_header) - sizeof(exec_blk))
|
2004-03-07 13:19:43 +01:00
|
|
|
|
|
|
|
#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
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
#define CHUNK 32256u /* =8000h-512; this value allows to combine
|
|
|
|
in one int value negative error codes
|
|
|
|
and positive read counters
|
|
|
|
*/
|
|
|
|
#define MAXENV 32768u /* maximum environment size */
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-05-10 22:49:43 +02:00
|
|
|
intvec getvec(unsigned char intno)
|
|
|
|
{
|
|
|
|
intvec iv;
|
|
|
|
disable();
|
2004-07-09 04:16:31 +02:00
|
|
|
iv = *MK_PTR(intvec, 0, 4 * intno);
|
2004-05-10 22:49:43 +02:00
|
|
|
enable();
|
|
|
|
return iv;
|
|
|
|
}
|
|
|
|
|
2004-05-10 22:15:37 +02:00
|
|
|
void setvec(unsigned char intno, intvec vector)
|
|
|
|
{
|
|
|
|
disable();
|
2004-07-09 04:16:31 +02:00
|
|
|
*MK_PTR(intvec, 0, 4 * intno) = vector;
|
2004-05-10 22:15:37 +02:00
|
|
|
enable();
|
|
|
|
}
|
|
|
|
|
2002-10-22 04:40:19 +02:00
|
|
|
ULONG SftGetFsize(int sft_idx)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
const sft FAR *s = idx_to_sft(sft_idx);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Get the SFT block that contains the SFT */
|
2002-10-22 04:40:19 +02:00
|
|
|
if (FP_OFF(s) == (size_t) -1)
|
2000-05-06 21:34:20 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* create a new environment for the process */
|
|
|
|
STATIC int ChildEnv(seg_t env_seg, seg_t *penv_seg, const char far *path)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
size_t env_sz, path_sz;
|
|
|
|
int rc;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* Every process requires an environment because of argv[0]
|
2004-07-09 04:16:31 +02:00
|
|
|
-- 1999/04/21 ska
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* make complete pathname */
|
|
|
|
if ((rc = truename(path, PriPathName, CDS_MODE_SKIP_PHYSICAL)) < SUCCESS)
|
|
|
|
return rc;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* get parent's environment if exec.env_seg == 0 */
|
|
|
|
if (env_seg == 0)
|
|
|
|
env_seg = MK_SEG_PTR(const psp, cu_psp)->ps_environ;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* count size of environment */
|
|
|
|
path_sz = strlen(PriPathName) + 5;
|
|
|
|
env_sz = 0;
|
|
|
|
if (env_seg && *MK_PTR(const char, env_seg, 0))
|
|
|
|
{
|
|
|
|
do
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
env_sz++;
|
|
|
|
if (env_sz + path_sz > MAXENV)
|
2001-11-18 15:01:12 +01:00
|
|
|
return DE_INVLDENV;
|
2004-07-09 04:16:31 +02:00
|
|
|
} while (*MK_PTR(const UWORD, env_seg, env_sz));
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* allocate space for env + path */
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
UWORD tmp;
|
|
|
|
if ((rc = DosMemAlloc((env_sz + path_sz + 15) / 16,
|
|
|
|
mem_access_mode, penv_seg, &tmp)) != SUCCESS)
|
|
|
|
return rc;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
seg_t dst_seg = *penv_seg + 1;
|
|
|
|
|
|
|
|
/* enviornment contains:
|
|
|
|
- 0 or more ASCIIZ strings (with variable definitions);
|
|
|
|
- empty ASCIIZ string (one null character);
|
|
|
|
- 16-bit counter (usually 1);
|
|
|
|
- ASCIIZ string with path.
|
|
|
|
*/
|
|
|
|
/* UNDOCUMENTED: with none variables before empty ASCIIZ string,
|
|
|
|
environment should get additional null character (ie. empty
|
|
|
|
environment contains two null characters). --avb
|
|
|
|
*/
|
|
|
|
fmemcpy(MK_SEG_PTR(char, dst_seg), MK_SEG_PTR(const char, env_seg), env_sz);
|
|
|
|
*MK_PTR(UWORD, dst_seg, env_sz) = 0;
|
|
|
|
*MK_PTR(UWORD, dst_seg, env_sz + 2) = 1;
|
|
|
|
fstrcpy(MK_PTR(char, dst_seg, env_sz + 4), PriPathName);
|
2000-05-08 06:30:00 +02:00
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* The following code is 8086 dependant */
|
|
|
|
void new_psp(seg_t para, seg_t cur_psp)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
psp _seg *p = MK_SEG_PTR(psp, para);
|
|
|
|
|
|
|
|
fmemcpy(p, MK_SEG_PTR(psp, cur_psp), sizeof(psp));
|
|
|
|
|
|
|
|
/* initialize all entries and exits */
|
|
|
|
p->ps_exit = 0x20cd; /* CP/M-like exit point: */
|
|
|
|
/* INT 20 opcode */
|
|
|
|
/* CP/M-like entry point: */
|
|
|
|
p->ps_farcall = 0x9a; /* FAR CALL opcode... */
|
|
|
|
p->ps_reentry = MK_FP(0xf01d,0xfef0); /* ...entry address */
|
|
|
|
|
|
|
|
/* entry address should point to 0:c0 (INT 30 vector), but
|
|
|
|
low word of ps_reentry should also contain "size of first
|
|
|
|
segment for .COM file" while preserving the far call;
|
|
|
|
in MS-DOS this is F01D:FEF0 --avb */
|
|
|
|
|
|
|
|
p->ps_unix[0] = 0xcd; /* unix style call: */
|
|
|
|
p->ps_unix[1] = 0x21; /* INT 21/RETF opcodes */
|
|
|
|
p->ps_unix[2] = 0xcb;
|
|
|
|
|
|
|
|
/* parent-child relationships */
|
|
|
|
p->ps_prevpsp = (VFP)-1l; /* previous psp address */
|
|
|
|
|
|
|
|
p->ps_isv22 = getvec(0x22); /* terminate handler */
|
|
|
|
p->ps_isv23 = getvec(0x23); /* break handler */
|
|
|
|
p->ps_isv24 = getvec(0x24); /* critical error handler */
|
|
|
|
|
|
|
|
/* File System parameters */
|
|
|
|
p->ps_maxfiles = sizeof p->ps_files; /* size of file table */
|
|
|
|
p->ps_filetab = p->ps_files; /* file table address */
|
2004-03-17 22:28:54 +01:00
|
|
|
}
|
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* !!! cur_psp always equal to cu_psp --avb */
|
|
|
|
void child_psp(seg_t para, seg_t cur_psp, seg_t beyond)
|
2004-03-17 22:28:54 +01:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
psp _seg *p;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-03-17 22:28:54 +01:00
|
|
|
new_psp(para, cur_psp);
|
2004-07-09 04:16:31 +02:00
|
|
|
p = MK_SEG_PTR(psp, para);
|
|
|
|
|
|
|
|
/* parent-child relationships */
|
|
|
|
p->ps_parent = cu_psp; /* parent psp segment */
|
|
|
|
|
|
|
|
/* Environment and memory useage parameters */
|
|
|
|
p->ps_size = beyond; /* segment of memory beyond */
|
|
|
|
/* memory allocated to program */
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* File System parameters */
|
|
|
|
{
|
|
|
|
psp _seg *q = MK_SEG_PTR(psp, cur_psp);
|
|
|
|
int i;
|
|
|
|
/* clone the file table, 0xff=unused */
|
|
|
|
for (i = 0; i < sizeof p->ps_files; i++)
|
|
|
|
p->ps_files[i] = CloneHandle(i) != SUCCESS ? 0xff : q->ps_filetab[i];
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
struct cds FAR *get_cds1(unsigned drv)
|
2004-02-06 21:55:55 +01:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
if (drv-- == 0) /* 0 = A:, 1 = B:, ... */
|
|
|
|
drv = default_drive;
|
|
|
|
return get_cds(drv);
|
2004-02-06 21:55:55 +01:00
|
|
|
}
|
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
STATIC void makePSP(seg_t pspseg, seg_t envseg, size_t asize, const char FAR * path)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
psp _seg *p = MK_SEG_PTR(psp, pspseg);
|
|
|
|
mcb _seg *pspmcb = MK_SEG_PTR(mcb, FP_SEG(p) - 1);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* identify the mcb as this functions' */
|
|
|
|
pspmcb->m_psp = FP_SEG(p);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* copy the file name less extension into MCB */
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
const char FAR *np;
|
|
|
|
int i;
|
|
|
|
for (np = path;;) /* find program name after path */
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
char ch = *path;
|
|
|
|
if (ch == '\0')
|
|
|
|
break;
|
|
|
|
path++;
|
|
|
|
if (ch == ':' || ch == '\\' || ch == '/')
|
|
|
|
np = path; /* remember position after path */
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2004-07-09 04:16:31 +02:00
|
|
|
i = 0;
|
|
|
|
do /* extract program name */
|
|
|
|
{
|
|
|
|
UBYTE ch = *np;
|
|
|
|
if (ch == '.' || ch == '\0')
|
|
|
|
{
|
|
|
|
pspmcb->m_name[i] = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ch >= 'a' && ch <= 'z')
|
|
|
|
ch -= (UBYTE)('a' - 'A');
|
|
|
|
pspmcb->m_name[i] = ch; /* copy name, without extension */
|
|
|
|
i++, np++;
|
|
|
|
} while (i < 8);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2004-07-09 04:16:31 +02:00
|
|
|
|
|
|
|
setvec(0x22, (intvec)MK_FP(user_r->CS, user_r->IP));
|
|
|
|
child_psp(FP_SEG(p), cu_psp, FP_SEG(p) + asize);
|
|
|
|
|
|
|
|
/* Patch in env segment, if present, also adjust its MCB */
|
|
|
|
if (envseg)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
MK_SEG_PTR(mcb, envseg)->m_psp = FP_SEG(p);
|
|
|
|
envseg++;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2004-07-09 04:16:31 +02:00
|
|
|
p->ps_environ = envseg;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
static void load_transfer(seg_t ds, exec_blk *ep, int mode)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
UWORD fcbcode;
|
|
|
|
psp _seg *p = MK_SEG_PTR(psp, ds);
|
|
|
|
{
|
|
|
|
psp _seg *q = MK_SEG_PTR(psp, cu_psp);
|
|
|
|
p->ps_parent = FP_SEG(q);
|
|
|
|
p->ps_prevpsp = q;
|
|
|
|
q->ps_stack = (BYTE FAR *)user_r;
|
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
user_r->FLAGS &= ~FLG_CARRY;
|
2004-07-09 04:16:31 +02:00
|
|
|
|
|
|
|
cu_psp = FP_SEG(p);
|
2002-10-22 04:40:19 +02:00
|
|
|
/* process dta */
|
|
|
|
dta = &p->ps_cmd;
|
2004-07-09 04:16:31 +02:00
|
|
|
|
|
|
|
/* complete the psp by adding the command line and FCBs */
|
|
|
|
/* UNDOCUMENTED: MS-DOS copies sizeof(CommandTail) bytes without
|
|
|
|
checking memory contents and fixing wrong (>7Fh) length field;
|
|
|
|
FCBs also copied without checking address validness --avb
|
|
|
|
*/
|
|
|
|
fmemcpy(&p->ps_fcb1, ep->exec.fcb_1, 12); /* drive+name+ext */
|
|
|
|
fmemcpy(&p->ps_fcb2, ep->exec.fcb_2, 12);
|
|
|
|
fmemcpy(&p->ps_cmd, ep->exec.cmd_line, sizeof(CommandTail));
|
|
|
|
|
|
|
|
/* AX value to be passed based on FCB values */
|
|
|
|
fcbcode = (get_cds1(p->ps_fcb1.fcb_drive) ? 0 : 0xff) |
|
|
|
|
(get_cds1(p->ps_fcb2.fcb_drive) ? 0 : 0xff00);
|
|
|
|
|
|
|
|
/* Transfer control to the executable */
|
2002-08-03 18:54:09 +02:00
|
|
|
if (mode == LOADNGO)
|
|
|
|
{
|
|
|
|
/* build the user area on the stack */
|
2004-07-25 11:55:58 +02:00
|
|
|
iregs FAR *irp = (iregs FAR *)ep->exec.stack - 1;
|
2004-07-09 04:16:31 +02:00
|
|
|
|
2003-08-28 22:47:25 +02:00
|
|
|
/* start allocating REGs (as in MS-DOS - some demos expect them so --LG) */
|
|
|
|
/* see http://www.beroset.com/asm/showregs.asm */
|
2004-07-09 04:16:31 +02:00
|
|
|
irp->AX =
|
|
|
|
irp->BX = fcbcode;
|
|
|
|
irp->DX =
|
|
|
|
irp->ES =
|
|
|
|
irp->DS = FP_SEG(p);
|
|
|
|
irp->CS = FP_SEG(ep->exec.start_addr);
|
|
|
|
irp->SI =
|
|
|
|
irp->IP = FP_OFF(ep->exec.start_addr);
|
|
|
|
irp->DI = FP_OFF(ep->exec.stack);
|
2003-08-28 22:47:25 +02:00
|
|
|
irp->BP = 0x91e; /* this is more or less random but some programs
|
|
|
|
expect 0x9 in the high byte of BP!! */
|
|
|
|
irp->CX = 0xFF;
|
2002-08-03 18:54:09 +02:00
|
|
|
irp->FLAGS = 0x200;
|
2004-07-09 04:16:31 +02:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
if (InDOS)
|
|
|
|
--InDOS;
|
2003-08-28 22:25:09 +02:00
|
|
|
exec_user(irp, 1);
|
2004-07-09 04:16:31 +02:00
|
|
|
|
|
|
|
/* We should never be here
|
|
|
|
panic("KERNEL RETURNED!!!"); */
|
2002-08-03 18:54:09 +02:00
|
|
|
}
|
2004-07-09 04:16:31 +02:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
/* mode == LOAD */
|
2004-07-09 04:16:31 +02:00
|
|
|
ep->exec.stack -= sizeof(UWORD);
|
|
|
|
*(UWORD FAR *)ep->exec.stack = fcbcode;
|
2002-08-03 18:54:09 +02:00
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
/* Now find out how many paragraphs are available
|
|
|
|
considering a threshold, trying HIGH then LOW */
|
|
|
|
STATIC int ExecMemLargest(UWORD *asize, UWORD threshold)
|
|
|
|
{
|
2002-10-22 04:40:19 +02:00
|
|
|
int rc;
|
|
|
|
if (mem_access_mode & 0x80)
|
2002-08-03 18:54:09 +02:00
|
|
|
{
|
|
|
|
mem_access_mode &= ~0x80;
|
2002-10-22 04:40:19 +02:00
|
|
|
mem_access_mode |= 0x40;
|
2002-08-03 18:54:09 +02:00
|
|
|
rc = DosMemLargest(asize);
|
2002-10-22 04:40:19 +02:00
|
|
|
mem_access_mode &= ~0x40;
|
|
|
|
/* less memory than the .COM/.EXE file has:
|
|
|
|
try low memory first */
|
|
|
|
if (rc != SUCCESS || *asize < threshold)
|
|
|
|
rc = DosMemLargest(asize);
|
2002-08-03 18:54:09 +02:00
|
|
|
mem_access_mode |= 0x80;
|
|
|
|
}
|
2002-10-22 04:40:19 +02:00
|
|
|
else
|
|
|
|
rc = DosMemLargest(asize);
|
2002-08-03 18:54:09 +02:00
|
|
|
return (*asize < threshold ? DE_NOMEM : rc);
|
|
|
|
}
|
2001-03-30 21:30:06 +02:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
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);
|
2001-03-30 21:30:06 +02:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
if (rc != SUCCESS)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-08-03 18:54:09 +02:00
|
|
|
if (rc == DE_NOMEM)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-08-03 18:54:09 +02:00
|
|
|
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;
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* with no error, we got exactly what we asked for */
|
|
|
|
*asize = size;
|
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
/* This should never happen, but ... */
|
|
|
|
if (rc == SUCCESS && *asize < size)
|
|
|
|
{
|
|
|
|
DosMemFree(*para);
|
|
|
|
return DE_NOMEM;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
COUNT DosComLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd)
|
|
|
|
{
|
|
|
|
UWORD mem;
|
2004-07-09 04:16:31 +02:00
|
|
|
UWORD env, asize;
|
|
|
|
UWORD com_size;
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2002-10-22 04:40:19 +02:00
|
|
|
ULONG com_size_long = SftGetFsize(fd);
|
2002-08-03 18:54:09 +02:00
|
|
|
/* maximally 64k - 256 bytes stack -
|
|
|
|
256 bytes psp */
|
2004-02-07 19:04:50 +01:00
|
|
|
com_size = ((UWORD)min(com_size_long, 0xfe00u) >> 4) + 0x10;
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
if ((mode & 0x7f) != OVERLAY)
|
2001-03-19 05:50:56 +01:00
|
|
|
{
|
2002-08-03 18:54:09 +02:00
|
|
|
COUNT rc;
|
|
|
|
UBYTE UMBstate = uppermem_link;
|
|
|
|
UBYTE orig_mem_access = mem_access_mode;
|
|
|
|
|
|
|
|
if (mode & 0x80)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2002-08-03 18:54:09 +02:00
|
|
|
mem_access_mode |= 0x80;
|
|
|
|
DosUmbLink(1); /* link in UMB's */
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
|
|
|
|
/* COMFILES will always be loaded in largest area. is that true TE */
|
|
|
|
/* yes, see RBIL, int21/ah=48 -- Bart */
|
2004-07-09 04:16:31 +02:00
|
|
|
if ((rc = ChildEnv(exp->exec.env_seg, &env, namep)) == SUCCESS)
|
|
|
|
{
|
|
|
|
if ((rc = ExecMemLargest(&asize, com_size)) != SUCCESS ||
|
|
|
|
/* Allocate our memory and pass back any errors */
|
|
|
|
(rc = ExecMemAlloc(asize, &mem, &asize)) != SUCCESS)
|
|
|
|
DosMemFree(env);
|
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
|
|
|
|
if (mode & 0x80)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2002-08-03 18:54:09 +02:00
|
|
|
DosUmbLink(UMBstate); /* restore link state */
|
|
|
|
mem_access_mode = orig_mem_access;
|
|
|
|
mode &= 0x7f;
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
if (rc != SUCCESS)
|
|
|
|
return rc;
|
|
|
|
|
2002-01-23 23:29:41 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
printf("DosComLoader. Loading '%S' at %04x\n", namep, mem);
|
|
|
|
#endif
|
2004-07-09 04:16:31 +02:00
|
|
|
++mem;
|
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* Now load the executable */
|
2002-08-03 18:54:09 +02:00
|
|
|
/* rewind to start */
|
2002-10-22 04:40:19 +02:00
|
|
|
SftSeek(fd, 0, 0);
|
2004-07-09 04:16:31 +02:00
|
|
|
/* MS DOS always only loads the very first 64KB - sizeof(psp) bytes.
|
|
|
|
-- 1999/04/21 ska */
|
2002-08-03 18:54:09 +02:00
|
|
|
/* read everything, but at most 64K - sizeof(PSP) */
|
2004-07-09 04:16:31 +02:00
|
|
|
/* !!! should be added check for reading success --avb */
|
|
|
|
DosRWSft(fd, 0xff00, mode == OVERLAY /* memory already allocated */
|
|
|
|
? MK_FP(exp->load.load_seg, 0)
|
|
|
|
: MK_FP(mem, sizeof(psp)), XFR_READ);
|
2002-10-22 04:40:19 +02:00
|
|
|
DosCloseSft(fd, FALSE);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
if (mode != OVERLAY)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
makePSP(mem, env, asize, namep);
|
2002-08-03 18:54:09 +02:00
|
|
|
/* set asize to end of segment */
|
2003-09-16 14:38:02 +02:00
|
|
|
if (asize > 0x1000)
|
|
|
|
asize = 0x1000;
|
|
|
|
if (asize < 0x11)
|
|
|
|
return DE_NOMEM;
|
|
|
|
asize -= 0x11;
|
|
|
|
/* CP/M compatibility--size of first segment for .COM files
|
|
|
|
while preserving the far call to 0:00c0 +
|
|
|
|
copy in HMA at ffff:00d0 */
|
2004-07-09 04:16:31 +02:00
|
|
|
MK_SEG_PTR(psp, mem)->ps_reentry = MK_FP(0xc - asize, asize << 4);
|
2003-09-16 14:38:02 +02:00
|
|
|
asize <<= 4;
|
|
|
|
asize += 0x10e;
|
2002-08-03 18:54:09 +02:00
|
|
|
exp->exec.stack = MK_FP(mem, asize);
|
|
|
|
exp->exec.start_addr = MK_FP(mem, 0x100);
|
2004-07-09 04:16:31 +02:00
|
|
|
*MK_PTR(UWORD, mem, asize) = 0;
|
|
|
|
load_transfer(mem, exp, mode);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
return SUCCESS;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
void return_user(void)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
/* restore parent */
|
2004-07-09 04:16:31 +02:00
|
|
|
psp _seg *p = MK_SEG_PTR(psp, cu_psp);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* When process returns - restore the isv */
|
|
|
|
setvec(0x22, p->ps_isv22);
|
|
|
|
setvec(0x23, p->ps_isv23);
|
|
|
|
setvec(0x24, p->ps_isv24);
|
|
|
|
|
|
|
|
/* And free all process memory if not a TSR return */
|
2004-04-20 20:43:03 +02:00
|
|
|
network_redirector(REM_PROCESS_END);
|
|
|
|
/* might be a good idea to do that after closing
|
|
|
|
but doesn't help NET either TE */
|
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
if (!tsr)
|
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
REG COUNT i;
|
2004-04-20 20:43:03 +02:00
|
|
|
network_redirector(REM_CLOSEALL);
|
2000-05-06 21:34:20 +02:00
|
|
|
for (i = 0; i < p->ps_maxfiles; i++)
|
|
|
|
{
|
|
|
|
DosClose(i);
|
|
|
|
}
|
2001-07-23 14:47:42 +02:00
|
|
|
FcbCloseAll();
|
2004-07-09 04:16:31 +02:00
|
|
|
FreeProcessMem(FP_SEG(p));
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
{
|
|
|
|
iregs FAR *irp = (iregs FAR *)MK_SEG_PTR(psp, cu_psp = p->ps_parent)->ps_stack;
|
|
|
|
irp->CS = FP_SEG(p->ps_isv22);
|
|
|
|
irp->IP = FP_OFF(p->ps_isv22);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
if (InDOS)
|
|
|
|
--InDOS;
|
|
|
|
exec_user(irp, 0);
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
COUNT DosExeLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
UWORD mem, env, start_seg, asize;
|
|
|
|
UWORD image_size;
|
2001-11-18 15:01:12 +01:00
|
|
|
|
|
|
|
/* compute image size by removing the offset from the */
|
|
|
|
/* number pages scaled to bytes plus the remainder and */
|
|
|
|
/* the psp */
|
2004-03-21 13:36:47 +01:00
|
|
|
/* First scale the size and remove the offset */
|
|
|
|
if (ExeHeader.exPages >= 2048)
|
|
|
|
return DE_INVLDDATA; /* we're not able to get >=1MB in dos memory */
|
|
|
|
image_size = ExeHeader.exPages * 32 - ExeHeader.exHeaderSize;
|
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* We should not attempt to allocate memory if we are overlaying
|
|
|
|
the current process, because the new process will simply re-use
|
|
|
|
the block we already have allocated. This was causing execl() to
|
|
|
|
fail in applications which use it to overlay (replace) the current
|
|
|
|
exe file with a new one. Jun 11, 2000 --rbc */
|
2002-08-03 18:54:09 +02:00
|
|
|
|
|
|
|
if ((mode & 0x7f) != OVERLAY)
|
2001-04-16 16:28:32 +02:00
|
|
|
{
|
2002-08-03 18:54:09 +02:00
|
|
|
UBYTE UMBstate = uppermem_link;
|
|
|
|
UBYTE orig_mem_access = mem_access_mode;
|
|
|
|
COUNT rc;
|
|
|
|
|
|
|
|
/* Clone the environement and create a memory arena */
|
2002-10-22 04:40:19 +02:00
|
|
|
if (mode & 0x80)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
|
|
|
DosUmbLink(1); /* link in UMB's */
|
|
|
|
mem_access_mode |= 0x80;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
if ((rc = ChildEnv(exp->exec.env_seg, &env, namep)) == SUCCESS)
|
|
|
|
{
|
|
|
|
image_size += sizeof(psp) / 16; /*TE 03/20/01 */
|
2002-08-03 18:54:09 +02:00
|
|
|
/* Now find out how many paragraphs are available */
|
2004-07-09 04:16:31 +02:00
|
|
|
if ((rc = ExecMemLargest(&asize, image_size + ExeHeader.exMinAlloc)) == SUCCESS)
|
|
|
|
{
|
|
|
|
unsigned max_size = image_size + ExeHeader.exMaxAlloc;
|
|
|
|
/* second test is for overflow (avoiding longs) --
|
|
|
|
exMaxAlloc can be high */
|
|
|
|
if (max_size > asize || max_size < image_size ||
|
|
|
|
/* TE if ExeHeader.exMinAlloc == ExeHeader.exMaxAlloc == 0,
|
|
|
|
DOS will allocate the largest possible memory area
|
|
|
|
and load the image as high as possible into it.
|
|
|
|
discovered (and after that found in RBIL), when testing NET */
|
|
|
|
(ExeHeader.exMinAlloc | ExeHeader.exMaxAlloc) == 0)
|
|
|
|
max_size = asize;
|
|
|
|
/* Allocate our memory and pass back any errors */
|
|
|
|
rc = ExecMemAlloc(max_size, &mem, &asize);
|
|
|
|
}
|
|
|
|
if (rc != SUCCESS)
|
|
|
|
DosMemFree(env);
|
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
|
|
|
|
if (mode & 0x80)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2002-08-03 18:54:09 +02:00
|
|
|
mem_access_mode = orig_mem_access; /* restore old situation */
|
|
|
|
DosUmbLink(UMBstate); /* restore link state */
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
2004-07-09 04:16:31 +02:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
if (rc != SUCCESS)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
mode &= 0x7f; /* forget about high loading from now on */
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
#ifdef DEBUG
|
2002-01-23 23:29:41 +01:00
|
|
|
printf("DosExeLoader. Loading '%S' at %04x\n", namep, mem);
|
2001-11-18 15:01:12 +01:00
|
|
|
#endif
|
|
|
|
/* memory found large enough - continue processing */
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* Now load the executable */
|
|
|
|
/* offset to start of image */
|
2004-03-21 13:36:47 +01:00
|
|
|
if (SftSeek(fd, ExeHeader.exHeaderSize * 16UL, 0) != SUCCESS)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2001-11-18 15:01:12 +01:00
|
|
|
if (mode != OVERLAY)
|
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
DosMemFree(mem);
|
2001-11-18 15:01:12 +01:00
|
|
|
DosMemFree(env);
|
|
|
|
}
|
2000-05-06 21:34:20 +02:00
|
|
|
return DE_INVLDDATA;
|
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
|
|
|
|
/* create the start seg for later computations */
|
2004-07-09 04:16:31 +02:00
|
|
|
start_seg = exp->load.load_seg;
|
2001-11-18 15:01:12 +01:00
|
|
|
if (mode != OVERLAY)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
start_seg = mem + 1 + sizeof(psp) / 16;
|
|
|
|
if ((ExeHeader.exMinAlloc | ExeHeader.exMaxAlloc) == 0)
|
2002-08-03 18:54:09 +02:00
|
|
|
/* then the image should be placed as high as possible */
|
2004-07-09 04:16:31 +02:00
|
|
|
start_seg += MK_SEG_PTR(const mcb, mem)->m_size - image_size;
|
|
|
|
image_size -= sizeof(psp) / 16;
|
2002-08-03 18:54:09 +02:00
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2004-03-21 13:36:47 +01:00
|
|
|
/* read in the image in 32256 chunks */
|
2002-08-03 18:54:09 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
seg_t sp = start_seg;
|
|
|
|
do
|
2002-08-03 18:54:09 +02:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
int toRead = CHUNK;
|
|
|
|
if (image_size < CHUNK/16)
|
|
|
|
{
|
|
|
|
toRead = image_size*16;
|
|
|
|
image_size = CHUNK/16;
|
|
|
|
}
|
|
|
|
if ((int)DosRWSft(fd, toRead, MK_FP(sp, 0), XFR_READ) < toRead)
|
2002-08-03 18:54:09 +02:00
|
|
|
break;
|
2004-03-21 13:36:47 +01:00
|
|
|
sp += CHUNK/16;
|
2004-07-09 04:16:31 +02:00
|
|
|
} while (image_size -= CHUNK/16);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
/* relocate the image for new segment */
|
|
|
|
SftSeek(fd, ExeHeader.exRelocTable, 0);
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
for (i = ExeHeader.exRelocItems; i; i--)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
UWORD reloc[2];
|
|
|
|
if (DosRWSft(fd, sizeof reloc, reloc, XFR_READ) != sizeof reloc)
|
2001-11-18 15:01:12 +01:00
|
|
|
{
|
2003-09-18 22:54:21 +02:00
|
|
|
if (mode != OVERLAY)
|
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
DosMemFree(mem);
|
2003-09-18 22:54:21 +02:00
|
|
|
DosMemFree(env);
|
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
return DE_INVLDDATA;
|
|
|
|
}
|
2004-07-09 04:16:31 +02:00
|
|
|
*MK_PTR(seg_t, reloc[1] + start_seg, reloc[0]) += start_seg;
|
2001-11-18 15:01:12 +01:00
|
|
|
}
|
2001-11-04 20:47:39 +01:00
|
|
|
}
|
2001-11-18 15:01:12 +01:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
/* and finally close the file */
|
2002-10-22 04:40:19 +02:00
|
|
|
DosCloseSft(fd, FALSE);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
/* exit here for overlay */
|
2004-07-09 04:16:31 +02:00
|
|
|
if (mode != OVERLAY)
|
2001-11-04 20:47:39 +01:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
mem++;
|
|
|
|
makePSP(mem, env, asize, namep);
|
2002-08-03 18:54:09 +02:00
|
|
|
exp->exec.stack =
|
|
|
|
MK_FP(ExeHeader.exInitSS + start_seg, ExeHeader.exInitSP);
|
|
|
|
exp->exec.start_addr =
|
|
|
|
MK_FP(ExeHeader.exInitCS + start_seg, ExeHeader.exInitIP);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2001-11-18 15:01:12 +01:00
|
|
|
/* Transfer control to the executable */
|
2004-07-09 04:16:31 +02:00
|
|
|
load_transfer(mem, exp, mode);
|
2001-11-04 20:47:39 +01:00
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
return SUCCESS;
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* mode = LOAD or EXECUTE
|
|
|
|
ep = EXE block
|
|
|
|
lp = filename to load (string)
|
|
|
|
|
|
|
|
leb = local copy of exe block
|
|
|
|
*/
|
|
|
|
COUNT DosExec(COUNT mode, exec_blk FAR * ep, BYTE FAR * lp)
|
|
|
|
{
|
2001-04-22 00:32:53 +02:00
|
|
|
COUNT rc;
|
2002-08-03 18:54:09 +02:00
|
|
|
COUNT fd;
|
2001-04-15 05:21:50 +02:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
if ((mode & 0x7f) > 3 || (mode & 0x7f) == 2)
|
|
|
|
return DE_INVLDFMT;
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
fmemcpy(&TempExeBlock, ep, sizeof(exec_blk));
|
2000-05-06 21:34:20 +02:00
|
|
|
/* If file not found - free ram and return error */
|
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
if (IsDevice(lp) || /* we don't want to execute C:>NUL */
|
2002-10-22 04:40:19 +02:00
|
|
|
(fd = (short)DosOpenSft(lp, O_LEGACY | O_OPEN | O_RDONLY, 0)) < 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
|
|
|
return DE_FILENOTFND;
|
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
|
2004-07-09 04:16:31 +02:00
|
|
|
rc = (int)DosRWSft(fd, sizeof(exe_header), &ExeHeader, XFR_READ);
|
2000-05-06 21:34:20 +02:00
|
|
|
|
2002-08-03 18:54:09 +02:00
|
|
|
if (rc == sizeof(exe_header) &&
|
|
|
|
(ExeHeader.exSignature == MAGIC || ExeHeader.exSignature == OLD_MAGIC))
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-08-03 18:54:09 +02:00
|
|
|
rc = DosExeLoader(lp, &TempExeBlock, mode, fd);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
else if (rc != 0)
|
2000-05-06 21:34:20 +02:00
|
|
|
{
|
2002-08-03 18:54:09 +02:00
|
|
|
rc = DosComLoader(lp, &TempExeBlock, mode, fd);
|
2000-05-06 21:34:20 +02:00
|
|
|
}
|
2002-08-03 18:54:09 +02:00
|
|
|
|
2002-10-22 04:40:19 +02:00
|
|
|
DosCloseSft(fd, FALSE);
|
2002-08-03 18:54:09 +02:00
|
|
|
|
2000-05-06 21:34:20 +02:00
|
|
|
if (mode == LOAD && rc == SUCCESS)
|
2002-08-03 18:54:09 +02:00
|
|
|
fmemcpy(ep, &TempExeBlock, sizeof(exec_blk));
|
2000-05-06 21:34:20 +02:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2004-03-07 13:19:43 +01:00
|
|
|
#include "config.h" /* config structure definition */
|
|
|
|
|
|
|
|
/* start process 0 (the shell) */
|
2004-07-09 04:16:31 +02:00
|
|
|
void ASMCFUNC P_0(const struct config FAR *);
|
|
|
|
#ifdef __WATCOMC__
|
|
|
|
# pragma aux (cdecl) P_0 aborts
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void ASMCFUNC P_0(const struct config FAR *Config)
|
2004-03-07 13:19:43 +01:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
int mode = Config->cfgP_0_startmode;
|
|
|
|
|
|
|
|
const char FAR *p = MK_PTR(const char, FP_SEG(Config), Config->cfgShell);
|
|
|
|
PStr endp = Shell;
|
|
|
|
while ((*endp = *p++) != '\0' &&
|
|
|
|
++endp < Shell + sizeofShell - 4); /* 4 for 0,ctCount and "\r\0" */
|
|
|
|
|
|
|
|
for (;;) /* endless shell load loop - reboot or shut down to exit it! */
|
2004-03-07 13:19:43 +01:00
|
|
|
{
|
2004-07-09 04:16:31 +02:00
|
|
|
PStr tailp = Shell - 1;
|
|
|
|
|
|
|
|
*endp = '\r', endp[1] = '\0'; /* terminate command line */
|
|
|
|
endp += 2;
|
|
|
|
|
|
|
|
/* find end of command name */
|
|
|
|
do tailp++; while ((UBYTE)*tailp > ' ' && *tailp != '/');
|
|
|
|
|
|
|
|
/* shift tail to right by 2 to make room for '\0' and ctCount */
|
|
|
|
{
|
|
|
|
PStr p = endp;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
p--;
|
|
|
|
p[2] = p[0];
|
|
|
|
} while (p > tailp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* terminate name */
|
|
|
|
*tailp = '\0';
|
|
|
|
|
|
|
|
/* init length of command line tail (ctCount field) */
|
|
|
|
tailp++;
|
|
|
|
*tailp = (UBYTE)(endp - tailp - 1); /* without "\r\0" */
|
|
|
|
|
|
|
|
{
|
|
|
|
exec_blk exb;
|
|
|
|
exb.exec.env_seg = DOS_PSP + 8;
|
|
|
|
exb.exec.cmd_line = (CommandTail *)tailp;
|
|
|
|
/*exb.exec.fcb_1 = exb.exec.fcb_2 = NULL;*/ /* unimportant */
|
|
|
|
|
2004-03-07 13:19:43 +01:00
|
|
|
#ifdef DEBUG
|
2004-07-09 04:16:31 +02:00
|
|
|
printf("Process 0 starting: %s%s\n\n", Shell, tailp + 1);
|
2004-03-07 13:19:43 +01:00
|
|
|
#endif
|
2004-07-09 04:16:31 +02:00
|
|
|
res_DosExec(mode, &exb, Shell);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* failure or exit */
|
|
|
|
put_string("\nBad or missing Command Interpreter\n"
|
|
|
|
"Enter the full shell command line:\n");
|
2004-03-07 13:19:43 +01:00
|
|
|
put_string(Shell);
|
2004-07-09 04:16:31 +02:00
|
|
|
*endp = '\n'; /* replace "\r\0" by "\n\0" */
|
|
|
|
put_string(++tailp);
|
|
|
|
endp = Shell + res_read(STDIN, Shell, sizeofShell) - 2; /* exclude "\r\n" */
|
2004-03-07 13:19:43 +01:00
|
|
|
}
|
|
|
|
}
|