mirror of
https://github.com/SEPPDROID/DR-DOS-OpenDOS.git
synced 2025-10-22 07:54:28 +00:00
2654 lines
68 KiB
C
2654 lines
68 KiB
C
/*
|
|
; File : $Workfile: BATCH.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$
|
|
; ENDLOG
|
|
*/
|
|
|
|
/*
|
|
* 27 Oct 87 Improve GOTO command to ignore trailing white space, only
|
|
* match on the first 8 characters and only allow valid
|
|
* filename characters.
|
|
* 28 Oct 87 Correct duplicate prompt display when a batch file label
|
|
* is read and the echo flag is ON.
|
|
* 9 Nov 87 Change Batch file termination so that Output Redirection is
|
|
* correctly handled.
|
|
* 13 Jan 88 If prompt display is aborted because of a critical error
|
|
* the following prompt will be forced to "$n$g".
|
|
* 25 Jan 88 Support redirection on the FOR command correctly
|
|
* 24 Feb 88 Generate batch file parameter %0 correctly as WS200 install
|
|
* requires that the drive specifier be present. Garry Silvey
|
|
* 5 May 88 Batch paramater %0 is now a copied from the invoking command
|
|
* line.
|
|
* 18 May 88 Support the ESC_CHAR in the command line.
|
|
* 20 May 88 Disable MULTI_CHAR support in DOSPLUS when the user enters the
|
|
* first command.
|
|
* 26 May 88 Added STACK switch and support $q in prompt.
|
|
* 27 May 88 Added string undefs.
|
|
* 6 Jun 88 Call resident portion to do readline (SideKick+ problem)
|
|
* 23 Jun 88 Support CR only delimited batch files and if errorlevel ==
|
|
* syntax used in installation files.
|
|
* 6 Jul 88 Support the FOR ... CALL syntax correctly. (IMS)
|
|
* 17 Aug 88 Jump to labels followed by comments (Ashton Tate By-Line)
|
|
* 21 Sep 88 Use KEYIN_FLG to allow the default ECHO state to be ON.
|
|
* 16 Nov 88 Disable BACK_CHAR in Concurrent DOS.
|
|
* 21 Dec 88 Allow leading whitespace before labels
|
|
* 5 Jan 89 Support Quoted strings in Batch files.
|
|
* 18 Apr 89 Support Quoted strings in IF command
|
|
* 19 Apr 89 Quotes in IF command: "x == "x" parses, "x=x" == "x.. doesn't
|
|
* 24 Apr 89 Increase MAX_LINE to 128 for pctools ver 5
|
|
* 19 May 89 Take out support for quoted strings in IF command
|
|
* 05 Jun 89 Do not echo command or display the prompt during FOR command.
|
|
* Restore support for batch files with long lines.
|
|
* 02 Nov 89 batch_line bodge which substitutes 0xFF for 0x00 changed - we
|
|
* now substitute '\r\n', then throw away rest of the line.
|
|
* 01 Dec 89 batch_line - trailing % at end of line is discarded
|
|
* 15 Dec 89 "if errorlevel -1" allowed
|
|
* 30 Jan 90 Added int2e_start and int2e_finish to save and restore
|
|
* important batch file variables to allow novell menu program
|
|
* to use int 2e to invoke batch files.
|
|
* 30 Jan 90 Forced batch data structures to appear on segment boundaries;
|
|
* Added dummy memory descriptor before batch structure;
|
|
* Put segment address of batch structure in batch_seg_ptr;
|
|
* All so novell can find and patch the drive letter of
|
|
* autoexec.bat during a remote boot.
|
|
* 6-Mar-90 Watcom C v 7.0
|
|
* 7-Mar-90 allow ESC_CHAR through unless followed by MULTI/BACK_CHAR
|
|
* 14-Mar-90 Reduce batch_buf to 32 bytes like wot dos is
|
|
* 20-Mar-90 Batch structures allocated by mem_alloc (ie. MS_M_ALLOC)
|
|
* rather than on heap. Batch file nesting no longer heap limited.
|
|
* 27-Mar-90 Allow "=", "==", "===" etc in "if errorlevel==n"
|
|
* 10-Apr-90 Make errorlevel 999 same as errorlevel 231 (mod 256)
|
|
* 8-May-90 Don't echo getcmd unless batch file (eg. "dir|more" shouldn't
|
|
* echo "C:>more")
|
|
* 23-May-90 batch_read no longer repeatedly deblanks line (which leads
|
|
* to the buffer happily wandering up memory).
|
|
* 30-May-90 "if ab de==ef" form doesn't generate syntax error
|
|
* 13-Jun-90 batch_line rejects unmatched "|" as syntax error
|
|
* 20-Sep-90 is_filechar() and is_pathchar() now take pointer instead of byte
|
|
* Changed batch_char() to return pointer instead of byte,
|
|
* renamed to batch_ptr().
|
|
* Amended make_label(), batch_start() and cmd_for() to check for
|
|
* DBCS lead bytes.
|
|
* 24-Sep-90 Add $m and $u option to PROMPT to display status of mail
|
|
and user name respectively
|
|
* 27-Sep-90 Add IF USERID <userid> COMMAND
|
|
IF LOGINNAME <loginname> COMMAND
|
|
IF GROUPNAME <groupname> COMMAND
|
|
IF ASK ["string"] <char> COMMAND
|
|
.. AND .. OR .. to IF processing
|
|
INPUT ["string"] <environment-variable>
|
|
INPUTC ["string"] <environment-variable>
|
|
* 10-Oct-90 inherit batch files from TMP when TSR auto-loads CDOS.COM
|
|
(a bodge for Stellar)
|
|
* 25-Oct-90 inherit echoflg from TMP when TSR auto-loads CDOS.COM
|
|
* 31-Oct-90 change IF ASK command to IF KEY command
|
|
|
|
DRDOS BUXTON
|
|
------------
|
|
* 25-Apr-91 '!' is now ignored during COMMAND /C processing.
|
|
* 28-May-91 leading white space is now ignored before labels.
|
|
* 09-Jun-91 Added GOSUB, RETURN and SWITCH commands.
|
|
* 24-Jul-91 if batch_seg_ptr is poked to zero all batch processing is
|
|
terminated.
|
|
* 26-Jul-91 batch files are now read into a far buffer. This avoids
|
|
reading directly to seg FFFF if we happen to be there and so
|
|
solves some NOVELL problems.
|
|
|
|
* 18-Jun-92 Support ? in batch files as in config.sys.
|
|
* 23-Jun-92 $u in prompt causes LOGINNAME in environment to be displayed.
|
|
* 07-Jul-92 IF EXIST now finds hidden files.
|
|
*/
|
|
|
|
#include "defines.h"
|
|
|
|
#include <string.h>
|
|
#if defined(MWC) && defined(strlen)
|
|
#undef strcmp /* These are defined as macros in string.h */
|
|
#undef strcpy /* which are expanded in line under */
|
|
#undef strlen /* Metaware C. These undefs avoid this. */
|
|
#endif
|
|
|
|
#include <portab.h>
|
|
|
|
#if !defined(DOSPLUS)
|
|
#include <ccpm.h>
|
|
#endif
|
|
|
|
#include "command.h"
|
|
#include "toupper.h"
|
|
#include "support.h"
|
|
#include "dosif.h"
|
|
#include "global.h"
|
|
#include "dos.h"
|
|
|
|
#include <setjmp.h>
|
|
|
|
/*RG-01*/
|
|
#if defined(CDOSTMP) || defined(CDOS)
|
|
#include <pd.h>
|
|
#define PATH_LEN 65 /* max path length (null terminated) */
|
|
EXTERN PD FAR * CDECL pd; /* Far pointer to Current PD */
|
|
EXTERN VOID CDECL cmd_set(BYTE *); /* COMINT.C */
|
|
#if !defined (NOSECURITY)
|
|
#include "security.h"
|
|
#include "login.h"
|
|
#endif
|
|
#endif
|
|
/*RG-01-end*/
|
|
|
|
EXTERN VOID CDECL cmd_pause();
|
|
|
|
EXTERN BOOLEAN parse(BYTE *);
|
|
|
|
EXTERN UWORD boot_key_scan_code; /* in COM.C */
|
|
|
|
/*RG-03*/
|
|
BOOLEAN if_context=FALSE;
|
|
BOOLEAN ifcond=FALSE;
|
|
/*RG-03-end*/
|
|
|
|
EXTERN jmp_buf break_env;
|
|
|
|
#define MAX_LINE 128 /* Maximum No of Chars in input line */
|
|
|
|
#if defined(CPM)
|
|
EXTERN UWORD user; /* USER Number variable for CPM.EXE */
|
|
#endif
|
|
EXTERN BYTE msg_prmeq[]; /* Static Environ String "PROMPT=" */
|
|
|
|
#if 0
|
|
#define FCONTROL struct fcc
|
|
MLOCAL FCONTROL {
|
|
BOOLEAN sflg; /* FOR File Search Flag */
|
|
DTA search; /* FOR Search structure */
|
|
BYTE *files; /* FOR File list */
|
|
BYTE *cmd; /* FOR Command Line */
|
|
BYTE forvar; /* FOR variable char */
|
|
};
|
|
#endif
|
|
|
|
MLOCAL FCONTROL *forptr;
|
|
|
|
#if 0
|
|
#define BCONTROL struct bcc
|
|
GLOBAL BCONTROL {
|
|
BCONTROL FAR *bcontrol; /* Previous Batch Control Structure */
|
|
BOOLEAN eof; /* End of File Flag */
|
|
LONG offset; /* Offset in BATCH file */
|
|
LONG ret_offset[4]; /* return offset from gosub */
|
|
BYTE *batcmd; /* Batch File Input parameters */
|
|
UWORD batshift; /* Shift Offset */
|
|
BYTE batfile[MAX_PATHLEN]; /* Batch File Name */
|
|
UWORD stream; /* Stream for this Batch File */
|
|
FCONTROL *fcontrol; /* Pointer to previous FOR command */
|
|
BYTE *heap_start; /* Heap pointer before extra bytes */
|
|
WORD heap_size; /* are added to shift to segment */
|
|
BYTE save_area[1]; /* boundary. - EJH */
|
|
} FAR *batch, FAR *batch_save; /* Master Batch Control Stucture */
|
|
#endif
|
|
|
|
/* Handle 255 is closed */
|
|
#define CLOSED 0xff
|
|
|
|
/* Keyboard Variables */
|
|
GLOBAL BYTE kbdbuf[MAX_LINE+2]= {0};/* Keyboard Input Buffer */
|
|
GLOBAL BYTE *kbdptr = kbdbuf+2; /* Keyboard Buffer Pointer */
|
|
MLOCAL BOOLEAN keyin_flg = FALSE; /* This flag is set to TRUE when the */
|
|
/* initial command line buffer setup */
|
|
/* by INIT() has been exhausted. */
|
|
MLOCAL WORD batchflg_save; /* Used during INT 2E handling. */
|
|
MLOCAL WORD echoflg_save; /* ditto above */
|
|
GLOBAL WORD echoflg_save2; /* saves echo state when batch file */
|
|
/* execed. */
|
|
/*
|
|
* Batch file buffering control structures.
|
|
*/
|
|
MLOCAL LONG batch_off; /* Offset of buffered data in File */
|
|
MLOCAL WORD batch_cnt = 0; /* Number of bytes in buffer */
|
|
MLOCAL BYTE batch_buf[32];
|
|
MLOCAL BYTE batch_eof[] = "\x1a"; /* End of file string */
|
|
|
|
MLOCAL BYTE batch_sep[] = "\t ;,="; /* Batch Command line option delimiters */
|
|
|
|
EXTERN VOID CDECL cmd_ver(BYTE *); /* COMINT.C Display Version */
|
|
EXTERN VOID docmd(BYTE *, BOOLEAN); /* COM.C */
|
|
EXTERN VOID CDECL int_break(VOID); /* COM.C */
|
|
|
|
GLOBAL BOOLEAN getcmd(BYTE *);
|
|
GLOBAL VOID for_end();
|
|
GLOBAL VOID batch_start(BYTE *, BYTE *, BYTE *);
|
|
GLOBAL VOID batch_end(VOID);
|
|
GLOBAL VOID batch_close(VOID);
|
|
MLOCAL VOID for_in(BYTE *);
|
|
MLOCAL WORD batch_open(VOID);
|
|
MLOCAL VOID batch_read(BYTE *, BOOLEAN);
|
|
MLOCAL VOID batch_line(BYTE *, BOOLEAN);
|
|
MLOCAL BYTE *batch_ptr(VOID);
|
|
MLOCAL VOID prompt(VOID);
|
|
MLOCAL BOOLEAN novell_extension(BYTE *, BYTE *);
|
|
|
|
#if !defined(CDOSTMP)
|
|
EXTERN UWORD FAR *batch_seg_ptr; /* For novell remote boot. see CSTART.ASM */
|
|
#endif
|
|
|
|
#if defined(CDOS) || defined(CDOSTMP)
|
|
#define TmpPspEchoFlgPtr 0x58 /* Magic location to keep echo flag */
|
|
#define TmpPspDataSeg 0x5a /* Magic location to keep Data Seg */
|
|
#define TmpPspBatchSeg 0x5c /* Magic location to keep Batch Ptr */
|
|
#define TmpPspMpad 0x5e /* Magic location to keep unlinked MPAD */
|
|
#endif
|
|
#if defined(CDOS)
|
|
typedef struct _mpad
|
|
{
|
|
UWORD link; /* address of next MPAD */
|
|
UWORD start; /* seg of allocation unit */
|
|
UWORD length; /* length in paras */
|
|
UWORD res0x06; /* reserved */
|
|
UWORD xios; /* Process id */
|
|
} MPAD;
|
|
GLOBAL VOID inherit_TMP_state(VOID);
|
|
#endif
|
|
|
|
/*.pa*/
|
|
GLOBAL BOOLEAN getcmd(line) /* read command line */
|
|
BYTE *line;
|
|
{
|
|
BYTE *s;
|
|
BOOLEAN quote = FALSE;
|
|
BOOLEAN cancel_prompt = FALSE;
|
|
#if defined(DOSPLUS)
|
|
WORD i;
|
|
BYTE cmd_name[16];
|
|
#endif
|
|
|
|
back_flag = FALSE; /* Disable BackGround Processing*/
|
|
|
|
*line = '\0';
|
|
|
|
FOREVER {
|
|
if(for_flag) { /* If Processing a FOR command */
|
|
for_in(line); /* then call then use the FOR_IN*/
|
|
return NO; /* routine to fill the keyboard */
|
|
} /* buffer and then return */
|
|
|
|
if(!batchflg) /* If no batch processing then */
|
|
break; /* skip further tests */
|
|
batch_restart:
|
|
|
|
#if defined(DOSPLUS)
|
|
if (!*batch_seg_ptr) { /* if batch_seg_ptr has been set to */
|
|
batch_endall(); /* zero terminate all batch files */
|
|
return NO;
|
|
}
|
|
#endif
|
|
|
|
if(batchflg && batch->eof) { /* Close the batch file if at */
|
|
batch_end(); /* the end of the file. */
|
|
if(batchflg == 0) /* BREAK if batch processing */
|
|
return NO; /* is complete. */
|
|
continue;
|
|
}
|
|
|
|
if(!batch_open()) /* Open the file and read a line*/
|
|
return YES; /* from the file */
|
|
|
|
batch_read(line, NO); /* Read Line */
|
|
|
|
if(batch->eof) /* If the end of the batch file */
|
|
batch_close(); /* has been detected then close */
|
|
/* the file. */
|
|
|
|
if (*line == '?' || boot_key_scan_code == 0x4200) {
|
|
optional_line(line);
|
|
}
|
|
|
|
if(*line == '@') { /* If first character in the */
|
|
strcpy(line, line+1); /* command line is '@' donot */
|
|
return NO; /* echo the command and move the*/
|
|
} /* string down 1 character. */
|
|
|
|
if (!cancel_prompt) {
|
|
if(crlfflg && echoflg)
|
|
crlf();
|
|
prompt();
|
|
}
|
|
return echoflg;
|
|
}
|
|
|
|
if(!*kbdptr) { /* Set the Keyboard Input flag */
|
|
keyin_flg = TRUE; /* after a initial command line */
|
|
/* buffer has been exhausted */
|
|
#if 1
|
|
if (c_option) { /* insert an EXIT command if we */
|
|
kbdptr = &kbdbuf[2]; /* are processing a /C command */
|
|
strcpy(&kbdbuf[2],"exit");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (!*kbdptr) { /* Check for existing line */
|
|
|
|
|
|
/* NEIL */
|
|
if(crlfflg && echoflg)
|
|
crlf();
|
|
/* NEIL end */
|
|
prompt(); /* issue command line prompt */
|
|
allow_pexec = FALSE;
|
|
|
|
/* $x in prompt string may cause batchflg to be set. */
|
|
/* If so we must jump to batch processing code. */
|
|
if (batchflg) {
|
|
cancel_prompt = TRUE;
|
|
goto batch_restart;
|
|
}
|
|
|
|
kbdptr = ""; /* Force KBDPTR to point to '\0'*/
|
|
/* in case we get ABORTED and */
|
|
/* drop through here again. */
|
|
kbdbuf[0] = MAX_LINE; /* set max. input length */
|
|
kbdbuf[kbdbuf[1]+2] = '\r'; /* Terminate current line. */
|
|
#if defined(CDOSTMP)
|
|
system(C_READSTR, kbdbuf); /* read a line */
|
|
#else
|
|
|
|
readline(kbdbuf);
|
|
#endif
|
|
|
|
crlf();
|
|
|
|
kbdbuf[kbdbuf[1] + 2]='\0'; /* terminate input */
|
|
kbdptr = kbdbuf + 2;
|
|
}
|
|
|
|
s = kbdptr;
|
|
|
|
while(*s) {
|
|
if(*s == '"') /* Check for a " character and */
|
|
quote = !quote; /* update the flag correctly */
|
|
|
|
#if !defined(DOSPLUS)
|
|
if(*s == ESC_CHAR && /* If the Escape character has */
|
|
!quote && /* been specified then do not */
|
|
((*(s+1) == MULTI_CHAR) || (*(s+1) == BACK_CHAR))) {
|
|
*line++ = *++s; /* process the following char. */
|
|
s++;
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
#if defined(DOSPLUS) /* Disable MULTI_CHAR support */
|
|
if(!(keyin_flg||c_option||k_option))
|
|
/* after the init command line */
|
|
#endif /* has been exhausted. */
|
|
if(*s == MULTI_CHAR && /* If a Multiple command char */
|
|
!quote) { /* and the QUOTE flag is FALSE */
|
|
s++; /* then break the command here */
|
|
break; /* and save the rest of the line*/
|
|
} /* for next time. */
|
|
|
|
#if FALSE /* defined(CDOSTMP) */
|
|
if(*s == BACK_CHAR && /* If a Back Ground processing */
|
|
!quote) { /* and the QUOTE flag is FALSE */
|
|
s++; /* then treat as for MULTI_CHAR */
|
|
back_flag = TRUE; /* except that the current */
|
|
break; /* command is executed in the */
|
|
} /* background. */
|
|
#endif
|
|
if(*s == PIPE_CHAR && /* If a Pipe enable character */
|
|
!quote) { /* and the QUOTE flag is FALSE */
|
|
s++; /* then break the command here */
|
|
pipe_out = YES; /* and save the rest of the line*/
|
|
break; /* for next time. */
|
|
}
|
|
|
|
copy_char(&line, &s); /* Just save the character */
|
|
}
|
|
|
|
*line = '\0'; /* Terminate the Buffer */
|
|
kbdptr = deblank(s); /* Copy the possibly null length*/
|
|
return NO; /* string to KBDBUF for next */
|
|
/* next invocation and save CCP */
|
|
}
|
|
|
|
MLOCAL VOID for_in(line) /* A FOR command is currently */
|
|
BYTE *line; /* executing so build the line */
|
|
{ /* from the internal FOR data */
|
|
BYTE *s,*t; /* initialized by CMD_FOR */
|
|
BYTE *bp1, *fp;
|
|
WORD i;
|
|
|
|
FOREVER {
|
|
fp = forptr->files; /* Get the next string and stop */
|
|
if(strlen(fp) == 0) { /* if its the zero length string */
|
|
*line = '\0'; /* which marks the end of the FOR */
|
|
crlfflg = YES; /* search list. */
|
|
for_end();
|
|
return;
|
|
}
|
|
|
|
if(!iswild(fp)) { /* If not an ambiguous file */
|
|
forptr->sflg = NO; /* then update the FOR */
|
|
forptr->files += strlen(fp)+1; /* pointer to the next file */
|
|
break; /* in the search list. */
|
|
}
|
|
|
|
if(forptr->sflg) /* Search for the next file */
|
|
i = ms_x_next(&forptr->search); /* file on the disk if */
|
|
else /* FOR_SFLG otherwise get first */
|
|
i = ms_x_first(fp, ATTR_RO, &forptr->search);
|
|
|
|
if(i < 0) { /* If the search failed */
|
|
forptr->sflg = NO; /* then update the FOR */
|
|
forptr->files += strlen(fp)+1; /* pointer to the next file */
|
|
continue; /* in the search list. */
|
|
} /* and get the next entry */
|
|
|
|
fp = (BYTE *) heap();
|
|
strip_path(forptr->files, fp); /* Extract the Path */
|
|
strcat(fp, forptr->search.fname); /* and then add the matching */
|
|
forptr->sflg = YES; /* filename and update the */
|
|
strupr(fp); /* variables. */
|
|
break; /* Force name to uppercase */
|
|
}
|
|
|
|
s = forptr->cmd;
|
|
t = line;
|
|
while (*s && (t - line) < MAX_LINE) { /* Copy the command */
|
|
if(*s == '%' && *(s+1) == forptr->forvar) { /* line looking for */
|
|
s += 2; /* the imbedded %c and insert*/
|
|
bp1 = fp; /* the current substition */
|
|
while(*bp1 && (t - line) < MAX_LINE) /* string pointed at by FP */
|
|
copy_char(&t, &bp1);
|
|
continue;
|
|
}
|
|
|
|
copy_char(&t, &s);
|
|
}
|
|
|
|
*t = '\0'; /* and terminate the string */
|
|
}
|
|
|
|
/*.pa*/
|
|
/*
|
|
* BATCH FILE CONTROL ROUTINES
|
|
* ===========================
|
|
*
|
|
* The following routines provide the interface from COMMAND.COM to
|
|
* a batch file. BATCH_START sets up all the local variables to enable
|
|
* batch processing while BATCH_END terminates batch processing. BATCH_READ
|
|
* reads a line of data from the batch file and expands it to contain the
|
|
* command line variables and variables from the environment.
|
|
*/
|
|
GLOBAL VOID batch_start(argv0, path, tail)
|
|
BYTE *argv0; /* Invoking Command */
|
|
BYTE *path; /* Complete filename */
|
|
BYTE *tail; /* Command Line Options */
|
|
{
|
|
BYTE *s2;
|
|
BYTE dirbuf[MAX_PATHLEN];
|
|
WORD i;
|
|
|
|
if(batchflg) /* If a batch file is currently */
|
|
batch_close(); /* close it. So minimum number */
|
|
/* of handles are used. */
|
|
|
|
s2 = path; /* Save the original Path */
|
|
if((path = d_check(path)) == NULL) /* Check that the file */
|
|
return; /* exists. */
|
|
|
|
batch_new(); /* new incarnation of batch */
|
|
|
|
forptr = (FCONTROL *) NULL; /* Disable current FOR control */
|
|
for_flag = NO; /* and Global FOR flag */
|
|
|
|
/*
|
|
* Generate the full path specification for the batch file
|
|
* and store in the batch control information. If the user
|
|
* has specified the full path use it otherwise determine the
|
|
* full path using ms_x_curdir.
|
|
*/
|
|
if (ddrive != -1 && *path != *pathchar) {
|
|
ms_x_curdir(ddrive+1, dirbuf);
|
|
sprintf(heap(), "%c:%s%s%s%s", ddrive + 'A',
|
|
pathchar,
|
|
dirbuf,
|
|
(*dirbuf ? pathchar : ""),
|
|
path);
|
|
}
|
|
else if (ddrive != -1)
|
|
sprintf(heap(), "%c:%s", ddrive + 'A', path);
|
|
else
|
|
ms_x_expand(heap(), path);
|
|
|
|
for (i=0; i<MAX_PATHLEN; i++) /* save the batch pathname */
|
|
batch->batfile[i] = heap()[i];
|
|
batch->batfile[MAX_PATHLEN-1] = 0;
|
|
|
|
/*
|
|
* Copy the invoking command and the individual elements
|
|
* of the command line into a buffer ready for processing
|
|
*/
|
|
batch->batcmd = (BYTE *)heap(); /* Initialize Parameter Buffer */
|
|
strcpy(heap(), argv0); /* Copy the invoking command */
|
|
heap_get(strlen(heap())+1); /* and protect the buffer */
|
|
|
|
while(*tail) { /* While there are command line */
|
|
s2 = (BYTE *)heap(); /* parameters copy them */
|
|
while(*tail && strchr(batch_sep, *tail))
|
|
tail = skip_char(tail);
|
|
|
|
while(*tail && !strchr(batch_sep, *tail))
|
|
copy_char(&s2, &tail);
|
|
|
|
*s2++ = '\0';
|
|
heap_get(strlen(heap()) + 1);
|
|
}
|
|
|
|
*(WORD *)heap_get(2) = 0; /* Double NULL is a terminator */
|
|
/* for command line params */
|
|
|
|
if(in_flag & REDIR_ACTIVE) /* If Input redirection has been */
|
|
in_flag |= REDIR_BATCH; /* enabled for this command force*/
|
|
/* it on for the complete command*/
|
|
|
|
if(out_flag & REDIR_ACTIVE) /* If Output redirection has been*/
|
|
out_flag |= REDIR_BATCH; /* enabled for this command force*/
|
|
/* it on for the complete command*/
|
|
|
|
|
|
batchflg++; /* increment batch flag */
|
|
|
|
crlfflg = YES; /* print CR/LF after this */
|
|
}
|
|
|
|
GLOBAL VOID batch_endall() /* This terminates BATCH */
|
|
{ /* processing by closing ALL */
|
|
while(batchflg) { /* active batch files */
|
|
batch_end();
|
|
}
|
|
}
|
|
|
|
GLOBAL VOID batch_end() /* This function is called for */
|
|
{ /* both NORMAL and ABNORMAL */
|
|
if(batchflg == 0) /* termination of batch file */
|
|
return; /* processing */
|
|
|
|
boot_key_scan_code = 0;
|
|
|
|
batch_close(); /* Close the Batch file */
|
|
for_end(); /* Terminate Any FOR command */
|
|
batch_old(); /* Restore the previous batch */
|
|
/* control structures to heap */
|
|
if(--batchflg == 0) {
|
|
*batch_seg_ptr = 0;
|
|
echoflg = echoflg_save2; /* Restore the original ECHO */
|
|
crlfflg = YES; /* flag and set CR/LF flag when */
|
|
} /* returning to the keyboard. */
|
|
}
|
|
|
|
|
|
MLOCAL BOOLEAN batch_open()
|
|
{
|
|
WORD h, i;
|
|
BYTE *name;
|
|
|
|
if(batch->eof) { /* If the End of the batch file */
|
|
batch_end(); /* was discovered last time then*/
|
|
return FALSE; /* End Batch file input and exit*/
|
|
}
|
|
|
|
if(batch->stream != CLOSED)
|
|
return batch->stream;
|
|
|
|
name = heap();
|
|
|
|
for (i=0; i<MAX_PATHLEN; i++)
|
|
name[i] = batch->batfile[i];
|
|
while ((h = ms_x_open(name, OPEN_READ)) < 0) {
|
|
err_flag = TRUE;
|
|
eprintf(MSG_BATMISS, name); /* prompt for batch file */
|
|
heap_get(strlen(name)+1);
|
|
cmd_pause("");
|
|
heap_set(name);
|
|
}
|
|
err_flag = FALSE;
|
|
batch->stream = h;
|
|
return TRUE;
|
|
}
|
|
|
|
GLOBAL VOID batch_close()
|
|
{
|
|
if(batchflg != 0 &&
|
|
batch->stream != CLOSED) { /* Check if the batch file */
|
|
batch_cnt = 0; /* currently open if YES */
|
|
ms_x_close(batch->stream); /* then flush the internal */
|
|
batch->stream = CLOSED; /* buffer and close file. */
|
|
}
|
|
}
|
|
|
|
#if defined(DOSPLUS)
|
|
|
|
GLOBAL VOID inherit_batch_file(bc)
|
|
BCONTROL FAR *bc;
|
|
{
|
|
WORD i;
|
|
BYTE FAR *p_heap;
|
|
BYTE *l_heap;
|
|
|
|
/* inherit any parent batch file first */
|
|
if (bc->bcontrol) inherit_batch_file(bc->bcontrol);
|
|
|
|
/* create a new batch structure */
|
|
batch_new();
|
|
|
|
batch->offset = bc->offset; /* continue at same offset */
|
|
for (i=0;i<4;i++) batch->ret_offset[i] = bc->ret_offset[i];
|
|
batch->batshift = bc->batshift;
|
|
|
|
for (i=0; i<MAX_PATHLEN; i++) /* get the batch pathname */
|
|
batch->batfile[i] = bc->batfile[i];
|
|
batch->batfile[MAX_PATHLEN-1] = 0;
|
|
|
|
/* get command line */
|
|
|
|
p_heap = MK_FP(*parent_psp+16,bc->batcmd);
|
|
l_heap = heap();
|
|
|
|
while (1) {
|
|
while(*p_heap) *l_heap++ = *p_heap++;
|
|
*l_heap++ = *p_heap++;
|
|
if (*p_heap == 0) {
|
|
*l_heap = 0;
|
|
break;
|
|
}
|
|
}
|
|
heap_get(l_heap-heap());
|
|
|
|
batchflg++;
|
|
}
|
|
|
|
|
|
GLOBAL VOID inherit_parent_state()
|
|
{
|
|
UWORD FAR *p;
|
|
BCONTROL FAR *bc;
|
|
UWORD root_psp;
|
|
|
|
root_psp = *parent_psp;
|
|
while(1) {
|
|
p = MK_FP(root_psp-1,8);
|
|
if (p[0] == 0x4F43 && p[1] == 0x4D4D &&
|
|
p[2] == 0x4E41 && p[3] == 0x0044) break;
|
|
|
|
p = MK_FP(root_psp,0x16);
|
|
root_psp = *p;
|
|
}
|
|
|
|
|
|
p = MK_FP(root_psp+16,batch_seg_ptr);
|
|
#if 0
|
|
printf("batch_seg_ptr = %04X:%04X\n",p);
|
|
printf("parent batch_seg_ptr = %04X\n",*p);
|
|
#endif
|
|
if (*p == 0 || *p == 0xFFFF) return;
|
|
|
|
bc = MK_FP(*p,0);
|
|
|
|
inherit_batch_file(bc);
|
|
|
|
*p = 0;
|
|
|
|
p = MK_FP(root_psp+16,&echoflg);
|
|
echoflg = *p;
|
|
}
|
|
#endif
|
|
|
|
GLOBAL VOID batch_new()
|
|
/* save current batch file heap contexts to high memory */
|
|
{
|
|
BYTE *hp_start;
|
|
WORD hp_size;
|
|
UWORD i;
|
|
BCONTROL FAR *bc;
|
|
#if defined(CDOSTMP)
|
|
UWORD FAR *ptr;
|
|
#endif
|
|
|
|
if (batchflg != 0)
|
|
hp_start = batch->heap_start;
|
|
else
|
|
hp_start = heap();
|
|
|
|
hp_size = heap() - hp_start;
|
|
|
|
i = (sizeof(BCONTROL) + hp_size + 15)/16;
|
|
mem_alloc(&bc, &i, i, i); /* allocate new batch structure */
|
|
|
|
if (i == 0) { /* if we can't allocate one */
|
|
longjmp(break_env, IA_HEAP);/* then pretend heap has run out*/
|
|
} /* to force termination. */
|
|
|
|
bc->bcontrol = batch; /* Link to Previous Structure */
|
|
batch = bc; /* make this current batch struc*/
|
|
batch->eof = NO; /* Have not found the EOF yet */
|
|
batch->offset = 0L; /* start at beginning of File */
|
|
for (i=0;i<4;i++) batch->ret_offset[i] = 0L;
|
|
batch->batshift = 0; /* No Shift Factor */
|
|
batch->stream = CLOSED; /* Batch file is not open */
|
|
batch->fcontrol = forptr; /* Save current FOR control */
|
|
batch->heap_start = hp_start; /* Save original heap */
|
|
batch->heap_size = hp_size;
|
|
|
|
for (i=0; i < hp_size; i++) {
|
|
batch->save_area[i] = hp_start[i];
|
|
}
|
|
|
|
heap_set(hp_start); /* free up heap used by old batch */
|
|
|
|
#if defined(CDOSTMP)
|
|
ptr = MK_FP(pd->P_PSP, TmpPspEchoFlgPtr);
|
|
*ptr = (UWORD)&echoflg;
|
|
ptr = (UWORD FAR *) &ptr; /* coerce a FAR * to local data */
|
|
i = FP_SEG(ptr); /* so we can get local data segment */
|
|
ptr = MK_FP(pd->P_PSP, TmpPspDataSeg);
|
|
*ptr = i; /* save local data segment */
|
|
ptr = MK_FP(pd->P_PSP, TmpPspBatchSeg);
|
|
*ptr = (UWORD)(((ULONG)batch) >> 16);
|
|
#else
|
|
/* Get segment address of batch and put it where novell */
|
|
/* can find it. */
|
|
|
|
*batch_seg_ptr = (UWORD)(((ULONG)batch) >> 16);
|
|
#endif
|
|
}
|
|
|
|
|
|
MLOCAL VOID batch_old()
|
|
/* restore current batch file heap contents from high memory */
|
|
{
|
|
BCONTROL FAR *bc;
|
|
UWORD i;
|
|
#if defined(CDOSTMP)
|
|
UWORD FAR *ptr;
|
|
#endif
|
|
|
|
heap_set(batch->heap_start+batch->heap_size);
|
|
for (i=0; i<batch->heap_size; i++) {
|
|
batch->heap_start[i] = batch->save_area[i];
|
|
}
|
|
bc = batch;
|
|
forptr = batch->fcontrol; /* Restore the previous for */
|
|
for_flag = (BOOLEAN) forptr; /* control structures */
|
|
batch = batch->bcontrol; /* restore ptr to previous batch */
|
|
mem_free(&bc); /* free up batch memory */
|
|
#if defined(CDOSTMP)
|
|
ptr = MK_FP(pd->P_PSP, TmpPspBatchSeg);
|
|
*ptr = (UWORD)(((ULONG)batch) >> 16);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Read lines repeatedly from the batch file until a line in
|
|
* the correct format is read from the batch file or the EOF
|
|
* has been reached.
|
|
*/
|
|
MLOCAL VOID batch_read(line, goto_flg)
|
|
BYTE *line; /* Command Line Buffer */
|
|
BOOLEAN goto_flg; /* Goto Command Flag */
|
|
{
|
|
BYTE *l; /* we need to deblank line */
|
|
do {
|
|
batch_line(line, goto_flg); /* Read the next line from */
|
|
l = deblank(line); /* the batch file and return*/
|
|
if(*l != ';') {
|
|
if(goto_flg && *l == ':') /* a line in the correct */
|
|
return; /* format. */
|
|
|
|
if(!goto_flg && *l != ':')
|
|
return;
|
|
}
|
|
} while(!batch->eof);
|
|
}
|
|
|
|
/*
|
|
* Read one line from the batch file and place the expanded data into
|
|
* the buffer LINE.
|
|
*/
|
|
MLOCAL VOID batch_line(line, goto_flg)
|
|
BYTE *line; /* Command Line Buffer */
|
|
BOOLEAN goto_flg; /* Goto Command Flag */
|
|
{
|
|
REG WORD i;
|
|
REG BYTE *s;
|
|
WORD n, env_start;
|
|
BYTE c, *bp;
|
|
BYTE env_str[128];
|
|
BOOLEAN quote = FALSE;
|
|
LONG old_offset;
|
|
int j;
|
|
|
|
env_start = NULL; /* Copy the environment into a */
|
|
|
|
#if 0
|
|
/* 'eject any line starting with 'rem' */
|
|
old_offset = batch->offset;
|
|
i=0;
|
|
do{
|
|
switch(c=*batch_ptr()){
|
|
case 0x1a:
|
|
batch->eof = YES; /* We have come to the end */
|
|
c = '\r'; /* of the batch file so set */
|
|
break; /* flag and mark end of line*/
|
|
default:
|
|
if (i < MAX_LINE)
|
|
line[i++] = c;
|
|
if (dbcs_lead(c)) {
|
|
if ((c = *batch_ptr()) >= ' ' && i < MAX_LINE)
|
|
line[i++] = c;
|
|
}
|
|
}/*switch*/
|
|
}while(c!='\r');
|
|
|
|
if (*batch_ptr() != '\n') batch->offset--;
|
|
line[i]=0;
|
|
j=0;
|
|
while(line[j]){
|
|
if (line[j] != ' ')
|
|
break;
|
|
j++;
|
|
}
|
|
if (( strlwr(line[j]) == 'r') &&
|
|
( strlwr(line[j+1]) == 'e') &&
|
|
( strlwr(line[j+2]) == 'm') &&
|
|
( strlwr(line[j+3]) == ' ')){
|
|
if (echoflg)
|
|
printf("%s\n",line);
|
|
line[0]='\0';
|
|
return;
|
|
}
|
|
|
|
batch->offset = old_offset;
|
|
batch->eof = NO;
|
|
|
|
#endif
|
|
/*rbf-end*/
|
|
|
|
/* process line */
|
|
i = 0;
|
|
do {
|
|
switch(c = *batch_ptr()) {
|
|
case '\0': /* In OS/2 install.bat file */
|
|
#if 0
|
|
if (i < MAX_LINE) /* "ECHO \0" displays blank */
|
|
line[i++] = '\r'; /* line - so we insert a CR */
|
|
while (c != '\r') { /* then swallow rest of line */
|
|
c = *batch_ptr(); /* read next character - if */
|
|
if (c == 0x1a) /* it's an EOF mark then use */
|
|
goto end_of_file; /* end-of-file code else end */
|
|
} /* up falling into '\r' code */
|
|
#else
|
|
c = *batch_ptr();
|
|
if ((c == '\r') && (i < MAX_LINE))
|
|
line[i++] = '\r';
|
|
#endif
|
|
|
|
case '\r': /* carriage return */
|
|
if(*batch_ptr() != '\n') /* skip line feed */
|
|
batch->offset--; /* if present */
|
|
break;
|
|
|
|
case '"': /* Support Quoted strings */
|
|
quote = !quote; /* in batch files. */
|
|
goto save_it;
|
|
|
|
case PIPE_CHAR: /* Handle Piped Output */
|
|
if(goto_flg || quote) /* Ignore this character if */
|
|
goto save_it; /* we are searching for a */
|
|
/* Label or Quote. */
|
|
line[i] = '\0';
|
|
c = *deblank(line); /* normal case we just */
|
|
if ((c !='\0') && (c != ':') && following_command()) {
|
|
c = '\r'; /* simulate a CR and set */
|
|
pipe_out = YES; /* Pipe Output flag. */
|
|
} else if (c == ':') { /* if it's a label */
|
|
for(;(c != '\r') && (c != 0x1A); c = *batch_ptr())
|
|
if (c == 0x1A) /* eat rest of the line */
|
|
batch->eof = YES;
|
|
if(*batch_ptr() != '\n')/* skip line feed */
|
|
batch->offset--; /* if present */
|
|
c = '\r';
|
|
} else { /* if it's a syntax error */
|
|
swallow_line(line); /* discard the rest of line */
|
|
i = 0; /* start again with new line */
|
|
}
|
|
break;
|
|
|
|
case '%': /* The following code checks to see if the */
|
|
/* string starting at line[env_start-1] is */
|
|
/* define in the environment if it is then */
|
|
/* its definition replaces it in the input */
|
|
/* line. Otherwise no change is made. */
|
|
if(env_start) {
|
|
env_start--;
|
|
line[i] = '\0'; /* Terminate Input */
|
|
strcpy(env_str, line+env_start);/* Copy the String */
|
|
strupr(env_str); /* and force string */
|
|
bp = (BYTE *)heap(); /* into Uppercase */
|
|
i = env_start;
|
|
env_start = NULL;
|
|
|
|
strcat(env_str,"=");
|
|
if (env_scan(env_str,bp)) {
|
|
if (novell_extension(env_str,bp)) break;
|
|
}
|
|
|
|
while(*bp && i < MAX_LINE-1)
|
|
line[i++] = *bp++;
|
|
break;
|
|
}
|
|
|
|
c = *batch_ptr();
|
|
if (c == '\r') {
|
|
batch->offset--; /* rewind to point to '\r' */
|
|
break; /* then break to normal code */
|
|
}
|
|
if (c < '0' || c > '9') { /* if not a parameter */
|
|
if(c != '%') /* or a '%' character */
|
|
env_start = i+1; /* save its start address in */
|
|
goto save_it; /* the string and wait for */
|
|
} /* the terminating '%' */
|
|
|
|
n = c - '0' + batch->batshift; /* get parameter # 0-9 and */
|
|
/* add in SHIFT offset */
|
|
s = batch->batcmd;
|
|
while(n-- && strlen(s)) /* skip all other parameters */
|
|
s += strlen(s)+1; /* before the one we want */
|
|
|
|
if((strlen(s) + i) >= MAX_LINE) /* Break if Greater than MAX_LINE*/
|
|
break;
|
|
strcpy (line + i, s); /* get the substitution */
|
|
i += strlen (s); /* add in its size */
|
|
break;
|
|
|
|
case 0x1a:
|
|
end_of_file:
|
|
batch->eof = YES; /* We have come to the end */
|
|
c = '\r'; /* of the batch file so set */
|
|
break; /* flag and mark end of line*/
|
|
|
|
default:
|
|
save_it:
|
|
if (i < MAX_LINE)
|
|
line[i++] = c;
|
|
if (dbcs_lead(c)) {
|
|
if ((c = *batch_ptr()) >= ' ' && i < MAX_LINE)
|
|
line[i++] = c;
|
|
}
|
|
}
|
|
} while (c != '\r'); /* repeat until CR */
|
|
|
|
line[i] = '\0'; /* Terminate the line and */
|
|
|
|
if(batch->eof)
|
|
return;
|
|
|
|
#if 0 /* not DOS compatible */
|
|
if(*batch_ptr() == 0x1A) /* Check if the next this */
|
|
batch->eof = YES; /* the end of the file if */
|
|
else /* YES then set the flag */
|
|
batch->offset--; /* force the character to */
|
|
#endif /* be re-read next time */
|
|
return; /* return to the caller */
|
|
}
|
|
|
|
MLOCAL BOOLEAN following_command()
|
|
/* return true if we have a possible command on the rest of the line */
|
|
{
|
|
LONG old_offset;
|
|
BOOLEAN res = FALSE;
|
|
BYTE *s;
|
|
|
|
old_offset = batch->offset; /* save batch offset */
|
|
while (TRUE) {
|
|
s = batch_ptr(); /* look ahead at batch file */
|
|
if (*s == '\r' || *s == 0x1a || (!dbcs_lead(*s) && *s == PIPE_CHAR))
|
|
break;
|
|
if (!is_blank(s)) {
|
|
res = TRUE; /* possible command if we */
|
|
break; /* hit non whitespace char */
|
|
}
|
|
if (dbcs_lead(*s)) {
|
|
s = batch_ptr();
|
|
if (*s == '\r' || *s == 0x1a)
|
|
break;
|
|
}
|
|
}
|
|
batch->offset = old_offset; /* restore batch offset */
|
|
return res;
|
|
}
|
|
|
|
MLOCAL VOID swallow_line(s)
|
|
BYTE *s;
|
|
/* there is a syntax error on this line - swallow it and say so */
|
|
{
|
|
BYTE c;
|
|
|
|
prompt(); /* possibly echo the prompt */
|
|
if (echoflg) /* echo to screen if wanted */
|
|
printf("%s%c",s,PIPE_CHAR);
|
|
|
|
do {
|
|
c = *batch_ptr();
|
|
if (c == 0x1a) {
|
|
c = '\r'; /* pretend to be end of line*/
|
|
batch->eof = YES; /* We have come to the end */
|
|
break; /* flag and mark end of line*/
|
|
}
|
|
if (echoflg) /* echo to screen if wanted */
|
|
putc(c);
|
|
} while (c != '\r');
|
|
if (echoflg)
|
|
putc('\n');
|
|
|
|
if (*batch_ptr() != '\n') /* skip line feed */
|
|
batch->offset--; /* if present */
|
|
|
|
eprintf(MSG_SYNTAX); /* report syntax error */
|
|
}
|
|
|
|
/*
|
|
* In order to improve performance of the batch file processing
|
|
* the Batch file is read in blocks of BATCH_BUF characters.
|
|
* and the routine BATCH_CHAR then returns a pointer to a character
|
|
* from the buffer (filling the buffer if required).
|
|
*/
|
|
MLOCAL BYTE *batch_ptr()
|
|
{
|
|
BYTE FAR *buf;
|
|
UWORD bufsize;
|
|
UWORD i;
|
|
|
|
if(batch->eof)
|
|
return(batch_eof);
|
|
|
|
if (batch->offset < batch_off ||
|
|
batch->offset >= (batch_off + (LONG) (batch_cnt - 1))) {
|
|
|
|
batch_off = batch->offset;
|
|
ms_x_lseek (batch->stream, batch->offset, 0);
|
|
batch_cnt = far_read(batch->stream, gp_far_buff, sizeof(batch_buf));
|
|
if(batch_cnt <= 0) {
|
|
batch->eof = YES;
|
|
return(batch_eof);
|
|
}
|
|
for (i=0; i<sizeof(batch_buf); i++) batch_buf[i] = gp_far_buff[i];
|
|
}
|
|
return(&batch_buf[(UWORD) (batch->offset++ - batch_off)]);
|
|
}
|
|
|
|
|
|
/*.pa*/
|
|
/*
|
|
* BATCH FILE COMMANDS
|
|
* ===================
|
|
*
|
|
* The following commands are used almost entirely in BATCH files and
|
|
* have little or no meaning outside that environment.
|
|
*/
|
|
GLOBAL VOID CDECL cmd_shift ()
|
|
{
|
|
batch->batshift++; /* Increment the Shift Offset */
|
|
}
|
|
|
|
|
|
MLOCAL WORD label_ignore_char(s)
|
|
BYTE *s;
|
|
{
|
|
if (*s == '=') return(1);
|
|
if (*s == ';') return(1);
|
|
if (*s == ',') return(1);
|
|
if (*s == ' ') return(1);
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Extract the first a valid characters from the label and then
|
|
* zero terminate the resulting string.
|
|
*/
|
|
MLOCAL BYTE * make_label(label)
|
|
BYTE *label;
|
|
{
|
|
REG BYTE *bp;
|
|
UWORD i;
|
|
|
|
label = deblank(label); /* remove leading white space */
|
|
while (label_ignore_char(label))
|
|
label = skip_char(label);
|
|
|
|
bp = label;
|
|
|
|
while (is_filechar(bp)) /* skip over valid chars */
|
|
bp = skip_char(bp);
|
|
|
|
*bp = '\0'; /* make label zero terminated */
|
|
return label;
|
|
}
|
|
|
|
GLOBAL VOID CDECL cmd_goto (label) /* goto label in batch file */
|
|
REG BYTE *label;
|
|
{
|
|
UWORD i;
|
|
BYTE *bp, s[MAX_LINE+2]; /* Allocate buffer for Batch Input */
|
|
|
|
if (!batchflg) /* if not in batch mode */
|
|
return; /* this command is ignored */
|
|
|
|
if(*label == ':') /* Ignore any leading ':' */
|
|
label++;
|
|
|
|
label = make_label(label); /* Convert to Label Format */
|
|
|
|
batch->offset = 0L; /* rewind the batch file */
|
|
batch->eof = NO; /* So it cannot be EOF */
|
|
|
|
if(!batch_open()) /* Check the Batch file is open */
|
|
return; /* and stop if the function fails. */
|
|
|
|
while(!batch->eof) { /* while not end of file read next */
|
|
batch_read(s, YES); /* line and return the next command */
|
|
bp = deblank(s);
|
|
if((*bp == ':') && !strnicmp(make_label(bp+1),label, 8))
|
|
return;
|
|
}
|
|
|
|
batch_end(); /* Stop any further batch file */
|
|
crlfflg = YES; /* processing and print the error */
|
|
eprintf(MSG_LABEL, label);
|
|
}
|
|
|
|
|
|
GLOBAL VOID CDECL cmd_gosub (label) /* gosub label in batch file */
|
|
REG BYTE *label;
|
|
{
|
|
UWORD i;
|
|
BYTE *bp, s[MAX_LINE+2]; /* Allocate buffer for Batch Input */
|
|
|
|
if (!batchflg) /* if not in batch mode */
|
|
return; /* this command is ignored */
|
|
|
|
if (batch->ret_offset[3] != 0L) {
|
|
batch_end();
|
|
crlfflg = YES;
|
|
eprintf(MSG_GOSUB);
|
|
return;
|
|
}
|
|
|
|
if(*label == ':') /* Ignore any leading ':' */
|
|
label++;
|
|
|
|
label = make_label(label); /* Convert to Label Format */
|
|
|
|
i = 0;
|
|
while (batch->ret_offset[i] != 0L) i++;
|
|
batch->ret_offset[i] = batch->offset;
|
|
|
|
batch->offset = 0L; /* rewind the batch file */
|
|
batch->eof = NO; /* So it cannot be EOF */
|
|
|
|
if(!batch_open()) /* Check the Batch file is open */
|
|
return; /* and stop if the function fails. */
|
|
|
|
while(!batch->eof) { /* while not end of file read next */
|
|
batch_read(s, YES); /* line and return the next command */
|
|
bp = deblank(s);
|
|
if((*bp == ':') && !strnicmp(make_label(bp+1),label, 8))
|
|
return;
|
|
}
|
|
|
|
batch_end(); /* Stop any further batch file */
|
|
crlfflg = YES; /* processing and print the error */
|
|
eprintf(MSG_LABEL, label);
|
|
}
|
|
|
|
GLOBAL VOID CDECL cmd_return()
|
|
{
|
|
UWORD i;
|
|
|
|
if (!batchflg) return;
|
|
if (batch->ret_offset[0] == 0L) {
|
|
batch_end();
|
|
crlfflg = YES;
|
|
eprintf(MSG_RETURN);
|
|
return;
|
|
}
|
|
i = 0;
|
|
while ((batch->ret_offset[i] != 0L)&&(i<4)) i++;
|
|
batch->offset = batch->ret_offset[i-1];
|
|
batch->ret_offset[i-1] = 0L;
|
|
}
|
|
|
|
#if SWITCH_ENABLED
|
|
GLOBAL VOID CDECL cmd_switch(list)
|
|
REG BYTE *list;
|
|
{
|
|
BYTE *list_start;
|
|
BYTE *label;
|
|
WORD i,j;
|
|
BYTE c;
|
|
|
|
if (!batchflg) return;
|
|
list_start = list;
|
|
|
|
switch_retry:
|
|
list = list_start;
|
|
i = psp_poke(STDIN,1);
|
|
|
|
#if defined(CDOSTMP)
|
|
c =(BYTE) bdos(C_RAWIO, 0xFD); /* Get a character from console */
|
|
|
|
if ((c==0) ||(dbcs_lead(c)))
|
|
bdos(C_RAWIO, 0xFD); /* skip second byte in DBCS pair */
|
|
#else
|
|
c = (BYTE) msdos(MS_C_RAWIN, 0);/* Get a character from console */
|
|
if ((c==0) || (dbcs_lead(c)))
|
|
msdos(MS_C_RAWIN, 0); /* skip second byte in DBCS pair */
|
|
#endif
|
|
psp_poke(STDIN,i);
|
|
|
|
if (c==0x03) int_break(); /* check for CTRL-C */
|
|
if (c==0x0d) c = '1'; /* return gives default of 1 */
|
|
|
|
i = (WORD) (c - '1');
|
|
if (i<0 || i>8) goto switch_retry; /* ignore invalid keys */
|
|
|
|
j = 0;
|
|
while (j<i) {
|
|
while (*list != ',' && *list != 0) list++;
|
|
if (*list == 0) goto switch_retry;
|
|
j++;
|
|
list++;
|
|
list = deblank(list);
|
|
}
|
|
label = list;
|
|
while (*list != ',' && *list != 0) list++;
|
|
*list = 0;
|
|
cmd_gosub(label);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*.pa*/
|
|
/*
|
|
* The IF command supports the following syntax:-
|
|
*
|
|
* IF [NOT] string1 == string2 COMMAND
|
|
* IF [NOT] ERRORLEVEL n COMMAND
|
|
* IF [NOT] EXIST filename COMMAND
|
|
/*RG-02-
|
|
* IF [NOT] USERID n COMMAND
|
|
* IF [NOT] LOGINNAME string COMMAND
|
|
* IF [NOT] GROUPNAME string COMMAND
|
|
* IF [NOT] KEY ["string"] char COMMAND
|
|
*
|
|
*/
|
|
#if defined(CDOSTMP) || defined(CDOS)
|
|
MLOCAL BYTE *if_opt[] = {"exist", "direxist", "errorlevel", "key", "userid", "loginname", "groupname", NULL };
|
|
#else
|
|
MLOCAL BYTE *if_opt[] = {"exist", "direxist", "errorlevel", NULL };
|
|
#endif
|
|
/*RG-02-end*/
|
|
|
|
MLOCAL UWORD if_index(cmd)
|
|
BYTE **cmd;
|
|
{
|
|
UWORD i, j;
|
|
|
|
for(i = 0; if_opt[i]; i++) { /* Scan Through the option */
|
|
j = strlen(if_opt[i]); /* list and return the index */
|
|
/* of the matching option */
|
|
if(strnicmp(*cmd, if_opt[i], j)) /* and update the string */
|
|
continue; /* pointer. */
|
|
*cmd = deblank(*cmd+j);
|
|
|
|
while(*(*cmd) == '=') /* Remove any "=" string */
|
|
(*cmd)++; /* present in the command */
|
|
*cmd = deblank(*cmd); /* Used by many install files*/
|
|
break;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
#define OP_EQ 0
|
|
#define OP_NE 1
|
|
#define OP_LE 2
|
|
#define OP_LT 3
|
|
#define OP_GE 4
|
|
#define OP_GT 5
|
|
|
|
MLOCAL WORD get_operator(op)
|
|
BYTE *op;
|
|
{
|
|
if (op[0] == '=') return(OP_EQ);
|
|
if (op[0] == '!' && op[1] == '=') return(OP_NE);
|
|
if (op[0] == '<') {
|
|
if (op[1] == '>') return(OP_NE);
|
|
if (op[1] == '=') return(OP_LE);
|
|
return(OP_LT);
|
|
}
|
|
if (op[0] == '>') {
|
|
if (op[1] == '=') return(OP_GE);
|
|
return(OP_GT);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
MLOCAL LONG get_decimal(s)
|
|
BYTE *s;
|
|
{
|
|
LONG total = 0;
|
|
|
|
if (*s == '#') s++;
|
|
|
|
while (*s>='0' && *s<='9') {
|
|
total *= 10;
|
|
total += (LONG) (*s-'0');
|
|
s++;
|
|
}
|
|
|
|
return(total);
|
|
}
|
|
|
|
MLOCAL BOOLEAN CDECL test_cond(cptr)
|
|
BYTE **cptr;
|
|
{
|
|
BYTE *cmd,*str1, *str2, *ptr;
|
|
DTA search;
|
|
BOOLEAN not, cond, neg,is_user;
|
|
BYTE level;
|
|
BYTE c[]=" \n";
|
|
WORD attr;
|
|
UWORD userid;
|
|
LONG val1,val2;
|
|
|
|
cmd=*cptr;
|
|
not = cond = NO; /* Initialise the Flags */
|
|
|
|
if(!strnicmp(cmd = deblank(cmd), "not", 3)) {
|
|
not = YES;
|
|
cmd = deblank(cmd+3);
|
|
}
|
|
|
|
switch(if_index(&cmd)) {
|
|
|
|
/*
|
|
* EXIST Option extract the possibly ambiguous filename
|
|
* and check if it exists.
|
|
*/
|
|
case 0:
|
|
cmd = deblank(get_filename(heap(), cmd, YES));
|
|
cond = !ms_x_first(heap(), ATTR_STD|ATTR_HID, &search);
|
|
break;
|
|
|
|
/*
|
|
* DIREXIST Option checks if the given directory exists
|
|
*/
|
|
case 1:
|
|
cmd = deblank(get_filename(heap(), cmd, YES));
|
|
attr = ms_x_chmod(heap(), ATTR_ALL, 0);
|
|
if (attr < 0) cond = FALSE;
|
|
else cond = (attr & 0x10);
|
|
break;
|
|
|
|
/*
|
|
* ERRORLEVEL Option extract the decimal number from the
|
|
* command line.
|
|
*/
|
|
case 2:
|
|
level = 0;
|
|
neg = FALSE;
|
|
|
|
if(*cmd =='-') {
|
|
neg = TRUE;
|
|
cmd++;
|
|
}
|
|
|
|
if(!isdigit(*cmd)) { /* SYNTAX error if the */
|
|
syntax(); /* first character is not a */
|
|
return FALSE; /* digit. */
|
|
}
|
|
|
|
while(isdigit(*cmd))
|
|
level = level * 10 + (*cmd++ - '0');
|
|
|
|
level = level & 0x00FF;
|
|
|
|
if (neg) level = -level;
|
|
|
|
cond = (level<=(err_ret & 0x00FF));
|
|
break;
|
|
|
|
|
|
/*RG-02*/
|
|
#if !defined(NOXBATCH)
|
|
#if (defined(CDOSTMP) || defined(CDOS))
|
|
/*
|
|
* KEY ["string"] [==] [""] Search for the string "string" and
|
|
* display it if it exists, then read a key and echo it.
|
|
* However, if the string to match is null "" then do a keyboard
|
|
* status check and return TRUE if there is no key there
|
|
*/
|
|
case 3:
|
|
cmd = deblank(cmd);
|
|
ptr=cmd;
|
|
if (display_string(&ptr)!=0)
|
|
return FALSE;
|
|
|
|
cmd = deblank(ptr);
|
|
while(*cmd == '=') /* Remove any "=" string */
|
|
cmd++;
|
|
|
|
cmd = deblank(cmd);
|
|
if ((*cmd==0)||(*(cmd+1)!=' ')) { /* check for condition */
|
|
syntax();
|
|
return FALSE;
|
|
}
|
|
|
|
/* read a character from the keyboard */
|
|
c[0]=bdos(C_RAWIO, 0xFD); /* Get a character from console */
|
|
|
|
/* echo the char typed */
|
|
if (echoflg) /* echo to screen if wanted */
|
|
putc(c[0]);
|
|
crlf(); /* print cr/lf */
|
|
|
|
/* check if it matches */
|
|
if((tolower(c[0])==*cmd)||(toupper(c[0])==*cmd))
|
|
cond=TRUE;
|
|
else
|
|
cond=FALSE;
|
|
|
|
/* skip the condition */
|
|
while (*cmd!=' ')
|
|
cmd++; /* skip the char */
|
|
|
|
break;
|
|
|
|
#endif
|
|
#if !defined (NOSECURITY) && (defined(CDOSTMP) || defined(CDOS))
|
|
/*
|
|
* USERID Option extract the 4 digit hex user id
|
|
* and check if it is us.
|
|
*/
|
|
case 4:
|
|
if (!login_enabled())
|
|
return FALSE;
|
|
cmd = deblank(cmd);
|
|
if(aschextobin(cmd)==get_user_on_station())
|
|
cond=TRUE;
|
|
else
|
|
cond=FALSE;
|
|
|
|
do { /* skip past the user id */
|
|
if ((*cmd>='0' && *cmd<='9')
|
|
||(tolower(*cmd)>='a' && tolower(*cmd)<='f'))
|
|
cmd++; /* skip the hex digit */
|
|
else {
|
|
syntax();
|
|
return FALSE;
|
|
}
|
|
} while (*cmd!=' ');
|
|
break;
|
|
|
|
/*
|
|
* LOGINNAME Option extract the loginname and check if it is us.
|
|
*/
|
|
case 5:
|
|
if (!login_enabled())
|
|
return FALSE;
|
|
is_user=TRUE;
|
|
|
|
/*
|
|
* GROUPNAME Option extract the loginname and check if it is us.
|
|
*/
|
|
case 6:
|
|
if (!login_enabled())
|
|
return FALSE;
|
|
cmd = deblank(cmd);
|
|
if(aschextobin(user_info.userid)!=get_user_on_station()) {
|
|
if(get_user_info(get_user_on_station())!=0) {
|
|
syntax();
|
|
is_user=cond=FALSE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
if((is_user==TRUE)&&(strncmp(strlwr(cmd),strlwr(user_info.loginname),strlen(user_info.loginname))==0)) {
|
|
cond=TRUE;
|
|
cmd+=strlen(user_info.loginname);
|
|
}
|
|
else if((is_user!=TRUE)&&(strncmp(strlwr(cmd),strlwr(user_info.groupname),strlen(user_info.groupname))==0)) {
|
|
cond=TRUE;
|
|
cmd+=strlen(user_info.groupname);
|
|
}
|
|
else {
|
|
cond=FALSE;
|
|
while (*cmd!=' ')
|
|
cmd++; /* skip the name */
|
|
}
|
|
if (*cmd!=' ') {
|
|
is_user=cond=FALSE;
|
|
}
|
|
is_user=FALSE;
|
|
break;
|
|
|
|
#endif
|
|
#endif /*NOXBATCH*/
|
|
/*RG-02-end*/
|
|
/*
|
|
* String comparison option.
|
|
*/
|
|
default:
|
|
str1 = cmd; /* Extract String 1 */
|
|
|
|
while ((!is_blank(cmd)) && (*cmd != '=') &&
|
|
((*cmd != '!') || (cmd[1]!= '=')) &&
|
|
(*cmd != '<') && (*cmd != '>')) {
|
|
|
|
cmd = skip_char(cmd);
|
|
}
|
|
|
|
str2 = cmd;
|
|
cmd = deblank(cmd);
|
|
|
|
attr = get_operator(cmd++);
|
|
|
|
if (attr == -1) {
|
|
syntax();
|
|
return(FALSE);
|
|
}
|
|
|
|
*str2 = 0;
|
|
|
|
if (*cmd == '=' || *cmd == '>') cmd++;
|
|
|
|
cmd = deblank(cmd);
|
|
str2 = cmd;
|
|
while (!is_blank(cmd)) cmd = skip_char(cmd);
|
|
*cmd++ = 0;
|
|
|
|
if (*str1 == '#') {
|
|
val1 = get_decimal(str1);
|
|
val2 = get_decimal(str2);
|
|
switch(attr) {
|
|
case OP_EQ: cond = (val1==val2); break;
|
|
case OP_NE: cond = (val1!=val2); break;
|
|
case OP_LT: cond = (val1<val2); break;
|
|
case OP_LE: cond = (val1<=val2); break;
|
|
case OP_GT: cond = (val1>val2); break;
|
|
case OP_GE: cond = (val1>=val2); break;
|
|
}
|
|
}
|
|
else switch(attr) {
|
|
case OP_EQ:
|
|
cond = (strcmp(str1,str2) == 0);
|
|
break;
|
|
case OP_NE:
|
|
cond = (strcmp(str1,str2) != 0);
|
|
break;
|
|
case OP_LT:
|
|
cond = (strcmp(str1,str2) < 0);
|
|
break;
|
|
case OP_LE:
|
|
cond = (strcmp(str1,str2) <= 0);
|
|
break;
|
|
case OP_GT:
|
|
cond = (strcmp(str1,str2) > 0);
|
|
break;
|
|
case OP_GE:
|
|
cond = (strcmp(str1,str2) >= 0);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(not) /* if negated condition */
|
|
cond = !cond;
|
|
|
|
*cptr=cmd;
|
|
return cond; /* write result back */
|
|
}
|
|
|
|
#if !defined(NOXBATCH)
|
|
BOOLEAN is_it_or(BYTE *cmd)
|
|
{
|
|
cmd--;
|
|
if ((*cmd != 0) && (*cmd != '\t') && (*cmd != ' '))
|
|
return FALSE;
|
|
cmd++;
|
|
if (strnicmp(cmd, "or", 2) != 0)
|
|
return FALSE;
|
|
cmd+=2;
|
|
if ((*cmd != '\t') && (*cmd != ' '))
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
GLOBAL VOID CDECL cmd_if(cmd)
|
|
BYTE *cmd;
|
|
{
|
|
BOOLEAN cond;
|
|
|
|
ifcond=cond=test_cond(&cmd);
|
|
|
|
if(!*deblank(cmd)) { /* and return a SYNTAX error*/
|
|
syntax(); /* if it is empty. */
|
|
return;
|
|
}
|
|
if(!cond) {
|
|
#if !defined(NOXBATCH)
|
|
while (!is_it_or(cmd) &&
|
|
(*cmd != 0)) {
|
|
if (strnicmp(cmd,"ECHO",4)==0) return;
|
|
cmd++;
|
|
}
|
|
if (*cmd==0) return; /* no OR's so quit now */
|
|
|
|
if_context = TRUE;
|
|
|
|
docmd(deblank(cmd), YES); /* New command starts at "or" */
|
|
|
|
#endif
|
|
}
|
|
else {
|
|
cmd = deblank(cmd);
|
|
|
|
if (strnicmp(cmd,"AND",3)) {
|
|
if (parse(cmd)) return; /* IF won't have been 'parsed' for */
|
|
/* > or < redirectors so do it now */
|
|
}
|
|
|
|
if_context = TRUE;
|
|
/* Execute command if the */
|
|
docmd(cmd, YES); /* condition flag is TRUE */
|
|
}
|
|
if_context=FALSE;
|
|
}
|
|
|
|
/*RG-03*/
|
|
#if !defined(NOXBATCH)
|
|
GLOBAL VOID CDECL cmd_or(cmd)
|
|
BYTE *cmd;
|
|
{
|
|
BOOLEAN cond;
|
|
BYTE *org_cmd;
|
|
|
|
cond=test_cond(&cmd);
|
|
if(!*deblank(cmd)) { /* and return a SYNTAX error*/
|
|
syntax(); /* if it is empty. */
|
|
return;
|
|
}
|
|
if(!cond) {
|
|
org_cmd = cmd; /* now look for "OR" */
|
|
while (!is_it_or(cmd) &&
|
|
(*cmd != 0)) {
|
|
if (strnicmp(cmd,"ECHO",4)==0) while(*cmd) cmd++;
|
|
else cmd++;
|
|
}
|
|
if (*cmd==0) { /* oh dear, no ORs */
|
|
if (ifcond) /* but so far so good, so do command anyway */
|
|
docmd(deblank(org_cmd), YES);
|
|
return;
|
|
}
|
|
docmd(deblank(cmd), YES); /* New command starts at "or" */
|
|
return;
|
|
}
|
|
else {
|
|
cmd = deblank(cmd);
|
|
|
|
if (strnicmp(cmd,"AND",3)) {
|
|
if (parse(cmd)) return; /* IF won't have been 'parsed' for */
|
|
/* > or < redirectors so do it now */
|
|
}
|
|
|
|
ifcond=cond; /* Execute command if the */
|
|
docmd(cmd, YES); /* condition flag is TRUE */
|
|
}
|
|
}
|
|
#endif /*NOXBATCH*/
|
|
/*RG-03-end*/
|
|
|
|
|
|
GLOBAL VOID CDECL cmd_for(s)
|
|
BYTE *s;
|
|
{
|
|
FCONTROL *fc;
|
|
BYTE *bp1;
|
|
|
|
fc = (FCONTROL *) heap_get(sizeof(FCONTROL));
|
|
|
|
/* Allocate Control Struct */
|
|
if(forptr) /* and prevent nesting of */
|
|
goto for_error; /* FOR Command. */
|
|
|
|
s = deblank(s); /* Remove leading blanks */
|
|
if ((*s++ != '%') || /* Get the FOR variable */
|
|
(fc->forvar = *s++) < ' ') /* character and save */
|
|
goto for_error;
|
|
|
|
if(strnicmp(s = deblank(s), "in", 2)) /* Check for the correct */
|
|
goto for_error; /* command syntax. */
|
|
|
|
s = deblank(s+2);
|
|
if (*s++ != '(')
|
|
goto for_error;
|
|
|
|
fc->files = (BYTE *)heap(); /* Allocate FOR parameter */
|
|
while(*s && *s != ')') { /* buffer and scan the */
|
|
bp1 = (BYTE *)heap(); /* command line generating */
|
|
/* zero terminated strings */
|
|
while(strchr(batch_sep, *s)) /* Skip any separators */
|
|
s = skip_char(s);
|
|
|
|
while( *s != ')' && /* then copy all valid */
|
|
!strchr(batch_sep, *s)) /* characters into buffer */
|
|
/* then zero terminate */
|
|
copy_char(&bp1, &s);
|
|
|
|
*bp1++ = '\0';
|
|
heap_get(strlen(heap()) + 1); /* Preserve String */
|
|
}
|
|
|
|
*(BYTE *)heap_get(1) = '\0'; /* Final String is zero */
|
|
/* bytes in length */
|
|
|
|
s = deblank(s);
|
|
if(*s++ != ')')
|
|
goto for_error;
|
|
|
|
if(strnicmp(s = deblank(s), "do", 2))
|
|
goto for_error;
|
|
|
|
if(in_flag & REDIR_ACTIVE) /* If Input redirection has been */
|
|
in_flag |= REDIR_FOR; /* enabled for this command force*/
|
|
/* it on for the complete command*/
|
|
|
|
if(out_flag & REDIR_ACTIVE) /* If Output redirection has been*/
|
|
out_flag |= REDIR_FOR; /* enabled for this command force*/
|
|
/* it on for the complete command*/
|
|
|
|
fc->cmd = (BYTE *)heap_get(strlen(s = deblank(s+2)) +1);
|
|
strcpy(fc->cmd, s);
|
|
|
|
fc->sflg = NO; /* File matching inactive */
|
|
for_flag = YES; /* Turn FOR processing ON */
|
|
forptr = fc; /* Save control Structure */
|
|
return;
|
|
|
|
for_error: /* When a Syntax error occurs */
|
|
heap_set((BYTE *) fc); /* restore the heap and print */
|
|
syntax(); /* an error message. */
|
|
return;
|
|
}
|
|
|
|
GLOBAL VOID for_end()
|
|
{
|
|
if(for_flag) {
|
|
heap_set((BYTE *) forptr); /* Terminate FOR processing */
|
|
forptr = (FCONTROL *) NULL; /* restore the HEAP and reset */
|
|
for_flag = NO; /* control flags. */
|
|
}
|
|
}
|
|
|
|
/*.pa*/
|
|
/*
|
|
* This command generates the displayed prompt based on the contents
|
|
* of the string PROMPT= in the environment. Otherwise the default
|
|
* prompt string DEFAULT_PROMPT is used.
|
|
*/
|
|
|
|
MLOCAL BOOLEAN prompt_flg = FALSE; /* Prompt Flag */
|
|
|
|
MLOCAL VOID prompt() /* display command line prompt */
|
|
{
|
|
REG BYTE *cp;
|
|
BYTE buf[MAX_PATHLEN];
|
|
BYTE c;
|
|
#if !STACK
|
|
BYTE cpbuf[MAX_ENVLEN];
|
|
#endif
|
|
/*rbf*/
|
|
#if 1
|
|
BYTE prmptcpbuf[MAX_ENVLEN];
|
|
REG BYTE *prmptcp = prmptcpbuf;
|
|
#endif
|
|
|
|
if(!echoflg) /* Return if No Echo */
|
|
return;
|
|
|
|
|
|
|
|
#if defined(CPM)
|
|
cp = heap();
|
|
strcpy(cp, "[CPM] $u$p$g");
|
|
#else
|
|
if(env_scan(msg_prmeq, cp = (BYTE *)heap()))
|
|
strcpy(cp, DEFAULT_PROMPT);
|
|
#endif
|
|
|
|
if(prompt_flg) /* If the previous Prompt display */
|
|
strcpy(cp, "$n$g"); /* terminated due to a Critical */
|
|
/* then just display the default */
|
|
prompt_flg = TRUE; /* drive. */
|
|
|
|
#if STACK
|
|
cp = stack(strlen(cp) + 1);
|
|
#else
|
|
cp = &cpbuf[0];
|
|
#endif
|
|
strcpy(cp, heap());
|
|
|
|
while((c = *cp++) != 0) { /* get next character */
|
|
if (c != '$') /* if not '$', print as is */
|
|
putc (c);
|
|
else {
|
|
c = *cp++;
|
|
switch(tolower(c)) { /* else get next character */
|
|
case '\0': /* Treat "$\0" as an invalid */
|
|
cp--; /* prompt command sequence */
|
|
break;
|
|
case 't': /* print current time */
|
|
disp_systime();
|
|
break;
|
|
case 'd': /* print current date */
|
|
disp_sysdate();
|
|
break;
|
|
case 'p': /* print current path */
|
|
if (ms_x_curdir(drive+1, buf) < 0)
|
|
printf(MSG_DRV_INVALID);
|
|
else
|
|
printf("%c:%s%s", drive+'A', pathchar, buf);
|
|
break;
|
|
case 'v': /* print version number */
|
|
cmd_ver("");
|
|
break;
|
|
case 'n': /* print default drive */
|
|
putc((BYTE) drive+'A');
|
|
break;
|
|
case 'g': /* print ">" */
|
|
putc ('>');
|
|
break;
|
|
case 'l': /* print "<" */
|
|
putc ('<');
|
|
break;
|
|
case 'b': /* print "|" */
|
|
putc ('|');
|
|
break;
|
|
case 'q': /* print "=" */
|
|
putc ('=');
|
|
break;
|
|
case '_': /* print CR,LF */
|
|
crlf();
|
|
break;
|
|
case 'h': /* print backspace, space, backspace */
|
|
printf("\b \b");
|
|
break;
|
|
case 'e': /* print ESC character */
|
|
putc ('\33');
|
|
break;
|
|
/*RG-01 */
|
|
|
|
#if !defined(NOXBATCH)
|
|
#if !defined (NOSECURITY)
|
|
#if defined(CDOSTMP) || defined(CDOS)
|
|
case 'm': /* print mail status */
|
|
if (login_enabled()) {
|
|
if(chk_mail()) { /* we have mail */
|
|
if(env_scan("MAIL=", heap()))
|
|
printf(MSG_UHAVEMAIL);
|
|
else
|
|
printf("%s",heap());
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'u': /* Display the User Name */
|
|
if (login_enabled()) {
|
|
if((aschextobin(user_info.userid)!=get_user_on_station())||(strlen(user_info.userid)==0)) {
|
|
if(get_user_info(get_user_on_station())!=0)
|
|
printf("#%04X",get_user_on_station());
|
|
else
|
|
printf("%s",user_info.loginname);
|
|
}
|
|
else
|
|
printf("%s",user_info.loginname);
|
|
}
|
|
break;
|
|
#endif
|
|
#endif
|
|
#endif /*NOXBATCH*/
|
|
/*RG-01-end*/
|
|
#if defined(CPM)
|
|
case 'u': /* Display the User Number */
|
|
printf("%d", user);
|
|
break;
|
|
#endif
|
|
#if defined(DOSPLUS)
|
|
case 'u':
|
|
if (!env_scan("LOGINNAME=",heap()))
|
|
printf("%s",heap());
|
|
break;
|
|
#endif
|
|
case '$':
|
|
putc ('$'); /* print single '$' */
|
|
break;
|
|
case 'x':
|
|
if ((allow_pexec)&&(!batchflg)) prompt_exec();
|
|
break;
|
|
default: /* Otherwise the character */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
prompt_flg = FALSE; /* Prompt display completed OK */
|
|
}
|
|
|
|
|
|
#if !defined(CDOSTMP)
|
|
/* The following functions are called by the int2e_handler function in
|
|
* COM.C. If a program is run from a batch file and calls INT 2E to
|
|
* execute a new batch file the original batch file must NOT be terminated.
|
|
* Therefore batch and batchflg must be saved, set to zero, and then
|
|
* restored when INT 2E returns. - EJH
|
|
*/
|
|
|
|
GLOBAL VOID int2e_start()
|
|
{
|
|
batchflg_save = batchflg;
|
|
batchflg = 0;
|
|
batch_save = batch;
|
|
echoflg_save = echoflg;
|
|
echoflg = ECHO_ON;
|
|
}
|
|
|
|
GLOBAL VOID int2e_finish()
|
|
{
|
|
batchflg = batchflg_save;
|
|
batch = batch_save;
|
|
echoflg = echoflg_save;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(CDOS)
|
|
MLOCAL VOID map_user_page(UWORD window_page, UWORD physical_page)
|
|
{
|
|
UWORD pblk[3];
|
|
pblk[0] = window_page;
|
|
pblk[1] = physical_page;
|
|
pblk[2] = 0;
|
|
bdos(181, pblk);
|
|
}
|
|
|
|
|
|
MLOCAL BYTE FAR * map_pd_mem(UWORD ppd, UWORD wp, UWORD seg, UWORD offset)
|
|
{
|
|
/* Map memory for another process into our memory space so we examine it */
|
|
UWORD base_seg;
|
|
UWORD page;
|
|
PD FAR * pdptr;
|
|
UWORD sysdat;
|
|
UWORD mptbl;
|
|
UWORD FAR * ptr;
|
|
UWORD mp_off;
|
|
UWORD i;
|
|
MPAD FAR * mp;
|
|
|
|
|
|
sysdat = FP_SEG(pd);
|
|
ptr = MK_FP(sysdat, 0xc8);
|
|
/* DEBUG */
|
|
if (*ptr == 0) /* for DEBUG under XM assume non-banked system */
|
|
return(MK_FP(seg, offset));
|
|
/* DEBUG */
|
|
ptr = MK_FP(sysdat, *ptr + 8);
|
|
mptbl = *ptr;
|
|
|
|
/* get segment of 4k page to map */
|
|
base_seg = (seg + (offset+15)/16) & 0xff00;
|
|
|
|
|
|
/* now find physical page to map */
|
|
|
|
pdptr = (PD FAR *) MK_FP(sysdat, ppd);
|
|
|
|
for (mp_off = pdptr->P_MPAR; mp_off !=0;) {
|
|
mp = MK_FP(sysdat, mp_off);
|
|
mp_off = mp->link;
|
|
if ((base_seg >= mp->start) &&
|
|
(base_seg < (mp->start + mp->length))) {
|
|
page = mp->xios;
|
|
for (i = 0; i < ((base_seg - mp->start)/1024); i++){
|
|
ptr = MK_FP(mptbl, page*2);
|
|
page = *ptr;
|
|
}
|
|
page = 4*page + (((base_seg - mp->start)/0x0100) & 3);
|
|
map_user_page(wp, page);
|
|
return(MK_FP(wp*0x0100,(seg*16+offset) & 0x0fff));
|
|
}
|
|
}
|
|
|
|
/* not found in mpad's - must be non-banked address */
|
|
return(MK_FP(seg, offset));
|
|
}
|
|
|
|
MLOCAL VOID ip_poke(UWORD ppd, UWORD wp, UWORD seg, UWORD offset, UBYTE val)
|
|
{
|
|
UBYTE FAR *ptr;
|
|
|
|
ptr = map_pd_mem(ppd, wp, seg, offset);
|
|
*ptr = val;
|
|
}
|
|
|
|
MLOCAL UBYTE ip_peek(UWORD ppd, UWORD wp, UWORD seg, UWORD offset)
|
|
{
|
|
UBYTE FAR *ptr;
|
|
|
|
ptr = map_pd_mem(ppd, wp, seg, offset);
|
|
return(*ptr);
|
|
}
|
|
|
|
MLOCAL UWORD ip_peek_word(UWORD ppd, UWORD wp, UWORD seg, UWORD offset)
|
|
{
|
|
return (ip_peek(ppd, wp, seg, offset) +
|
|
256*ip_peek(ppd, wp, seg, offset+1));
|
|
}
|
|
|
|
GLOBAL VOID inherit_TMP_state(VOID)
|
|
/* inherit batch files */
|
|
/* NB. This is bodged - we don't inherit FOR state, or redirection */
|
|
{
|
|
PD FAR *parent;
|
|
UWORD batch_seg;
|
|
UWORD tmp_mpad;
|
|
UWORD mp_off;
|
|
MPAD FAR * mp;
|
|
VOID FAR *window;
|
|
UWORD win_page;
|
|
UWORD i;
|
|
|
|
parent = (PD FAR *) MK_FP(FP_SEG(pd), pd->P_PARENT);
|
|
|
|
/* verify our parent is a Tmp, forget if it isn't */
|
|
if ((parent->P_NAME[0] != 'T') ||
|
|
(parent->P_NAME[1] != 'm') ||
|
|
(parent->P_NAME[2] != 'p'))
|
|
return;
|
|
|
|
/* allocate a 4k aligned window to bank data into */
|
|
i = 2*4096/16;
|
|
mem_alloc(&window, &i, i, i);
|
|
if (i==0)
|
|
return;
|
|
win_page = (FP_SEG(window) + 0x0100) / 0x100;
|
|
|
|
batch_seg = ip_peek_word(pd->P_PARENT, win_page,
|
|
parent->P_PSP, TmpPspBatchSeg);
|
|
|
|
/* do we have any batch files to inherit */
|
|
if (batch_seg) {
|
|
|
|
echoflg = (BOOLEAN)ip_peek_word(pd->P_PARENT, win_page,
|
|
ip_peek_word(pd->P_PARENT, win_page,
|
|
parent->P_PSP, TmpPspDataSeg),
|
|
ip_peek_word(pd->P_PARENT, win_page,
|
|
parent->P_PSP, TmpPspEchoFlgPtr));
|
|
|
|
/* recover Tmp's hidden mpads */
|
|
|
|
tmp_mpad = ip_peek_word(pd->P_PARENT, win_page,
|
|
parent->P_PSP, TmpPspMpad);
|
|
|
|
for (mp_off = parent->P_MPAR; mp_off != 0;) {
|
|
mp = MK_FP(FP_SEG(parent), parent->P_MPAR);
|
|
mp_off = mp->link;
|
|
}
|
|
|
|
mp->link = tmp_mpad;
|
|
inherit_batch_file(pd->P_PARENT, win_page, batch_seg);
|
|
mp->link = 0; /* unlink again */
|
|
}
|
|
map_user_page(0, 0); /* force user page to be unmapped */
|
|
bdos(141,0); /* dispatch to re-map TPA memory */
|
|
mem_free(&window); /* free the window */
|
|
}
|
|
|
|
MLOCAL VOID inherit_batch_file(UWORD ppd, UWORD win_page, UWORD batch_seg)
|
|
{
|
|
UBYTE FAR * dst;
|
|
BCONTROL FAR *save0;
|
|
FCONTROL *save1;
|
|
BYTE *save2;
|
|
WORD save3;
|
|
UWORD i;
|
|
UWORD data_seg;
|
|
PD FAR *parent;
|
|
|
|
|
|
|
|
/* if we are in a nested batch file, inherit older batch file first */
|
|
i = ip_peek_word(ppd, win_page, batch_seg, 2);
|
|
|
|
if (i != 0)
|
|
inherit_batch_file( ppd, win_page, i);
|
|
|
|
batch_new(); /* new incarnation of batch */
|
|
|
|
save0 = batch->bcontrol; save1 = batch->fcontrol;
|
|
save2 = batch->heap_start; save3 = batch->heap_size;
|
|
|
|
dst = (BYTE FAR *) batch; /* copy batch structure */
|
|
for (i=0; i<sizeof(BCONTROL); i++) /* from parental PD */
|
|
dst[i] = ip_peek(ppd, win_page, batch_seg, i);
|
|
|
|
/* now terminate parental batch processing by poking EOF */
|
|
ip_poke(ppd, win_page,
|
|
batch_seg, (UWORD) &batch->eof - (UWORD) &batch->bcontrol,
|
|
(UBYTE) TRUE);
|
|
|
|
/*
|
|
* Copy the invoking command and the individual elements
|
|
* of the command line into a buffer ready for processing
|
|
*/
|
|
|
|
parent = (PD FAR *) MK_FP(FP_SEG(pd), pd->P_PARENT);
|
|
data_seg = ip_peek_word(pd->P_PARENT, win_page,
|
|
parent->P_PSP, TmpPspDataSeg);
|
|
|
|
i = (UWORD) batch->batcmd;
|
|
batch->batcmd = (BYTE *)heap(); /* Initialize Parameter Buffer */
|
|
|
|
while (ip_peek_word(ppd, win_page, data_seg, i) != 0)
|
|
*(BYTE *)heap_get(1) = ip_peek(ppd, win_page, data_seg, i++);
|
|
|
|
*(WORD *)heap_get(2) = 0; /* Double NULL is a terminator */
|
|
/* for command line params */
|
|
|
|
batch->bcontrol = save0; batch->fcontrol = save1;
|
|
batch->heap_start = save2; batch->heap_size = save3;
|
|
|
|
batchflg++; /* increment batch flag */
|
|
|
|
crlfflg = YES; /* print CR/LF after this */
|
|
}
|
|
#endif
|
|
|
|
|
|
EXTERN N_CMD novell_ext_list[];
|
|
|
|
EXTERN BYTE FAR * CDECL farptr(BYTE *);
|
|
EXTERN BYTE FAR * CDECL cgroupptr(BYTE *);
|
|
|
|
EXTERN BOOLEAN CDECL call_novell(BYTE *, BYTE *, WORD);
|
|
EXTERN BOOLEAN CDECL nov_station(WORD *);
|
|
EXTERN WORD CDECL nov_connection();
|
|
|
|
|
|
MLOCAL BOOLEAN novell_extension(src,dst)
|
|
BYTE *src;
|
|
BYTE *dst;
|
|
/*
|
|
* Check if src string is a novell string to be expanded. eg login_name.
|
|
* if so, put expansion in dst.
|
|
*/
|
|
{
|
|
N_CMD FAR *n_cmd_p;
|
|
BYTE FAR *cpf;
|
|
WORD i;
|
|
|
|
for (i=0;src[i] && src[i]!='=';i++);
|
|
src[i] = 0;
|
|
|
|
n_cmd_p = (N_CMD FAR *)farptr((BYTE *)&novell_ext_list[0]);
|
|
|
|
while(n_cmd_p->string) {
|
|
|
|
cpf = cgroupptr(n_cmd_p->string);
|
|
|
|
for(i=0; (cpf[i]==src[i]) && src[i]; i++);
|
|
|
|
if(cpf[i]==src[i]) {
|
|
(*n_cmd_p->func)(dst);
|
|
return(0);
|
|
}
|
|
|
|
n_cmd_p++;
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
GLOBAL VOID CDECL get_login_name(dst)
|
|
BYTE *dst;
|
|
{
|
|
struct s_nov_e346_in {
|
|
WORD len;
|
|
BYTE code;
|
|
} nov_e346_in;
|
|
struct s_nov_e346_out {
|
|
WORD len;
|
|
BYTE level;
|
|
LONG id;
|
|
} nov_e346_out;
|
|
struct s_nov_e336_in {
|
|
WORD len;
|
|
BYTE code;
|
|
LONG id;
|
|
} nov_e336_in;
|
|
struct s_nov_e336_out {
|
|
WORD len;
|
|
LONG id;
|
|
WORD type;
|
|
BYTE name[48];
|
|
} nov_e336_out;
|
|
|
|
nov_e346_in.len = 1;
|
|
nov_e346_in.code = 0x46;
|
|
nov_e346_out.len = 5;
|
|
nov_e346_out.id = -1L;
|
|
call_novell((BYTE *)&nov_e346_in, (BYTE *)&nov_e346_out, 0xE3);
|
|
|
|
if (nov_e346_out.id == -1L) {
|
|
*dst = 0;
|
|
return;
|
|
}
|
|
|
|
nov_e336_in.len = 5;
|
|
nov_e336_in.code = 0x36;
|
|
nov_e336_in.id = nov_e346_out.id;
|
|
nov_e336_out.len = 54;
|
|
call_novell((BYTE *)&nov_e336_in, (BYTE *)&nov_e336_out, 0xE3);
|
|
|
|
strcpy(dst,nov_e336_out.name);
|
|
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_pstation(dst)
|
|
BYTE *dst;
|
|
{
|
|
WORD sn[3];
|
|
|
|
if (nov_station(sn)) {
|
|
*dst = 0;
|
|
return;
|
|
}
|
|
|
|
sprintf(dst,"%04X%04X%04X",sn[0],sn[1],sn[2]);
|
|
}
|
|
|
|
|
|
GLOBAL VOID CDECL get_full_name(dst)
|
|
BYTE *dst;
|
|
{
|
|
/* scan bindery */
|
|
struct s_nov_e337_in {
|
|
WORD len;
|
|
BYTE code;
|
|
LONG last_object_id;
|
|
WORD object_type;
|
|
BYTE object_name_len;
|
|
BYTE object_name[48];
|
|
} nov_e337_in;
|
|
|
|
struct s_nov_e337_out {
|
|
WORD len;
|
|
LONG object_id;
|
|
WORD object_type;
|
|
BYTE object_name[48];
|
|
BYTE object_flag;
|
|
BYTE object_security;
|
|
BYTE object_has_properties;
|
|
} nov_e337_out;
|
|
|
|
|
|
/* scan property */
|
|
struct s_nov_e33c_in {
|
|
WORD len;
|
|
BYTE code;
|
|
WORD object_type;
|
|
BYTE object_name_len;
|
|
BYTE object_name[48];
|
|
LONG sequence_num;
|
|
BYTE property_name_len;
|
|
BYTE property_name[16];
|
|
} nov_e33c_in;
|
|
|
|
struct s_nov_e33c_out {
|
|
WORD len;
|
|
BYTE property_name[16];
|
|
BYTE property_flags;
|
|
BYTE property_security;
|
|
LONG sequence_num;
|
|
BYTE property_has_value;
|
|
BYTE more_properties;
|
|
} nov_e33c_out;
|
|
|
|
|
|
/* read property */
|
|
struct s_nov_e33d_in {
|
|
WORD len;
|
|
BYTE code;
|
|
WORD object_type;
|
|
BYTE object_name_len;
|
|
BYTE object_name[48];
|
|
BYTE segment_num;
|
|
BYTE property_name_len;
|
|
BYTE property_name[16];
|
|
} nov_e33d_in;
|
|
|
|
struct s_nov_e33d_out {
|
|
WORD len;
|
|
BYTE property_value[128];
|
|
BYTE more_segments;
|
|
BYTE property_flags;
|
|
} nov_e33d_out;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
get_login_name(nov_e337_in.object_name);
|
|
nov_e337_in.object_name_len = strlen(nov_e337_in.object_name);
|
|
if (!nov_e337_in.object_name_len){
|
|
*dst = 0;
|
|
return;
|
|
}
|
|
|
|
nov_e337_in.code = 0x37;
|
|
nov_e337_in.len = sizeof(struct s_nov_e337_in) - 2;
|
|
nov_e337_out.len = sizeof(struct s_nov_e337_out) -2 ;
|
|
nov_e337_in.last_object_id = -1L;
|
|
nov_e337_in.object_type = 0x0100; /*user*/
|
|
|
|
|
|
for(;;){
|
|
res = call_novell((BYTE *)&nov_e337_in, (BYTE *)&nov_e337_out, 0xe3 );
|
|
if ( res == 0xfc )
|
|
break;
|
|
else if ( res ){
|
|
*dst= 0;
|
|
return;
|
|
}
|
|
|
|
if ( nov_e337_out.object_has_properties ){
|
|
nov_e33c_in.code = 0x3c;
|
|
nov_e33c_in.len = sizeof(struct s_nov_e33c_in) - 2;
|
|
nov_e33c_out.len = sizeof(struct s_nov_e33c_out) - 2;
|
|
nov_e33c_in.object_type = nov_e337_out.object_type;
|
|
nov_e33c_in.object_name_len = sizeof( nov_e33c_in.object_name );
|
|
strcpy( nov_e33c_in.object_name, nov_e337_out.object_name );
|
|
nov_e33c_in.sequence_num = -1L;
|
|
nov_e33c_in.property_name_len = 1;
|
|
nov_e33c_in.property_name[0] = '*';
|
|
|
|
for(;;){
|
|
res = call_novell( (BYTE *)&nov_e33c_in, (BYTE *)&nov_e33c_out, 0xe3 );
|
|
if ( res == 0xfb )
|
|
break;
|
|
else if ( res ){
|
|
*dst = 0;
|
|
return;
|
|
}
|
|
|
|
if ( nov_e33c_out.property_has_value ){
|
|
nov_e33d_in.code = 0x3d;
|
|
nov_e33d_in.len = sizeof (struct s_nov_e33d_in) - 2;
|
|
nov_e33d_out.len = sizeof (struct s_nov_e33d_out) - 2;
|
|
nov_e33d_in.object_type = nov_e337_out.object_type;
|
|
nov_e33d_in.object_name_len = sizeof( nov_e33d_in.object_name );
|
|
strcpy( nov_e33d_in.object_name, nov_e337_out.object_name );
|
|
nov_e33d_in.segment_num = 1;
|
|
nov_e33d_in.property_name_len = strlen( nov_e33c_out.property_name );
|
|
strcpy(nov_e33d_in.property_name, nov_e33c_out.property_name );
|
|
for(;;){
|
|
res = call_novell( (BYTE *)&nov_e33d_in, (BYTE *)&nov_e33d_out, 0xe3);
|
|
if ( res == 0xec )
|
|
break;
|
|
else if ( res ){
|
|
*dst = 0;
|
|
return;
|
|
}
|
|
|
|
if (!strcmp(nov_e33c_out.property_name,"IDENTIFICATION")){
|
|
strcpy(dst,nov_e33d_out.property_value);
|
|
return;
|
|
}
|
|
nov_e33d_in.segment_num++;
|
|
}/*for*/
|
|
}/*if*/
|
|
nov_e33c_in.sequence_num = nov_e33c_out.sequence_num;
|
|
}/*for*/
|
|
nov_e337_in.last_object_id = nov_e337_out.object_id;
|
|
}/*if*/
|
|
}/*for*/
|
|
}
|
|
|
|
|
|
|
|
GLOBAL VOID CDECL get_hour(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSTIME time;
|
|
|
|
ms_gettime(&time);
|
|
|
|
if (time.hour > 12) time.hour -= 12;
|
|
if (time.hour == 0) time.hour = 12;
|
|
|
|
sprintf(dst,"%d",time.hour);
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_hour24(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSTIME time;
|
|
|
|
ms_gettime(&time);
|
|
|
|
sprintf(dst,"%02d",time.hour);
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_minute(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSTIME time;
|
|
|
|
ms_gettime(&time);
|
|
|
|
sprintf(dst,"%02d",time.min);
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_second(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSTIME time;
|
|
|
|
ms_gettime(&time);
|
|
|
|
sprintf(dst,"%02d",time.sec);
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_am_pm(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSTIME time;
|
|
BYTE FAR *p;
|
|
|
|
ms_gettime(&time);
|
|
|
|
if (time.hour >= 12) p = cgroupptr(PM_TIME);
|
|
else p = cgroupptr(AM_TIME);
|
|
|
|
while (*p) *dst++ = *p++;
|
|
*dst = 0;
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_greeting(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSTIME time;
|
|
BYTE FAR *p;
|
|
|
|
ms_gettime(&time);
|
|
|
|
if (time.hour < 12)
|
|
p = cgroupptr(GREETING_MORNING);
|
|
else if (time.hour < 17)
|
|
p = cgroupptr(GREETING_AFTERNOON);
|
|
else
|
|
p = cgroupptr(GREETING_EVENING);
|
|
|
|
while (*p) *dst++ = *p++;
|
|
*dst = 0;
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_year(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSDATE date;
|
|
|
|
ms_getdate(&date);
|
|
|
|
sprintf(dst,"%d",date.year);
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_short_year(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSDATE date;
|
|
|
|
ms_getdate(&date);
|
|
|
|
sprintf(dst,"%d",date.year%100);
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_month(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSDATE date;
|
|
|
|
ms_getdate(&date);
|
|
|
|
sprintf(dst,"%d",date.month);
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_month_name(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSDATE date;
|
|
BYTE *m;
|
|
|
|
ms_getdate(&date);
|
|
|
|
switch(date.month) {
|
|
case 1: m = JAN_M; break;
|
|
case 2: m = FEB_M; break;
|
|
case 3: m = MAR_M; break;
|
|
case 4: m = APR_M; break;
|
|
case 5: m = MAY_M; break;
|
|
case 6: m = JUN_M; break;
|
|
case 7: m = JUL_M; break;
|
|
case 8: m = AUG_M; break;
|
|
case 9: m = SEP_M; break;
|
|
case 10: m = OCT_M; break;
|
|
case 11: m = NOV_M; break;
|
|
case 12: m = DEC_M; break;
|
|
}
|
|
|
|
sprintf(dst,"%s",m);
|
|
}
|
|
|
|
|
|
|
|
|
|
GLOBAL VOID CDECL get_day(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSDATE date;
|
|
|
|
ms_getdate(&date);
|
|
|
|
sprintf(dst,"%d",date.day);
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_nday_of_week(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSDATE date;
|
|
|
|
ms_getdate(&date);
|
|
|
|
sprintf(dst,"%d",date.dow+1);
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_day_of_week(dst)
|
|
BYTE *dst;
|
|
{
|
|
SYSDATE date;
|
|
|
|
ms_getdate(&date);
|
|
|
|
sprintf(dst,"%s",day_names(date.dow));
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_os_version(dst)
|
|
BYTE *dst;
|
|
{
|
|
env_scan("VER=",dst);
|
|
}
|
|
|
|
GLOBAL VOID CDECL get_connection(dst)
|
|
BYTE *dst;
|
|
{
|
|
int i;
|
|
|
|
i = nov_connection();
|
|
if (i==-1) {
|
|
*dst = 0;
|
|
return;
|
|
}
|
|
|
|
sprintf(dst,"%d",i);
|
|
}
|