Files
DR-DOS-OpenDOS/COMMAND/COM.C
2020-11-04 23:59:28 +01:00

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