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

1303 lines
33 KiB
C

/*
; File : $Workfile: SUPPORT.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
*/
/*
File SUPPORT.C
Title SUPPORT routines for command.com
Revision History:-
==================
Date Description
-----------------------------------------------------------------------------
10 Apr 86 EQU function now makes a case independant match.
29 Apr 86 Single $ preceeds the screen control variables
Fix bug where if the last character of a screen control
variable was an octal character it was not printed
6 May 86 yes() now requires a default to be specified previously
it assumed the default was NO.
21 May 86 Fixed bug with yes() function when default is NO.
22 May 86 Allow the screen control codes to be patched to longer strings
Upd`te ZAP_SPACES to delete all white space
Version 1.2
===========
31 Jul 86 Conditionally remove functions that cannot be fully supported
in a CDOS version of COMMAND.COM
4 Aug 86 ANSI C compatibility MSC /W1
30 Oct 86 FREE_DRIVE now forces the drive to point to the root
directory of the current drive.
17 Feb 87 Rewrote repwild() function to fix minor problems
Aug 87 Make all routines PASCAL calling convention (for Concurrent 6)
26 Oct 87 Update the F_CHECK routine to support multiple switches ie
"/wc" as well as "/w /c".
27 Oct 87 Stop F_CHECK from forcing the input line to lower case.
10 Nov 87 Modify F_CHECK flag zapping
18 Nov 87 Prevent GET_FILENAME copying a filename > than MAX_PATHLEN
16 Dec 87 Update D_CHECK to make fewer system calls.
29 Feb 88 Tidy the REPWILD routine - No Functional Change
15 Mar 88 Use ANSI Escape sequences for DOS Plus
27 Apr 88 Restore Range check to D_CHECK routine
25 May 88 Print a CR after a CLS to reset the current column count.
26 May 88 Change the Default HighLight and LowLight strings to NULL
for DOSPLUS.
27 May 88 Added string undefs.
23 Jun 88 Add new ONOFF function for XXX [=] ON|OFF parsing
28 Jun 88 Correct bug in YES routine for FAR messages
1 Jul 88 Support Control-C from YES for TMP.
6 Jul 88 Support the CON:filename syntax for COPY.
19 Sep 88 Enhance error checking on the F_CHECK routine. Now traps the
condition when switchar is at the end of the line.
1 Dec 88 Convert all path parsing routines to be KANJI friendly.
21 Dec 88 Add generic ISDEV routine to SUPPORT.C
21 Dec 88 "*" to "*.*" conversion moved to CMD_DIR.
18 Apr 89 c_write: write to STDERR if err_flag set
6 Jun 89 Correct GET_FILENAME to parse path passwords.
6 Jun 89 echo: check for endline after on/off.
10 Aug 89 get rid of sysdate_fmt (year does not need to be %04d, which
upsets Japanese day)
10 Aug 89 day_name_len for day_names array elements
22 Aug 89 Japanese dayname comes after date
Remove day_name_len & work out length from array.
11 Sep 89 strupr(), strlwr() and stricmp() are now Kanji aware.
toupper() is now in DOSIF.ASM and uses international routine.
16 Oct 89 Kanji specific routines replaced with DBCS routines.
30 Oct 89 "Internal Error" moved to message.c (and no longer resident)
15 Dec 89 errors 50-72 give "Network error" rather than "Internal error"
6-Mar-90 Watcom C v 7.0
13-Mar-90 Output CR/LF after errors
4-May-90 append_slash added
4-May-90 get_filename stops at ';' unless followed by pathchar(s)
("append;" bug)
20-Sep-90 Created skip_char() and copy_char().
Created is_blank() and amended deblank(), zap_spaces(),
is_filechar() and is_pathchar() to use it.
13-Mar-91 changed nofiles() function to cope with DIR.. on NOVELL drives.
18-Mar-91 tolower() ( and therefore strlwr() ) is now aware of TURKISH
capital I's with dots.
6-Aug-91 prompt_exec() function no longer uses the heap. This screwed us
up if the file to be execed was a batch file.
09-Jun-92 is_pathchar and d_check now cope with drive '[', etc, as used
by some novell applications. See also INVALID_DRV in command.h.
18-Jun-92 Added optional_line() function for '?' support in batch files.
-----------------------------------------------------------------------------
*/
#include "defines.h"
#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(CDOSTMP)
#include <ccpm.h>
#include <sysdat.h>
#endif
#include "command.h"
#include "toupper.h"
#include "dosif.h"
#include "global.h"
#include "dos.h"
EXTERN jmp_buf break_env;
EXTERN VOID CDECL printf(BYTE *, ...);
EXTERN VOID CDECL eprintf(BYTE *, ...);
EXTERN VOID CDECL sprintf(BYTE *, BYTE *, ...);
#if defined(CDOSTMP)
EXTERN VOID CDECL int_break(VOID); /* COM.C Internal Break */
#endif
MLOCAL VOID screen(BYTE *, BYTE *);
MLOCAL VOID outs(BYTE *);
GLOBAL VOID crlf(VOID);
GLOBAL VOID putc(BYTE);
GLOBAL VOID c_write(BYTE *, UWORD);
GLOBAL BYTE * fptr(BYTE *);
GLOBAL BYTE * day_names(UWORD);
/*.pa*/
/*
* The following screen control sequences can be redefined or removed
* by entries in the environment or the OEM can patch these areas in the
* COMMAND.COM object and change the default values.
*
*/
#define CLS_KEY "$CLS=" /* CLS entry in environment */
#define REVON_KEY "$ON=" /* REVON entry in environment */
#define REVOFF_KEY "$OFF=" /* REVOFF entry in environment */
#ifdef DOSPLUS
/*
* For DOSPLUS the default screen control sequences are for an
* ANSI Terminal (IBM Sub-Set).
*/
#define CLS_DEF "\033[2J\0***" /* Default CLS string "ESC [2J"*/
#define REVON_DEF "\0********" /* Default REVON string NULL */
#define REVOFF_DEF "\0********" /* Default REVOFF string NULL */
EXTERN BOOLEAN CDECL int10_cls(VOID); /* Dirty Clear Screen Subroutine */
#else
/*
* For Concurrent DOS the default screen control sequences are for a
* standard VT52 Terminal.
*/
#define CLS_DEF "\033E\0*****" /* Default CLS string "ESC E" */
#define REVON_DEF "\033p\0*****" /* Default REVON string "ESC p" */
#define REVOFF_DEF "\033q\0*****" /* Default REVOFF string "ESC q" */
#endif
/* Invalid FileName Characters as */
/* specified by the IBM DOS Tech */
/* Reference Page 6-96 "func 29" */
MLOCAL BYTE invalid_filechar[] = "*?\\.:;,=+<>|/\"[]";
/*.pa*/
/*
* TIME AND DATE SUPPORT ROUTINES
* ==============================
*
* The following routines print the TIME and DATE using the international
* data. Two sets of routines are provided to display the SYSTEM Time and
* Date the second routine displays FILE based time and date.
*/
MLOCAL BYTE date_fmt [] = "%2d%c%02d%c%02d";
GLOBAL VOID disp_filetime(time)
unsigned time;
{
WORD h, m;
BYTE ap;
ap = ' '; /* assume no AM/PM used */
h = (time >> 11);
m = (time >> 5) & 0x3f;
if (country.ampm == 0) /* if anglo saxon fashion */
{ /* need to convert things */
ap = 'a'; /* assume morning */
if (h == 0) /* 00:00 through 00:59 */
h = 12; /* is special... */
else if (h >= 12) /* test if afternoon */
{
ap = 'p'; /* mark as afternoon */
if (h > 12) /* if 13:00 through 23:59 */
h -= 12; /* need to make " 1:00p" */
}
}
printf ("%2d%c%02d%c",
h, country.dtime[0], /* print hour, delimiter */
m, ap); /* print minute, am/pm (if enabled) */
}
GLOBAL VOID disp_filedate(date)
unsigned date;
{
WORD y, m, d;
WORD b;
y = ((date >> 9) + 80)%100;
m = (date >> 5) & 0x0f;
d = date & 0x1f;
b = country.ddate[0];
switch (country.dt_fmt)
{
case 1: /* European format dd/mm/yy */
printf (date_fmt, d,b,m,b,y);
break;
case 2: /* Japanese format yy/mm/dd */
printf (date_fmt, y,b,m,b,d);
break;
default: /* US format mm/dd/yy for the rest*/
printf (date_fmt, m,b,d,b,y);
break;
};
}
GLOBAL VOID disp_systime()
{
SYSTIME time;
WORD b = country.dtime[0];
ms_gettime(&time);
printf ("%2d%c%02d%c%02d.%02d",
time.hour, b, /* print hour, delimiter */
time.min, b, /* print minute, delimiter */
time.sec, time.hsec); /* Print the second and Hundredths */
}
/* Return address of null terminated day name, given index (day). */
GLOBAL BYTE * day_names(day)
UWORD day; /* day of week: 0=sunday, 1=monday, .. */
{
switch (day)
{
case 0: return SUN_D;
case 1: return MON_D;
case 2: return TUE_D;
case 3: return WED_D;
case 4: return THU_D;
case 5: return FRI_D;
default: break;
}
return SAT_D;
}
GLOBAL VOID disp_sysdate()
{
SYSDATE date;
WORD y, m, d;
WORD b;
ms_getdate(&date); /* Get the current date */
y = date.year;
m = date.month;
d = date.day;
b = country.ddate[0];
if (country.dt_fmt != 2) /* Japanese day comes after date */
printf("%s ", day_names(date.dow));
switch (country.dt_fmt)
{
case 1: /* European format dd/mm/yy */
printf (date_fmt, d,b,m,b,y);
break;
case 2: /* Japanese format yy/mm/dd */
printf (date_fmt, y,b,m,b,d);
printf(" %s", day_names(date.dow));
break;
default: /* US format mm/dd/yy for the rest*/
printf (date_fmt, m,b,d,b,y);
break;
};
}
/*.pa*/
/*
* Screen handling routines to CLEAR the screen and emphasise text
*/
GLOBAL VOID CDECL cmd_cls()
{
#if defined(DOSPLUS)
if(!int10_cls()) /* If no console device is */
screen(CLS_KEY, CLS_DEF); /* active use the default */
/* $CLS string. */
#else /* For Concurrent DOS never*/
screen(CLS_KEY, CLS_DEF); /* use INT 10 */
#endif /* Finally print a CR to */
putc('\r'); /* reset the internal */
/* Column count. */
}
GLOBAL VOID revon()
{
screen(REVON_KEY, REVON_DEF);
}
GLOBAL VOID revoff()
{
screen(REVOFF_KEY, REVOFF_DEF);
}
MLOCAL VOID screen(key, def)
BYTE *key; /* Key name to match in the environment */
BYTE *def; /* Default string to output if no match */
{
REG BYTE *cp;
if(!env_scan(key, cp = (BYTE *)heap()))
/* and then search for the key */
outs(cp); /* output the string on a match */
else /* otherwise use the default */
printf(def); /* supplied on entry */
}
/*
* This string output function will output a string containing
* a C format imbedded Octal number. This is mainly used for the
* CLS function.
*/
MLOCAL VOID outs(s)
BYTE *s;
{
BYTE b = 0;
REG WORD f = 0;
for(; *s; s++) {
if(f) { /* Generating an OCTAL number*/
if(*s >= '0' && *s < '8') { /* check for a valid number */
b <<= 3; /* and flush the buffer if it*/
b += *s - '0'; /* is illegal. Otherwise add */
} /* to the buffer and flush */
else { /* after three characters */
if(f != 3)
putc(b);
putc(*s);
f = 0;
continue;
}
if(f-- == 1)
putc(b);
continue;
}
if(*s == '\\') {
f = 3; /* Initialise the Character count */
b = 0; /* Zero the display value */
continue;
}
putc(*s);
}
if(f && b)
putc(b);
}
/*.pa*/
/*
* GENERAL PURPOSE STRING MANIPULATION ROUTINES
* ============================================
*
*/
GLOBAL BYTE tolower(b)
BYTE b;
{
if (b==0x8D) return('i'); /* For turkish dotted capital I */
return((b < 'A' || b > 'Z') ? b : b + 0x20);
}
GLOBAL BOOLEAN isdigit(b)
BYTE b;
{
return (b >= '0' && b <= '9');
}
GLOBAL BYTE * skip_char(s)
REG BYTE *s;
{
s++;
if (dbcs_lead(*(s - 1)) && *s >= ' ')
s++;
return(s);
}
GLOBAL BYTE * copy_char(dest, source)
REG BYTE **dest, **source;
{
if (dbcs_lead(**source))
{
if (*(*source + 1) >= ' ')
{
*(*dest)++ = *(*source)++;
*(*dest)++ = *(*source);
}
}
else
{
*(*dest)++ = *(*source);
}
(*source)++;
return(*source);
}
/* Check if character in string is blank.
Return size in bytes of blank character, zero if not blank character. */
GLOBAL WORD is_blank(s)
REG BYTE *s;
{
WORD blank_size;
if (*s == ' ' || *s == '\t')
blank_size = 1;
else if (dbcs_expected() && *s == 0x81 && *(s + 1) == 0x40)
blank_size = 2; /* KANJI space */
else
blank_size = 0;
return(blank_size);
}
GLOBAL BYTE * deblank(s) /* scan off leading white space */
REG BYTE *s; /* starting address of scan */
{
REG WORD blank_size;
while ((blank_size = is_blank(s)) != 0)
s += blank_size;
return (s); /* return deblanked string */
}
#if !(defined(MSC) || defined(MWC) || defined(TURBOC) || defined(WATCOMC))
GLOBAL BYTE * strchr(s, b)
BYTE *s, b;
{
while(b != *s && *s)
s++;
if(*s)
return s;
else
return NULL;
}
#endif
/* Convert all uppercase characters in ASCIIZ string to lowercase.
If country code is JAPAN Kanji character code pairs (ie 8 bit Kanji
escape code followed immediatly by 8 bit Kanji character code) are
not changed. */
GLOBAL BYTE *strlwr(s)
BYTE *s;
{
REG BYTE *bp;
if (dbcs_expected()) /* are we looking out for DBCS? */
{ /* yes - DON'T CHANGE DBCS CODES */
for (bp = s; *bp; bp++)
{
if (dbcs_lead(*bp)) /* is this first of a DBCS pair? */
{
bp++; /* yes - skip over it */
if (*bp == '\0') /* it is followed by its partner? */
break; /* no - invalid DBCS, exit loop */
}
else
*bp = tolower(*bp); /* no - lower case it */
}
}
else
for (bp = s; *bp; bp++)
*bp = tolower(*bp);
return s;
}
/* Convert all lowercase characters in ASCIIZ string to uppercase.
Double byte characters are not changed. */
GLOBAL BYTE *strupr(s)
BYTE *s;
{
REG BYTE *bp;
if (dbcs_expected()) /* are we looking out for DBCS? */
{ /* yes - DON'T CHANGE DBCS CODES */
for (bp = s; *bp; bp++)
{
if (dbcs_lead(*bp)) /* is this first of a DBCS pair? */
{
bp++; /* yes - skip over it */
if (*bp == '\0') /* it is followed by its partner? */
break; /* no - invalid DBCS, exit loop */
}
else
*bp = toupper(*bp); /* no - upper case it */
}
}
else
for (bp = s; *bp; bp++)
*bp = toupper(*bp);
return s;
}
/*
* STRNICMP does a caseless match on the two input strings for LEN
* characters. This function is only used for token matching for
* commands like FOR and IF. Double byte character set aware.
*/
GLOBAL WORD strnicmp(str1, str2, len)
REG BYTE *str1, *str2;
UWORD len;
{
while (len--) /* loop until len == 0 */
{
if (dbcs_lead(*str1) || dbcs_lead(*str2))
{ /* one or both characters are DBCS */
if (*str1 != *str2) /* are they identical? */
return -1; /* no - return SMALER */
if(!*str1)
break;
str1++; str2++; /* skip DBCS escape */
if (*str1 != *str2) /* are DBCS char codes identical? */
return -1; /* no - return SMALLER */
}
else
if (toupper(*str1) != toupper(*str2))
return -1;
if(!*str1)
break;
str1++; str2++;
}
return 0; /* return EQUAL */
}
/*
* ZAP_SPACES removes all white space from a string
*/
GLOBAL VOID zap_spaces(cp)
REG BYTE *cp;
{
REG BYTE *cp1;
do {
cp1 = deblank(cp); /* Skip leading whitespace */
if (cp1 != cp) /* If whitespace has been */
strcpy(cp, cp1); /* skipped then move string */
while (*cp && !is_blank(cp)) /* Now skip over */
cp++; /* normal characters */
/* and repeat till the end */
} while (*cp);
}
GLOBAL VOID strip_path(path, dir)
BYTE *path;
BYTE *dir;
{
REG BYTE *cp;
REG WORD i;
i = 0; /* assume empty path */
for (cp=path; *cp; cp++) { /* scan the file name */
if(dbcs_lead(*cp)) { /* If this is a DBCS */
cp++; /* character then skip */
continue; /* the next char */
}
if ((*cp == *pathchar) || /* if path delimiter */
(*cp == ':')) /* or drive specifier */
i = (cp+1)-path; /* remember offset */
}
strcpy (dir, path); /* make a copy */
dir[i] = '\0'; /* discard all but path */
}
GLOBAL BOOLEAN getdigit(n, s)
WORD *n; /* Pointer to the word number to save */
BYTE **s; /* String to Process */
{
*n = 0; /* Zero the number */
while(!isdigit(**s) && **s) /* Skip all non digits */
(*s)++;
if(**s) {
while(isdigit(**s)) { /* Add all the digits in */
*n = **s - '0' + *n * 10;
(*s)++;
}
return TRUE; /* and return success */
}
else
return FALSE;
}
/*
* Check that the number input by the user and held in S is in
* the range specified by MIN and MAX if this is so then update
* VALUE and return SUCCESS otherwise VALUE is unchabged and
* return FAILURE.
*/
GLOBAL BOOLEAN check_num(s, min, max, value)
BYTE *s; /* Input String */
WORD min, max; /* Minimum and Maximum values */
UWORD *value; /* Value Input */
{
WORD u;
deblank(s);
if(getdigit(&u, &s) == FALSE)
return FAILURE;
if(*s)
return FAILURE;
if(u < min || u > max)
return FAILURE;
*value = u;
return SUCCESS;
}
GLOBAL BOOLEAN iswild (path)
REG BYTE *path;
{
while (*path && (*path != '*') && (*path != '?'))
path ++;
return (*path != '\0');
}
GLOBAL BOOLEAN is_filechar(s)
REG BYTE *s;
{
if (*s == 0) return FALSE;
if (is_blank(s) || strchr(invalid_filechar, *s))
return FALSE;
return TRUE;
}
GLOBAL BOOLEAN is_pathchar(s)
REG BYTE *s;
{
if (is_filechar(s) ||
*s == *pathchar ||
*s == '.' ||
*s == ':' ||
(*s >= 'Z'+1 && *s <= 'Z'+6))
return TRUE;
return FALSE;
}
/*
* Copy the file specification from OLDPATH to the buffer NEWPATH
* and return a pointer to the first byte after the extracted name.
* Remove any terminating ':' character from the file specification
* as the FDOS/PCMODE will try to match all characters in the string.
*/
GLOBAL BYTE * get_filename(newpath, oldpath, ambiguous)
REG BYTE *oldpath, *newpath;
BOOLEAN ambiguous;
{
UWORD count = 0;
BYTE *pathname = oldpath;
#if defined(PASSWORD)
while(is_pathchar(oldpath) ||
((*oldpath == *pwdchar) && (is_pathchar(oldpath + 1))) ||
(ambiguous && (*oldpath == '*' || *oldpath == '?'))) {
#else
while(is_pathchar(oldpath) ||
(ambiguous && (*oldpath == '*' || *oldpath == '?'))) {
#endif
if(++count < MAX_PATHLEN) {
*newpath++ = *oldpath;
if(dbcs_lead(*oldpath)) {
*newpath++=*++oldpath;
count++;
}
}
if(*oldpath++ == ':' && count > 2 && !is_pathchar(oldpath)) {
/* Handle the CON:filename */
newpath--; /* so loved by the users of */
break; /* the COPY command. */
}
}
*newpath = '\0'; /* Terminate newpath with \0 */
if(count >= MAX_PATHLEN) {
longjmp(break_env, IA_FILENAME);
}
return oldpath;
}
/*
* Returns the offset of the filename in a correctly formatted
* pathname string.
*/
GLOBAL BYTE * fptr(s)
REG BYTE *s;
{
REG BYTE *tp;
for(tp = s; *s; s++) {
if(dbcs_lead(*s)) {
s++;
continue;
}
if(*s == ':' || *s == *pathchar)
tp = s+1;
}
return(tp);
}
/* repwild replaces the wildcards in the destination filespec with
* the relevant information from the source filespec
* src is an explicit filename
* dest is a filename with wildcards
*
* eg src = fred.lst
* dest = *.txt becomes fred.txt
* dest = ?.* becomes f.lst
* dest = z*.* becomes zred.lst
*
* nb dest must be in a buffer with room for expansion
*/
GLOBAL VOID repwild(src,dest)
REG BYTE *src,*dest;
{
BYTE t[13];
BYTE *temp;
temp=&t[0]; /* ptr to temp array */
if(!iswild(dest)) /* return if not wild */
return;
src = fptr(src); /* point to filename */
if(!*src) /* If a blank filename has been */
return; /* specified then return as an */
/* invalid source specification */
dest = fptr(dest);
strcpy(temp,dest); /* copy wild dest to temp, as dest will get overwritten */
while (*temp) { /* while still more temp to process */
if(*temp=='.') { /* advance src ptr to '.' */
while(*src && *src!='.')
src++;
} /* drop into next check */
if(*src=='.') {
if(*temp=='.') {
*dest=*temp; /* copy '.' */
goto inc;
}
else { /* advance temp to '.' or '\0', copying valid chars to dest */
while(*temp && *temp!='.') {
if(*temp!='*' && *temp!='?') {
*dest=*temp;
dest++;
}
temp++;
}
goto skipinc;
}
}
if(*temp=='*') {
while(*src && *src!='.') { /* copy rest of src till */
*dest=*src; /* src = '.' or '\0' */
dest++;
src++;
}
while(*temp && *temp!='.') /* inc temp past '*' */
temp++;
goto skipinc;
}
if (*temp=='?')
*dest=*src; /* copy src character to dest */
else /* else *temp==normal char */
*dest=*temp; /* copy temp character to dest */
inc:
if(*src) /* dont advance past terminator */
src++;
dest++;
temp++;
skipinc:
;
} /* loop till end of while */
*dest='\0'; /* add terminator to dest */
}
/*.pa*/
/*
* Read a character from the console. The ABORT flag determines
* whether a ^C will abort the command or be treated as a negative
* reponse. DEF determines the default value that yes() will use.
*
*/
EXTERN BYTE FAR * CDECL farptr(BYTE *);
#define YES_CHAR (*farptr(YES_NO+0))
#define NO_CHAR (*farptr(YES_NO+1))
GLOBAL BOOLEAN yes(abort, def)
BOOLEAN abort, def;
{
BYTE yn;
#if defined(CDOSTMP)
yn = (BYTE) bdos(C_RAWIO, 0xFD); /* Input a character and */
if(abort && yn == 0x03) /* check for Control-C */
int_break();
#else
yn = (BYTE) msdos((abort ? MS_C_NOECHO : MS_C_RAWIN), NULL);
#endif /* read the response */
if(yn >= ' ') /* If its printable then*/
putc(yn); /* display the charcter */
crlf(); /* new line */
if(def) /* Now using the correct*/
return((yn & 0xdf) != NO_CHAR); /* default value return */
else /* process the users */
return((yn & 0xdf) == YES_CHAR); /* input and return. */
}
/*
* ONOFF scans the command line for [=](ON|OFF) and returns
* YES, NO or FAILURE
*/
GLOBAL WORD onoff(cmd)
BYTE *cmd;
{
cmd = deblank(cmd); /* Deblank the string and */
if (*cmd == '=') /* remove optional '=' */
cmd = deblank(cmd+1);
sprintf(heap(), "%s", MSG_ON); /* Check for ON */
if(!strnicmp(cmd, heap(), strlen(heap())))
if (*(deblank (cmd + strlen(heap()))) == 0) /* end of line? */
return YES;
sprintf(heap(), "%s", MSG_OFF); /* Check for OFF */
if(!strnicmp(cmd, heap(), strlen(heap())))
if (*(deblank (cmd + strlen(heap()))) == 0) /* end of line? */
return NO;
return FAILURE;
}
GLOBAL VOID syntax()
{
eprintf(MSG_SYNTAX);
crlfflg = YES;
}
GLOBAL VOID crlf()
{
printf("\n");
}
GLOBAL VOID putc(c)
BYTE c;
{
printf("%c", c);
}
GLOBAL VOID puts(s)
BYTE *s;
{
printf("%s",s);
}
GLOBAL VOID c_write(s, l)
BYTE *s;
UWORD l;
{
ms_x_write (err_flag ? STDERR : STDOUT, s, l);
}
GLOBAL WORD e_check(ret)
REG WORD ret;
{
REG BYTE *s;
if (ret >= 0) /* if no error code */
return ret; /* it's O.K. */
if (ret == ED_GENFAIL) ret = extended_error();
crlfflg = YES; /* Force a CR LF after the error */
switch (ret)
{
case ED_ROOM: /* Force ED_ROOM to return File Not Found msg */
case ED_FILE: s = ERR02; break; /* File Not Found Error */
case -1:
case ED_PATH: s = ERR03; break; /* Path Not Found */
case ED_HANDLE: s = ERR04; break; /* Too many Open Files */
case ED_ACCESS: s = ERR05; break; /* Access denied */
case ED_MEMORY: s = ERR08; break; /* Insufficient Memory */
case ED_ENVIRON: s = MSG_ENVERR;break; /* Invalid Environment */
case ED_DRIVE: s = ERR15; break; /* Invalid Drive Spec */
case ED_PROTECT: s = ERR19; break; /* Write Protect Disk */
case ED_SHAREFAIL:s = ERR20; break; /* Sharing Conflict */
default:
if(ret==ED_FAIL)
{s = ERR83; break;} /* Physical Media - FAILED */
if(ret==ED_PASSWORD)
{s = ERR86; break;} /* Invalid Password */
#if defined(CDOS) || defined(CDOSTMP)
if(ret==(-255))
{s = ERR_RSC; break;} /* Resource is not Available */
#endif
if (ED_NET >= ret && ret > ED_NETPWD)
{s = MSG_NETWORK; break;} /* Network Error */
s = MSG_INTERNAL; break; /* Internal Error */
}
eprintf(s, 0-ret);
eprintf("\n");
return ret;
}
#if 0
MLOCAL BYTE *err_tab[] = { NULLPTR, /* 01 - Invalid Function Code */
err02, /* 02 - File Not Found Error */
err03, /* 03 - Path Not Found */
err04, /* 04 - Too many Open Files */
err05, /* 05 - Access denied */
NULLPTR, /* 06 - Invalid Handle */
NULLPTR, /* 07 - Invalid Memory Cntl Blk */
err08, /* 08 - Insufficient Memory */
NULLPTR, /* 09 - Invalid Memory Cntl Blk */
msg_enverr, /* 10 - Invalid Environment */
NULLPTR, /* 11 - Invalid Format */
NULLPTR, /* 12 - Invalid Access Code */
NULLPTR, /* 13 - Invalid Data */
NULLPTR, /* 14 - Unused Error Code */
err15, /* 15 - Invalid Drive Spec */
err20, /* 20 - Sharing Conflict */
err83, /* 83 - Physical Media - FAILED */
err86, /* 86 - Invalid Password */
err_rsc}; /* Resource is not Available */
GLOBAL WORD e_check(ret)
REG WORD ret;
{
REG WORD error; /* Local copy of the error code */
if (ret >= 0) /* if no error code */
return ret; /* it's O.K. */
crlfflg = YES; /* Force a CR LF after the error */
error = ret; /* message has been displayed */
if(error == ED_ROOM) /* Force ED_ROOM to return File Not */
error = ED_FILE; /* found message. */
if(error < ED_DRIVE) { /* Check for error codes which have */
if(error == ED_SHAREFAIL) /* been remapped so save space */
error = (-16);
if(error == ED_FAIL) /* Check for FAIL */
error = (-17);
if(error == ED_PASSWORD) /* Password Error */
error = (-18);
}
error = -error;
if(error <= sizeof(err_tab)/sizeof(BYTE *) && err_tab[error-1])
eprintf(err_tab[error-1]);
else
eprintf("Internal Error Code %03d", error);
return ret;
}
#endif
GLOBAL BOOLEAN UNC(char *path) {
if (*path == '\\' && path[1] == '\\') return TRUE;
if (!*(path++) || !*(path++)) return FALSE;
while (*path) if (*(path++) == ':') return TRUE;
return FALSE;
}
GLOBAL BYTE * d_check(path)
REG BYTE *path;
{
ddrive = -1; /* return -1 for UNC names */
if (UNC(path)) return(path);
ddrive = drive; /* if no drive is specified */
if(!*path || path[1] != ':') /* then DDRIVE is set to */
return(path); /* the default drive. */
ddrive = toupper(path[0]) - 'A'; /* Otherwise the requested */
path += 2; /* drive is selected and */
/* range checked */
if(ddrive == drive) /* If the requested drive is*/
return(path); /* the default drive is OK. */
/*
* If TRUE the D_CHECK only range checks the selected drive and
* returns a pointer to the next element of the path. If FALSE
* the drive is phyically selected.
*/
#if TRUE
if(!INVALID_DRV(ddrive))
return(path);
#else
if(!INVALID_DRV(ddrive) && ms_drv_set(ddrive) == ddrive) {
ms_drv_set(drive); /* Restore Original Drive */
return(path); /* and return Path */
}
#endif
e_check(ED_DRIVE); /* Print an error message */
return (NULL); /* and return a NULLPTR */
}
GLOBAL BOOLEAN f_check(cmd, fchars, farray, ignore)
REG BYTE *cmd;
BYTE *fchars;
UWORD *farray;
BOOLEAN ignore; /* Ignore Illegal Options */
{
BYTE *s, *flg_start;
BOOLEAN flg_skip, flg_error;
BYTE c;
*farray = 0; /* assume none of the flags present */
while(*cmd) {
if(*cmd++ != *switchar)
continue;
flg_start = cmd - 1; /* Save switchar offset */
flg_skip = FALSE; /* No Chars skipped */
flg_error = TRUE; /* Assume first char is bad */
FOREVER {
c = tolower(*cmd); /* Scan the string till the */
if(!((c>='a' && c<='z')||(c>='0' && c<='9')))
break; /* first non-alpha character*/
if((s=(BYTE *)strchr(fchars, c))) {/* check each char against */
*farray |= 1 << (s-fchars); /* options string passed by */
strcpy(cmd, cmd+1); /* the calling routine. */
flg_error = FALSE; /* Reset error flag and set */
} /* correct flag bit. */
else {
flg_skip = flg_error = TRUE;/* On error set flg_skip and*/
if(!ignore) /* break out of the loop if */
break; /* ignore is FALSE. */
cmd++;
}
}
if(!flg_skip) /* If all characters have */
*flg_start = ' '; /* been used then remove '/' */
if(flg_error && !ignore) { /* If an invalid char and */
eprintf(MSG_BADOPT, *switchar, c); /* ignore is FALSE then */
crlfflg = YES; /* print the error message */
return FAILURE;
}
}
return SUCCESS;
}
GLOBAL BOOLEAN nofiles(path, attrib, exist, append_stardotstar)
REG BYTE *path; /* Search Path */
WORD attrib; /* Search Attributes */
BOOLEAN exist; /* Must files exist */
BOOLEAN append_stardotstar;
{
REG BYTE *cp;
DTA search;
WORD ret;
if ((cp = d_check (path)) == NULLPTR) /* if bad drive letter */
return FAILURE; /* don't do it */
if (!*fptr(cp)) { /* If only a path has been */
strcat(cp, d_slash_stardotstar+3); /* specified expand to *.* */
}
else if(!iswild (cp)) /* else is it path or file? */
{ /* wild cards imply files */
ret = ms_x_first(path, ATTR_ALL, &search); /* get attributes */
if(ret == ED_ROOM)
ret = ED_FILE;
if (ret < 0) /* if any errors */
if(!exist && (ret == ED_FILE || ret == ED_PATH)) {
/* If file does not exist and*/
/* this is NOT an error... */
if (append_stardotstar) {
append_slash(path); /* "DIR .." on NOVELL drives */
strcat(path, d_slash_stardotstar+3);
/* requires that we append */
/* "*.*" here */
}
return SUCCESS; /* return OK. */
}
else {
e_check (ret); /* otherwise print message */
return FAILURE; /* no files found */
}
if (search.fattr & ATTR_DIR) { /* if path names directory */
append_slash(path); /* make it all files in it */
strcat(path, d_slash_stardotstar+3);
}
if(!exist) /* Must we check the file(s) */
return SUCCESS; /* exist. If no return */
}
ret = ms_x_first(path, attrib, &search); /* Search for the file */
if(ret < 0) /* Check the error returned */
if(!exist && (ret==ED_FILE || ret==ED_ROOM)) /* If file does not exist but*/
return SUCCESS; /* this is not an error then */
else { /* return Ok. */
e_check (ret); /* otherwise print message */
return FAILURE; /* no files found */
}
return SUCCESS;
}
/*
* Check if FILENAME can be opened in Read Only mode and return the
* result. The file is then closed
*/
GLOBAL BOOLEAN file_exist(filename)
BYTE *filename;
{
BYTE filebuf[MAX_PATHLEN];
WORD h;
get_filename(filebuf, filename, NO);
if((h = ms_x_open(filebuf, OPEN_READ)) > 0) {
ms_x_close(h);
return TRUE;
}
return FALSE;
}
/*
* Check if the handle passed to this routine is open on a FILE
* or a DEVICE.
*/
GLOBAL BOOLEAN isdev(handle)
UWORD handle;
{
return (0x0080 & ms_x_ioctl(handle) ? TRUE : FALSE);
}
/*
* If the string that has been passed doesn't end with a '\' add one
*/
GLOBAL append_slash(s)
BYTE *s;
{
BYTE lastchar;
while (*s) {
lastchar = *s;
if (dbcs_lead(*s)) /* is this first of a DBCS pair? */
s++;
s++;
}
if ((lastchar != '\\') && (lastchar != '/'))
strcat(s, pathchar); /* append a slash */
}
GLOBAL VOID prompt_exec()
{
BYTE temp[128];
if (!env_scan("PEXEC=",temp)) docmd(temp,TRUE);
}
GLOBAL VOID optional_line(line)
BYTE *line;
{
BYTE c;
BYTE *s;
if (*line == 13 || *line == 10 || *line == 0) return;
if (*line == '?') strcpy(line,line+1);
if (*line == '\"') {
s = line+1;
while (*s && *s != '\"') putc(*s++);
s++;
strcpy(line,s);
}
else printf(MSG_OPTLINE,line);
if (!yes(NO,NO)) *line = 0;
/*printf("\n");*/
}