Subversion Repositories SvarDOS

Compare Revisions

Ignore whitespace Rev 580 → Rev 581

/svarcom/tags/svarcom-2022.0/cmd/_notimpl.c
0,0 → 1,32
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* handler for all "not implemented yet" commands
*/
 
static enum cmd_result cmd_notimpl(struct cmd_funcparam *p) {
outputnl("This command is not implemented yet. Sorry!");
return(CMD_FAIL);
}
/svarcom/tags/svarcom-2022.0/cmd/break.c
0,0 → 1,90
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* break
*/
 
static enum cmd_result cmd_break(struct cmd_funcparam *p) {
unsigned char brkflag = 0;
 
if (cmd_ishlp(p)) {
outputnl("Sets or clears extended CTRL+C checking");
outputnl("");
outputnl("BREAK [ON | OFF]");
outputnl("");
outputnl("Type BREAK without a parameter to display the current BREAK setting.");
return(CMD_OK);
}
 
/* no params: display current break state */
if (p->argc == 0) {
_asm {
push ax
push dx
 
mov ax, 0x3300 /* query break-check flag */
int 0x21 /* status (0=OFF, 1=ON) in DL */
mov [brkflag], dl
 
pop dx
pop ax
}
if (brkflag == 0) {
outputnl("BREAK is off");
} else {
outputnl("BREAK is on");
}
return(CMD_OK);
}
 
/* too many params? */
if (p->argc > 1) {
outputnl("Too many parameters");
return(CMD_FAIL);
}
 
/* exactly 1 parameter - "on" or "off" */
if (imatch(p->argv[0], "on")) {
brkflag = 1;
} else if (!imatch(p->argv[0], "off")) {
outputnl("Invalid parameter");
return(CMD_FAIL);
}
 
/* set break accordingly to brkflag */
_asm {
push ax
push dx
 
mov ax, 0x3301 /* set break-check level */
mov dl, [brkflag] /* 0=OFF 1=ON */
int 0x21
 
pop dx
pop ax
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/cd.c
0,0 → 1,106
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* chdir
*
* displays the name of or changes the current directory.
*
* CHDIR [drive:][path]
* CD..
*
* Type CD drive: to display the current directory in the specified drive.
* Type CD without parameters to display the current drive and directory.
*/
 
 
static enum cmd_result cmd_cd(struct cmd_funcparam *p) {
char *buffptr = p->BUFFER;
 
/* CD /? */
if (cmd_ishlp(p)) {
outputnl("Displays the name of or changes the current directory.");
outputnl("");
outputnl("CHDIR [drive:][path]");
outputnl("CHDIR[..]");
outputnl("CD [drive:][path]");
outputnl("CD[..]");
outputnl("");
outputnl(".. Specifies that you want to change to the parent directory.");
outputnl("");
outputnl("Type CD drive: to display the current directory in the specified drive.");
outputnl("Type CD without parameters to display the current drive and directory.");
return(CMD_OK);
}
 
/* one argument max */
if (p->argc > 1) {
outputnl("Too many parameters");
return(CMD_FAIL);
}
 
/* no argument? display current drive and dir ("CWD") */
if (p->argc == 0) {
curpathfordrv(buffptr, 0);
outputnl(buffptr);
return(CMD_OK);
}
 
/* argument can be either a drive (D:) or a path */
if (p->argc == 1) {
const char *arg = p->argv[0];
unsigned short err = 0;
/* drive (CD B:) */
if ((arg[0] != '\\') && (arg[1] == ':') && (arg[2] == 0)) {
unsigned char drive = arg[0];
if (drive >= 'a') {
drive -= ('a' - 1);
} else {
drive -= ('A' - 1);
}
 
err = curpathfordrv(buffptr, drive);
if (err == 0) outputnl(buffptr);
} else { /* path */
_asm {
push dx
push ax
mov ah, 0x3B /* CHDIR (set current directory) */
mov dx, arg
int 0x21
jnc DONE
mov [err], ax
DONE:
pop ax
pop dx
}
}
if (err != 0) {
nls_outputnl_doserr(err);
return(CMD_FAIL);
}
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/chcp.c
0,0 → 1,115
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* chcp
*/
 
static enum cmd_result cmd_chcp(struct cmd_funcparam *p) {
unsigned short nnn = 0;
unsigned short errcode = 0;
 
if (cmd_ishlp(p)) {
outputnl("Displays or sets the active code page number");
outputnl("");
outputnl("CHCP [nnn]");
outputnl("");
outputnl("nnn Specifies a code page number");
outputnl("");
outputnl("Type CHCP without a parameter to display the active code page number.");
return(CMD_OK);
}
 
/* too many parameters */
if (p->argc > 1) {
outputnl("Too many parameters");
return(CMD_FAIL);
}
 
/* one param? must be numeric in range 1+ */
if (p->argc == 1) {
unsigned char nlsfuncflag = 0;
if (atous(&nnn, p->argv[0]) != 0) {
outputnl("Invalid code page number");
return(CMD_FAIL);
}
_asm {
/* verify that NLSFUNC is installed */
push ax
push bx
 
mov ax, 0x1400 /* DOS 3+ -- is NLSFUNC.EXE installed? */
int 0x2f /* AL = 0xff -> installed */
cmp al, 0xff
jne DONE
mov [nlsfuncflag], 1
 
/* set code page to nnn */
 
mov ax, 0x6602 /* DOS 3.3+ -- Activate Code Page */
mov bx, [nnn]
int 0x21 /* CF set on error and err code in AX */
jnc DONE
mov [errcode], ax /* store err code in nnn on failure */
DONE:
 
pop bx
pop ax
}
if (nlsfuncflag == 0) {
outputnl("NLSFUNC not installed");
} else if (errcode != 0) {
outputnl("Failed to change code page");
return(CMD_FAIL);
}
 
} else { /* no parameter given: display active code page */
 
_asm {
push ax
push bx
push dx
 
mov ax, 0x6601 /* DOS 3.3+ -- Query Active Code Page */
int 0x21 /* CF set on error, current CP in BX */
mov [nnn], bx
jnc DONE
mov [errcode], ax
DONE:
 
pop dx
pop bx
pop ax
}
if (errcode == 0) {
sprintf(p->BUFFER, "Active code page: %d", nnn);
outputnl(p->BUFFER);
} else {
nls_outputnl_doserr(errcode);
return(CMD_FAIL);
}
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/cls.c
0,0 → 1,87
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* cls
*/
 
static enum cmd_result cmd_cls(struct cmd_funcparam *p) {
unsigned char screenw, screenh;
const char *ansiesc = "\x1B[2J$";
 
if (cmd_ishlp(p)) {
outputnl("Clears the screen");
outputnl("");
outputnl("CLS");
return(CMD_OK);
}
 
screenw = screen_getwidth();
screenh = screen_getheight();
 
_asm {
/* output an ANSI ESC code for "clear screen" in case the console is
* some kind of terminal */
mov ah, 0x09 /* write $-terminated string to stdout */
mov dx, ansiesc
int 0x21
 
/* check what stdout is set to */
mov ax, 0x4400 /* IOCTL query device/flags flags */
mov bx, 1 /* file handle (1 = stdout) */
int 0x21 /* CF set on error, otherwise DX set with flags */
jc DONE /* abort on error */
/* DX = 10000010
| |||
| ||+--- indicates standard output
| |+---- set if NUL device
| +----- set if CLOCK device
+--------- set if handle is a device (ie. not a file)
in other words, DL & 10001110 (8Eh) should result in 10000010 (82h)
*/
and dl, 0x8e
cmp dl, 0x82
jne DONE /* abort on error */
 
/* scroll vram out of screen */
mov ax, 0x0600 /* scroll up entire rectangle */
mov bh, 0x07 /* fill screen with white-on-black */
xor cx, cx /* upper left location in CH,CL (0,0) */
/* DX is bottom right location of rectangle (DH=row, DL=column) */
mov dh, [screenh]
dec dh
mov dl, [screenw]
dec dl
int 0x10
 
/* set cursor to top left corner (0,0) of the screen */
mov ah, 0x02 /* set cursor position */
xor bh, bh /* page number */
xor dx, dx /* location in DH,DL */
int 0x10
DONE:
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/copy.c
0,0 → 1,363
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* copy
*/
 
/* /A - Used to copy ASCII files. Applies to the filename preceding it and to
* all following filenames. Files will be copied until an end-of-file mark is
* encountered in the file being copied. If an end-of-file mark is encountered
* in the file, the rest of the file is not copied. DOS will append an EOF
* mark at the end of the copied file.
*
* /B - Used to copy binary files. Applies to the filename preceding it and to
* all following filenames. Copied files will be read by size (according to
* the number of bytes indicated in the file`s directory listing). An EOF mark
* is not placed at the end of the copied file.
*
* /V - Checks after the copy to assure that a file was copied correctly. If
* the copy cannot be verified, the program will display an error message.
* Using this option will result in a slower copying process.
*
* special case: "COPY A+B+C+D" means "append B, C and D files to the A file"
* if A does not exist, then "append C and D to B", etc.
*/
 
struct copy_setup {
const char *src[64];
unsigned short src_count; /* how many sources are declared */
char cursrc[256]; /* buffer for currently processed src */
char dst[256];
unsigned short dstlen;
char src_asciimode[64];
char dst_asciimode;
char last_asciimode; /* /A or /B impacts the file preceding it and becomes the new default for all files that follow */
char verifyflag;
char lastitemwasplus;
unsigned short databufsz;
char databuf[1];
};
 
 
/* copies src to dst, overwriting or appending to the destination.
* - copy is performed in ASCII mode if asciiflag set (stop at first EOF in src
* and append an EOF in dst).
* - returns zero on success, DOS error code on error */
static unsigned short cmd_copy_internal(const char *dst, char dstascii, const char *src, char srcascii, unsigned char appendflag, void *buff, unsigned short buffsz) {
unsigned short errcode = 0;
unsigned short srch = 0xffff, dsth = 0xffff;
_asm {
 
/* open src */
OPENSRC:
mov ax, 0x3d00 /* DOS 2+ -- open an existing file, read access mode */
mov dx, src /* ASCIIZ fname */
int 0x21 /* CF clear on success, handle in AX */
jc FAIL
mov [srch], ax /* store src handle in memory */
 
/* check appendflag so I know if I have to try opening dst for append */
xor al, al
or al, [appendflag]
jz CREATEDST
 
/* try opening dst first if appendflag set */
mov ax, 0x3d01 /* DOS 2+ -- open an existing file, write access mode */
mov dx, dst /* ASCIIZ fname */
int 0x21 /* CF clear on success, handle in AX */
jc CREATEDST /* failed to open file (file does not exist) */
mov [dsth], ax /* store dst handle in memory */
 
/* got file open, LSEEK to end of it now so future data is appended */
mov bx, ax /* file handle in BX (was still in AX) */
mov ax, 0x4202 /* DOS 2+ -- set file pointer to end of file + CX:DX */
xor cx, cx /* offset zero */
xor dx, dx /* offset zero */
int 0x21 /* CF set on error */
jc FAIL
jmp COPY
 
/* create dst */
CREATEDST:
mov ah, 0x3c /* DOS 2+ -- create a file */
mov dx, dst
xor cx, cx /* zero out attributes */
int 0x21 /* handle in AX on success, CF set on error */
jc FAIL
mov [dsth], ax /* store dst handle in memory */
 
/* perform actual copy */
COPY:
/* read a block from src */
mov ah, 0x3f /* DOS 2+ -- read from file */
mov bx, [srch]
mov cx, [buffsz]
mov dx, [buff] /* DX points to buffer */
int 0x21 /* CF set on error, bytes read in AX (0=EOF) */
jc FAIL /* abort on error */
/* EOF? (ax == 0) */
test ax, ax
jz ENDOFFILE
/* write block of AX bytes to dst */
mov cx, ax /* block length */
mov ah, 0x40 /* DOS 2+ -- write to file (CX bytes from DS:DX) */
mov bx, [dsth] /* file handle */
/* mov dx, [buff] */ /* DX points to buffer already */
int 0x21 /* CF clear and AX=CX on success */
jc FAIL
cmp ax, cx /* sould be equal, otherwise failed */
mov ax, 0x08 /* preset to DOS error "Insufficient memory" */
jne FAIL
jmp COPY
 
ENDOFFILE:
/* if dst ascii mode -> add an EOF (ASCII mode not supported for the time being) */
 
jmp CLOSESRC
 
FAIL:
mov [errcode], ax
 
CLOSESRC:
/* close src and dst */
mov bx, [srch]
cmp bx, 0xffff
je CLOSEDST
mov ah, 0x3e /* DOS 2+ -- close a file handle */
int 0x21
 
CLOSEDST:
mov bx, [dsth]
cmp bx, 0xffff
je DONE
mov ah, 0x3e /* DOS 2+ -- close a file handle */
int 0x21
 
DONE:
}
return(errcode);
}
 
 
static enum cmd_result cmd_copy(struct cmd_funcparam *p) {
struct copy_setup *setup = (void *)(p->BUFFER);
unsigned short i;
unsigned short copiedcount_in = 0, copiedcount_out = 0; /* number of input/output copied files */
struct DTA *dta = (void *)0x80; /* use DTA at default location in PSP */
 
if (cmd_ishlp(p)) {
outputnl("Copies one or more files to another location.");
outputnl("");
outputnl("COPY [/A|/B] source [/A|/B] [+source [/A|/B] [+...]] [destination [/A|/B]] [/V]");
outputnl("");
outputnl("source Specifies the file or files to be copied");
outputnl("/A Indicates an ASCII text file");
outputnl("/B Indicates a binary file");
outputnl("destination Specifies the directory and/or filename for the new file(s)");
outputnl("/V Verifies that new files are written correctly");
outputnl("");
outputnl("To append files, specify a single file for destination, but multiple files");
outputnl("for source (using wildcards or file1+file2+file3 format).");
outputnl("");
outputnl("NOTE: /A and /B are no-ops (ignored), provided only for compatibility reasons.");
return(CMD_OK);
}
 
/* parse cmdline and fill the setup struct accordingly */
 
memset(setup, 0, sizeof(*setup));
setup->databufsz = p->BUFFERSZ - sizeof(*setup);
 
for (i = 0; i < p->argc; i++) {
 
/* switch? */
if (p->argv[i][0] == '/') {
if ((imatch(p->argv[i], "/a")) || (imatch(p->argv[i], "/b"))) {
setup->last_asciimode = 'b';
if (imatch(p->argv[i], "/a")) setup->last_asciimode = 'a';
/* */
if (setup->dst[0] != 0) {
setup->dst_asciimode = setup->last_asciimode;
} else if (setup->src_count != 0) {
setup->src_asciimode[setup->src_count - 1] = setup->last_asciimode;
}
} else if (imatch(p->argv[i], "/v")) {
setup->verifyflag = 1;
} else {
outputnl("Invalid switch");
return(CMD_FAIL);
}
continue;
}
 
/* not a switch - must be either a source, a destination or a + */
if (p->argv[i][0] == '+') {
/* a plus cannot appear after destination or before first source */
if ((setup->dst[0] != 0) || (setup->src_count == 0)) {
outputnl("Invalid syntax");
return(CMD_FAIL);
}
setup->lastitemwasplus = 1;
/* a plus may be immediately followed by a filename - if so, emulate
* a new argument */
if (p->argv[i][1] != 0) {
p->argv[i] += 1;
i--;
}
continue;
}
 
/* src? (first non-switch or something that follows a +) */
if ((setup->lastitemwasplus) || (setup->src_count == 0)) {
setup->src[setup->src_count] = p->argv[i];
setup->src_asciimode[setup->src_count] = setup->last_asciimode;
setup->src_count++;
setup->lastitemwasplus = 0;
continue;
}
 
/* must be a dst then */
if (setup->dst[0] != 0) {
outputnl("Invalid syntax");
return(CMD_FAIL);
}
if (file_truename(p->argv[i], setup->dst) != 0) {
outputnl("Invalid destination");
return(CMD_FAIL);
}
setup->dst_asciimode = setup->last_asciimode;
/* if dst is a directory then append a backslash */
setup->dstlen = path_appendbkslash_if_dir(setup->dst);
}
 
/* DEBUG: output setup content ("if 1" to enable) */
#if 0
printf("src: ");
for (i = 0; i < setup->src_count; i++) {
if (i != 0) printf(", ");
printf("%s [%c]", setup->src[i], setup->src_asciimode[i]);
}
printf("\r\n");
printf("dst: %s [%c]\r\n", setup->dst, setup->dst_asciimode);
printf("verify: %s\r\n", (setup->verifyflag)?"ON":"OFF");
#endif
 
/* must have at least one source */
if (setup->src_count == 0) {
outputnl("Required parameter missing");
return(CMD_FAIL);
}
 
/* perform the operation based on setup directives:
* iterate over every source and copy it to dest */
 
for (i = 0; i < setup->src_count; i++) {
unsigned short t;
unsigned short cursrclen;
unsigned short pathendoffset;
 
/* resolve truename of src and write it to buffer */
t = file_truename(setup->src[i], setup->cursrc);
if (t != 0) {
output(setup->src[i]);
output(" - ");
nls_outputnl_doserr(t);
continue;
}
cursrclen = strlen(setup->cursrc); /* remember cursrc length */
 
/* if length zero, skip (not sure why this would be possible, though) */
if (cursrclen == 0) continue;
 
/* if src does not end with a backslash AND it is a directory then append a backslash */
cursrclen = path_appendbkslash_if_dir(setup->cursrc);
 
/* if src ends with a '\' then append *.* */
if (setup->cursrc[cursrclen - 1] == '\\') {
strcat(setup->cursrc, "*.*");
}
 
/* remember where the path in cursrc ends */
for (t = 0; setup->cursrc[t] != 0; t++) {
if (setup->cursrc[t] == '\\') pathendoffset = t + 1;
}
 
/* */
if (findfirst(dta, setup->cursrc, 0) != 0) {
continue;
}
 
do {
char appendflag;
if (dta->attr & DOS_ATTR_DIR) continue; /* skip directories */
 
/* compute full path/name of the file */
strcpy(setup->cursrc + pathendoffset, dta->fname);
 
/* if there was no destination, then YOU are the destination now!
* this handles situations like COPY a.txt+b.txt+c.txt */
if (setup->dst[0] == NULL) {
strcpy(setup->dst, setup->cursrc);
setup->dstlen = strlen(setup->dst);
copiedcount_in++;
copiedcount_out++;
continue;
}
 
/* is dst ending with a backslash? then append fname to it */
if (setup->dst[setup->dstlen - 1] == '\\') strcpy(setup->dst + setup->dstlen, dta->fname);
 
/* now cursrc contains the full source and dst contains the full dest... COPY TIME! */
 
/* if dst file exists already -> overwrite it or append?
- if dst is a dir (dstlen-1 points at a \\) -> overwrite
- otherwise: if copiedcount_in==0 overwrite, else append */
output(setup->cursrc);
if ((setup->dst[setup->dstlen - 1] == '\\') || (copiedcount_in == 0)) {
appendflag = 0;
output(" > ");
copiedcount_out++;
} else {
appendflag = 1;
output(" >> ");
}
outputnl(setup->dst);
 
t = cmd_copy_internal(setup->dst, 0, setup->cursrc, 0, appendflag, setup->databuf, setup->databufsz);
if (t != 0) {
nls_outputnl_doserr(t);
return(CMD_FAIL);
}
 
copiedcount_in++;
} while (findnext(dta) == 0);
 
}
 
sprintf(setup->databuf, "%u file(s) copied", copiedcount_out);
outputnl(setup->databuf);
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/date.c
0,0 → 1,226
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* date [date]
*/
 
 
/* parse a NULL-terminated string int hour, minutes and seconds, returns 0 on success
* valid inputs: 0, 7, 5:5, 23:23, 17:54:45, 9p, 9:05, ...
*/
static int cmd_date_parse(const char *s, unsigned short *year, unsigned char *mo, unsigned char *dy, struct nls_patterns *nls) {
unsigned short i;
const char *ptrs[2] = {NULL, NULL};
 
*year = 0;
*mo = 0;
*dy = 0;
 
/* validate input - must contain only chars 0-9 and time separator */
for (i = 0; s[i] != 0; i++) {
switch (s[i]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
default:
if ((s[i] != nls->datesep[0]) || (i == 0)) return(-1);
if (ptrs[0] == NULL) {
ptrs[0] = s + i + 1;
} else if (ptrs[1] == NULL) {
ptrs[1] = s + i + 1;
} else { /* too many separators */
return(-1);
}
break;
}
}
 
/* did I get all separators? */
if ((ptrs[0] == NULL) || (ptrs[1] == NULL)) goto FAIL;
 
/* d/m/y order depends on NLS settings */
switch (nls->dateformat) {
case 0: /* m/d/y */
atous(&i, s);
*mo = i;
atous(&i, ptrs[0]);
*dy = i;
atous(year, ptrs[1]);
break;
case 1: /* d/m/y */
atous(&i, s);
*dy = i;
atous(&i, ptrs[0]);
*mo = i;
atous(year, ptrs[1]);
break;
default: /* y/m/d */
atous(year, s);
atous(&i, ptrs[0]);
*mo = i;
atous(&i, ptrs[1]);
*dy = i;
break;
}
 
return(0);
 
FAIL:
*year = 0;
return(-1);
}
 
 
/* set system date, return 0 on success */
static int cmd_date_set(unsigned short year, unsigned char mo, unsigned char dy) {
_asm {
push ax
push bx
push cx
push dx
 
mov ax, 0x2b00 /* DOS 1+ -- Set DOS Date */
mov cx, [year] /* year (1980-2099) */
mov dh, [mo] /* month (1-12) */
mov dl, [dy] /* day (1-31) */
int 0x21 /* AL = 0 on success */
cmp al, 0
je DONE
mov [year], 0
DONE:
 
pop dx
pop cx
pop bx
pop ax
}
 
if (year == 0) return(-1);
return(0);
}
 
 
static enum cmd_result cmd_date(struct cmd_funcparam *p) {
struct nls_patterns *nls = (void *)(p->BUFFER);
char *buff = p->BUFFER + sizeof(*nls);
unsigned short i;
unsigned short year = 0;
unsigned char mo, dy;
 
if (cmd_ishlp(p)) {
outputnl("Displays or sets the system date.");
outputnl("");
outputnl("DATE [date]");
outputnl("");
outputnl("Type DATE with no parameters to display the current date and a prompt for a");
outputnl("new one. Press ENTER to keep the same date.");
return(CMD_OK);
}
 
i = nls_getpatterns(nls);
if (i != 0) {
nls_outputnl_doserr(i);
return(CMD_FAIL);
}
 
/* display current date if no args */
if (p->argc == 0) {
/* get cur date */
_asm {
push ax
push cx
push dx
 
mov ah, 0x2a /* DOS 1+ -- Query DOS Date */
int 0x21 /* CX=year DH=month DL=day */
mov [year], cx
mov [mo], dh
mov [dy], dl
 
pop dx
pop cx
pop ax
}
buff[0] = ' ';
nls_format_date(buff + 1, year, mo, dy, nls);
output("Current date is");
outputnl(buff);
year = 0;
} else { /* parse date if provided */
if ((cmd_date_parse(p->argv[0], &year, &mo, &dy, nls) != 0) || (cmd_date_set(year, mo, dy) != 0)) {
outputnl("Invalid date");
year = 0;
}
}
 
/* ask for date if not provided or if input was malformed */
while (year == 0) {
output("Enter new date:");
output(" ");
/* collect user input into buff */
_asm {
push ax
push bx
push dx
 
mov ah, 0x0a /* DOS 1+ -- Buffered String Input */
mov bx, buff
mov dx, bx
mov al, 16
mov [bx], al /* max input length */
mov al, 1
mov [bx+1], al /* zero out the "previous entry" length */
int 0x21
/* terminate the string with a NULL terminator */
xor ax, ax
inc bx
mov al, [bx] /* read length of input string */
mov bx, ax
add bx, dx
mov [bx+2], ah
/* output a \n */
mov ah, 2
mov dl, 0x0A
int 0x21
 
pop dx
pop bx
pop ax
}
if (buff[1] == 0) break; /* empty string = no date change */
if ((cmd_date_parse(buff + 2, &year, &mo, &dy, nls) == 0) && (cmd_date_set(year, mo, dy) == 0)) break;
outputnl("Invalid date");
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/del.c
0,0 → 1,143
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* del/erase
*/
 
static enum cmd_result cmd_del(struct cmd_funcparam *p) {
const char *delspec = NULL;
unsigned short err = 0;
unsigned short confirmflag = 0;
unsigned short i;
unsigned short pathlimit = 0;
char *buff = p->BUFFER;
 
struct DTA *dta = (void *)0x80; /* use the default DTA at location 80h in PSP */
char *fname = dta->fname;
 
if (cmd_ishlp(p)) {
outputnl("Deletes one or more files.");
outputnl("");
outputnl("DEL [drive:][path]filename [/P]");
outputnl("ERASE [drive:][path]filename [/P]");
outputnl("");
outputnl("[drive:][path]filename Specifies the file(s) to delete.");
outputnl("/P Prompts for confirmation before deleting each file.");
return(CMD_OK);
}
 
if (p->argc == 0) {
outputnl("Required parameter missing");
return(CMD_FAIL);
}
 
/* scan argv for delspec and possible /p or /v */
for (i = 0; i < p->argc; i++) {
/* delspec? */
if (p->argv[i][0] == '/') {
if (imatch(p->argv[i], "/p")) {
confirmflag = 1;
} else {
output("Invalid switch:");
output(" ");
outputnl(p->argv[i]);
return(CMD_FAIL);
}
} else if (delspec != NULL) { /* otherwise its a delspec */
outputnl("Too many parameters");
return(CMD_FAIL);
} else {
delspec = p->argv[i];
}
}
 
/* convert path to canonical form */
file_truename(delspec, buff);
 
/* is delspec pointing at a directory? if so, add a \*.* */
i = path_appendbkslash_if_dir(buff);
if (buff[i - 1] == '\\') strcat(buff, "????????.???");
 
/* parse delspec in buff and remember where last backslash or slash is */
for (i = 0; buff[i] != 0; i++) if (buff[i] == '\\') pathlimit = i + 1;
 
/* is this about deleting all content inside a directory? if no per-file
* confirmation set, ask for a global confirmation */
if ((confirmflag == 0) && (imatch(buff + pathlimit, "????????.???"))) {
outputnl("All files in directory will be deleted!");
if (askchoice("Are you sure (Y/N)?", "YN") != 0) return(CMD_FAIL);
}
 
for (i = 0;; i = 1) {
 
/* exec FindFirst or FindNext */
if (i == 0) {
err = findfirst(dta, buff, DOS_ATTR_RO | DOS_ATTR_SYS | DOS_ATTR_HID);
if (err != 0) { /* report the error only if query had no wildcards */
for (i = 0; buff[i] != 0; i++) if (buff[i] == '?') break;
if (buff[i] == 0) nls_outputnl_doserr(err);
break;
}
} else {
if (findnext(dta) != 0) break; /* do not report errors on findnext() */
}
 
/* prep the full path/name of the file in buff */
/* NOTE: buff contained the search pattern but it is no longer needed so I
* can reuse it now */
strcpy(buff + pathlimit, fname);
 
/* ask if confirmation required: PLIK.TXT Delete (Y/N)? */
if (confirmflag) {
output(buff);
output(" \t");
if (askchoice("Delete (Y/N)?", "YN") != 0) continue;
}
 
/* del found file */
_asm {
push ax
push dx
mov ah, 0x41 /* delete a file, DS:DX points to an ASCIIZ filespec (no wildcards allowed) */
mov dx, buff
int 0x21
jnc DONE
mov [err], ax
DONE:
pop dx
pop ax
}
 
if (err != 0) {
output(fname);
output(": ");
nls_outputnl_doserr(err);
break;
}
}
 
if (err == 0) return(CMD_OK);
return(CMD_FAIL);
}
/svarcom/tags/svarcom-2022.0/cmd/dir.c
0,0 → 1,444
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* dir
*
* Displays a list of files and subdirectories in a directory.
*
* DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]
*
* /P Pauses after each screenful of information.
* /W Uses wide list format.
*
* /A Displays file with specified attributes:
* D Directories R Read-only files H Hidden files
* A Ready for archiving S System files - prefix meaning "not"
*
* /O List files in sorted order:
* N by name S by size E by extension
* D by date G group dirs first - prefix to reverse order
*
* /S Displays files in specified directory and all subdirectories.
* /B Uses bare format (no heading information or summary)
* /L Uses lowercases
*/
 
/* NOTE: /A attributes are matched in an exclusive way, ie. only files with
* the specified attributes are matched. This is different from how DOS
* itself matches attributes hence DIR cannot rely on the attributes
* filter within FindFirst.
*
* NOTE: Multiple /A are not supported - only the last one is significant.
*/
 
#define WCOLWIDTH 15 /* width of a column in wide mode output */
 
 
/* fills freebytes with free bytes for drv (A=0, B=1, etc)
* returns DOS ERR code on failure */
static unsigned short cmd_dir_df(unsigned long *freebytes, unsigned char drv) {
unsigned short res = 0;
unsigned short sects_per_clust = 0, avail_clusts = 0, bytes_per_sect = 0;
 
_asm {
push ax
push bx
push cx
push dx
 
mov ah, 0x36 /* DOS 2+ -- Get Disk Free Space */
mov dl, [drv] /* A=1, B=2, etc (0 = DEFAULT DRIVE) */
inc dl
int 0x21 /* AX=sects_per_clust, BX=avail_clusts, CX=bytes_per_sect, DX=tot_clusters */
cmp ax, 0xffff /* AX=0xffff on error (invalid drive) */
jne COMPUTEDF
mov [res], 0x0f /* fill res with DOS error code 15 ("invalid drive") */
jmp DONE
 
COMPUTEDF:
/* freebytes = AX * BX * CX */
mov [sects_per_clust], ax
mov [avail_clusts], bx
mov [bytes_per_sect], cx
 
DONE:
pop dx
pop cx
pop bx
pop ax
}
 
/* multiple steps to avoid uint16 overflow */
*freebytes = sects_per_clust;
*freebytes *= avail_clusts;
*freebytes *= bytes_per_sect;
 
return(res);
}
 
 
static void dir_pagination(unsigned short *availrows) {
*availrows -= 1;
if (*availrows == 0) {
press_any_key();
*availrows = screen_getheight() - 1;
}
}
 
 
/* parse an attr list like "Ar-hS" and fill bitfield into attrfilter_may and attrfilter_must.
* /AHS -> adds S and H to mandatory attribs ("must")
* /A-S -> removes S from allowed attribs ("may")
* returns non-zero on error. */
static int dir_parse_attr_list(const char *arg, unsigned char *attrfilter_may, unsigned char *attrfilter_must) {
for (; *arg != 0; arg++) {
unsigned char curattr;
char not;
if (*arg == '-') {
not = 1;
arg++;
} else {
not = 0;
}
switch (*arg) {
case 'd':
case 'D':
curattr = DOS_ATTR_DIR;
break;
case 'r':
case 'R':
curattr = DOS_ATTR_RO;
break;
case 'a':
case 'A':
curattr = DOS_ATTR_ARC;
break;
case 'h':
case 'H':
curattr = DOS_ATTR_HID;
break;
case 's':
case 'S':
curattr = DOS_ATTR_SYS;
break;
default:
return(-1);
}
/* update res bitfield */
if (not) {
*attrfilter_may &= ~curattr;
} else {
*attrfilter_must |= curattr;
}
}
return(0);
}
 
 
#define DIR_ATTR_DEFAULT (DOS_ATTR_RO | DOS_ATTR_DIR | DOS_ATTR_ARC)
 
static enum cmd_result cmd_dir(struct cmd_funcparam *p) {
const char *filespecptr = NULL;
struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */
unsigned short i;
unsigned short availrows; /* counter of available rows on display (used for /P) */
unsigned short wcols = screen_getwidth() / WCOLWIDTH; /* number of columns in wide mode */
unsigned char wcolcount;
struct nls_patterns *nls = (void *)(p->BUFFER + (p->BUFFERSZ / 2));
char *buff2 = p->BUFFER + (p->BUFFERSZ / 2) + sizeof(*nls);
unsigned long summary_fcount = 0;
unsigned long summary_totsz = 0;
unsigned char drv = 0;
unsigned char attrfilter_may = DIR_ATTR_DEFAULT;
unsigned char attrfilter_must = 0;
 
#define DIR_FLAG_PAUSE 1
#define DIR_FLAG_RECUR 4
#define DIR_FLAG_LCASE 8
unsigned char flags = 0;
 
#define DIR_OUTPUT_NORM 1
#define DIR_OUTPUT_WIDE 2
#define DIR_OUTPUT_BARE 3
unsigned char format = DIR_OUTPUT_NORM;
 
if (cmd_ishlp(p)) {
outputnl("Displays a list of files and subdirectories in a directory");
outputnl("");
outputnl("DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]");
outputnl("");
outputnl("/P Pauses after each screenful of information");
outputnl("/W Uses wide list format");
outputnl("");
outputnl("/A Displays files with specified attributes:");
outputnl(" D Directories R Read-only files H Hidden files");
outputnl(" A Ready for archiving S System files - prefix meaning \"not\"");
outputnl("");
outputnl("/O List files in sorted order:");
outputnl(" N by name S by size E by extension");
outputnl(" D by date G group dirs first - prefix to reverse order");
outputnl("");
outputnl("/S Displays files in specified directory and all subdirectories");
outputnl("/B Uses bare format (no heading information or summary)");
outputnl("/L Uses lowercases");
return(CMD_OK);
}
 
i = nls_getpatterns(nls);
if (i != 0) nls_outputnl_doserr(i);
 
/* parse command line */
for (i = 0; i < p->argc; i++) {
if (p->argv[i][0] == '/') {
const char *arg = p->argv[i] + 1;
char neg = 0;
/* detect negations and get actual argument */
if (*arg == '-') {
neg = 1;
arg++;
}
/* */
switch (*arg) {
case 'a':
case 'A':
arg++;
/* preset defaults */
attrfilter_may = DIR_ATTR_DEFAULT;
attrfilter_must = 0;
/* /-A only allowed without further parameters (used to cancel possible previous /Asmth) */
if (neg) {
if (*arg != 0) {
nls_outputnl_err(0, 2); /* invalid switch */
return(CMD_FAIL);
}
} else {
/* start with "allow everything" */
attrfilter_may = (DOS_ATTR_ARC | DOS_ATTR_DIR | DOS_ATTR_HID | DOS_ATTR_SYS | DOS_ATTR_RO);
if (dir_parse_attr_list(arg, &attrfilter_may, &attrfilter_must) != 0) {
nls_outputnl_err(0, 3); /* invalid parameter format */
return(CMD_FAIL);
}
}
break;
case 'b':
case 'B':
format = DIR_OUTPUT_BARE;
break;
case 'l':
case 'L':
flags |= DIR_FLAG_LCASE;
break;
case 'o':
case 'O':
/* TODO */
outputnl("/O NOT IMPLEMENTED YET");
return(CMD_FAIL);
break;
case 'p':
case 'P':
flags |= DIR_FLAG_PAUSE;
if (neg) flags &= (0xff ^ DIR_FLAG_PAUSE);
break;
case 's':
case 'S':
/* TODO */
outputnl("/S NOT IMPLEMENTED YET");
return(CMD_FAIL);
break;
case 'w':
case 'W':
format = DIR_OUTPUT_WIDE;
break;
default:
nls_outputnl_err(0, 2); /* invalid switch */
return(CMD_FAIL);
}
} else { /* filespec */
if (filespecptr != NULL) {
nls_outputnl_err(0, 4); /* too many parameters */
return(CMD_FAIL);
}
filespecptr = p->argv[i];
}
}
 
if (filespecptr == NULL) filespecptr = ".";
 
availrows = screen_getheight() - 2;
 
/* special case: "DIR drive:" (truename() fails on "C:" under MS-DOS 6.0) */
if ((filespecptr[0] != 0) && (filespecptr[1] == ':') && (filespecptr[2] == 0)) {
if ((filespecptr[0] >= 'a') && (filespecptr[0] <= 'z')) {
p->BUFFER[0] = filespecptr[0] - ('a' - 1);
} else {
p->BUFFER[0] = filespecptr[0] - ('A' - 1);
}
i = curpathfordrv(p->BUFFER, p->BUFFER[0]);
} else {
i = file_truename(filespecptr, p->BUFFER);
}
if (i != 0) {
nls_outputnl_doserr(i);
return(CMD_FAIL);
}
 
if (format != DIR_OUTPUT_BARE) {
drv = p->BUFFER[0];
if (drv >= 'a') {
drv -= 'a';
} else {
drv -= 'A';
}
cmd_vol_internal(drv, buff2);
sprintf(buff2, "Directory of %s", p->BUFFER);
/* trim at first '?', if any */
for (i = 0; buff2[i] != 0; i++) if (buff2[i] == '?') buff2[i] = 0;
outputnl(buff2);
outputnl("");
availrows -= 3;
}
 
/* if dir: append a backslash (also get its len) */
i = path_appendbkslash_if_dir(p->BUFFER);
 
/* if ends with a \ then append ????????.??? */
if (p->BUFFER[i - 1] == '\\') strcat(p->BUFFER, "????????.???");
 
/* ask DOS for list of files, but only with allowed attribs */
i = findfirst(dta, p->BUFFER, attrfilter_may);
if (i != 0) {
nls_outputnl_doserr(i);
return(CMD_FAIL);
}
 
wcolcount = 0; /* may be used for columns counting with wide mode */
 
do {
/* if mandatory attribs are requested, filter them now */
if ((attrfilter_must & dta->attr) != attrfilter_must) continue;
 
/* if file contains attributes that are not allowed -> skip */
if ((~attrfilter_may & dta->attr) != 0) continue;
 
/* turn string lcase (/L) */
if (flags & DIR_FLAG_LCASE) _strlwr(dta->fname); /* OpenWatcom extension, probably does not care about NLS so results may be odd with non-A-Z characters... */
 
summary_fcount++;
if ((dta->attr & DOS_ATTR_DIR) == 0) summary_totsz += dta->size;
 
switch (format) {
case DIR_OUTPUT_NORM:
/* print fname-space-extension (unless it's "." or "..", then print as-is) */
if (dta->fname[0] == '.') {
output(dta->fname);
i = strlen(dta->fname);
while (i++ < 12) output(" ");
} else {
file_fname2fcb(buff2, dta->fname);
memmove(buff2 + 9, buff2 + 8, 4);
buff2[8] = ' ';
output(buff2);
}
output(" ");
/* either <DIR> or right aligned 10-chars byte size */
memset(buff2, ' ', 10);
if (dta->attr & DOS_ATTR_DIR) {
strcpy(buff2 + 10, "<DIR>");
} else {
_ultoa(dta->size, buff2 + 10, 10); /* OpenWatcom extension */
}
output(buff2 + strlen(buff2) - 10);
/* two spaces and NLS DATE */
buff2[0] = ' ';
buff2[1] = ' ';
nls_format_date(buff2 + 2, dta->date_yr + 1980, dta->date_mo, dta->date_dy, nls);
output(buff2);
 
/* one space and NLS TIME */
nls_format_time(buff2 + 1, dta->time_hour, dta->time_min, 0xff, nls);
outputnl(buff2);
break;
 
case DIR_OUTPUT_WIDE: /* display in columns of 12 chars per item */
i = strlen(dta->fname);
if (dta->attr & DOS_ATTR_DIR) {
i += 2;
output("[");
output(dta->fname);
output("]");
} else {
output(dta->fname);
}
while (i++ < WCOLWIDTH) output(" ");
if (++wcolcount == wcols) {
wcolcount = 0;
outputnl("");
} else {
availrows++; /* wide mode is the only one that does not write one line per file */
}
break;
 
case DIR_OUTPUT_BARE:
outputnl(dta->fname);
break;
}
 
if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
 
} while (findnext(dta) == 0);
 
if (wcolcount != 0) {
outputnl(""); /* in wide mode make sure to end on a clear row */
if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
}
 
/* print out summary (unless bare output mode) */
if (format != DIR_OUTPUT_BARE) {
unsigned short alignpos;
/* x file(s) */
memset(buff2, ' ', 13); /* 13 is the max len of a 32 bit number with thousand separators (4'000'000'000) */
i = nls_format_number(buff2 + 13, summary_fcount, nls);
alignpos = sprintf(buff2 + 13 + i, " %s ", "file(s)");
output(buff2 + i);
/* xxxx bytes */
i = nls_format_number(buff2 + 13, summary_totsz, nls);
output(buff2 + i);
output(" ");
outputnl("bytes");
if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
/* xxxx bytes free */
i = cmd_dir_df(&summary_totsz, drv);
if (i != 0) nls_outputnl_doserr(i);
alignpos += 13 + 13;
memset(buff2, ' ', alignpos); /* align the freebytes value to same column as totbytes */
i = nls_format_number(buff2 + alignpos, summary_totsz, nls);
output(buff2 + i);
output(" ");
outputnl("bytes free");
if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/echo.c
0,0 → 1,95
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* echo
*/
 
static enum cmd_result cmd_echo(struct cmd_funcparam *p) {
const char *arg = p->cmdline + 5;
 
/* display help only if /? is the only argument */
if ((p->argc == 1) && (imatch(p->argv[0], "/?"))) {
outputnl("Displays messages, or turns command-echoing on or off");
outputnl("");
outputnl("ECHO [ON | OFF]");
outputnl("ECHO [message]");
outputnl("");
outputnl("Type ECHO without parameters to display the current echo setting.");
return(CMD_OK);
}
 
/* ECHO without any parameter: display current state */
if (p->argc == 0) {
if (p->rmod->flags & FLAG_ECHOFLAG) {
outputnl("ECHO is on");
} else {
outputnl("ECHO is off");
}
return(CMD_OK);
}
 
/* ECHO ON */
if ((p->argc == 1) && (imatch(p->argv[0], "on"))) {
p->rmod->flags |= FLAG_ECHOFLAG;
return(CMD_OK);
}
 
/* ECHO OFF */
if ((p->argc == 1) && (imatch(p->argv[0], "off"))) {
p->rmod->flags &= ~FLAG_ECHOFLAG;
return(CMD_OK);
}
 
/* ECHO MSG (start at cmdline+5 since first 5 are "ECHO" + separator) */
_asm {
push ax
push dx
push si
 
mov si, [arg]
cld /* clear direction flag (DF) so lodsb increments SI */
mov ah, 0x02 /* display char from DL */
NEXTYBTE:
lodsb /* load byte at DS:[SI] into AL and inc SI (if DF clear) */
or al, al /* is AL == 0? then end of string reached */
jz DONE
mov dl, al
int 0x21
jmp NEXTYBTE
 
/* output a final CR/LF */
DONE:
mov dl, 0x0D
int 0x21
mov dl, 0x0A
int 0x21
 
pop si
pop dx
pop ax
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/exit.c
0,0 → 1,40
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* exit
*
* Quits the COMMAND.COM program (command interpreter)
*
*/
 
static enum cmd_result cmd_exit(struct cmd_funcparam *p) {
if (cmd_ishlp(p)) {
outputnl("EXIT\r\n");
outputnl("Quits the COMMAND.COM program (command interpreter)");
} else {
sayonara(p->rmod);
}
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/if.c
0,0 → 1,138
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* if [not] exists
* if [not] errorlevel 1
* if [not] string ==string (string==string and string == string works, too)
* if [not] errorlevel == 1 <-- I do NOT support this one, even though
* MSDOS 5 and 6 considers it equivalent to
* IF ERRORLEVEL 1. This is a misleading and
* undocumented syntax (does not actually
* check for equality).
*/
 
 
#define JMP_NEXT_ARG(s) while ((*s != ' ') && (*s != 0)) s++; while (*s == ' ') s++;
 
 
static enum cmd_result cmd_if(struct cmd_funcparam *p) {
unsigned char negflag = 0;
unsigned short i;
const char *s = p->cmdline + p->argoffset;
 
/* help screen ONLY if /? is the only argument - I do not want to output
* help for ex. for "if %1 == /? echo ..." */
if ((p->argc == 1) && (imatch(p->argv[0], "/?"))) {
outputnl("Performs conditional processing in batch programs.");
outputnl("");
outputnl("IF [NOT] ERRORLEVEL num command");
outputnl("IF [NOT] string1==string2 command");
outputnl("IF [NOT] EXIST filename command");
outputnl("");
outputnl("NOT command is executed only if condition is NOT met");
outputnl("ERRORLEVEL num condition: last program returned an exit code >= num");
outputnl("string1==string2 condition: both strings must be equal");
outputnl("EXIST filename condition: filename exists (wildcards accepted)");
outputnl("command command to carry out if condition is met.");
return(CMD_OK);
}
 
/* negation? */
if (imatchlim(s, "NOT ", 4)) {
negflag = 1;
JMP_NEXT_ARG(s);
}
 
/* IF ERRORLEVEL x cmd */
if (imatchlim(s, "ERRORLEVEL ", 11)) {
unsigned char far *rmod_exitcode = MK_FP(p->rmod->rmodseg, RMOD_OFFSET_LEXITCODE);
JMP_NEXT_ARG(s);
if (*s == 0) goto SYNTAX_ERR;
/* convert errorlevel to an uint */
if ((*s < '0') || (*s > '9')) {
i = 0xffff;
} else {
atous(&i, s);
}
/* move s to command */
JMP_NEXT_ARG(s);
/* is errorlevel matching? */
if (i <= *rmod_exitcode) negflag ^= 1;
goto EXEC_S_CMD_IF_NEGFLAG_SET;
}
 
/* IF EXIST fname (or wildcard)
* TODO: checking for a file on an empty diskette drive should NOT lead bother
* the user with the stupid 'retry, abort, fail' query! */
if (imatchlim(s, "EXIST ", 6)) {
struct DTA *dta = (void *)(0x80); /* default dta location */
JMP_NEXT_ARG(s);
/* copy filename to buffer */
for (i = 0; (s[i] != ' ') && (s[i] != 0); i++) p->BUFFER[i] = s[i];
p->BUFFER[i] = 0;
/* move s to command */
JMP_NEXT_ARG(s);
if (*s == 0) goto SYNTAX_ERR; /* check now to avoid moving the diskette drive if syntax bad anyway */
/* does file exist? */
if (findfirst(dta, p->BUFFER, 0) == 0) negflag ^= 1;
goto EXEC_S_CMD_IF_NEGFLAG_SET;
}
 
/* IF str1==str2 ? (and if that's not it, then it's a syntax error) */
if (strstr(s, "==") != NULL) {
/* copy first argument to BUFF, until first '=' or space */
for (i = 0; (s[i] != '=') && (s[i] != ' '); i++) p->BUFFER[i] = s[i];
/* 1st arg cannot be empty */
if (i == 0) goto SYNTAX_ERR;
/* terminate buff string and move s forward to the equality char (or space) */
p->BUFFER[i++] = 0;
s += i;
while (*s == ' ') s++;
/* if second char is not a '=' then syntax error (equality sign is not
* allowed in first string) */
if (*s != '=') goto SYNTAX_ERR;
/* skip all trailing equality chars (MSDOS accepts many of them, ie all
* these are fine: "dupa==dupa", "dupa===dupa", "dupa====dupa", etc) */
while (*s == '=') s++;
while (*s == ' ') s++; /* skip any leading spaces */
/* move along until space or NULL terminator, checking equality */
for (i = 0; (p->BUFFER[i] != 0) && (p->BUFFER[i] == s[i]); i++);
if ((p->BUFFER[i] == 0) && (s[i] == ' ')) negflag ^= 1;
JMP_NEXT_ARG(s);
goto EXEC_S_CMD_IF_NEGFLAG_SET;
}
 
/* invalid syntax */
SYNTAX_ERR:
outputnl("Syntax error");
return(CMD_FAIL);
 
/* let's exec command (write it to start of cmdline and parse again) */
EXEC_S_CMD_IF_NEGFLAG_SET:
if (*s == 0) goto SYNTAX_ERR;
if (negflag == 0) return(CMD_OK);
memmove((void *)(p->cmdline), s, strlen(s) + 1); /* cmdline and s share the same memory! */
return(CMD_CHANGED);
}
/svarcom/tags/svarcom-2022.0/cmd/ln.c
0,0 → 1,257
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021-2022 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* ln add linkname linkdir
* ln del linkname
* ln list [pattern]
*/
 
static enum cmd_result cmd_lnadd(char *BUFFER, const char *linkname, const char *targetdir, unsigned short env_seg) {
const char *ext;
char *realdirname = BUFFER;
unsigned short realdirnamelen;
char *buff = BUFFER + 256;
unsigned short doserr;
 
/* convert dirname to realpath */
doserr = file_truename(targetdir, realdirname);
if (doserr != 0) {
nls_outputnl_doserr(doserr);
return(CMD_FAIL);
}
 
/* does EXENAME in DIRECTORY exist? */
if (lookup_cmd(buff, linkname, realdirname, &ext) != 0) {
outputnl("No matching executable found in given path.");
return(CMD_FAIL);
}
 
/* open DOSDIR\CFG\LINKS.DB and write realdirname to */
if (link_computefname(buff, linkname, env_seg) != 0) return(CMD_FAIL);
 
realdirnamelen = strlen(realdirname);
 
/* open file *only if it does not exist yet* and write realdirname to it */
_asm {
push ax
push bx
push cx
push dx
 
mov ax, 0x6c00 /* extended OPEN */
mov bx, 1 /* open for WRITE */
xor cx, cx /* create the file with no attributes */
mov dx, 0x0010 /* create file if it does not exists, otherwise fail */
mov si, buff /* file name */
int 0x21
jnc WRITE
mov doserr, ax
jmp DONE
 
WRITE:
mov bx, ax /* file handle */
mov ah, 0x40 /* write to file */
mov cx, realdirnamelen
mov dx, realdirname
int 0x21
 
mov ah, 0x3e /* close file in BX */
int 0x21
 
DONE:
 
pop dx
pop cx
pop bx
pop ax
}
 
if (doserr != 0) {
nls_outputnl_doserr(doserr);
return(CMD_FAIL);
}
 
return(CMD_OK);
}
 
 
static enum cmd_result cmd_lndel(char *buff, const char *linkname, unsigned short env_seg) {
unsigned short i;
 
/* is the argument valid? (must not contain any dot nor backslash) */
for (i = 0; linkname[i] != 0; i++) {
if ((linkname[i] == '.') || (linkname[i] == '/') || (linkname[i] == '\\')) {
outputnl("Bad link name");
return(CMD_OK);
}
}
 
/* prep link filename to look at */
if (link_computefname(buff, linkname, env_seg) != 0) return(CMD_FAIL);
 
/* try removing it */
i = 0;
_asm {
push ax
push bx
push cx
push dx
 
mov ah, 0x41
mov dx, buff
int 0x21
jnc SUCCESS
mov i, ax
SUCCESS:
 
pop dx
pop cx
pop bx
pop ax
}
 
if (i != 0) nls_outputnl_doserr(i);
 
return(CMD_OK);
}
 
 
static enum cmd_result cmd_lnlist(char *buff, const char *linkname, unsigned short env_seg) {
unsigned short i, pathlen;
struct DTA *dta = (void *)0x80;
char *buff128 = buff + 256;
char *buff16 = buff128 + 128;
 
if (linkname != NULL) {
/* make sure link pattern is valid (must not contain '.' or '\\' or '/') */
for (i = 0; linkname[i] != 0; i++) {
switch (linkname[i]) {
case '.':
case '/':
case '\\':
outputnl("Invalid link pattern");
return(CMD_FAIL);
}
}
} else {
linkname = "*";
}
 
/* fetch %DOSDIR% */
pathlen = env_lookup_valcopy(buff, 128, env_seg, "DOSDIR");
if (pathlen == 0) {
outputnl("%DOSDIR% not defined");
return(CMD_FAIL);
}
 
/* prep DOSDIR\LINKS\pattern */
if (buff[pathlen - 1] == '\\') pathlen--;
pathlen += sprintf(buff + pathlen, "\\LINKS\\");
sprintf(buff + pathlen, "%s.LNK", linkname);
 
if (findfirst(dta, buff, DOS_ATTR_RO | DOS_ATTR_ARC) != 0) return(CMD_OK);
 
do {
/* print link file name (but trim ".lnk") */
for (i = 0; (dta->fname[i] != 0) && (dta->fname[i] != '.'); i++) buff16[i] = dta->fname[i];
if (i < 8) buff16[i++] = '\t';
buff16[i] = 0;
output(buff16);
output(" @ ");
/* prep full link filename */
strcpy(buff + pathlen, dta->fname);
/* read up to 128 bytes from link file to buff and display it */
i = 0;
_asm {
push ax
push bx
push cx
push dx
 
/* open file */
mov ax, 0x3d00
mov dx, buff /* filename */
int 0x21
jc FAIL_FOPEN
/* read from file */
mov bx, ax
mov ah, 0x3f
mov cx, 128
mov dx, buff128
int 0x21
jc FAIL_FREAD
mov i, ax
/* close file */
FAIL_FREAD:
mov ah, 0x3e
int 0x21
FAIL_FOPEN:
 
pop dx
pop cx
pop bx
pop ax
}
buff128[i] = 0;
/* make sure no cr or lf is present */
for (i = 0; buff128[i] != 0; i++) {
if ((buff128[i] == '\r') || (buff128[i] == '\n')) {
buff128[i] = 0;
break;
}
}
outputnl(buff128);
} while (findnext(dta) == 0);
 
return(CMD_OK);
}
 
 
static enum cmd_result cmd_ln(struct cmd_funcparam *p) {
if (cmd_ishlp(p)) {
outputnl("Adds, deletes or displays executable links.");
outputnl("");
outputnl("LN ADD linkname targetdir");
outputnl("LN DEL linkname");
outputnl("LN LIST [pattern]");
return(CMD_OK);
}
 
if (p->argc == 0) {
outputnl("Not enough parameters");
return(CMD_OK);
}
 
/* detect what subfunction the user wants */
if ((imatch(p->argv[0], "add")) && (p->argc == 3)) return(cmd_lnadd(p->BUFFER, p->argv[1], p->argv[2], p->env_seg));
if ((imatch(p->argv[0], "del")) && (p->argc == 2)) return(cmd_lndel(p->BUFFER, p->argv[1], p->env_seg));
if (imatch(p->argv[0], "list")) {
if (p->argc == 1) return(cmd_lnlist(p->BUFFER, NULL, p->env_seg));
if (p->argc == 2) return(cmd_lnlist(p->BUFFER, p->argv[1], p->env_seg));
}
 
outputnl("Invalid argument");
return(CMD_FAIL);
}
/svarcom/tags/svarcom-2022.0/cmd/mkdir.c
0,0 → 1,77
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* mkdir
*/
 
static enum cmd_result cmd_mkdir(struct cmd_funcparam *p) {
const char *dname = p->argv[0];
unsigned short err = 0;
 
if (cmd_ishlp(p)) {
outputnl("Creates a directory");
outputnl("");
outputnl("MKDIR [drive:]path");
outputnl("MD [drive:]path");
return(CMD_OK);
}
 
if (p->argc == 0) {
outputnl("Required parameter missing");
return(CMD_FAIL);
}
 
if (p->argc > 1) {
outputnl("Too many parameters");
return(CMD_FAIL);
}
 
if (p->argv[0][0] == '/') {
outputnl("Invalid parameter");
return(CMD_FAIL);
}
 
_asm {
push ax
push dx
 
mov ah, 0x39 /* create new directory, DS:DX points to ASCIIZ dir name */
mov dx, [dname]
int 0x21
jnc DONE
mov [err], ax
DONE:
 
pop dx
pop ax
}
 
if (err != 0) {
nls_outputnl_doserr(err);
return(CMD_FAIL);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/path.c
0,0 → 1,90
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* path
*
* Displays or sets a search path for executable files.
*/
 
static enum cmd_result cmd_path(struct cmd_funcparam *p) {
char *buff = p->BUFFER;
 
/* help screen (/?) */
if (cmd_ishlp(p)) {
output("Displays or sets a search path for executable files.\r\n"
"\r\n"
"PATH [[drive:]path[;...]]\r\n"
"PATH ;\r\n"
"\r\n"
"Type PATH ; to clear all search-path settings and direct DOS to search\r\n"
"only in the current directory.\r\n"
"\r\n"
"Type PATH without parameters to display the current path.\r\n");
return(CMD_OK);
}
 
/* no parameter - display current path */
if (p->argc == 0) {
char far *curpath = env_lookup(p->env_seg, "PATH");
if (curpath == NULL) {
outputnl("No Path");
} else {
unsigned short i;
for (i = 0;; i++) {
buff[i] = curpath[i];
if (buff[i] == 0) break;
}
outputnl(buff);
}
return(CMD_FAIL);
}
 
/* more than 1 parameter */
if (p->argc > 1) {
outputnl("Too many parameters");
return(CMD_FAIL);
}
 
/* IF HERE: THERE IS EXACTLY 1 ARGUMENT (argc == 1) */
 
/* reset the PATH string (PATH ;) */
if (imatch(p->argv[0], ";")) {
env_dropvar(p->env_seg, "PATH");
return(CMD_OK);
}
 
/* otherwise set PATH to whatever is passed on command-line */
{
unsigned short i;
strcpy(buff, "PATH=");
for (i = 0;; i++) {
buff[i + 5] = p->argv[0][i];
if (buff[i + 5] == 0) break;
}
env_setvar(p->env_seg, buff);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/pause.c
0,0 → 1,38
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* pause
*/
 
 
static enum cmd_result cmd_pause(struct cmd_funcparam *p) {
if (cmd_ishlp(p)) {
nls_outputnl(15, 0);
outputnl("\r\nPAUSE");
} else {
press_any_key();
}
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/prompt.c
0,0 → 1,60
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* prompt
*
* Changes the DOS command prompt.
*
*/
 
static enum cmd_result cmd_prompt(struct cmd_funcparam *p) {
 
if (cmd_ishlp(p)) {
outputnl("Changes the DOS command prompt.");
outputnl("");
outputnl("PROMPT [new command prompt specification]");
return(CMD_OK);
}
 
/* no parameter - restore default prompt path */
if (p->argc == 0) {
env_dropvar(p->env_seg, "PROMPT");
return(CMD_OK);
}
 
/* otherwise set PROMPT to whatever is passed on command-line */
{
unsigned short i;
char *buff = p->BUFFER;
strcpy(buff, "PROMPT=");
for (i = 0;; i++) {
buff[i + 7] = p->cmdline[p->argoffset + i];
if (buff[i + 7] == 0) break;
}
env_setvar(p->env_seg, buff);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/rem.c
0,0 → 1,38
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* rem
*/
 
static enum cmd_result cmd_rem(struct cmd_funcparam *p) {
/* help screen ONLY if /? is the only argument - I do not want to output
* help for ex. for "REM mouse.com /?" */
if ((p->argc == 1) && (imatch(p->argv[0], "/?"))) {
outputnl("Records comments (remarks) in a batch file or CONFIG.SYS");
outputnl("");
outputnl("REM [comment]");
}
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/rename.c
0,0 → 1,163
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* rename/ren
*/
 
static enum cmd_result cmd_rename(struct cmd_funcparam *p) {
char *src = p->BUFFER;
char *dst = p->BUFFER + 256;
char *buff1 = p->BUFFER + 512;
char *buff2 = p->BUFFER + 1024;
unsigned short i, fnameoffset;
struct DTA *dta = (void *)0x80; /* use default DTA in PSP */
 
if (cmd_ishlp(p)) {
outputnl("Renames a file or files");
outputnl("");
outputnl("RENAME [drive:][path]filename1 filename2");
outputnl("REN [drive:][path]filename1 filename2");
outputnl("");
outputnl("Note that you cannot specify a new drive or path for your destination file.");
outputnl("Use MOVE to rename a directory, or to move files from one directory to another.");
return(CMD_OK);
}
 
/* I expect exactly two arguments */
if (p->argc != 2) {
outputnl("Invalid syntax");
return(CMD_FAIL);
}
 
/* convert src to truename format */
i = file_truename(p->argv[0], src);
if (i != 0) {
nls_outputnl_doserr(i);
return(CMD_FAIL);
}
 
/* copy src path to buffers and remember where the filename starts */
fnameoffset = 0;
for (i = 0;; i++) {
buff1[i] = src[i];
buff2[i] = src[i];
if (buff1[i] == '\\') fnameoffset = i + 1;
if (buff1[i] == 0) break;
}
 
/* now append dst filename to the buffer and validate it: cannot contain backslash, slash or ':' */
for (i = 0;; i++) {
switch (p->argv[1][i]) {
case ':':
case '\\':
case '/':
outputnl("Invalid destination");
return(CMD_FAIL);
}
buff1[fnameoffset + i] = p->argv[1][i];
if (buff1[fnameoffset + i] == 0) break;
}
 
/* apply truename to dest to normalize wildcards into ? chars */
i = file_truename(buff1, dst);
if (i != 0) {
nls_outputnl_doserr(i);
return(CMD_FAIL);
}
 
/* we're good to go, src and dst should look somehow like that now:
* src = C:\TEMP\PATH\FILE????.TXT
* dst = C:\TEMP\PATH\FILE????.DOC
* buff1 = C:\TEMP\PATH\
* buff2 = C:\TEMP\PATH\
* fnameoffset = 13
*
* src is used for FindFirst/FindNext iterations, then buff1 is filled with
* the source filename found by FindFirst/FindNext and buff2 is filled with
* the destination file (with ?'s replaced by whatever is found at the same
* location in buff1).
*/
 
i = findfirst(dta, src, 0);
if (i != 0) nls_outputnl_doserr(i);
 
while (i == 0) {
/* write found fname into buff1 and dst fname into buff2 - both in FCB
* format (MYFILE EXT) so it is easy to compare them */
file_fname2fcb(buff1 + fnameoffset, dta->fname);
file_fname2fcb(buff2 + fnameoffset, dst + fnameoffset);
 
/* scan buff2 fname for '?' and replace them with whatever is in buff1 */
for (i = fnameoffset; buff2[i] != 0; i++) {
if (buff2[i] == '?') buff2[i] = buff1[i];
}
 
/* fill buff1 with the 8+3 found file and convert the one in buff2 to 8+3 as well */
file_fcb2fname(buff1 + fnameoffset, buff2 + fnameoffset);
strcpy(buff2 + fnameoffset, buff1 + fnameoffset);
strcpy(buff1 + fnameoffset, dta->fname);
 
/* buff1 contains now a fully resolved source and buff2 a proper destination */
#if 0 /* DEBUG ("if 1" to enable) */
output(buff1);
output(" -> ");
outputnl(buff2);
#endif
/* call DOS to do the actual job */
i = 0;
_asm {
push ax
push di
push dx
push es
 
mov ah, 0x56 /* rename file: DS:DX=ASCIIZ of src ES:DI=ASCIIZ of dst */
push ds
pop es
mov dx, buff1
mov di, buff2
int 0x21 /* CF clear on success, otherwise err code in AX */
jnc DONE
mov [i], ax /* copy error code to i */
DONE:
 
pop es
pop dx
pop di
pop ax
}
if (i != 0) {
output(buff1 + fnameoffset);
output(" -> ");
output(buff2 + fnameoffset);
output(" ");
nls_outputnl_doserr(i);
}
/* next please */
i = findnext(dta);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/rmdir.c
0,0 → 1,77
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* rmdir
*/
 
static enum cmd_result cmd_rmdir(struct cmd_funcparam *p) {
const char *dname = p->argv[0];
unsigned short err = 0;
 
if (cmd_ishlp(p)) {
outputnl("Removes (deletes) a directory");
outputnl("");
outputnl("RMDIR [drive:]path");
outputnl("RD [drive:]path");
return(CMD_OK);
}
 
if (p->argc == 0) {
outputnl("Required parameter missing");
return(CMD_FAIL);
}
 
if (p->argc > 1) {
outputnl("Too many parameters");
return(CMD_FAIL);
}
 
if (p->argv[0][0] == '/') {
outputnl("Invalid parameter");
return(CMD_FAIL);
}
 
_asm {
push ax
push dx
 
mov ah, 0x3a /* delete a directory, DS:DX points to ASCIIZ dir name */
mov dx, [dname]
int 0x21
jnc DONE
mov [err], ax
DONE:
 
pop dx
pop ax
}
 
if (err != 0) {
nls_outputnl_doserr(err);
return(CMD_FAIL);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/set.c
0,0 → 1,100
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* set [varname[=value]]
*
* value cannot contain any '=' character, but it can contain spaces
* varname can also contain spaces
*/
 
 
static enum cmd_result cmd_set(struct cmd_funcparam *p) {
char far *env = MK_FP(p->env_seg, 0);
char *buff = p->BUFFER;
 
if (cmd_ishlp(p)) {
outputnl("Displays, sets, or removes DOS environment variables");
outputnl("");
outputnl("SET [variable=[string]]");
outputnl("");
outputnl("variable Specifies the environment-variable name");
outputnl("string Specifies a series of characters to assign to the variable");
outputnl("");
outputnl("Type SET without parameters to display the current environment variables.");
return(CMD_OK);
}
 
/* no arguments - display content */
if (p->argc == 0) {
while (*env != 0) {
unsigned short i;
/* copy string to local buff for display */
for (i = 0;; i++) {
buff[i] = *env;
env++;
if (buff[i] == 0) break;
}
outputnl(buff);
}
} else { /* set variable (do not rely on argv, SET has its own rules...) */
const char far *ptr;
unsigned short i;
/* locate the first space */
for (ptr = p->cmdline; *ptr != ' '; ptr++);
/* now locate the first non-space: that's where the variable name begins */
for (; *ptr == ' '; ptr++);
/* copy variable to buff and switch it upercase */
i = 0;
for (; *ptr != '='; ptr++) {
if (*ptr == 0) goto syntax_err;
buff[i] = *ptr;
if ((buff[i] >= 'a') && (buff[i] <= 'z')) buff[i] -= ('a' - 'A');
i++;
}
 
/* copy value now */
while (*ptr != 0) {
buff[i++] = *ptr;
ptr++;
}
 
/* terminate buff */
buff[i] = 0;
 
/* commit variable to environment */
i = env_setvar(p->env_seg, buff);
if (i == ENV_INVSYNT) goto syntax_err;
if (i == ENV_NOTENOM) {
outputnl("Not enough available space within the environment block");
return(CMD_FAIL);
}
}
return(CMD_OK);
 
syntax_err:
 
outputnl("Syntax error");
return(CMD_FAIL);
}
/svarcom/tags/svarcom-2022.0/cmd/shift.c
0,0 → 1,52
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* shift
*/
 
static enum cmd_result cmd_shift(struct cmd_funcparam *p) {
char far *batargv = p->rmod->batargv;
char far *nextarg;
 
if (cmd_ishlp(p)) {
nls_outputnl(16, 0);
nls_outputnl(16, 1);
outputnl("");
outputnl("SHIFT");
return(CMD_OK);
}
 
/* abort if batargv is empty */
if (*batargv == 0) return(CMD_OK);
 
/* find the next argument in batargv */
for (nextarg = batargv + 1; *nextarg != 0; nextarg++);
nextarg++; /* move ptr past the zero terminator */
 
/* move down batargv so 2nd argument is at the head now */
_fmemmove(batargv, nextarg, sizeof(p->rmod->batargv) - (nextarg - batargv));
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/time.c
0,0 → 1,254
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* time [time]
*/
 
 
/* read a one or two digit number and write it to buff */
static int cmd_time_get_item(char *buff, const char *s) {
unsigned short i;
 
for (i = 0; i < 3; i++) {
if ((s[i] < '0') || (s[i] > '9')) {
buff[i] = 0;
return(0);
}
buff[i] = s[i];
}
 
/* err */
*buff = 0;
return(-1);
}
 
 
/* parse a NULL-terminated string int hour, minutes and seconds, returns 0 on success
* valid inputs: 0, 7, 5:5, 23:23, 17:54:45, 9p, 9:05, ...
*/
static int cmd_time_parse(const char *s, signed char *ho, signed char *mi, signed char *se, struct nls_patterns *nls) {
unsigned short i;
const char *ptrs[2] = {NULL, NULL}; /* minutes, seconds */
char buff[3];
char ampm = 0;
 
*ho = -1;
*mi = 0;
*se = 0;
 
/* validate input - must contain only chars 0-9, time separator and 'a' or 'p' */
for (i = 0; s[i] != 0; i++) {
switch (s[i]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
case 'a':
case 'A':
case 'p':
case 'P':
/* these can be only at last position and never at the first */
if ((s[i + 1] != 0) || (i == 0)) return(-1);
ampm = s[i];
if (ampm >= 'a') ampm -= ('a' - 'A');
break;
default:
if ((s[i] != nls->timesep[0]) || (i == 0)) return(-1);
if (ptrs[0] == NULL) {
ptrs[0] = s + i + 1;
} else if (ptrs[1] == NULL) {
ptrs[1] = s + i + 1;
} else { /* too many separators */
return(-1);
}
break;
}
}
 
/* read hour */
if (cmd_time_get_item(buff, s) != 0) goto FAIL;
if (atous(&i, buff) != 0) goto FAIL;
*ho = i;
 
/* if minutes provided, read them */
if (ptrs[0] != NULL) {
if (cmd_time_get_item(buff, ptrs[0]) != 0) goto FAIL;
if (atous(&i, buff) != 0) goto FAIL;
*mi = i;
}
 
/* if seconds provided, read them */
if (ptrs[1] != NULL) {
if (cmd_time_get_item(buff, ptrs[1]) != 0) goto FAIL;
if (atous(&i, buff) != 0) goto FAIL;
*se = i;
}
 
/* validate ranges */
if ((*ho > 23) || (*mi > 59) || (*se > 59)) goto FAIL;
 
/* am? */
if ((ampm == 'A') && (*ho > 12)) goto FAIL;
if ((ampm == 'A') && (*ho == 12)) *ho = 0; /* 12:00am is 00:00 (midnight) */
 
/* pm? */
if (ampm == 'P') {
if (*ho > 12) goto FAIL;
if (*ho < 12) *ho += 12;
}
 
return(0);
 
FAIL:
*ho = -1;
return(-1);
}
 
 
static enum cmd_result cmd_time(struct cmd_funcparam *p) {
struct nls_patterns *nls = (void *)(p->BUFFER);
char *buff = p->BUFFER + sizeof(*nls);
unsigned short i;
signed char ho = -1, mi = -1, se = -1;
 
if (cmd_ishlp(p)) {
outputnl("Displays or sets the system time.");
outputnl("");
outputnl("TIME [time]");
outputnl("");
outputnl("Type TIME with no parameters to display the current time and a prompt for a");
outputnl("new one. Press ENTER to keep the same time.");
return(CMD_OK);
}
 
i = nls_getpatterns(nls);
if (i != 0) {
nls_outputnl_doserr(i);
return(CMD_FAIL);
}
 
/* display current time if no args */
if (p->argc == 0) {
/* get cur time */
_asm {
push ax
push bx
push cx
push dx
 
mov ah, 0x2c /* DOS 1+ -- Query DOS Time */
int 0x21 /* CH=hour CL=minutes DH=seconds DL=1/100sec */
mov [ho], ch
mov [mi], cl
mov [se], dh
 
pop dx
pop cx
pop bx
pop ax
}
buff[0] = ' ';
nls_format_time(buff + 1, ho, mi, se, nls);
output("Current time is");
outputnl(buff);
ho = -1;
} else { /* parse time if provided */
if (cmd_time_parse(p->argv[0], &ho, &mi, &se, nls) != 0) {
outputnl("Invalid time");
ho = -1;
}
}
 
/* ask for time if not provided or if input was malformed */
while (ho < 0) {
output("Enter new time:");
output(" ");
/* collect user input into buff */
_asm {
push ax
push bx
push dx
 
mov ah, 0x0a /* DOS 1+ -- Buffered String Input */
mov bx, buff
mov dx, bx
mov al, 16
mov [bx], al /* max input length */
mov al, 1
mov [bx+1], al /* zero out the "previous entry" length */
int 0x21
/* terminate the string with a NULL terminator */
xor ax, ax
inc bx
mov al, [bx] /* read length of input string */
mov bx, ax
add bx, dx
mov [bx+2], ah
/* output a \n */
mov ah, 2
mov dl, 0x0A
int 0x21
 
pop dx
pop bx
pop ax
}
if (buff[1] == 0) break; /* empty string = do not change time */
if (cmd_time_parse(buff + 2, &ho, &mi, &se, nls) == 0) break;
outputnl("Invalid time");
return(CMD_FAIL);
}
 
if (ho >= 0) {
/* set time */
_asm {
push ax
push bx
push cx
push dx
 
mov ah, 0x2d /* DOS 1+ -- Set DOS Time */
mov ch, [ho] /* hour (0-23) */
mov cl, [mi] /* minutes (0-59) */
mov dh, [se] /* seconds (0-59) */
mov dl, 0 /* 1/100th seconds (0-99) */
int 0x21
 
pop dx
pop cx
pop bx
pop ax
}
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/type.c
0,0 → 1,113
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* type
*/
 
static enum cmd_result cmd_type(struct cmd_funcparam *p) {
char *buff = p->BUFFER;
const char *fname = p->argv[0];
unsigned short err = 0;
 
if (cmd_ishlp(p)) {
outputnl("Displays the contents of a text file.");
outputnl("");
outputnl("TYPE [drive:][path]filename");
return(CMD_OK);
}
 
if (p->argc == 0) {
outputnl("Required parameter missing");
return(CMD_FAIL);
}
 
if (p->argc > 1) {
outputnl("Too many parameters");
return(CMD_FAIL);
}
 
/* if here then display the file */
_asm {
push ax
push bx
push cx
push dx
push si
 
mov ax, 0x3d00 /* open file via handle, access mode in AL (0 = read) */
mov dx, fname
int 0x21 /* file handle in ax on success (CF clear) */
jnc FILE_OPEN_OK
mov [err], ax /* on error AX contains the DOS err code */
jmp FOPENFAIL
FILE_OPEN_OK:
/* copy obtained file handle to BX */
mov bx, ax
 
READNEXTBLOCK:
/* read file block by block */
mov cx, 1024 /* read 1K at a time */
mov dx, buff
mov ah, 0x3f /* read CX bytes from file handle in BX and write to DS:DX */
int 0x21 /* CF set on error, AX=errno or AX=number of bytes read */
jc GOTERROR /* abort on error */
test ax, ax /* EOF? */
jz ENDFILE
/* display read block (AX=len) */
mov si, dx /* preset DS:SI to DS:DX (DL will be reused soon) */
mov cx, ax /* set loop count to CX */
mov ah, 0x02 /* write character in DL to stdout */
NEXTCHAR:
mov dl, [si]
inc si
int 0x21
loopnz NEXTCHAR /* CX-- ; jnz NEXTCHAR (display CX characters) */
/* read (and display) next block */
jmp READNEXTBLOCK
 
GOTERROR:
mov [err], ax
 
ENDFILE:
/* close file */
mov ah, 0x3e /* close file handle (file handle already in BX) */
int 0x21
 
FOPENFAIL:
 
pop si
pop dx
pop cx
pop bx
pop ax
}
 
if (err != 0) {
nls_outputnl_doserr(err);
return(CMD_FAIL);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/ver.c
0,0 → 1,126
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021-2022 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* ver
*/
 
#define PVER "2022.0"
#define COPYRDATE "2021-2022"
 
static enum cmd_result cmd_ver(struct cmd_funcparam *p) {
char *buff = p->BUFFER;
unsigned char maj = 0, min = 0;
 
/* help screen */
if (cmd_ishlp(p)) {
outputnl("Displays the DOS version.");
outputnl("");
outputnl("ver [/about]");
#ifdef VERDBG
outputnl("ver /dbg");
#endif
return(CMD_OK);
}
 
#ifdef VERDBG
if ((p->argc == 1) && (imatch(p->argv[0], "/dbg"))) {
unsigned short far *rmod_envseg = MK_FP(p->rmod->rmodseg, RMOD_OFFSET_ENVSEG);
unsigned char far *rmod_exitcode = MK_FP(p->rmod->rmodseg, RMOD_OFFSET_LEXITCODE);
unsigned short far *rmod_comspecptr = MK_FP(p->rmod->rmodseg, RMOD_OFFSET_COMSPECPTR);
char far *fptr;
unsigned short i;
printf("rmod->rmodseg = 0x%04X\r\n", p->rmod->rmodseg);
printf("rmod->origparent = %04X:%04X\r\n", p->rmod->origparent >> 16, p->rmod->origparent & 0xffff);
printf("rmod->origenvseg = 0x%04X\r\n", p->rmod->origenvseg);
printf("rmod->flags = 0x%02X\r\n", p->rmod->flags);
printf("[rmod:RMOD_OFFSET_ENVSEG] = 0x%04X\r\n", *rmod_envseg);
printf("environment allocated size: %u bytes\r\n", env_allocsz(*rmod_envseg));
for (fptr = MK_FP(p->rmod->rmodseg, RMOD_OFFSET_BOOTDRIVE), i = 0; *fptr != 0; fptr++) buff[i++] = *fptr;
buff[i] = 0;
printf("[rmod:RMOD_OFFSET_BOOTCOMSPEC] = '%s'\r\n", buff);
if (*rmod_comspecptr == 0) {
sprintf(buff, "NULL");
} else {
for (fptr = MK_FP(*rmod_envseg, *rmod_comspecptr), i = 0; *fptr != 0; fptr++) buff[i++] = *fptr;
buff[i] = 0;
}
printf("[rmod:RMOD_OFFSET_COMSPECPTR] = '%s'\r\n", buff);
printf("[rmod:RMOD_OFFSET_LEXITCODE] = %u\r\n", *rmod_exitcode);
printf("rmod dump (first 64 bytes at [rmodseg:0100h]):\r\n");
fptr = MK_FP(p->rmod->rmodseg, 0x100);
for (i = 0; i < 64; i += 16) {
int ii;
for (ii = i; ii < i + 16; ii++) printf(" %02X", fptr[ii]);
printf(" ");
for (ii = i; ii < i + 16; ii++) {
if (fptr[ii] < ' ') {
printf(".");
} else {
printf("%c", fptr[ii]);
}
}
printf("\r\n");
}
 
return(CMD_OK);
}
#endif
 
if ((p->argc == 1) && (imatch(p->argv[0], "/about"))) {
outputnl("SvarCOM is a shell interpreter for DOS kernels compatible with MS-DOS 5+.");
outputnl("");
outputnl("This software is distributed under the terms of the MIT license.");
outputnl("Copyright (C) " COPYRDATE " Mateusz Viste");
outputnl("");
outputnl("Program ten dedykuje Milenie i Mojmirowi. Zycze wam, byscie w swoim zyciu");
outputnl("potrafili docenic wartosci minionych pokolen, jednoczesnie czerpiac radosc");
outputnl("z prostych przyjemnosci dnia codziennego. Lair, jesien 2021.");
return(CMD_OK);
}
 
if (p->argc != 0) {
outputnl("Invalid parameter");
return(CMD_FAIL);
}
 
_asm {
push ax
push bx
push cx
mov ah, 0x30 /* Get DOS version number */
int 0x21 /* AL=maj_ver_num AH=min_ver_num BX,CX=OEM */
mov [maj], al
mov [min], ah
pop cx
pop bx
pop ax
}
 
sprintf(buff, "DOS kernel version %u.%u", maj, min);
 
outputnl(buff);
outputnl("SvarCOM shell ver " PVER);
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/verify.c
0,0 → 1,87
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* verify
*/
 
static enum cmd_result cmd_verify(struct cmd_funcparam *p) {
 
if (cmd_ishlp(p)) {
outputnl("Tells DOS whether to verify that files are written correctly to disk.");
outputnl("\r\nVERIFY [ON | OFF]\r\n");
outputnl("Type VERIFY without a parameter to display its current setting.");
return(CMD_OK);
}
 
if (p->argc > 1) {
outputnl("Too many parameters");
return(CMD_FAIL);
}
 
if (p->argc == 0) {
unsigned char verstate = 0;
_asm {
push ax
mov ah, 0x54 /* Get VERIFY status */
int 0x21 /* AL == 0 (off) or AL == 1 (on) */
mov [verstate], al
pop ax
}
if (verstate == 0) {
outputnl("VERIFY is off");
} else {
outputnl("VERIFY is on");
}
return(CMD_OK);
}
 
/* argc == 1*/
if (imatch(p->argv[0], "on")) {
_asm {
push ax
push dx
mov ax, 0x2e01 /* set verify ON */
xor dl, dl /* apparently required by MS-DOS 2.x */
int 0x21
pop dx
pop ax
}
} else if (imatch(p->argv[0], "off")) {
_asm {
push ax
push dx
mov ax, 0x2e00 /* set verify OFF */
xor dl, dl /* apparently required by MS-DOS 2.x */
int 0x21
pop dx
pop ax
}
} else {
outputnl("Must specify ON or OFF");
return(CMD_FAIL);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2022.0/cmd/vol.c
0,0 → 1,150
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
 
/*
* vol [drive:]
*/
 
static void cmd_vol_internal(unsigned char drv, char *buff) {
unsigned short *buff16 = (void *)(buff);
unsigned short err = 0;
struct DTA *dta = (void *)0x80; /* use the default DTA at location 80h in PSP */
 
outputnl(""); /* start with an empty line to mimic MS-DOS */
 
/* look for volume label in root dir via a FindFirst call */
sprintf(buff, "%c:\\????????.???", drv + 'A');
_asm {
push ax
push cx
push dx
mov [err], 0 /* preset errflag to zero */
mov ah, 0x4e /* FindFirst */
mov dx, buff
mov cx, 0x08 /* match volume labels only */
int 0x21 /* dta filled or CF set on error */
jnc DONE
mov [err], ax
DONE:
pop dx
pop cx
pop ax
}
 
if (err != 0) {
sprintf(buff, "Volume in drive %c has no label", drv + 'A');
} else {
/* if label > 8 chars then drop the dot (DRIVE_LA.BEL -> DRIVE_LABEL) */
if (strlen(dta->fname) > 8) memmove(dta->fname + 8, dta->fname + 9, 4);
sprintf(buff, "Volume in drive %c is %s", drv + 'A', dta->fname);
}
outputnl(buff);
 
/* try to fetch the disk's serial number (DOS 4+ internal call) */
err = 0;
_asm {
push ax
push bx
push dx
mov ax, 0x6900
mov bl, drv /* A=1, B=2, etc */
inc bl /* adjust BL to +1 since drv is 0-based (A=0, B=1, etc) */
xor bh, bh /* "info level", must be 0 */
mov dx, buff /* pointer to a location where a DiskInfo struct will be written */
int 0x21
jnc DONE
mov [err], ax /* err code */
DONE:
pop dx
pop bx
pop ax
}
/* Format of DiskInfo struct (source: RBIL)
Offset Size Description (Table 01766)
00h WORD 0000h (info level)
02h DWORD disk serial number (binary)
06h 11 BYTEs volume label or "NO NAME " if none present
11h 8 BYTEs filesystem type */
if ((err == 0) && (buff16[1] | buff16[2])) {
sprintf(buff + 64, "Volume Serial Number is %04X-%04X", buff16[2], buff16[1]);
outputnl(buff + 64);
}
}
 
 
static enum cmd_result cmd_vol(struct cmd_funcparam *p) {
char drv = 0;
char curdrv = 0;
unsigned short i;
 
if (cmd_ishlp(p)) {
outputnl("Displays the disk volume label and serial number, if they exist.");
outputnl("");
outputnl("VOL [drive:]");
return(CMD_OK);
}
 
for (i = 0; i < p->argc; i++) {
if (p->argv[i][0] == '/') {
outputnl("Invalid switch");
return(CMD_FAIL);
}
if (drv != 0) {
outputnl("Too many parameters");
return(CMD_FAIL);
}
if ((p->argv[i][0] == 0) || (p->argv[i][1] != ':') || (p->argv[i][2] != 0)) {
outputnl("Invalid parameter format");
return(CMD_FAIL);
}
drv = p->argv[i][0];
/* convert drive letter to a value 1..x (1=A, 2=B, etc) */
if ((drv >= 'a') && (drv <= 'z')) {
drv -= 'a';
} else {
drv -= 'A';
}
}
 
/* fetch current drive */
_asm {
push ax
mov ah, 0x19 /* query default (current) disk */
int 0x21 /* drive in AL (0=A, 1=B, etc) */
mov [curdrv], al
pop ax
}
 
/* if no drive specified, use the default one */
if (drv == 0) {
drv = curdrv;
} else if (!isdrivevalid(drv)) { /* is specified drive valid? */
outputnl("Invalid drive");
return(CMD_FAIL);
}
 
cmd_vol_internal(drv, p->BUFFER);
 
return(CMD_OK);
}