mirror of
https://github.com/SEPPDROID/DR-DOS-OpenDOS.git
synced 2025-10-22 07:54:28 +00:00
1834 lines
52 KiB
C
1834 lines
52 KiB
C
/* File : $Workfile: COM.C$
|
|
;
|
|
; Description :
|
|
;
|
|
; Original Author : DIGITAL RESEARCH
|
|
;
|
|
; Last Edited By : $CALDERA$
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
; Copyright Work of Caldera, Inc. All Rights Reserved.
|
|
;
|
|
; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
|
|
; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
|
|
; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
|
|
; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
|
|
; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
|
|
; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
|
|
; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
|
|
; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
|
|
; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
|
|
; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
|
|
; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
|
|
; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
|
|
; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
|
|
; CIVIL LIABILITY.
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; *** Current Edit History ***
|
|
; *** End of Current Edit History ***
|
|
;
|
|
; $Log$
|
|
* COM.C 1.2 97/03/21 14:41:21
|
|
* Added /n option to disable critical error handler
|
|
* COM.C 1.59 94/12/01 10:05:21
|
|
* Removed closing handles 5 and 6 in error_code() in order to be able
|
|
* to continue with a batch file if the user wants to. JBEULICH
|
|
* Enabled UNC filenames
|
|
* COM.C 1.58 94/08/10 14:49:22
|
|
* After first run through looking for a file to execute, now strips the D:
|
|
* off the path, if only a drive and not a directory is specified. So, if you
|
|
* type D:TEST, it will look for TEST on the current directory of drive D:, then
|
|
* continue to search the path. It will only skip searching the path if a
|
|
* specific directory is specified.
|
|
* COM.C 1.57 94/03/29 16:12:11
|
|
* docmd_int2f in CSTART.ASM returns 1 if it has been accepted.
|
|
* In this case, we don't want it, so docmd_offer returns TRUE.
|
|
* All cases of docmd_offer return if TRUE, so we don't process
|
|
* the line ourselves.
|
|
* COM.C 1.56 94/02/08 11:50:17
|
|
* Fixed a problem where typing COMMAND DIR A: after giving the correct error
|
|
* message for DIR being an incorrect loadpath, tries to access A: and crashes
|
|
* under /MULTI.
|
|
* Break added after error message to fix crashing problem.
|
|
* Variable lferror added so that after an incorrect loadpath, it does not use
|
|
* the next bit (ie. A:) as keyboard input.
|
|
* COM.C 1.54 93/12/09 18:07:04
|
|
* Fixed a bug which screwed the upper memory link if you entered c:lh dir
|
|
* COM.C 1.53 93/12/01 23:14:02
|
|
* Fix parsing bug "<infile >outfile command" would fail
|
|
* COM.C 1.49 93/12/01 11:32:08
|
|
* Now do a flush cache call before displaying prompt.
|
|
* COM.C 1.48 93/12/01 00:17:17
|
|
* docmd_offer() will do an int 2F/AE (2 if external) within batch files
|
|
* SPR: 811218, shouldn't access drive whatever the prompt
|
|
* COM.C 1.45 93/11/19 21:08:14
|
|
* Put code to report "Syntax Error" for "| command" and "command |" back to
|
|
* it's original state.
|
|
* COM.C 1.43 93/11/08 23:59:19
|
|
* F8 key now only affects autoexec, not 1st batch file
|
|
* COM.C 1.42 93/11/05 13:03:00
|
|
* Fix problem with /P /MH (missing break;....)
|
|
* COM.C 1.41 93/11/05 00:44:07
|
|
* /MU option only valid with /P option. The problem is if you "exit" with upper
|
|
* memory unlinked the resident portion isn't freed, and you eat upper memory.
|
|
* COM.C 1.40 93/10/29 17:05:51
|
|
* Add PROMPT=$P$G and PATH=d:\NWDOS to default env
|
|
* COM.C 1.39 93/10/22 11:51:30
|
|
* Changed Beta string from 3 to 4
|
|
* COM.C 1.36 93/09/15 18:56:39
|
|
* FOR command now allows any char in brackets. eg for %%v in (+ -) do...
|
|
* COM.C 1.34 93/08/26 09:39:05
|
|
* Now use PSP for stack during func 4b exec. There's some debug
|
|
* code in case things screw up.
|
|
* COM.C 1.30 93/07/05 08:32:57
|
|
* Memory allocation strategy now restored if ctrl-c pressed during a hiload.
|
|
* COM.C 1.25 93/05/24 11:34:43
|
|
* psp now points to itself when /P isn't specified.
|
|
* COM.C 1.24 93/05/17 11:22:28
|
|
* Added support for F5 and F8 being pressed during boot-up.
|
|
* COM.C 1.23 93/04/22 14:51:10
|
|
* Now close handles 5-19 after an exec.
|
|
* echoflg is now correctly preserved when batch files are chained. See
|
|
* echoflg_save2.
|
|
* COM.C 1.19 93/01/21 14:29:44
|
|
* Now do INT 21 ah=29 when changing default drive.
|
|
* COM.C 1.16 92/11/25 09:30:15
|
|
* Password support enabled/disabled by #if defined(PASSWORD) statements.
|
|
* HOMEDIR support disabled.
|
|
* COM.C 1.12 92/09/25 19:48:56
|
|
* Removed .cmd from search order if DOSPLUS defined.
|
|
* Fixed bug when ;; appears in path.
|
|
* COM.C 1.11 92/09/17 11:30:14
|
|
* Piping a batch file through MORE no longer stops with Syntax Error
|
|
* displayed.
|
|
* COM.C 1.10 92/09/11 10:43:41
|
|
* COMMAND /P: disables time and date prompt and copyright message.
|
|
* COMMAND ? no longer hangs.
|
|
* ENDLOG
|
|
*/
|
|
|
|
#include "defines.h"
|
|
|
|
#if 0
|
|
#if defined(DLS)
|
|
#define MSG_VER 111 /* required message file version No. */
|
|
#else
|
|
#define MSG_VER msg_ver111 /* required message file version No. */
|
|
extern char *MSG_VER;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#include <setjmp.h>
|
|
#include <string.h>
|
|
|
|
#if defined(MWC) && defined(strlen)
|
|
#undef strcmp /* These are defined as macros in string.h */
|
|
#undef strcpy /* which are expaneded in line under */
|
|
#undef strlen /* Metaware C. These undefs avoid this. */
|
|
#endif
|
|
|
|
#include <portab.h>
|
|
#include <mserror.h>
|
|
#if !defined(DOSPLUS)
|
|
#include <ccpm.h>
|
|
#include <sysdat.h>
|
|
#endif
|
|
|
|
#include "command.h" /* Command Definitions */
|
|
#include "support.h" /* Support routines */
|
|
#include "dos.h" /* MSDOS function definitions */
|
|
#include "dosif.h" /* DOS interface definitions */
|
|
#include "toupper.h"
|
|
#include "global.h" /* Global Variables */
|
|
|
|
/* RG-00- */
|
|
#define PATH_LEN 65 /* max path length (null terminated) */
|
|
#if !defined(NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
|
|
#include <pd.h>
|
|
#include "security.h"
|
|
#include "login.h"
|
|
#endif
|
|
/* RG-00- end */
|
|
|
|
MLOCAL BYTE valid_sepchar[] = ":.;,=+";
|
|
|
|
|
|
#if defined(DOSPLUS) /* we now define initial */
|
|
MLOCAL BYTE PATH_DIR[] = "A:\\OPENDOS";
|
|
MLOCAL BYTE SET_PATH[] = "PATH=%s";
|
|
MLOCAL BYTE SET_PROMPT[] = "PROMPT=$P$G";
|
|
MLOCAL BYTE SET_OS[] = "OS=OPENDOS"; /* environment in COMMAND */
|
|
MLOCAL BYTE SET_VER[] = "VER=7"; /* not in BIOSINIT */
|
|
#if !defined(FINAL)
|
|
MLOCAL BYTE SET_BETA[] = "BETA=Beta 4";
|
|
#endif
|
|
#endif
|
|
|
|
GLOBAL jmp_buf break_env;
|
|
|
|
#if defined(DOSPLUS)
|
|
EXTERN UWORD _psp;
|
|
EXTERN VOID *batchptr_off;
|
|
EXTERN VOID *batchflg_off;
|
|
EXTERN VOID *echoflg_off;
|
|
EXTERN UWORD FAR *batch_seg_ptr;
|
|
#endif
|
|
|
|
/*RG-03*/
|
|
EXTERN BOOLEAN if_context; /* BATCH.C */
|
|
/*RG-03-end*/
|
|
|
|
|
|
#if defined(DOSPLUS)
|
|
EXTERN VOID CDECL show_help(WORD); /* CSTART.ASM */
|
|
EXTERN VOID CDECL put_resident_high(WORD); /* CSTART.ASM */
|
|
EXTERN BYTE FAR * CDECL get_config_env(VOID); /* CTSART.ASM */
|
|
EXTERN UWORD CDECL get_original_envsize(VOID);
|
|
EXTERN VOID CDECL copy_crit_msgs(VOID); /* CSUP.ASM */
|
|
EXTERN VOID CDECL copy_rld_msgs(VOID); /* CSUP.ASM */
|
|
EXTERN WORD CDECL dos_parse_filename(BYTE *);
|
|
EXTERN UWORD CDECL docmd_int2f(BYTE *, BYTE *, UWORD);
|
|
#endif
|
|
EXTERN void CDECL flush_cache(void);
|
|
|
|
EXTERN BYTE *kbdptr;
|
|
EXTERN BYTE msg_patheq[]; /* Static Environ String "PATH=" */
|
|
EXTERN S_CMD cmd_list[]; /* CMDLIST.C */
|
|
|
|
#if defined(DOSPLUS)
|
|
EXTERN VOID inherit_parent_state();
|
|
#endif
|
|
|
|
EXTERN WORD echoflg_save2;
|
|
EXTERN VOID batch_start(BYTE *, BYTE *, BYTE *);
|
|
EXTERN VOID batch_end(VOID); /* BATCH.C */
|
|
EXTERN VOID batch_endall(VOID); /* BATCH.C */
|
|
EXTERN VOID batch_close(VOID); /* BATCH.C */
|
|
EXTERN VOID for_end(VOID); /* BATCH.C */
|
|
EXTERN BOOLEAN getcmd(BYTE *); /* BATCH.C */
|
|
#if !defined(CDOSTMP)
|
|
EXTERN VOID int2e_start(); /* BATCH.C */
|
|
EXTERN VOID int2e_finish(); /* BATCH.C */
|
|
#endif
|
|
|
|
EXTERN VOID CDECL cmd_cd(BYTE *); /* COMINT.C */
|
|
EXTERN VOID CDECL cmd_ver(); /* COMINT.C */
|
|
EXTERN VOID CDECL cmd_set(BYTE *); /* COMINT.C */
|
|
|
|
GLOBAL VOID docmd(BYTE *, BOOLEAN); /* COM.C */
|
|
MLOCAL VOID cmd_loop (BYTE *); /* COM.C */
|
|
MLOCAL VOID error_code(UWORD); /* COM.C */
|
|
|
|
MLOCAL VOID cmd_cleantp(VOID); /* COM.C */
|
|
GLOBAL BOOLEAN parse(BYTE *); /* COM.C */
|
|
MLOCAL VOID init(BYTE *); /* COM.C */
|
|
MLOCAL BOOLEAN doexec(BYTE *, BYTE *, UWORD, BYTE *);
|
|
|
|
#if !defined(CDOSTMP)
|
|
MLOCAL BYTE msg_comspec[] = "COMSPEC=";
|
|
/*EXTERN BYTE *reload_file; CSTART.ASM */
|
|
|
|
EXTERN VOID CDECL get_reload_file(VOID); /* CSUP.ASM */
|
|
EXTERN VOID CDECL set_reload_file(VOID); /* CSUP.ASM */
|
|
EXTERN VOID CDECL get_out_pipe(VOID); /* CSUP.ASM */
|
|
|
|
EXTERN VOID CDECL install_perm(VOID); /* CSTART.ASM */
|
|
EXTERN VOID CDECL master_env(UWORD); /* CSTART.ASM */
|
|
GLOBAL WORD CDECL findfile(BYTE *, UWORD *); /* COM.C for MS-DOS */
|
|
MLOCAL WORD checkfile(BYTE *, UWORD *, BYTE *, BYTE *, BYTE *, BYTE *);
|
|
EXTERN BYTE cbreak_ok; /* control break handler initialised */
|
|
#else
|
|
EXTERN WORD CDECL findfile(BYTE *, UWORD *); /* DOSIF.A86 (P_PATH) */
|
|
EXTERN VOID network_init(VOID); /* NETWORK.C */
|
|
EXTERN PD FAR * CDECL pd; /* Far pointer to Current PD */
|
|
MLOCAL BOOLEAN system_init = TRUE;
|
|
#endif
|
|
EXTERN BYTE FAR * CDECL farptr(BYTE *);
|
|
EXTERN BYTE FAR * CDECL cgroupptr(BYTE *);
|
|
|
|
#if defined(CPM)
|
|
EXTERN UWORD CDECL cpm_init(VOID); /* CP/M Init Routine */
|
|
#endif
|
|
|
|
#if !defined(NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
|
|
/* global VC data */
|
|
UWORD vc_base; /* first vc number for this station */
|
|
UWORD num_of_vcs; /* number of vcs on this station */
|
|
#endif
|
|
|
|
#if !defined(CDOSTMP)
|
|
BYTE autoexec_name[13] = "autoexec.bat";
|
|
#endif
|
|
|
|
#if defined(DOSPLUS)
|
|
UWORD boot_key_scan_code = 0;
|
|
#endif
|
|
|
|
#if !defined(FINAL)
|
|
void save_psp(void);
|
|
void check_psp(void);
|
|
WORD psp_xsum;
|
|
#endif
|
|
|
|
VOID FAR CDECL _main(cmd)
|
|
BYTE *cmd;
|
|
{
|
|
BYTE cmd_buf[128];
|
|
|
|
#if defined(CDOSTMP) /* Insure the NETWORK_INIT */
|
|
network_init(); /* function is called before */
|
|
#endif /* any disk activity so that */
|
|
/* Diskless DRNET systems can*/
|
|
/* be generated. */
|
|
|
|
#if !defined(NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
|
|
/* get the VC data and make global */
|
|
vc_data(&vc_base, &num_of_vcs, &station);
|
|
#endif
|
|
|
|
#if defined(DOSPLUS) && defined(DLS)
|
|
copy_crit_msgs();
|
|
copy_rld_msgs();
|
|
#endif
|
|
|
|
init(cmd); /* Initialize COMMAND.??? */
|
|
|
|
#if defined(CPM)
|
|
if(cpm_init()) { /* If this is the CP/M Media */
|
|
eprintf(MSG_SINGLECPM); /* Access program then call */
|
|
ms_x_exit(1); /* the CPM_INIT function */
|
|
}
|
|
#endif
|
|
|
|
ms_drv_set(drive); /* try to set default drive */
|
|
|
|
FOREVER {
|
|
|
|
error_code(setjmp(break_env)); /* Initialize Error Handler */
|
|
#if !defined(CDOSTMP)
|
|
cbreak_ok = TRUE; /* we can handle break now */
|
|
#endif
|
|
#if !defined(NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
|
|
#if defined(CDOSTMP)
|
|
|
|
ms_drv_set(drive); /* try to set default drive */
|
|
|
|
/* Ensure we are the foreground process on the Virtual Console */
|
|
/* before displaying login prompt. */
|
|
if(login_enabled()) {
|
|
disable_vc_switch(); /* stop user switching to another console */
|
|
|
|
/* if 1st time through on VC 0 then run system autoexec */
|
|
if (system_init) {
|
|
login_save_initial_state();
|
|
if (pd->P_CNS==0) {
|
|
/* log this event */
|
|
logevent("",LOG_POWERON);
|
|
/* process system Autoexec.bat */
|
|
while (*kbdptr || batchflg)
|
|
cmd_loop (cmd_buf);
|
|
}
|
|
system_init = FALSE;
|
|
}
|
|
if(waiting_on_login() && !background_proc())
|
|
login_station(); /* login station */
|
|
login_consoles(); /* initialise all VCs */
|
|
enable_vc_switch();
|
|
}
|
|
#endif
|
|
FOREVER {
|
|
error_code(setjmp(break_env)); /* Initialize Error Handler */
|
|
|
|
if (login_enabled()) {
|
|
if(!logged_in()) /* keep going until logged out */
|
|
break;
|
|
}
|
|
#endif
|
|
cmd_loop (cmd_buf);
|
|
|
|
#if !defined(NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
|
|
}
|
|
if(login_enabled()) {
|
|
/* kill off any remaining batch processes still running */
|
|
while (batchflg)
|
|
cmd_exit("");
|
|
#if defined(CDOSTMP)
|
|
/* the logout event */
|
|
if(!background_proc())
|
|
logout();
|
|
#else
|
|
return; /* CDOS.COM just dies when logout happens */
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*MLOCAL*/ VOID cmd_loop (cmd)
|
|
BYTE *cmd;
|
|
{
|
|
WORD echoing;
|
|
REG BYTE *cmdline;
|
|
BYTE first_ch;
|
|
|
|
cmd_cleanup(); /* Cleanup after the command */
|
|
cmdline = cmd;
|
|
|
|
if (!batchflg) flush_cache();
|
|
echoing = getcmd(cmdline); /* do not echo Labels */
|
|
|
|
first_ch = *deblank(cmdline);
|
|
|
|
if((pipe_out && !batchflg && !*deblank(kbdptr)) ||
|
|
/* if "|<nul command>" */
|
|
(pipe_in && (first_ch == 0 || first_ch == ':'))) {
|
|
/* or "<null command>|" */
|
|
eprintf(MSG_SYNTAX); /* report syntax error */
|
|
pipe_out = NO; /* forget about pipes */
|
|
pipe_in = NO;
|
|
if (!batchflg)
|
|
*kbdptr = '\0'; /* discard rest of line */
|
|
crlfflg = YES; /* remember to do a LF */
|
|
return; /* stop now before echo */
|
|
}
|
|
|
|
if(echoing && first_ch != ':') {
|
|
/* Echo command line if ECHO */
|
|
puts(cmdline); /* ON and source not keyboard*/
|
|
crlf(); /* and not a label */
|
|
}
|
|
|
|
crlfflg = NO; /* NO CR/LF req'd */
|
|
cmdline = deblank(cmdline); /* remove leading spaces */
|
|
|
|
if(*cmdline && *cmdline != ':') /* Check for a command */
|
|
{ /* not a LABEL */
|
|
|
|
if (!strnicmp(cmdline,"IF",2)) docmd(cmdline,YES);
|
|
else {
|
|
if(!parse(cmdline)) { /* If the Parse succeeds then*/
|
|
docmd(cmdline, YES); /* execute the command. */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*.pa*/
|
|
/*
|
|
*
|
|
*/
|
|
#define COMMAND_P (cflag & 1) /* Permanent Flag */
|
|
#define COMMAND_C (cflag & 2) /* One Command Option */
|
|
#define COMMAND_T (cflag & 4) /* CDOS TSR option */
|
|
|
|
|
|
MLOCAL VOID init(cmd)
|
|
BYTE *cmd;
|
|
{
|
|
UBYTE console = 1; /* Concurrent Console No. +1 */
|
|
SYSDATE date; /* System Date Structure */
|
|
WORD ret; /* General Variable */
|
|
UWORD cflag;
|
|
BYTE *s;
|
|
#if defined(CDOSTMP)
|
|
UWORD vc_base, vc_num, pc_num; /* Virtual Console Data */
|
|
#else
|
|
BYTE buf[MAX_ENVLEN], c;
|
|
UWORD envsize = 256;
|
|
#endif
|
|
#if defined(DOSPLUS)
|
|
BOOLEAN no_timedate = FALSE;
|
|
WORD prh_function = 0;
|
|
UWORD FAR *p_batch_seg;
|
|
#endif
|
|
BYTE lferror = 0;
|
|
strcpy(kbdptr, ""); /* start with no commands */
|
|
|
|
#if 0
|
|
#if defined(DLS)
|
|
dls_msg_ver(MSG_VER); /* check message file version*/
|
|
#else
|
|
s = MSG_VER; /* ensure label is referenced */
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(CDOS)
|
|
ret = ioctl_ver();
|
|
if(ret < 0x1450 || ret > 0x1499) { /* Get the CDOS BDOS Version */
|
|
eprintf(MSG_BADOS); /* and quit if it is not 5.0 */
|
|
ms_x_exit(-1); /* or Above */
|
|
}
|
|
#endif
|
|
|
|
#if defined(DOSPLUS)
|
|
|
|
batchptr_off = (VOID *) &batch;
|
|
batchflg_off = (VOID *) &batchflg;
|
|
echoflg_off = (VOID *) &echoflg;
|
|
|
|
envsize = get_original_envsize(); /* BAP - sets envsize to */
|
|
/* same as original COMMAND */
|
|
if ((envsize < 128) || (envsize > 32752)) envsize = 256; /* shouldn't really need this */
|
|
|
|
parent_psp = MK_FP(_psp, 0x16); /* our parental PSP is here */
|
|
ret = ioctl_ver(); /* Get the BDOS Version No. */
|
|
|
|
if(ret < 0x1071) { /* Abort if this is not DOS */
|
|
eprintf(MSG_BADOS); /* PLUS with a BDOS version */
|
|
if ((*parent_psp) && (*parent_psp != _psp))
|
|
ms_x_exit(-1); /* abort unless root process */
|
|
while(1){};
|
|
}
|
|
|
|
#if 0
|
|
#if defined(DLS)
|
|
dls_msg_crit(); /* init crit error messages */
|
|
#endif
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if defined(CDOSTMP)
|
|
console = (UBYTE) bdos(C_GET, 0) + 1; /* CDOS Console No. + 1 */
|
|
execed = NO; /* COMMAND.RSP not EXECED */
|
|
err_ret = 0; /* Initial Error Code 0000 */
|
|
|
|
#else
|
|
execed = YES; /* Assume we have been loaded*/
|
|
/* from the command line */
|
|
break_flag = ms_set_break(NO); /* Get the Current Break Flag*/
|
|
err_ret = ms_x_wait(); /* Get the completion code */
|
|
/* for process's that cause */
|
|
/* COMMAND.COM to be reloaded*/
|
|
|
|
init_switchar(); /* initialise switchar and */
|
|
/* pathchar */
|
|
#endif
|
|
|
|
drive = ms_drv_get(); /* get default drive. */
|
|
country.code = ms_s_country(&country); /* Initialise the Country data*/
|
|
in_handle = psp_poke(STDIN, 0xFF); /* Get the standard input */
|
|
psp_poke(STDIN, in_handle); /* and save internally */
|
|
|
|
out_handle = psp_poke(STDOUT, 0xFF); /* Get the standard Output */
|
|
psp_poke(STDOUT, out_handle); /* and save internally */
|
|
|
|
for(ret=5;ret<20;ms_x_close(ret++)); /* close handles 5-20 */
|
|
|
|
if(initflg) /* is this a warm boot? */
|
|
return; /* Yes then QUIT */
|
|
|
|
initflg = YES; /* there's only one 1st time */
|
|
cflag = 0; /* Clear the switch variable */
|
|
|
|
#if !defined(CDOSTMP)
|
|
/*
|
|
*
|
|
* COMMAND.COM
|
|
* The following command line formats must be supported for
|
|
* applications that exec the command processor.
|
|
*
|
|
* COMMAND /CCOPY filex filey FrameWork Install
|
|
* COMMAND /C DIR *.* /P Procomm directory option
|
|
* COMMAND /C=DIR *.*
|
|
*
|
|
* These varients prevent support for multiple options and
|
|
* force the option scanning to be halted at the first command
|
|
*
|
|
* COMMAND /T - TSR support for CDOS
|
|
*
|
|
* We are auto-invoking COMMAND after detecting a TSR, so
|
|
* try and inherit any open batch files.
|
|
*
|
|
*/
|
|
|
|
s = (BYTE *) heap_get(128); /* allocate some heap memory */
|
|
|
|
FOREVER {
|
|
cmd = deblank(cmd); /* Deblank the command line */
|
|
if((*cmd == '\0') || (*cmd == *switchar))
|
|
break; /* stop at option or end */
|
|
|
|
cmd = get_filename(s, cmd, NO);
|
|
|
|
if(strlen(s)) { /* look for Loadpath/STDIO */
|
|
if((ret = ms_x_open(s, OPEN_RW)) >= 0) {
|
|
if(isdev(ret)) {
|
|
strcat(kbdptr,"ctty "); /* if its a R/W device put */
|
|
strcat(kbdptr, s); /* CTTY <dev> into buffer */
|
|
strcat(kbdptr,"!");
|
|
}
|
|
else /* otherwise its an error */
|
|
eprintf(MSG_LOADPATH); /* an invalid loadpath */
|
|
ms_x_close(ret); /* Close the handle */
|
|
}
|
|
else {
|
|
append_slash(s); /* user specified loadpath */
|
|
get_reload_file(); /* get reload_file on heap */
|
|
strcat(s, fptr(heap()));
|
|
if(file_exist(s)) { /* append existing load file */
|
|
ms_x_expand(heap(), s);
|
|
set_reload_file(); /* copy heap to reload_file */
|
|
}
|
|
else { /* Print an error message if */
|
|
eprintf(MSG_LOADPATH); /* an invalid path used. */
|
|
lferror = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
eprintf(MSG_LOADPATH);
|
|
break;
|
|
}
|
|
}
|
|
|
|
heap_set(s); /* free up heap memory */
|
|
|
|
c_option = FALSE;
|
|
k_option = FALSE;
|
|
FOREVER {
|
|
cmd = deblank(cmd); /* Deblank the command line */
|
|
if(*cmd != *switchar) /* Stop the option check if */
|
|
break; /* the next character is not */
|
|
cmd++; /* a switch character. */
|
|
c = toupper(*cmd++);
|
|
switch(c) {
|
|
/*RG-05-*/
|
|
#if (defined(CDOS)||defined(DOSPLUS)) && !defined(NOHELP)
|
|
case 'H': /* Support /H Help Option */
|
|
case '?': /* Support /? Help Option */
|
|
cflag |= 2;
|
|
cmd_ver();
|
|
crlf();
|
|
printf(HELP_COM);
|
|
ms_x_exit(0);
|
|
break;
|
|
#endif
|
|
/*RG-05-end*/
|
|
case 'C': /* Support /C Option */
|
|
echoflg = ECHO_OFF; /* Don't issue CR LF */
|
|
c_option = TRUE;
|
|
case 'K':
|
|
k_option = TRUE;
|
|
cmd = deblank(cmd);
|
|
if (*cmd == '=') {
|
|
cmd++; /* Skip optional '=' */
|
|
cmd = deblank(cmd);
|
|
}
|
|
|
|
cflag |= 2;
|
|
break;
|
|
|
|
case 'N':
|
|
n_option = TRUE;
|
|
break;
|
|
|
|
case 'P': /* Support /P Option */
|
|
cflag |= 1;
|
|
if (*cmd == ':') { /* See if a different fname */
|
|
cmd++; /* has been specified for */
|
|
ret = 0; /* AUTOEXEC.BAT. */
|
|
while ((*cmd > 32) && (ret < 12))
|
|
autoexec_name[ret++] = *cmd++;
|
|
autoexec_name[ret] = 0;
|
|
while (*cmd > 32) cmd++;
|
|
}
|
|
break;
|
|
|
|
case 'E': /* Environment Option */
|
|
if(*cmd != ':') /* Check for /E:nnn */
|
|
break;
|
|
cmd++;
|
|
if(getdigit(&ret, &cmd) && ret > 128 && ret < 32752)
|
|
envsize = ret;
|
|
break;
|
|
|
|
#if defined(CDOS)
|
|
case 'T': /* TSR support */
|
|
cflag |= 5;
|
|
inherit_TMP_state(); /* inherit batch files etc */
|
|
break;
|
|
#endif
|
|
|
|
#if defined(DOSPLUS)
|
|
case 'T':
|
|
inherit_parent_state();
|
|
break;
|
|
#endif
|
|
|
|
|
|
#if defined(DOSPLUS)
|
|
case 'M': /* relocate resident portion */
|
|
c = toupper(*cmd++);
|
|
if (c == 'H') prh_function = 1;
|
|
if (c == 'U') prh_function = 2;
|
|
if (c == 'L') prh_function = -1;
|
|
break;
|
|
|
|
case 'D':
|
|
no_timedate = TRUE;
|
|
break;
|
|
#endif
|
|
|
|
case '\0': /* Treat the NULL character */
|
|
cmd--; /* specially in case some of*/
|
|
break; /* the following command "/"*/
|
|
|
|
default: /* Skip invalid options. */
|
|
break;
|
|
}
|
|
}
|
|
#if defined(DOSPLUS)
|
|
/* We cannot allow COMMAND to go into upper memory unless "/P" has also */
|
|
/* been given. If we do the memory won't be freed up on exit */
|
|
|
|
switch(prh_function) {
|
|
case 0: /* try high, upper, then low */
|
|
if(COMMAND_P)
|
|
put_resident_high(0);
|
|
else
|
|
put_resident_high(1);
|
|
break;
|
|
case 1: /* try high, then low */
|
|
put_resident_high(1);
|
|
break;
|
|
case 2: /* try upper, then low */
|
|
if(COMMAND_P)
|
|
put_resident_high(2);
|
|
break;
|
|
default:/* try low */
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
master_env(envsize); /* Allocate the master */
|
|
/* environment of ENVSIZE */
|
|
/* bytes in length */
|
|
#if 0
|
|
/*
|
|
* If no COMSPEC has been defined or it is different from
|
|
* the RELOAD_FILE specification then update COMSPEC.
|
|
*/
|
|
if(env_scan(msg_comspec, heap()) || stricmp(heap(), reload_file)) {
|
|
sprintf(buf, "%s%s", msg_comspec, reload_file);
|
|
cmd_set(buf);
|
|
}
|
|
#else
|
|
/* BAP changed this */
|
|
get_reload_file();
|
|
if(env_scan(msg_comspec,heap())) {
|
|
sprintf(buf,"%s%s",msg_comspec,heap());
|
|
cmd_set(buf);
|
|
}
|
|
#endif
|
|
|
|
#if defined(DOSPLUS)
|
|
save_parent = *parent_psp;
|
|
*parent_psp = _psp; /* Always do this */
|
|
|
|
if(COMMAND_P) { /* Action the /P flag for */
|
|
execed = NO; /* DOSPLUS.COM */
|
|
|
|
PATH_DIR[0] = drive + 'A'; /* if DRDOS directory exists */
|
|
ret = ms_x_chmod(PATH_DIR, ATTR_ALL, 0);
|
|
if ((ret > 0) && (ret & 0x10)) {/* point the path at it */
|
|
sprintf(buf, SET_PATH, PATH_DIR);
|
|
cmd_set(buf);
|
|
}
|
|
cmd_set(SET_PROMPT);
|
|
cmd_set(SET_OS);
|
|
cmd_set(SET_VER);
|
|
#if !defined(FINAL)
|
|
cmd_set(SET_BETA);
|
|
#endif
|
|
install_perm(); /* Install Backdoor entry */
|
|
}
|
|
|
|
/* process the environment created by config.sys */
|
|
process_config_env();
|
|
#endif
|
|
|
|
#endif
|
|
|
|
FOREVER {
|
|
if(execed) { /* If this is a transient */
|
|
if (!lferror)
|
|
strcat(kbdptr, cmd); /* command processor then */
|
|
ret = FALSE; /* get the command line and*/
|
|
break; /* ignore AUTOEXEC.BAT. */
|
|
}
|
|
|
|
/* Check for the presence of STARTnnn.BAT in the root */
|
|
/* of the boot disk if not found check for AUTOEXEC */
|
|
/* if neither are present then if this is console 0 */
|
|
/* and this is < 1987 ask for the date. */
|
|
|
|
#if defined(CDOSTMP)
|
|
vc_data(&vc_base, &vc_num, &pc_num); /* Get VC Data */
|
|
vc_num = console - vc_base; /* Relative VC Num */
|
|
sprintf(heap(), "!start%02d%1d.bat", pc_num, vc_num);
|
|
if((ret = file_exist(heap()+1)) == 0) {
|
|
strcpy(heap(), "!autoexec.bat");
|
|
ret = file_exist(heap()+1);
|
|
}
|
|
|
|
if(ret != 0) {
|
|
strcat(kbdptr, heap());
|
|
sprintf(heap(), " %d %d %d", console, pc_num, vc_num);
|
|
strcat(kbdptr, heap());
|
|
break;
|
|
}
|
|
|
|
#else
|
|
strcpy(heap(), "!");
|
|
strcat(heap(), autoexec_name);
|
|
if((ret = file_exist(heap()+1)) != 0) {
|
|
if (boot_key_scan_code != 0x3f00 /*F5*/)
|
|
strcat(kbdptr,heap());
|
|
break;
|
|
} else {
|
|
boot_key_scan_code = 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(DOSPLUS)
|
|
if (!no_timedate && *autoexec_name!=0)
|
|
strcat(kbdptr, "!date!time");
|
|
#else
|
|
ms_getdate(&date);
|
|
if(console == 1 && date.year < 1987)
|
|
strcat(kbdptr, "!date!time");
|
|
#endif
|
|
break;
|
|
}
|
|
#if defined(CDOS) && !defined(CPM)
|
|
if(COMMAND_P) /* Action the /P flag for */
|
|
execed = NO; /* CDOS.COM to disable EXIT */
|
|
#endif
|
|
|
|
#if 0
|
|
if(COMMAND_C) { /* Append EXIT if COMMAND.COM*/
|
|
strcat(kbdptr, "!exit 0"); /* is just used to execute a */
|
|
} /* a command. */
|
|
#endif
|
|
|
|
#if !defined(CDOSTMP)
|
|
#if 0
|
|
else {
|
|
#else
|
|
if(!COMMAND_C) {
|
|
#endif
|
|
#if defined(DOSPLUS)
|
|
if (*autoexec_name != 0) {
|
|
cmd_ver(); /* display the signon */
|
|
|
|
printf(MSG_OEMCPYRT);
|
|
crlf();
|
|
}
|
|
#else
|
|
if(!COMMAND_T) { /* if it's CDOS TSR support */
|
|
cmd_ver(); /* don't display signon */
|
|
crlf();
|
|
}
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* The following function is called to clean up COMMAND.COM after
|
|
* an internal or external command has been executed. The major areas
|
|
* to be handled by this function are:-
|
|
*
|
|
* 1) Control-C termination for Batch file termination
|
|
* 2) I/O Redirection
|
|
* 3) Hiloading off
|
|
*/
|
|
MLOCAL VOID cmd_cleanup()
|
|
{
|
|
BYTE cmdbuf[128];
|
|
#if 0
|
|
hiload_set(NO); /* HILOADing off now */
|
|
#endif
|
|
|
|
if(err_ret == BREAK_EXIT || /* Check for Control-C */
|
|
err_ret == ERROR_EXIT) { /* or Critical Error Exit */
|
|
|
|
if(pipe_out) { /* If a Pipe'ed command is */
|
|
pipe_out = NO; /* is aborted then absorb */
|
|
getcmd(cmdbuf); /* the second command. */
|
|
crlf();
|
|
}
|
|
|
|
if(batchflg) {
|
|
eprintf(MSG_BATTERM); /* Processing a BATCH file */
|
|
err_flag = TRUE; /* ask if the uses wishes to */
|
|
if(yes(NO, YES)) /* to abort this batch job */
|
|
batch_endall(); /* Close ALL batch files */
|
|
err_flag = FALSE;
|
|
}
|
|
else if(for_flag) /* If processing a FOR */
|
|
for_end(); /* command outside a batch */
|
|
} /* file then abort it. */
|
|
|
|
err_ret &= 0x00FF; /* Mask the Termination */
|
|
/* condition this should only*/
|
|
/* be tested once. */
|
|
|
|
/*
|
|
* After the termination of a Batch file or a Program then
|
|
* the relevant redirection is removed. If the redirection
|
|
* was instigated because of the PIPE facility then the
|
|
* correct clean up code is executed.
|
|
*/
|
|
|
|
while(in_flag & REDIR_ACTIVE) { /* Is Redirection Active */
|
|
if((in_flag & REDIR_BATCH) && batchflg)
|
|
break;
|
|
|
|
if((in_flag & REDIR_FOR) && for_flag)
|
|
break;
|
|
|
|
ms_x_close(STDIN); /* Close the Redirected File */
|
|
psp_poke(STDIN, in_handle); /* Restore original Handle */
|
|
|
|
if(pipe_in) {
|
|
pipe_in = NO;
|
|
ms_x_unlink(old_pipe);
|
|
heap_set(old_pipe);
|
|
}
|
|
|
|
in_flag = NULL;
|
|
}
|
|
|
|
while(out_flag & REDIR_ACTIVE) { /* Is Redirection Active */
|
|
if((out_flag & REDIR_BATCH) && batchflg)
|
|
break;
|
|
|
|
if((out_flag & REDIR_FOR) && for_flag)
|
|
break;
|
|
|
|
ms_x_close(STDOUT); /* Close the Redirected File */
|
|
psp_poke(STDOUT, out_handle); /* Restore original Handle */
|
|
|
|
if(pipe_out) {
|
|
pipe_in = YES; pipe_out = NO;
|
|
old_pipe = heap_get(strlen(out_pipe)+1);
|
|
strcpy(old_pipe,out_pipe);
|
|
}
|
|
|
|
out_flag = NULL;
|
|
}
|
|
|
|
country.code = ms_s_country(&country); /* re-init the Country data */
|
|
#if 0
|
|
#if defined(DLS)
|
|
dls_msg_crit(); /* re-init crit error msgs */
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
/*.pa*/
|
|
/*
|
|
* ERROR_INIT is the "CRITICAL" error handler which will initialize
|
|
* the error handling code, displays error messages and clean-up the
|
|
* environment after an error has occurred.
|
|
*/
|
|
/*RG-00*/
|
|
/*MLOCAL VOID error_code(error)*/
|
|
VOID error_code(error)
|
|
/*RG-00-end*/
|
|
UWORD error;
|
|
{
|
|
switch(error) {
|
|
case 0: /* Setting JMPBUF. Enable */
|
|
#if !defined(CDOSTMP) /* break checking in case */
|
|
ms_set_break(YES); /* this is the first time */
|
|
#endif /* through the command proc. */
|
|
return;
|
|
|
|
case IA_BREAK:
|
|
putc('\r'); /* A CR here makes SideKick+ */
|
|
/* look good when it */
|
|
/* deinstalls itself */
|
|
/* The following two function calls close the batch file during an INT 23
|
|
thus disallowing to continue with a batch file if the user chooses to
|
|
do so after being prompted. However, there migh have been a reason why
|
|
this has been inserted before which I don't know of. JBM */
|
|
/* ms_x_close(5); ##jc## Close Unused Handles*/
|
|
/* ms_x_close(6); ##jc## Close Unused Handles*/
|
|
mem_free(&bufaddr); /* Free External Copy Buffer */
|
|
#if defined(CDOSTMP) /* On Concurrent DOS and */
|
|
bdos(DRV_RESET, 0xFFFF); /* DOSPLUS reset the disk */
|
|
crlf(); /* when we get a Control-C. */
|
|
#endif
|
|
break;
|
|
|
|
case IA_STACK: /* Stack Overflow Error */
|
|
case IA_HEAP: /* Heap Overflow Error */
|
|
batch_endall(); /* Out of memory error */
|
|
eprintf(MSG_BATNEST); /* probably caused by nesting*/
|
|
break; /* batch files TOO deep. */
|
|
|
|
case IA_FILENAME: /* FileName Error */
|
|
eprintf(ERR_FILE); /* display an error message */
|
|
break; /* and terminate the command */
|
|
|
|
default:
|
|
eprintf(MSG_LONGJMP, error);
|
|
break;
|
|
}
|
|
|
|
crlfflg = NO; /* Reset CR/LF Flag */
|
|
}
|
|
|
|
/*
|
|
* This function is invoked after a CONTROL-BREAK or Critical Error
|
|
* during the execution of an internal function. Any BREAK specific
|
|
* cleanup is executed here. The break handler then restarts normal
|
|
* code execution by executing a LONGJMP.
|
|
*/
|
|
GLOBAL VOID CDECL int_break()
|
|
{
|
|
int i;
|
|
|
|
if (show_file_buf) mem_free(&show_file_buf);
|
|
|
|
if (global_in_hiload) {
|
|
/* if ctrl-c pressed during a hiload, restore memory */
|
|
/* allocation strategy. */
|
|
|
|
for(i=1;i<10;i++) { /* free up any UMB's we have */
|
|
if (hidden_umb[i]) {
|
|
free_region(hidden_umb[i]);
|
|
hidden_umb[i] = 0;
|
|
}
|
|
}
|
|
set_upper_memory_link(global_link);
|
|
set_alloc_strategy(global_strat);
|
|
global_in_hiload = 0;
|
|
}
|
|
|
|
err_ret = BREAK_EXIT; /* Update the Global Error Return */
|
|
longjmp(break_env, IA_BREAK); /* Either Control-C or Critical */
|
|
/* Error Process Termination. */
|
|
}
|
|
|
|
/*.pa*/
|
|
/*
|
|
* This function parses the command line and extracts all unquoted
|
|
* >>, > and < character sequences and their corresponding filenames.
|
|
* The last redirection specification of the same type is used all
|
|
* previous references will be removed. Redirection will only be
|
|
* enabled if no redirection of the same type is already active.
|
|
* ie. If redirection is enabled on a batch file all redirection
|
|
* commands of the same type inside the file are ignored.
|
|
*/
|
|
GLOBAL BOOLEAN parse(s) /* Parse the command line looking */
|
|
BYTE *s; /* for Redirection commands */
|
|
{
|
|
REG BYTE *bps;
|
|
BYTE *bpi, *bpo;
|
|
BYTE infile[MAX_FILELEN]; /* Input Redirection FileName */
|
|
BYTE outfile[MAX_FILELEN]; /* Output Redirection FileName */
|
|
BYTE cmdbuf[128]; /* Command buffer for Aborted Pipe */
|
|
WORD h;
|
|
BOOLEAN quote = NO; /* Check for Quoted Statements */
|
|
BOOLEAN append; /* Out Redirection Append */
|
|
|
|
crlfflg = YES; /* Force a CRLF in case an error */
|
|
/* occurs in the command line parsing*/
|
|
|
|
for(bpi = NULL, bpo = NULL; *s; s++) {
|
|
|
|
if(*s == '"') { /* Maintain the correct */
|
|
quote = !quote; /* Status of the QUOTE flag*/
|
|
continue;
|
|
}
|
|
|
|
if(quote) /* If the QUOTE flag is */
|
|
continue; /* then skip the following */
|
|
|
|
if(*s == '>') { /* Found Output redirection */
|
|
bpo = outfile; /* Character extract the Path*/
|
|
bps = s+1; append = FALSE; /* and save locally */
|
|
|
|
if(*(bps) == '>') { /* Check for append mode */
|
|
append = TRUE;
|
|
bps++;
|
|
}
|
|
|
|
bps = get_filename(bpo, deblank(bps), NO);
|
|
/* Extract the FileName */
|
|
bps = deblank(bps);
|
|
strcpy(s--, bps); /* Then remove data from Line*/
|
|
continue; /* S decrement to force new */
|
|
} /* next character to be read */
|
|
|
|
if(*s == '<') { /* Found Input redirection */
|
|
bpi = infile; /* Character extract the Path*/
|
|
bps = get_filename(bpi, deblank(s+1), NO);
|
|
/* Extract the FileName */
|
|
bps = deblank(bps);
|
|
strcpy(s--, bps); /* Then remove data from Line*/
|
|
} /* S decrement to force new */
|
|
} /* next character to be read */
|
|
|
|
|
|
#if defined(DOSPLUS)
|
|
/* only redirect if not already redirected */
|
|
if ((pipe_in || bpi) && (!(in_flag & REDIR_ACTIVE))) {
|
|
#else
|
|
if(pipe_in || bpi) { /* Check for any redirection */
|
|
if(in_flag & REDIR_ACTIVE) { /* If Standard Input has been*/
|
|
eprintf(MSG_INACTIVE); /* redirected then fail */
|
|
return FAILURE;
|
|
}
|
|
#endif
|
|
|
|
bpi = pipe_in ? out_pipe : infile; /* BPI points to the filename*/
|
|
|
|
h = ms_x_open(bpi, OPEN_READ);
|
|
if(h < 0) {
|
|
/* Attempt to Open the file */
|
|
e_check(h); /* || device specified and */
|
|
return FAILURE; /* print an error message if */
|
|
} /* we fail. */
|
|
|
|
psp_poke(STDIN, psp_poke(h, 0xFF)); /* Force New input file onto */
|
|
/* Standard Input and close */
|
|
in_flag = REDIR_ACTIVE; /* the returned handle */
|
|
}
|
|
|
|
#if defined(DOSPLUS)
|
|
/* only redirect if not already redirected */
|
|
if ((pipe_out || bpo) && (!(out_flag & REDIR_ACTIVE))) {
|
|
#else
|
|
if(pipe_out || bpo) { /* Check for any redirection */
|
|
if(out_flag & REDIR_ACTIVE) { /* If Standard Output has been*/
|
|
eprintf(MSG_OUTACTIVE); /* redirected then fail */
|
|
return FAILURE;
|
|
}
|
|
#endif
|
|
|
|
if(pipe_out) {
|
|
#if defined(CDOSTMP)
|
|
out_pipe[0] = *SYSDATB(TEMPDISK)+'A'; /* Initialise the DRIVE */
|
|
out_pipe[3] = '\0'; /* Terminate String */
|
|
#else
|
|
if (!env_scan("TEMP=",out_pipe)) {
|
|
|
|
/* if TEMP != "d:\" check its a valid directory */
|
|
if ((strlen(out_pipe) > 3) || (out_pipe[1] !=':')) {
|
|
|
|
h = ms_x_chmod(out_pipe,ATTR_ALL,0);
|
|
if ((h<0) || !(h&0x10)) goto assume_root;
|
|
}
|
|
append_slash(out_pipe);
|
|
}
|
|
else {
|
|
assume_root:
|
|
get_out_pipe(); /* get string from low_seg */
|
|
out_pipe[0] = drive+'A'; /* Initialise the DRIVE */
|
|
out_pipe[3] = '\0'; /* Terminate String */
|
|
}
|
|
#endif
|
|
bpo = out_pipe;
|
|
h = ms_x_unique(out_pipe, ATTR_SYS);
|
|
|
|
}
|
|
else { /* Create the output file if */
|
|
bpo = outfile; /* not Appending or the OPEN */
|
|
/* on the file fails. */
|
|
if(!append || (h = ms_x_open(bpo, OPEN_WRITE)) < 0)
|
|
h = ms_x_creat(bpo, 0);
|
|
}
|
|
|
|
if(e_check(h) < 0) { /* Display any error message */
|
|
if(pipe_out) { /* Pipe'ed command then */
|
|
pipe_out = NO; /* absorb the second command*/
|
|
getcmd(cmdbuf); /* return FAILURE on error */
|
|
crlfflg = YES;
|
|
}
|
|
return FAILURE;
|
|
}
|
|
|
|
if(append) /* If in APPEND mode then */
|
|
ms_x_lseek(h, 0L, 2); /* seek to the end. */
|
|
|
|
psp_poke(STDOUT, psp_poke(h, 0xFF));/* Force New input file onto */
|
|
/* Standard Ouput and close */
|
|
out_flag = REDIR_ACTIVE; /* the returned handle */
|
|
|
|
if(pipe_out)
|
|
out_flag |= REDIR_PIPE;
|
|
}
|
|
|
|
crlfflg = NO;
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
MLOCAL BOOLEAN docmd_offer(BYTE *cp, BYTE *command, UWORD internal_flag)
|
|
{
|
|
BYTE *lcp;
|
|
int i;
|
|
UWORD int2f_gotit = 0;
|
|
|
|
lcp = heap();
|
|
|
|
lcp[0] = 0x80; /* copy command line to buffer */
|
|
lcp[1] = strlen(cp); /* with "readline" format */
|
|
for (i=0;i<lcp[1];i++)
|
|
lcp[i+2]=cp[i];
|
|
lcp[i+2] = '\r';
|
|
|
|
/* offer command line to interested parties */
|
|
if(int2f_gotit = docmd_int2f(lcp,command,internal_flag))
|
|
return 1; /* if they want it, docmd_offer = TRUE */
|
|
|
|
|
|
for(i=command[0];i<8;command[1+(i++)]=' ');
|
|
/* if length is altered, space fill */
|
|
|
|
for(i=0;i<lcp[1];i++)
|
|
cp[i] = lcp[i+2]; /* copy it back in case it was changed */
|
|
cp[i] = 0; /* null terminate it */
|
|
return 0; /* docmd_offer = FALSE, cos the int2f didn't want it */
|
|
}
|
|
|
|
GLOBAL VOID docmd(cp, internal)
|
|
REG BYTE *cp; /* Command Line To be Parsed */
|
|
BOOLEAN internal; /* Search for INTERNAL Commands */
|
|
{
|
|
REG S_CMD FAR *s_cmd_p;
|
|
WORD i;
|
|
BYTE FAR *cpf;
|
|
BYTE loadfile[MAX_FILELEN];
|
|
BYTE *cp1, *lcp;
|
|
UWORD loadtype;
|
|
BYTE argv0[MAX_FILELEN];
|
|
|
|
heap_get(0); /* check for stack overflow */
|
|
lcp = cp; /* in case 1st parse fails.. */
|
|
crlfflg = YES;
|
|
|
|
for(i=0;i<12;loadfile[i++]=' '); /* initialise with blanks */
|
|
ms_f_parse(loadfile, cp, 1); /* parse for internal cmd */
|
|
for(i=7;(i>=0) && (loadfile[i+1] == ' '); i--);
|
|
loadfile[0] = i+1; /* set length of cmd */
|
|
|
|
for(;strchr(valid_sepchar,*cp);cp++); /* ignore leading separators */
|
|
for(;is_filechar(cp);cp++); /* skip the command itself */
|
|
/* offer command line to */
|
|
/* interested parties */
|
|
if(docmd_offer(lcp,loadfile,0xFF00+strlen(cp))) /* If they want it */
|
|
return; /* we don't */
|
|
|
|
cp = lcp;
|
|
if ((cp[0] != 0) && (cp[1] == ':')) cp+=2;
|
|
for(;strchr(valid_sepchar,*cp);cp++);
|
|
for(;is_filechar(cp);cp++); /* skip the command itself */
|
|
|
|
cp1 = cp;
|
|
i = 0;
|
|
while (*cp1 != '\0') {
|
|
if (*cp1 == '"')
|
|
i ^= 1;
|
|
if (is_blank(cp1) == 2 && !i) /* replace each KANJI space */
|
|
*cp1 = *(cp1 + 1) = ' '; /* with one ASCII space */
|
|
cp1 = skip_char(cp1);
|
|
}
|
|
|
|
s_cmd_p = (S_CMD FAR *)farptr((BYTE *)&cmd_list[0]);
|
|
while(internal && s_cmd_p->cmnd) { /* while more builtins */
|
|
cpf = cgroupptr(s_cmd_p->cmnd);
|
|
for(i=0;cpf[i];i++) /* make upper case copy */
|
|
argv0[i]=toupper(cpf[i]);
|
|
for(;i<8;argv0[i++]=' '); /* space fill it to 8 */
|
|
|
|
if(!strncmp(argv0,loadfile+1,8)) { /* Is this a match ? */
|
|
|
|
#if !defined(NOHELP)
|
|
/* Handle /H or /? in command */
|
|
strcpy(heap(),deblank(cp));
|
|
if(!strnicmp(heap(),"/h",2)||!strnicmp(heap(),"/?",2)) {
|
|
if (s_cmd_p->help_index != -1)
|
|
show_help(s_cmd_p->help_index);
|
|
crlf();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* check for embedded commands in IF that only have meaning in
|
|
that context */
|
|
if(s_cmd_p->needparm==PARAM_IFCONTEXT) {
|
|
if(if_context==FALSE) break;
|
|
}
|
|
|
|
cp1 = deblank(cp); /* Remove Blanks from Options*/
|
|
|
|
if(s_cmd_p->needparm!=PARAM_NONE /* if a parameter is needed */
|
|
&& !*cp1) { /* but none is supplied */
|
|
|
|
switch ((UWORD)s_cmd_p->needparm) /* display an error message */
|
|
{
|
|
case PARAM_NEEDFILE: eprintf(MSG_NEEDFILE); break;
|
|
case PARAM_NEEDPATH: eprintf(MSG_NEEDPATH); break;
|
|
case PARAM_NEEDDEV: eprintf(MSG_NEEDDEV); break;
|
|
default: eprintf(MSG_SYNTAX); break;
|
|
}
|
|
eprintf("\n");
|
|
return; /* ignore the command */
|
|
}
|
|
|
|
page_len = get_lines_page(); /* so /P works in 43 and 50 */
|
|
/* line modes */
|
|
(*s_cmd_p->func)(cp1, cp); /* Just Invoke builtin */
|
|
return;
|
|
}
|
|
s_cmd_p ++; /* compare with next command */
|
|
}
|
|
|
|
/* it's not an internal command - could it be help ? */
|
|
if ((!strnicmp(lcp,"/h",2))||(!strncmp(lcp,"/?",2))) {
|
|
show_help(0);
|
|
s_cmd_p = (S_CMD FAR *)farptr((BYTE *)&cmd_list[0]);
|
|
while(s_cmd_p->cmnd) {
|
|
cpf = cgroupptr(s_cmd_p->cmnd);
|
|
printf("%s\t",cpf);
|
|
s_cmd_p++;
|
|
}
|
|
crlf();
|
|
return;
|
|
}
|
|
|
|
/* command is not builtin, must be disk based so determine path ... */
|
|
if(docmd_offer(lcp,loadfile,strlen(cp))) /* offer command line to */
|
|
return; /* interested parties */
|
|
/* If they want it, we don't */
|
|
|
|
cp = get_filename(loadfile, lcp, NO);
|
|
strcpy(argv0, loadfile); /* the original command name */
|
|
strlwr(loadfile);
|
|
|
|
if((loadfile[strlen(loadfile)-1] == '\\') ||
|
|
((strlen(loadfile) == 2) && (loadfile[1] == ':'))) {
|
|
if(!dos_parse_filename(loadfile) && d_check(loadfile)) {
|
|
if (ddrive != -1)
|
|
{
|
|
ms_drv_set(ddrive); /* then check the requested */
|
|
drive = ddrive; /* drive and make it the */
|
|
crlfflg = NO; /* default if OK. */
|
|
}
|
|
}
|
|
else {
|
|
eprintf(ERR15);
|
|
crlf();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (strcmp(loadfile,"________") == 0) {
|
|
ms_x_first("________.???",ATTR_HID+ATTR_STD,(DTA *) heap());
|
|
strcpy(loadfile,"C:\\________.COM");
|
|
}
|
|
else if((i = findfile(loadfile, &loadtype)) < 0) {
|
|
if(i == ED_FILE || /* Determine the full */
|
|
i == ED_ROOM || /* path and type of the */
|
|
i == ED_PATH) { /* command and return if*/
|
|
eprintf(MSG_BADCMD); /* file or command cannot be located */
|
|
}
|
|
else {
|
|
e_check(i);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
if(!env_scan(msg_comspec, heap())) /* If COMSPEC is defined */
|
|
set_reload_file(); /* then update RELOAD_FILE */
|
|
|
|
doexec(argv0, loadfile, loadtype, cp); /* Load the file */
|
|
allow_pexec = TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* FindFile searches the file system copying the actions of the
|
|
* Concurrent DOS P_PATH function. If this is TMP for Concurrent
|
|
* DOS then use the system call otherwise use the C function.
|
|
*
|
|
* If no extension is specified then check the file types in
|
|
* the following order .CMD, .COM, .EXE, .BAT
|
|
*
|
|
* If a Path is specified then just check that location otherwise
|
|
* check the current directory and then all entries in the path.
|
|
*/
|
|
#if !defined(CDOSTMP)
|
|
GLOBAL WORD CDECL findfile(loadpath, loadtype)
|
|
BYTE *loadpath; /* Command Name expanded to full path */
|
|
UWORD *loadtype; /* Command file Type */
|
|
{
|
|
REG BYTE *s;
|
|
BYTE sppath[MAX_PATHLEN]; /* Buffer for the optional */
|
|
/* load path. */
|
|
BYTE fname[8+1+3+1+8+1]; /* Buffer for the filename */
|
|
/* optional extension and */
|
|
/* password */
|
|
BYTE *path; /* Environment Load path */
|
|
BYTE *ftype; /* Optional file type */
|
|
BYTE *pwd; /* Optional Password */
|
|
BYTE *envpath; /* current PATH= in env */
|
|
WORD i, ret;
|
|
#if !STACK
|
|
BYTE pathbuf[MAX_ENVLEN]; /* temporary path buffer */
|
|
#endif
|
|
|
|
strip_path(loadpath, sppath); /* isolate the optional path*/
|
|
ftype = loadpath+strlen(sppath); /* get the Filename Address */
|
|
|
|
if(strlen(ftype) < sizeof(fname)) /* If the filename is not */
|
|
strcpy(fname, ftype); /* too long then copy to an */
|
|
else /* internal buffer otherwise*/
|
|
longjmp(break_env, IA_FILENAME); /* break with FILENAME error*/
|
|
|
|
if((ftype = strchr(fname, '.')) != 0) { /* then extract the optional*/
|
|
*ftype++ = '\0'; /* file type from the name */
|
|
pwd = ftype;
|
|
}
|
|
else { /* If no type has been */
|
|
ftype = NULLPTR; /* specified then make it */
|
|
pwd = fname; /* file type a NULL pointer */
|
|
}
|
|
|
|
if ((ret = ms_x_open (fname, 0)) > 0) { /* don't exec a device in */
|
|
i = isdev (ret); /* any shape or form */
|
|
ms_x_close (ret);
|
|
if (i)
|
|
return (ED_FILE);
|
|
}
|
|
|
|
#if defined(PASSWORD)
|
|
if((pwd = strchr(pwd, *pwdchar)) != 0) /* Finally extract the */
|
|
*pwd++ = '\0'; /* optional password if none*/
|
|
else /* exists then default to a */
|
|
pwd = NULLPTR; /* NULL pointer. */
|
|
#endif
|
|
|
|
if(ftype) { /* If a file type has been */
|
|
for(i=0; ftypes[i]; i++) /* specified then check that*/
|
|
if(!strcmp(ftype, ftypes[i])) /* is legal and return an */
|
|
break; /* error if not. */
|
|
|
|
if(!ftypes[i]) /* If an illegal filetype */
|
|
return ED_FILE; /* has been given then */
|
|
} /* return FAILURE */
|
|
|
|
*loadtype = i; /* Save the Load File Type */
|
|
|
|
/*
|
|
* Check if a path is currently defined if YES then get
|
|
* a copy of the path and save locally on the heap. Protecting
|
|
* it against being overwritten.
|
|
*/
|
|
|
|
if(!env_scan(msg_patheq, heap())) {
|
|
envpath = heap();
|
|
while (*envpath) { /* process path in env */
|
|
if(dbcs_lead(*envpath)) /* so delimiters are the */
|
|
envpath++; /* pathchar we expect */
|
|
else
|
|
if((*envpath == '/') || (*envpath == '\\'))
|
|
*envpath = *pathchar;
|
|
envpath++;
|
|
}
|
|
#if STACK
|
|
envpath = stack(strlen(heap()) + 1);
|
|
#else
|
|
envpath = &pathbuf[0];
|
|
#endif
|
|
strcpy(envpath, heap());
|
|
}
|
|
else
|
|
envpath = "";
|
|
|
|
/*
|
|
* First attempt to load the file from the default/specified
|
|
* path and then if no path was specified attempt to load the
|
|
* file from all the entries in the search path defined in the
|
|
* environment.
|
|
*/
|
|
|
|
if(*sppath)
|
|
path = sppath;
|
|
else
|
|
path = "";
|
|
|
|
do {
|
|
i = checkfile(loadpath, loadtype, path, fname, ftype, pwd);
|
|
|
|
switch (i)
|
|
{
|
|
case SUCCESS:
|
|
strupr(loadpath);
|
|
return SUCCESS;
|
|
case ED_FAIL:
|
|
case ED_DRIVE: /* if bad drive in search */
|
|
if ((!*sppath) && (*path)) /* path, print msg & carry on*/
|
|
{
|
|
eprintf(MSG_PATHDRV);
|
|
i = ED_FILE;
|
|
break;
|
|
}
|
|
default:
|
|
break; /* get next search path */
|
|
}
|
|
|
|
path = envpath; /* Set PATH to the next */
|
|
if((s=strchr(envpath, ';')) != 0) { /* element in the search path*/
|
|
while (*s == ';') { /* Skip over extra semicolons*/
|
|
*s = 0;
|
|
s++;
|
|
}
|
|
envpath = s;
|
|
}
|
|
else
|
|
envpath = ""; /* path exhausted, -> null */
|
|
|
|
/* If you type FILENAME.EXE, it will search the current drive then */
|
|
/* the path. If you type C:\DIR\FILENAME.EXE, it will search */
|
|
/* C:\DIR. Now, if you type C:FILENAME.EXE, it will search the */
|
|
/* current directory on C:, then path. This is done by resetting */
|
|
/* sppath after the first run through, if it is just D: */
|
|
if((strlen(sppath) == 2) && (sppath[1] == ':'))
|
|
sppath[0] = '\0';
|
|
|
|
} while(!*sppath && *path);
|
|
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
* CHECKFILE generates the full path of the load file and
|
|
* attempts to open the file. If the file is located and
|
|
* can successfully be opened return SUCCESS with the full
|
|
* path in LOADPATH and the LOADTYPE initialised.
|
|
*
|
|
* If no file extension has been specified then use the standard
|
|
* search order.
|
|
*
|
|
* ATTR_SEARCH specifies the attributes used to locate the file
|
|
* to be loaded.
|
|
*/
|
|
|
|
#define ATTR_SEARCH ATTR_STD + ATTR_HID
|
|
|
|
MLOCAL WORD checkfile(loadpath, loadtype, path, fname, ftype, pwd)
|
|
BYTE *loadpath;
|
|
UWORD *loadtype;
|
|
BYTE *path, *fname, *ftype, *pwd;
|
|
{
|
|
UWORD type;
|
|
WORD ret;
|
|
DTA search;
|
|
BYTE curpath[MAX_PATHLEN+1];
|
|
|
|
if((path = d_check(path)) == NULL) /* Remove the drive specifier*/
|
|
return ED_DRIVE; /* and return on Error. */
|
|
/* get path starting from root. n.b. don't use ms_x_expand (func 60h) */
|
|
/* as it upsets Novell */
|
|
|
|
if (ddrive != -1)
|
|
{
|
|
sprintf(loadpath, "%c:%c", ddrive + 'A', *pathchar);
|
|
if((*path == '\\') || (*path == '/')) /* If path is absolute then */
|
|
strcpy(loadpath+2, path); /* just append to drive */
|
|
else { /* Otherwise append the */
|
|
ms_x_curdir(ddrive+1, loadpath+3); /* path to the drive and */
|
|
if(*fptr(loadpath)) /* current subdirectory. */
|
|
append_slash(loadpath);
|
|
strcat(loadpath, path);
|
|
}
|
|
}
|
|
else
|
|
ms_x_expand(loadpath,path);
|
|
|
|
|
|
if(*fptr(loadpath))
|
|
append_slash(loadpath);
|
|
|
|
strcat(loadpath, fname); /* Add the FileName */
|
|
strcat(loadpath, ".");
|
|
path = loadpath + strlen(loadpath); /* Save the Extension Offset */
|
|
|
|
#if defined(PCDOS)
|
|
/*
|
|
* If running under PCDOS the check if any extension has been specified
|
|
* if not then search first for filename.* and return if no match occurs
|
|
* This will be quicker than opening each file in turn.
|
|
*/
|
|
if(!ftype) {
|
|
strcat(path, "*");
|
|
if((ret = ms_x_first(loadpath, ATTR_SEARCH, &search)) < 0) {
|
|
if( ret == ED_FILE || /* Abort if an error occurs */
|
|
ret == ED_ROOM || /* but ignore File not Found */
|
|
ret == ED_PATH) /* and invalid path errors */
|
|
return ED_FILE;
|
|
else
|
|
return e_check(ret);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ftype == 0)
|
|
type = COM_FILETYPE; /* Initialize the Type Index */
|
|
else /* correctly depending on the */
|
|
type = *loadtype; /* initial file type. */
|
|
|
|
do {
|
|
strcpy(path, ftypes[type]); /* Add the first file type */
|
|
|
|
#if defined(PASSWORD)
|
|
if(pwd) { /* followed by the optional */
|
|
strcat(path, pwdchar); /* password and attempt to */
|
|
strcat(path, pwd); /* open the file. */
|
|
}
|
|
#endif
|
|
|
|
if((ret = ms_x_first(loadpath, ATTR_SEARCH, &search)) < 0) {
|
|
if(ret == ED_PATH) /* Stop scanning this */
|
|
return ED_FILE; /* element of the path if */
|
|
/* it is invalid. */
|
|
#if 0
|
|
if(ret != ED_FILE && ret != ED_ROOM)
|
|
return ret;
|
|
#endif
|
|
}
|
|
else {
|
|
*loadtype = type; /* Set the correct loadtype */
|
|
return SUCCESS; /* and return SUCCESS */
|
|
}
|
|
if (++type > BAT_FILETYPE)
|
|
#if defined(DOSPLUS) || defined(NETWARE)
|
|
type = COM_FILETYPE;
|
|
#else
|
|
type = CMD_FILETYPE;
|
|
#endif
|
|
} while(!ftype && (type != COM_FILETYPE));
|
|
return ED_FILE;
|
|
}
|
|
#endif
|
|
|
|
MLOCAL BOOLEAN doexec(argv0, loadpath, loadtype, tail)
|
|
BYTE *argv0; /* Invoking Command */
|
|
BYTE *loadpath; /* Fully expanded filename */
|
|
UWORD loadtype; /* File Type .BAT, .EXE etc. */
|
|
BYTE *tail; /* Command line options */
|
|
{
|
|
WORD ret;
|
|
WORD i;
|
|
BYTE *s;
|
|
#if !STACK
|
|
BYTE tailbuf[128];
|
|
#endif
|
|
|
|
#if 0
|
|
printf("DOEXEC Load File \"%s\" Command Line \"%s\"\n",
|
|
loadpath, (tail ? tail : ""));
|
|
#endif
|
|
|
|
|
|
if(loadtype == BAT_FILETYPE) { /* if Batch file then:- */
|
|
|
|
if (batchflg == 0) echoflg_save2 = echoflg;
|
|
|
|
ret = echoflg; /* Save the Current ECHO State */
|
|
batch_end(); /* Close any Existing Batch file */
|
|
echoflg = ret; /* restore the ECHO status */
|
|
batch_start(argv0, loadpath, tail); /* and initialize the new batch */
|
|
return YES; /* use "CALL" to nest batches. */
|
|
}
|
|
/* if CMD, COM or EXE */
|
|
if(batchflg) /* close the BATCH file if OPEN cos */
|
|
batch_close(); /* some programs update the running */
|
|
/* batch file. */
|
|
|
|
s = deblank(tail); /* No SPACE before options */
|
|
if(!*s) /* if this is a blank line */
|
|
tail = s;
|
|
|
|
#if defined(CDOSTMP)
|
|
ret = exec(loadpath, loadtype, tail, back_flag);
|
|
#else
|
|
ms_set_break(break_flag);
|
|
#if STACK
|
|
s = stack(strlen(tail)+2)+1;
|
|
#else
|
|
s = &tailbuf[1];
|
|
#endif
|
|
tail = strcpy(s, tail) - 1;
|
|
*tail = (UBYTE) strlen(tail+1);
|
|
strcat(tail+1, "\r");
|
|
#if !defined(FINAL)
|
|
save_psp();
|
|
#endif
|
|
ret = exec(loadpath, loadtype, tail, back_flag);
|
|
#if !defined(FINAL)
|
|
check_psp();
|
|
#endif
|
|
init_switchar(); /* switch character may have changed */
|
|
break_flag = ms_set_break(YES);
|
|
#endif
|
|
|
|
/*
|
|
* Novell use the MS_DRV_GET function to detect abnormal
|
|
* program termination. They assume this function is only
|
|
* called by the command processor when a child has terminated.
|
|
* They close all Remote Handles when the parent command
|
|
* processor calls this function.
|
|
*/
|
|
drive = ms_drv_get(); /* get default drive. */
|
|
|
|
for (i=5;i<20;i++) ms_x_close(i); /* Close all handles */
|
|
|
|
if(ret < 0) { /* Get the returned Error Code */
|
|
#if defined(CDOS) || defined(CDOSTMP)
|
|
if(ret == ED_ENVIRON) /* Check for an Environment */
|
|
ret = (-255); /* error this is really */
|
|
#endif /* a resource unavailable. */
|
|
|
|
/* Print a message if the exec */
|
|
e_check(ret); /* went wrong otherwise get the */
|
|
/* completion status and return */
|
|
return FAILURE;
|
|
}
|
|
|
|
err_ret = ms_x_wait();
|
|
return YES;
|
|
}
|
|
|
|
#if !defined(CDOSTMP)
|
|
VOID FAR CDECL int2e_handler (cmd)
|
|
BYTE *cmd;
|
|
{
|
|
BYTE *p;
|
|
jmp_buf save_jmpbuf;
|
|
|
|
/* save the normal setjmp environment and reset it to ourselves */
|
|
/* so that the int2e caller does not get aborted on criterr or */
|
|
/* Control break */
|
|
|
|
memmove (&save_jmpbuf, &break_env, sizeof (jmp_buf));
|
|
|
|
if (setjmp (break_env) == 0) {
|
|
|
|
if ((p = strchr (cmd, 0xd)) != NULL)
|
|
*p = '\0';
|
|
|
|
int2e_start();
|
|
|
|
docmd (deblank (cmd), TRUE);
|
|
|
|
/* if int2e is executing a batch file, do not return until all */
|
|
/* batch file commands have been processed. Loop round as in main */
|
|
/* loop */
|
|
|
|
while (batchflg > 0)
|
|
{
|
|
cmd_loop (cmd);
|
|
}
|
|
|
|
int2e_finish();
|
|
}
|
|
memmove (&break_env, &save_jmpbuf, sizeof (jmp_buf));
|
|
}
|
|
|
|
|
|
MLOCAL VOID init_switchar()
|
|
{
|
|
*switchar = ms_switchar(); /* get switch character */
|
|
if (*switchar == '/') /* if not UNIX path char */
|
|
*pathchar = '\\'; /* then be compatible */
|
|
else
|
|
*pathchar = '/';
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(DOSPLUS)
|
|
|
|
GLOBAL VOID process_config_env()
|
|
{
|
|
BYTE FAR *config_env;
|
|
WORD i;
|
|
BYTE buff[128];
|
|
BYTE *s;
|
|
|
|
config_env = get_config_env();
|
|
if (config_env) {
|
|
FOREVER {
|
|
i = 0;
|
|
while ((*config_env) && (*config_env!=0x1A) &&
|
|
(i < 127)) {
|
|
|
|
buff[i++] = *config_env++;
|
|
}
|
|
if (i == 0) {
|
|
while (*config_env != 0x1A) config_env++;
|
|
config_env++;
|
|
boot_key_scan_code = * ((UWORD far *) config_env);
|
|
break;
|
|
}
|
|
buff[i] = 0;
|
|
cmd_set(buff);
|
|
while (*config_env) config_env++;
|
|
config_env++;
|
|
}
|
|
#if 0
|
|
s = heap();
|
|
if (!env_scan("HOMEDIR=",s)) {
|
|
if (s[1] == ':') ms_drv_set(toupper(*s)-'A');
|
|
ms_x_chdir(s);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if !defined(FINAL)
|
|
void save_psp()
|
|
{
|
|
BYTE far *fp;
|
|
WORD i;
|
|
|
|
fp = MK_FP(_psp,0);
|
|
|
|
psp_xsum = 0;
|
|
for (i=64;i<128;i++) psp_xsum += fp[i];
|
|
}
|
|
|
|
void check_psp()
|
|
{
|
|
BYTE far *fp;
|
|
WORD xsum;
|
|
WORD i;
|
|
|
|
fp = MK_FP(_psp,0);
|
|
|
|
xsum = 0;
|
|
for (i=64;i<128;i++) xsum += fp[i];
|
|
|
|
if (xsum != psp_xsum) {
|
|
printf("BETA DEBUG ERROR: Need more stack!\n");
|
|
printf("Press a key to continue.\n");
|
|
getch();
|
|
}
|
|
}
|
|
#endif
|
|
|