Subversion Repositories SvarDOS

Compare Revisions

Ignore whitespace Rev 1178 → Rev 1203

/svarcom/tags/svarcom-2023.1/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-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.
*/
 
/*
* break
*/
 
static enum cmd_result cmd_break(struct cmd_funcparam *p) {
unsigned char brkflag = 0;
 
if (cmd_ishlp(p)) {
nls_outputnl(14,0); /* "Sets or clears extended CTRL+C checking" */
outputnl("");
outputnl("BREAK [ON | OFF]");
outputnl("");
nls_outputnl(14,1); /* "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) {
nls_outputnl(14,2); /* "BREAK is off" */
} else {
nls_outputnl(14,3); /* "BREAK is on" */
}
return(CMD_OK);
}
 
/* too many params? */
if (p->argc > 1) {
nls_outputnl(0,4);
return(CMD_FAIL);
}
 
/* exactly 1 parameter - "on" or "off" */
if (imatch(p->argv[0], "on")) {
brkflag = 1;
} else if (!imatch(p->argv[0], "off")) {
nls_outputnl(0,6); /* "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-2023.1/cmd/call.c
0,0 → 1,49
/* 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.
*/
 
/*
* calls one batch program from another.
*
* CALL [drive:][path]filename [batch-parameters]
*
* batch-parameters Specifies any command-line information required by the
* batch program.
*/
 
static enum cmd_result cmd_call(struct cmd_funcparam *p) {
if (cmd_ishlp(p)) {
nls_outputnl(13,0); /* "Calls one batch program from another" */
outputnl("");
nls_outputnl(13,1); /* "CALL [drive:][path]filename [batch-parameters]" */
return(CMD_OK);
}
 
/* no argument? do nothing */
if (p->argc == 0) return(CMD_OK);
 
/* change the command by moving batch filename and arguments to the start of the string */
memmove((void *)(p->cmdline), p->cmdline + p->argoffset, strlen(p->cmdline + p->argoffset) + 1);
 
return(CMD_CHANGED_BY_CALL); /* notify callee that command needs to be reevaluated */
}
/svarcom/tags/svarcom-2023.1/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-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.
*/
 
/*
* 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)) {
nls_outputnl(12,0); /* "Displays the name of or changes the current directory." */
outputnl("");
nls_outputnl(12,1); /* "CHDIR [drive:][path]" */
nls_outputnl(12,2); /* "CHDIR[..]" */
nls_outputnl(12,3); /* "CD [drive:][path]" */
nls_outputnl(12,4); /* "CD[..]" */
outputnl("");
nls_outputnl(12,5); /* ".. Specifies that you want to change to the parent directory." */
outputnl("");
nls_outputnl(12,6); /* "Type CD drive: to display the current directory in the specified drive." */
nls_outputnl(12,7); /* "Type CD without parameters to display the current drive and directory." */
return(CMD_OK);
}
 
/* one argument max */
if (p->argc > 1) {
nls_outputnl(0,4); /* "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-2023.1/cmd/chcp.c
0,0 → 1,117
/* 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.
*/
 
/*
* chcp
*/
 
static enum cmd_result cmd_chcp(struct cmd_funcparam *p) {
unsigned short nnn = 0;
unsigned short errcode = 0;
 
if (cmd_ishlp(p)) {
nls_outputnl(11,0); /* "Displays or sets the active code page number" */
outputnl("");
nls_outputnl(11,1); /* "CHCP [nnn]" */
outputnl("");
nls_outputnl(11,2); /* "nnn Specifies a code page number" */
outputnl("");
nls_outputnl(11,3); /* "Type CHCP without a parameter to display the active code page number." */
return(CMD_OK);
}
 
/* too many parameters */
if (p->argc > 1) {
nls_outputnl(0,4); /* "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) {
nls_outputnl(11,4); /* "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) {
nls_outputnl(11,5); /* "NLSFUNC not installed" */
} else if (errcode != 0) {
nls_outputnl(11,6); /* "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) {
nls_output(11,7); /* Active code page: */
output(" ");
sprintf(p->BUFFER, "%u", nnn);
outputnl(p->BUFFER);
} else {
nls_outputnl_doserr(errcode);
return(CMD_FAIL);
}
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/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-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.
*/
 
/*
* cls
*/
 
static enum cmd_result cmd_cls(struct cmd_funcparam *p) {
unsigned char screenw, screenh;
const char *ansiesc = "\x1B[2J$";
 
if (cmd_ishlp(p)) {
nls_outputnl(10,0); /* "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-2023.1/cmd/copy.c
0,0 → 1,362
/* 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.
*/
 
/*
* 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)) {
nls_outputnl(38,0); /* "Copies one or more files to another location." */
outputnl("");
nls_outputnl(38,1); /* "COPY [/A|/B] source [/A|/B] [+source [/A|/B] [+...]] [destination [/A|/B]] [/V]" */
outputnl("");
nls_outputnl(38,2); /* "source Specifies the file or files to be copied" */
nls_outputnl(38,3); /* "/A Indicates an ASCII text file" */
nls_outputnl(38,4); /* "/B Indicates a binary file" */
nls_outputnl(38,5); /* "destination Specifies the directory and/or filename for the new file(s)" */
nls_outputnl(38,6); /* "/V Verifies that new files are written correctly" */
outputnl("");
nls_outputnl(38,7); /* "To append files, specify a single file for destination, but multiple (...)" */
outputnl("");
nls_outputnl(38,8); /* "NOTE: /A and /B are no-ops, 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 {
nls_outputnl(0,2); /* "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)) {
nls_outputnl(0,1); /* "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) {
nls_outputnl(0,1); /* "Invalid syntax" */
return(CMD_FAIL);
}
if (file_truename(p->argv[i], setup->dst) != 0) {
nls_outputnl(0,8); /* "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) {
nls_outputnl(0,7); /* "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, svarlang_str(38,9)/*"%u file(s) copied"*/, copiedcount_out);
outputnl(setup->databuf);
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/cmd/ctty.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-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.
*/
 
/*
* ctty
*/
 
static enum cmd_result cmd_ctty(struct cmd_funcparam *p) {
nls_outputnl(0,9); /* "This command is not implemented" */
return(CMD_FAIL);
}
/svarcom/tags/svarcom-2023.1/cmd/date.c
0,0 → 1,225
/* 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.
*/
 
/*
* 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)) {
nls_outputnl(32,0); /* "Displays or sets the system date."); */
outputnl("");
nls_outputnl(32,1); /* "DATE [date]" */
outputnl("");
nls_outputnl(32,2); /* "Type DATE with no parameters to display the (...)" */
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);
nls_output(32,4); /* "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)) {
nls_outputnl(32,3); /* "Invalid date" */
year = 0;
}
}
 
/* ask for date if not provided or if input was malformed */
while (year == 0) {
nls_output(32,5); /* "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;
nls_outputnl(32,3); /* "Invalid date" */
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/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-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.
*/
 
/*
* 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)) {
nls_outputnl(36,0); /* "Deletes one or more files." */
outputnl("");
nls_outputnl(36,1); /* "DEL [drive:][path]filename [/P]" */
nls_outputnl(36,2); /* "ERASE [drive:][path]filename [/P]" */
outputnl("");
nls_outputnl(36,3); /* "[drive:][path]filename Specifies the file(s) to delete." */
nls_outputnl(36,4); /* "/P Prompts for confirmation before deleting each file." */
return(CMD_OK);
}
 
if (p->argc == 0) {
nls_outputnl(0,7); /* "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 {
nls_output(0,2); /* "Invalid switch" */
output(": ");
outputnl(p->argv[i]);
return(CMD_FAIL);
}
} else if (delspec != NULL) { /* otherwise its a delspec */
nls_outputnl(0,4); /* "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, "????????.???"))) {
nls_outputnl(36,5); /* "All files in directory will be deleted!" */
if (askchoice(svarlang_str(36,6)/*"Are you sure?"*/, svarlang_str(0,10)/*"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(svarlang_str(36,7)/*"Delete?"*/, svarlang_str(0,10)) != 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-2023.1/cmd/dir.c
0,0 → 1,456
/* 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.
*/
 
/*
* 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 screenw = screen_getwidth();
unsigned short wcols = screenw / 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)) {
nls_outputnl(37,0); /* "Displays a list of files and subdirectories in a directory" */
outputnl("");
nls_outputnl(37,1); /* "DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]" */
outputnl("");
nls_outputnl(37,2); /* "/P Pauses after each screenful of information" */
nls_outputnl(37,3); /* "/W Uses wide list format" */
outputnl("");
nls_outputnl(37,4); /* "/A Displays files with specified attributes:" */
nls_outputnl(37,5); /* " D Directories R Read-only files H Hidden files" */
nls_outputnl(37,6); /* " A Ready for archiving S System files - prefix meaning "not"" */
outputnl("");
nls_outputnl(37,7); /* "/O List files in sorted order:" */
nls_outputnl(37,8); /* " N by name S by size E by extension" */
nls_outputnl(37,9); /* " D by date G group dirs first - prefix to reverse order" */
outputnl("");
nls_outputnl(37,10); /* "/S Displays files in specified directory and all subdirectories" */
nls_outputnl(37,11); /* "/B Uses bare format (no heading information or summary)" */
nls_outputnl(37,12); /* "/L Uses lowercases" */
return(CMD_OK);
}
 
i = nls_getpatterns(nls);
if (i != 0) nls_outputnl_doserr(i);
 
/* disable usage of thousands separator on narrow screens */
if (screenw < 80) nls->thousep[0] = 0;
 
/* 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 {
/* skip colon if present */
if (*arg == ':') arg++;
/* 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, svarlang_str(37,20)/*"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, svarlang_str(37,21));
} else {
nls_format_number(buff2 + 10, dta->size, nls);
}
output(buff2 + strlen(buff2) - 10);
/* two spaces and NLS DATE */
buff2[0] = ' ';
buff2[1] = ' ';
if (screenw >= 80) {
nls_format_date(buff2 + 2, dta->date_yr + 1980, dta->date_mo, dta->date_dy, nls);
} else {
nls_format_date(buff2 + 2, (dta->date_yr + 80) % 100, 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;
unsigned char uint32maxlen = 13; /* 13 is the max len of a 32 bit number with thousand separators (4'000'000'000) */
if (screenw < 80) uint32maxlen = 10;
/* x file(s) */
memset(buff2, ' ', uint32maxlen);
i = nls_format_number(buff2 + uint32maxlen, summary_fcount, nls);
alignpos = sprintf(buff2 + uint32maxlen + i, " %s ", svarlang_str(37,22)/*"file(s)"*/);
output(buff2 + i);
/* xxxx bytes */
i = nls_format_number(buff2 + uint32maxlen, summary_totsz, nls);
output(buff2 + i + 1);
output(" ");
nls_outputnl(37,23); /* "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 += uint32maxlen * 2;
memset(buff2, ' ', alignpos); /* align the freebytes value to same column as totbytes */
i = nls_format_number(buff2 + alignpos, summary_totsz, nls);
output(buff2 + i + 1);
output(" ");
nls_outputnl(37,24); /* "bytes free" */
if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/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-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.
*/
 
/*
* 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], "/?"))) {
nls_outputnl(31,0); /* "Displays messages, or turns command-echoing on or off" */
outputnl("");
outputnl("ECHO [ON | OFF]");
nls_outputnl(31,1); /* "ECHO [message]" */
outputnl("");
nls_outputnl(31,2); /* "Type ECHO without parameters to display the current setting." */
return(CMD_OK);
}
 
/* ECHO without any parameter: display current state */
if (p->argc == 0) {
if (p->rmod->flags & FLAG_ECHOFLAG) {
nls_outputnl(31,3); /* "ECHO is on" */
} else {
nls_outputnl(31,4); /* "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-2023.1/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-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.
*/
 
/*
* 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");
nls_outputnl(30,0); /* "Quits the COMMAND.COM program (command interpreter)" */
} else {
sayonara(p->rmod);
}
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/cmd/for.c
0,0 → 1,155
/* 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.
*/
 
/*
* FOR %variable IN (set) DO command [command-parameters]
*
* %variable a replaceable parameter name
* (set) a set of one of more files. Wildcards allowed.
* command the command to carry out for each matched file
* command-parameters parameters or switches for the specified command
*
* To use FOR in a batch program, use %%variable instead of %variable
*
* the set of files must be surrounded by parenthesis, and may contain one
* or more space-delimited wildcards. Examples:
* (file.txt other.txt)
* (*.exe *.com *.bat)
* (jan*.txt 199201??.txt)
*/
 
/* Implementation notes:
*
* For cannot be nested (no "FOR ... do FOR ..." allowed)
*
* When executed, FOR allocates a "FOR context" to RMOD's memory, this context
* holds the memory state of a FindNext iteration, as well as the command
* to run on each matched file.
*
* This FOR context is looked at by command.c and used to provide a command
* instead of getting the command from interactive cli or BAT file. Repeats
* until the FindNext buffer stops matching files.
*
* This file only provides the help screen of FOR, as well as the FOR-context
* initialization. Actual execution happens within command.c.
*/
 
 
/* normalizing for-loop pattern-list separators.
* returns a space char if c is a for-pattern separator, c otherwise */
static char cmd_for_sepnorm(char c) {
/* the list of valid delimiters has been researched and kindly shared by Robert
* Riebisch via the ticket at https://osdn.net/projects/svardos/ticket/44058 */
switch (c) {
case ' ':
case '\t':
case ';':
case ',':
case '/':
case '=':
return(' '); /* normalize FOR-loop separators to a space */
default: /* anything else is kept as-is */
return(c);
}
}
 
 
static enum cmd_result cmd_for(struct cmd_funcparam *p) {
struct forctx *f = (void *)(p->BUFFER);
unsigned short i;
 
/* forbid nested FORs */
if (p->rmod->forloop) {
nls_outputnl(18,7); /* "FOR cannot be nested" */
return(CMD_FAIL);
}
 
/* help screen ONLY if /? is the only argument */
if ((p->argc == 1) && (imatch(p->argv[0], "/?"))) {
nls_outputnl(18,0); /* "Runs a specified command for each element in a list." */
outputnl("");
nls_outputnl(18,1); /* "FOR %variable IN (list) DO command [parameters]" */
outputnl("");
nls_outputnl(18,2); /* "%variable Single-letter variable (a-z or A-Z)." */
nls_outputnl(18,3); /* "(list) One or more space-separated strings or filename wildcards." */
nls_outputnl(18,4); /* "command The command to carry out for each element. %variable allowed." */
nls_outputnl(18,5); /* "parameters Parameters or switches for the specified command." */
outputnl("");
nls_outputnl(18,6); /* "To use FOR in a batch program, use %%variable instead of %variable" */
return(CMD_OK);
}
 
/* clear out struct and copy command line to it */
bzero(f, sizeof(*f));
strcpy(f->cmd, p->cmdline);
 
/* locate the %varname (single char) */
i = p->argoffset;
while (f->cmd[i] == ' ') i++;
if ((f->cmd[i] != '%') || (f->cmd[i+1] == ' ') || (f->cmd[i+2] != ' ')) goto INVALID_SYNTAX;
f->varname = f->cmd[i+1];
i += 3;
 
/* look (and skip) the "IN" part */
while (f->cmd[i] == ' ') i++;
if (((f->cmd[i] & 0xDF) != 'I') && ((f->cmd[i+1] & 0xDF) != 'N') && (f->cmd[i+2] != ' ')) goto INVALID_SYNTAX;
i += 3;
 
/* look for patterns start */
while (f->cmd[i] == ' ') i++;
if (f->cmd[i] != '(') goto INVALID_SYNTAX;
i++;
while (cmd_for_sepnorm(f->cmd[i]) == ' ') i++;
f->nextpat = i;
/* look for patterns end and normalize all separators to a space */
while ((f->cmd[i] != ')') && (f->cmd[i] != 0)) {
f->cmd[i] = cmd_for_sepnorm(f->cmd[i]);
i++;
}
if (f->cmd[i] != ')') goto INVALID_SYNTAX;
f->cmd[i++] = 0; /* terminate patterns and move to next field */
 
/* look (and skip) the "DO" part */
while (f->cmd[i] == ' ') i++;
if (((f->cmd[i] & 0xDF) != 'D') && ((f->cmd[i+1] & 0xDF) != 'O') && (f->cmd[i+2] != ' ')) goto INVALID_SYNTAX;
i += 3;
while (f->cmd[i] == ' ') i++;
 
/* rest is the exec string */
f->exec = i;
 
/* alloc memory for the forctx context and copy f to it */
p->rmod->forloop = rmod_fcalloc(sizeof(*f), p->rmod->rmodseg, "SVFORCTX");
if (p->rmod->forloop == NULL) {
nls_outputnl_doserr(8);
return(CMD_FAIL);
}
_fmemcpy(p->rmod->forloop, f, sizeof(*f));
 
return(CMD_OK);
 
INVALID_SYNTAX:
nls_outputnl(0,1); /* "Invalid syntax" */
return(CMD_FAIL);
}
/svarcom/tags/svarcom-2023.1/cmd/goto.c
0,0 → 1,261
/* 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.
*/
 
/*
* goto label
*
* if label does not exist in the currently processed batch file, then a error
* "Label not found" is displayed and the batch file is aborted. Any parent
* batches are ALSO aborted. Same behavior if called without any parameter.
*
* if called outside of a batch file, this command has no effect (and does not
* display any error, even when called without any argument).
*
* it reacts to /? by outputing its help screen
*
* only 1st argument is processed, any extra arguments are ignored (even /?).
*
* Labels can be written as:
* :LABEL
* :LABEL
* : LABEL
*
* A label can also be followed by one or more space or tabs, followed by
* anything. The label is parsed only to the first space, tab, end of line or
* end of file. Hence this would be perfectly ok:
*
* :LABEL this is a comment
*
* Labels are searched in the batch file from top to bottom and first match
* is jumped to. Matching labels is case-insensitive (ie. LABEL == LaBeL)
*/
 
 
static void goto_close_dos_handle(unsigned short fhandle) {
_asm {
push bx
 
mov ah, 0x3e
mov bx, fhandle
int 0x21
 
pop bx
}
}
 
 
static enum cmd_result cmd_goto(struct cmd_funcparam *p) {
char *buff = NULL;
const char *label;
unsigned short bufflen = 0;
unsigned short fhandle = 0;
unsigned short doserr = 0;
unsigned short batname_seg;
unsigned short batname_off;
unsigned char eof_reached = 0;
unsigned short i;
 
/* help? reacts only to /? being passed as FIRST argument */
if ((p->argc > 0) && imatch(p->argv[0], "/?")) {
nls_outputnl(17,0); /* "Directs batch processing to a labelled line in the batch program." */
outputnl("");
nls_outputnl(17,1); /* "GOTO LABEL" */
outputnl("");
nls_outputnl(17,2); /* "LABEL specifies a text string used in the batch program as a label." */
outputnl("");
nls_outputnl(17,3); /* "A label is on a line by itself and must be preceded by a colon." */
return(CMD_OK);
}
 
/* not inside a batch file? not given any argument? then do nothing */
if ((p->rmod->bat == NULL) || (p->argc == 0)) return(CMD_OK);
 
/* label is in first arg */
label = p->argv[0];
 
/* open batch file (read-only) */
batname_seg = FP_SEG(p->rmod->bat->fname);
batname_off = FP_OFF(p->rmod->bat->fname);
_asm {
push bx
push dx
 
mov ax, batname_seg
push ds /* save ds */
mov ds, ax
mov dx, batname_off
mov ax, 0x3d00
int 0x21 /* handle in ax on success */
pop ds
jnc OPEN_SUCCESS
mov doserr, ax
 
OPEN_SUCCESS:
mov fhandle, ax /* save file handle */
 
pop dx
pop bx
}
 
/* file open failed? */
if (doserr != 0) {
nls_outputnl_doserr(doserr);
return(CMD_FAIL);
}
 
/* reset the rmod bat counter since I will scan all lines from top to bottom */
p->rmod->bat->nextline = 0; /* remember this is a byte offset, not a line number */
 
/* read bat file line by line until label is found or EOF */
for (;;) {
 
/* move any existing data to the start of the buffer */
if (bufflen > 0) memmove(p->BUFFER, buff, bufflen);
 
buff = p->BUFFER; /* assumption: must be big enough to hold 2 sectors (2 * 512) */
 
/* if buffer has less than 512b then load it with another sector (unless eof) */
if ((eof_reached == 0) && (bufflen < 512)) {
/* load 512b of data into buffer */
_asm {
push ax
push bx
push cx
push dx
pushf
 
mov ah, 0x3f /* read from file handle */
mov bx, fhandle /* file handle where to read from */
mov cx, 512 /* read 512 bytes (one sector) */
mov dx, buff /* target buffer */
add dx, bufflen /* data must follow existing pending data */
int 0x21 /* CF clear on success and AX=number of bytes read */
/* error? */
jnc READ_OK
mov doserr, ax
READ_OK:
add bufflen, ax
/* set eof if amount of bytes read is shorter than cx */
cmp ax, cx
je EOF_NOT_REACHED
mov eof_reached, byte ptr 1
EOF_NOT_REACHED:
 
popf
pop dx
pop cx
pop bx
pop ax
}
 
/* on error close the file and quit */
if (doserr != 0) {
goto_close_dos_handle(fhandle);
nls_outputnl_doserr(doserr);
return(CMD_FAIL);
}
}
 
/* advance buffer to first non-space/non-tab/non-CR/non-LF */
while (bufflen > 0) {
if ((*buff != ' ') && (*buff != '\t') && (*buff != '\r') && (*buff != '\n')) break;
bufflen--;
buff++;
p->rmod->bat->nextline++;
}
 
/* if the line does not start with a colon, then jump to next line */
if ((bufflen > 0) && (*buff != ':')) {
while ((bufflen > 0) && (*buff != '\n')) {
bufflen--;
buff++;
p->rmod->bat->nextline++;
}
}
 
/* refill buffer if needed */
if ((bufflen < 512) && (eof_reached == 0)) continue;
 
/* eof? */
if (bufflen == 0) break;
 
/* skip the colon */
if (*buff == ':') {
bufflen--;
buff++;
p->rmod->bat->nextline++;
}
 
/* skip any leading white spaces (space or tab) */
while (bufflen > 0) {
if ((*buff != ' ') && (*buff != '\t')) break;
bufflen--;
buff++;
p->rmod->bat->nextline++;
}
 
/* read the in-file label and compare it with what's in the label buff */
for (i = 0;; i++) {
/* if end of label then check if it is also end of in-file label (ends with space, tab, \r or \n) */
if ((i == bufflen) || (buff[i] == ' ') || (buff[i] == '\t') || (buff[i] == '\r') || (buff[i] == '\n')) {
if (label[i] == 0) {
/* match found -> close file, skip to end of line and quit */
while (bufflen > 0) {
bufflen--;
buff++;
p->rmod->bat->nextline++;
if (*buff == '\n') break;
}
goto_close_dos_handle(fhandle);
return(CMD_OK);
}
break;
}
/* end of label = mismatch */
if (label[i] == 0) break;
/* case-insensitive comparison */
if ((label[i] & 0xDF) != (buff[i] & 0xDF)) break;
}
 
/* no match, move forward to end of line and repeat */
while ((bufflen > 0) && (*buff != '\n')) {
bufflen--;
buff++;
p->rmod->bat->nextline++;
}
}
 
/* close the batch file handle */
goto_close_dos_handle(fhandle);
 
/* label not found, display error message and abort all batch scripts */
nls_outputnl(17, 10); /* "Label not found" */
rmod_free_bat_llist(p->rmod);
 
/* restore echo flag as it was before running the (first) bat file */
p->rmod->flags &= ~FLAG_ECHOFLAG;
if (p->rmod->flags & FLAG_ECHO_BEFORE_BAT) p->rmod->flags |= FLAG_ECHOFLAG;
 
return(CMD_FAIL);
}
/svarcom/tags/svarcom-2023.1/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-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.
*/
 
/*
* 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], "/?"))) {
nls_outputnl(35,0); /* "Performs conditional processing in batch programs." */
outputnl("");
nls_outputnl(35,1); /* "IF [NOT] ERRORLEVEL num command" */
nls_outputnl(35,2); /* "IF [NOT] string1==string2 command" */
nls_outputnl(35,3); /* "IF [NOT] EXIST filename command" */
outputnl("");
nls_outputnl(35,4); /* "NOT command is executed only if condition is NOT met" */
nls_outputnl(35,5); /* "ERRORLEVEL num condition: last program returned an exit code >= num" */
nls_outputnl(35,6); /* "string1==string2 condition: both strings must be equal" */
nls_outputnl(35,7); /* "EXIST filename condition: filename exists (wildcards accepted)" */
nls_outputnl(35,8); /* "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:
nls_outputnl(0,1); /* "Invalid syntax" */
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-2023.1/cmd/ln.c
0,0 → 1,252
/* 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) {
nls_outputnl(29,4); /* "No matching executable found in given path." */
return(CMD_FAIL);
}
 
/* compute the filename of the link file */
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] == '\\')) {
nls_outputnl(0,3); /* "Invalid parameter format" */
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 '\\':
nls_outputnl(0,3); /* "Invalid parameter format" */
return(CMD_FAIL);
}
}
} else {
linkname = "*";
}
 
/* prep DOSDIR\LINKS\pattern */
if (link_computefname(buff, linkname, env_seg) != 0) return(CMD_FAIL);
 
/* set pathlen to end of path (char after last backslash) */
pathlen = 0;
for (i = 0; buff[i] != 0; i++) if (buff[i] == '\\') pathlen = i + 1;
 
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)) {
nls_outputnl(29,0); /* "Adds, deletes or displays executable links." */
outputnl("");
nls_outputnl(29,1); /* "LN ADD linkname targetdir" */
nls_outputnl(29,2); /* "LN DEL linkname" */
nls_outputnl(29,3); /* "LN LIST [pattern]" */
return(CMD_OK);
}
 
if (p->argc == 0) {
nls_outputnl(0,7); /* "Required parameter missing */
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));
}
 
nls_outputnl(0,6); /* "Invalid parameter" */
return(CMD_FAIL);
}
/svarcom/tags/svarcom-2023.1/cmd/loadhigh.c
0,0 → 1,42
/* 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.
*/
 
/*
* loadhigh
*/
 
static enum cmd_result cmd_loadhigh(struct cmd_funcparam *p) {
 
if ((p->argc == 0) || (imatch(p->argv[0], "/?"))) {
nls_outputnl(0,9); /* "This command is not implemented" */
return(CMD_OK);
}
 
/* set the command to be executed */
if (p->cmdline[p->argoffset] != 0) {
memmove((void *)p->cmdline, p->cmdline + p->argoffset, strlen(p->cmdline + p->argoffset) + 1);
}
 
return(CMD_CHANGED);
}
/svarcom/tags/svarcom-2023.1/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-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.
*/
 
/*
* 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)) {
nls_outputnl(28,0); /* "Creates a directory" */
outputnl("");
nls_outputnl(28,1); /* "MKDIR [drive:]path" */
nls_outputnl(28,2); /* "MD [drive:]path" */
return(CMD_OK);
}
 
if (p->argc == 0) {
nls_outputnl(0,7); /* "Required parameter missing" */
return(CMD_FAIL);
}
 
if (p->argc > 1) {
nls_outputnl(0,4); /* "Too many parameters" */
return(CMD_FAIL);
}
 
if (p->argv[0][0] == '/') {
nls_outputnl(0,6); /* "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-2023.1/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-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.
*/
 
/*
* 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)) {
nls_outputnl(27,0); /* "Displays or sets a search path for executable files." */
outputnl("");
nls_outputnl(27,1); /* "PATH [[drive:]path[;...]]" */
outputnl("PATH ;");
outputnl("");
nls_outputnl(27,2); /* "Type PATH ; to clear all search-path settings and (...)" */
outputnl("");
nls_outputnl(27,3); /* "Type PATH without parameters to display the current path." */
return(CMD_OK);
}
 
/* no parameter - display current path */
if (p->argc == 0) {
char far *curpath = env_lookup(p->env_seg, "PATH");
if (curpath == NULL) {
nls_outputnl(27,4); /* "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) {
nls_outputnl(0,4); /* "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;
}
nls_strtoup(buff); /* upcase path, ref: https://osdn.net/projects/svardos/ticket/44146 */
env_setvar(p->env_seg, buff);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/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-2023.1/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-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.
*/
 
/*
* prompt
*
* Changes the DOS command prompt.
*
*/
 
static enum cmd_result cmd_prompt(struct cmd_funcparam *p) {
 
if (cmd_ishlp(p)) {
nls_outputnl(33,0); /* "Changes the DOS command prompt." */
outputnl("");
nls_outputnl(33,1); /* "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-2023.1/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-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.
*/
 
/*
* 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], "/?"))) {
nls_outputnl(26,0); /* "Records comments (remarks) in a batch file." */
outputnl("");
nls_outputnl(26,1); /* "REM [comment]" */
}
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/cmd/rename.c
0,0 → 1,162
/* 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.
*/
 
/*
* 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)) {
nls_outputnl(25,0); /* "Renames one or more files or directories." */
outputnl("");
nls_outputnl(25,1); /* "RENAME [drive:][path]oldname newname" */
nls_outputnl(25,2); /* "REN [drive:][path]oldname newname" */
outputnl("");
nls_outputnl(25,3); /* "Note that you cannot specify a new drive or (...)" */
return(CMD_OK);
}
 
/* I expect exactly two arguments */
if (p->argc != 2) {
nls_outputnl(0,1); /* "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 '/':
nls_outputnl(0,8); /* "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, DOS_ATTR_RO | DOS_ATTR_HID | DOS_ATTR_SYS | DOS_ATTR_ARC | DOS_ATTR_DIR);
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-2023.1/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-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.
*/
 
/*
* 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)) {
nls_outputnl(24,0); /* "Removes (deletes) a directory" */
outputnl("");
nls_outputnl(24,1);/* "RMDIR [drive:]path" */
nls_outputnl(24,2);/* "RD [drive:]path" */
return(CMD_OK);
}
 
if (p->argc == 0) {
nls_outputnl(0,7); /* "Required parameter missing" */
return(CMD_FAIL);
}
 
if (p->argc > 1) {
nls_outputnl(0,4); /* "Too many parameters" */
return(CMD_FAIL);
}
 
if (p->argv[0][0] == '/') {
nls_outputnl(0,6); /* "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-2023.1/cmd/set.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-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.
*/
 
/*
* 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)) {
nls_outputnl(23,0); /* "Displays, sets, or removes DOS environment variables"); */
outputnl("");
nls_outputnl(23,1); /* "SET [variable=[string]]" */
outputnl("");
nls_outputnl(23,2); /* "variable Specifies the environment-variable name" */
nls_outputnl(23,3); /* "string Specifies a series of characters to assign to the variable" */
outputnl("");
nls_outputnl(23,4); /* "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 (note that cmdline separators should be sanitized
* to space only by now) */
for (ptr = p->cmdline; *ptr != ' '; ptr++);
 
/* now locate the first non-space: that's where the variable name begins */
for (; *ptr == ' '; ptr++);
 
/* copy variable name to buff */
i = 0;
for (; *ptr != '='; ptr++) {
if (*ptr == 0) goto syntax_err;
buff[i++] = *ptr;
}
 
/* make variable name all caps (country-dependend) */
buff[i] = 0;
nls_strtoup(buff);
 
/* 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) {
nls_outputnl(23,5); /* "Not enough available space within the environment block" */
return(CMD_FAIL);
}
}
return(CMD_OK);
 
syntax_err:
 
nls_outputnl(0,1); /* "Invalid syntax" */
return(CMD_FAIL);
}
/svarcom/tags/svarcom-2023.1/cmd/shift.c
0,0 → 1,53
/* 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;
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 ((p->rmod->bat == NULL) || (p->rmod->bat->argv[0] == 0)) return(CMD_OK);
batargv = p->rmod->bat->argv;
 
/* 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->bat->argv) - (nextarg - batargv));
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/cmd/time.c
0,0 → 1,253
/* 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.
*/
 
/*
* 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)) {
nls_outputnl(22,0); /* "Displays or sets the system time." */
outputnl("");
nls_outputnl(22,1); /* "TIME [time]" */
outputnl("");
nls_outputnl(22,2); /* "Type TIME with no parameters to display the current time and (...)" */
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);
nls_output(22,3); /* "Current time is" */
outputnl(buff);
ho = -1;
} else { /* parse time if provided */
if (cmd_time_parse(p->argv[0], &ho, &mi, &se, nls) != 0) {
nls_outputnl(22,4); /* "Invalid time" */
ho = -1;
}
}
 
/* ask for time if not provided or if input was malformed */
while (ho < 0) {
nls_output(22,5); /* "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;
nls_outputnl(22,4); /* "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-2023.1/cmd/truename.c
0,0 → 1,58
/* 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.
*/
 
/*
* truename [path]
*/
 
static enum cmd_result cmd_truename(struct cmd_funcparam *p) {
unsigned short res;
 
if (cmd_ishlp(p)) {
nls_outputnl(39,0);
outputnl("");
nls_outputnl(39,1);
return(CMD_OK);
}
 
if (p->argc > 1) {
nls_outputnl(0,4); /* too many parameters */
return(CMD_FAIL);
}
 
if (p->argc == 0) {
res = file_truename(".", p->BUFFER);
} else {
res = file_truename(p->argv[0], p->BUFFER);
}
 
if (res != 0) {
nls_outputnl_doserr(res);
return(CMD_FAIL);
}
 
outputnl(p->BUFFER);
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/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-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.
*/
 
/*
* 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)) {
nls_outputnl(21,0); /* "Displays the contents of a text file." */
outputnl("");
nls_outputnl(21,1); /* "TYPE [drive:][path]filename" */
return(CMD_OK);
}
 
if (p->argc == 0) {
nls_outputnl(0,7); /* "Required parameter missing" */
return(CMD_FAIL);
}
 
if (p->argc > 1) {
nls_outputnl(0,4); /* "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-2023.1/cmd/ver.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-2023 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 "2023.1"
#define COPYRDATE "2021-2023"
 
static enum cmd_result cmd_ver(struct cmd_funcparam *p) {
char *buff = p->BUFFER;
unsigned char maj = 0, min = 0, retcode = 0, truemaj = 0, truemin = 0, rev = 0, verflags = 0;
 
/* help screen */
if (cmd_ishlp(p)) {
nls_outputnl(20,0); /* "Displays the DOS kernel and SvarCOM shell versions." */
outputnl("");
output("ver [/about]");
#ifdef VERDBG
output(" [/dbg]");
#endif
outputnl("");
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"))) {
nls_outputnl(20,3); /* "SvarCOM is a shell interpreter for DOS kernels compatible with MS-DOS 5+." */
outputnl("");
nls_outputnl(20,4); /* "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);
}
 
_asm {
push ax
push bx
push cx
push dx
 
/* get the "normal" (spoofable) DOS version */
mov ah, 0x30 /* function supported on DOS 2+ */
int 0x21 /* AL=maj_ver_num AH=min_ver_num BX,CX=OEM */
mov [maj], al
mov [min], ah
 
/* get the "true" DOS version, along with a couple of extra data */
mov ax, 0x3306 /* function supported on DOS 5+ */
int 0x21
mov [retcode], al /* AL=return_code for DOS < 5 */
mov [truemaj], bl /* BL=maj_ver_num BH=min_ver_num */
mov [truemin], bh
mov [rev], dl /* DL=revision DH=kernel_memory_area */
mov [verflags], dh
 
pop dx
pop cx
pop bx
pop ax
}
 
sprintf(buff, svarlang_str(20,1), maj, min); /* "DOS kernel version %u.%u" */
output(buff);
 
/* can we trust in the data returned? */
/* DR DOS 5&6 return 0x01, MS-DOS 2-4 return 0xff */
/* 'truemaj' is checked to mitigate the conflict from the CBIS redirector */
if ((retcode > 1) && (retcode < 255) && (truemaj > 4) && (truemaj < 100)) {
if ((maj != truemaj) || (min != truemin)) {
output(" (");
sprintf(buff, svarlang_str(20,10), truemaj, truemin); /* "true ver xx.xx" */
output(buff);
output(")");
}
outputnl("");
 
sprintf(buff, svarlang_str(20,5), 'A' + rev); /* "Revision %c" */
outputnl(buff);
 
{
const char *loc = svarlang_str(20,7); /* "low memory" */
if (verflags & 16) loc = svarlang_str(20,8); /* "HMA" */
if (verflags & 8) loc = svarlang_str(20,9); /* "ROM" */
sprintf(buff, svarlang_str(20,6), loc); /* "DOS is in %s" */
outputnl(buff);
}
}
 
outputnl("");
nls_output(20,2); /* "SvarCOM shell ver" */
outputnl(" " PVER);
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/cmd/verify.c
0,0 → 1,89
/* 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.
*/
 
/*
* verify
*/
 
static enum cmd_result cmd_verify(struct cmd_funcparam *p) {
 
if (cmd_ishlp(p)) {
nls_outputnl(19,0); /* "Tells DOS whether to verify that files are written correctly to disk." */
outputnl("");
outputnl("VERIFY [ON | OFF]");
outputnl("");
nls_outputnl(19,1); /* "Type VERIFY without a parameter to display its current setting." */
return(CMD_OK);
}
 
if (p->argc > 1) {
nls_outputnl(0,4); /* "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) {
nls_outputnl(19,2); /* "VERIFY is off" */
} else {
nls_outputnl(19,3); /* "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 {
nls_outputnl(19,4); /* "Must specify ON or OFF" */
return(CMD_FAIL);
}
 
return(CMD_OK);
}
/svarcom/tags/svarcom-2023.1/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-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.
*/
 
/*
* 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, svarlang_str(34,2)/*"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, svarlang_str(34,3)/*"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, svarlang_str(34,4)/*"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)) {
nls_outputnl(34,0); /* "Displays the disk volume label and serial number, if they exist." */
outputnl("");
nls_outputnl(34,1); /* "VOL [drive:]" */
return(CMD_OK);
}
 
for (i = 0; i < p->argc; i++) {
if (p->argv[i][0] == '/') {
nls_outputnl(0,2); /* "Invalid switch" */
return(CMD_FAIL);
}
if (drv != 0) {
nls_outputnl(0,4); /* "Too many parameters" */
return(CMD_FAIL);
}
if ((p->argv[i][0] == 0) || (p->argv[i][1] != ':') || (p->argv[i][2] != 0)) {
nls_outputnl(0,3); /* "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? */
nls_outputnl(255,15); /* "Invalid drive" */
return(CMD_FAIL);
}
 
cmd_vol_internal(drv, p->BUFFER);
 
return(CMD_OK);
}