Subversion Repositories SvarDOS

Compare Revisions

No changes between revisions

Ignore whitespace Rev 1202 → 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);
}
/svarcom/tags/svarcom-2023.1/cmd.c
0,0 → 1,305
/* 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.
*/
 
/* entry point for internal commands, it matches internal commands and
* executes them.
*
* returns one of the following values:
* CMD_OK command executed successfully
* CMD_FAIL command ended in error
* CMD_CHANGED command-line has been modified (used by IF)
* CMD_CHANGED_BY_CALL command-line has been modified by CALL
* CMD_NOTFOUND command unrecognized
*/
 
#include <i86.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "svarlang.lib/svarlang.h"
 
#include "env.h"
#include "helpers.h"
#include "redir.h"
#include "rmodinit.h"
#include "sayonara.h"
 
#include "cmd.h"
 
 
/* struct used to pass all necessary information to the sub-commands */
struct cmd_funcparam {
int argc; /* number of arguments */
const char *argv[128]; /* pointers to each argument */
char argvbuf[256]; /* buffer that hold data pointed out by argv[] */
unsigned short env_seg; /* segment of environment block */
struct rmod_props far *rmod; /* rmod settings */
unsigned short argoffset; /* offset of cmdline where first argument starts */
const char *cmdline; /* original cmdline (terminated by a NULL) */
unsigned short BUFFERSZ; /* avail space in BUFFER */
char BUFFER[1]; /* a buffer for whatever is needed (must be last) */
};
 
 
/* scans argv for the presence of a "/?" parameter.
* returns 1 if found, 0 otherwise
* this is used by most sub-commands to detect /? invocations */
static int cmd_ishlp(const struct cmd_funcparam *p) {
int i;
for (i = 0; i < p->argc; i++) {
if ((p->argv[i][0] == '/') && (p->argv[i][1] == '?')) return(1);
}
return(0);
}
 
#include "cmd/break.c"
#include "cmd/call.c"
#include "cmd/cd.c"
#include "cmd/chcp.c"
#include "cmd/cls.c"
#include "cmd/copy.c"
#include "cmd/ctty.c"
#include "cmd/date.c"
#include "cmd/del.c"
#include "cmd/for.c"
#include "cmd/goto.c"
#include "cmd/if.c"
#include "cmd/vol.c" /* must be included before dir.c due to dependency */
#include "cmd/dir.c"
#include "cmd/echo.c"
#include "cmd/exit.c"
#include "cmd/loadhigh.c"
#include "cmd/ln.c"
#include "cmd/mkdir.c"
#include "cmd/path.c"
#include "cmd/pause.c"
#include "cmd/prompt.c"
#include "cmd/rem.c"
#include "cmd/rename.c"
#include "cmd/rmdir.c"
#include "cmd/set.c"
#include "cmd/shift.c"
#include "cmd/time.c"
#include "cmd/truename.c"
#include "cmd/type.c"
#include "cmd/ver.c"
#include "cmd/verify.c"
 
 
struct CMD_ID {
const char *cmd;
enum cmd_result (*func_ptr)(struct cmd_funcparam *); /* pointer to handling function */
};
 
const struct CMD_ID INTERNAL_CMDS[] = {
{"BREAK", cmd_break},
{"CALL", cmd_call},
{"CD", cmd_cd},
{"CHCP", cmd_chcp},
{"CHDIR", cmd_cd},
{"CLS", cmd_cls},
{"COPY", cmd_copy},
{"CTTY", cmd_ctty},
{"DATE", cmd_date},
{"DEL", cmd_del},
{"DIR", cmd_dir},
{"ECHO", cmd_echo},
{"ERASE", cmd_del},
{"EXIT", cmd_exit},
{"FOR", cmd_for},
{"GOTO", cmd_goto},
{"IF", cmd_if},
{"LH", cmd_loadhigh},
{"LN", cmd_ln},
{"LOADHIGH",cmd_loadhigh},
{"MD", cmd_mkdir},
{"MKDIR", cmd_mkdir},
{"PAUSE", cmd_pause},
{"PATH", cmd_path},
{"PROMPT", cmd_prompt},
{"RD", cmd_rmdir},
{"REM", cmd_rem},
{"REN", cmd_rename},
{"RENAME", cmd_rename},
{"RMDIR", cmd_rmdir},
{"SET", cmd_set},
{"SHIFT", cmd_shift},
{"TIME", cmd_time},
{"TRUENAME",cmd_truename},
{"TYPE", cmd_type},
{"VER", cmd_ver},
{"VERIFY", cmd_verify},
{"VOL", cmd_vol},
{NULL, NULL}
};
 
 
/* NULL if cmdline is not matching an internal command, otherwise returns a
* pointer to a CMD_ID struct */
static const struct CMD_ID *cmd_match(const char *cmdline, unsigned short *argoffset) {
unsigned short i;
char buff[10];
 
/* copy command to buffer, until space, NULL, tab, return, dot, slash or backslash */
for (i = 0; i < 9; i++) {
if (cmdline[i] == ' ') break;
if (cmdline[i] == 0) break;
if (cmdline[i] == '\t') break;
if (cmdline[i] == '\r') break;
if (cmdline[i] == '.') break;
if (cmdline[i] == '/') break;
if (cmdline[i] == '\\') break;
buff[i] = cmdline[i];
}
buff[i] = 0;
 
/* advance to nearest non-space to find where arguments start */
while (cmdline[i] == ' ') i++;
*argoffset = i;
 
/* try matching an internal command */
for (i = 0; INTERNAL_CMDS[i].cmd != NULL; i++) {
/*printf("imatch(%s,%s)\r\n", buff, INTERNAL_CMDS[i].cmd); */
if (imatch(buff, INTERNAL_CMDS[i].cmd)) {
/*printf("match cmd i=%u (buff=%s)\r\n", i, buff);*/
return(&(INTERNAL_CMDS[i]));
}
}
 
return(NULL); /* command is not recognized as internal */
}
 
 
/* explodes a command into an array of arguments where last arg is NULL.
* if argvlist is not NULL, it will be filled with pointers that point to buff
* locations. buff is filled with all the arguments, each argument being
* zero-separated. buff is terminated with an empty argument to mark the end
* of arguments.
* returns number of args */
unsigned short cmd_explode(char *buff, const char far *s, char const **argvlist) {
int si = 0, argc = 0, i = 0;
for (;;) {
/* skip to next non-space character */
while (s[si] == ' ') si++;
/* end of string? */
if (s[si] == 0) break;
/* set argv ptr */
if (argvlist) argvlist[argc] = buff + i;
argc++;
/* find next arg delimiter (spc, null, slash or plus) while copying arg to local buffer */
do {
buff[i++] = s[si++];
} while (s[si] != ' ' && s[si] != 0 && s[si] != '/' && s[si] != '+');
buff[i++] = 0;
/* is this end of string? */
if (s[si] == 0) break;
}
buff[i] = 0; /* terminate with one extra zero to tell "this is the end of list" */
if (argvlist) argvlist[argc] = NULL;
return(argc);
}
 
 
enum cmd_result cmd_process(struct rmod_props far *rmod, unsigned short env_seg, const char *cmdline, void *BUFFER, unsigned short BUFFERSZ, const struct redir_data *redir, unsigned char delstdin) {
const struct CMD_ID *cmdptr;
unsigned short argoffset;
enum cmd_result cmdres;
struct cmd_funcparam *p = (void *)BUFFER;
p->BUFFERSZ = BUFFERSZ - sizeof(*p);
 
/* special case: is this a drive change? (like "E:") */
if ((cmdline[0] != 0) && (cmdline[1] == ':') && ((cmdline[2] == ' ') || (cmdline[2] == 0))) {
if (((cmdline[0] >= 'a') && (cmdline[0] <= 'z')) || ((cmdline[0] >= 'A') && (cmdline[0] <= 'Z'))) {
unsigned char drive = cmdline[0];
unsigned char curdrive = 0;
if (drive >= 'a') {
drive -= 'a';
} else {
drive -= 'A';
}
_asm {
push ax
push dx
mov ah, 0x0e /* DOS 1+ - SELECT DEFAULT DRIVE */
mov dl, drive /* DL = new default drive (00h = A:, 01h = B:, etc) */
int 0x21
mov ah, 0x19 /* DOS 1+ - GET CURRENT DRIVE */
int 0x21
mov curdrive, al /* cur drive (0=A, 1=B, etc) */
pop dx
pop ax
}
if (curdrive == drive) return(CMD_OK);
nls_outputnl_doserr(0x0f);
return(CMD_FAIL);
}
}
 
/* try matching an internal command */
cmdptr = cmd_match(cmdline, &argoffset);
if (cmdptr == NULL) return(CMD_NOTFOUND); /* command is not recognized as internal */
 
/* printf("recognized internal command: '%s', tail of command at offset %u\r\n", cmdptr->cmd, argoffset); */
 
/* apply redirections (if any) */
if (redir_apply(redir) != 0) return(CMD_FAIL);
 
/* prepare function parameters and feed it to the cmd handling function */
p->argc = cmd_explode(p->argvbuf, cmdline + argoffset, p->argv);
p->env_seg = env_seg;
p->rmod = rmod;
p->argoffset = argoffset;
p->cmdline = cmdline;
 
cmdres = (cmdptr->func_ptr)(p);
 
/* cancel redirections */
redir_revert();
 
/* delete stdin temporary file */
if (delstdin) {
const char *fname = redir->stdinfile;
unsigned short doserr = 0;
_asm {
push ax
push dx
mov ah, 0x41 /* delete a file */
mov dx, fname /* DS:DX - filename to delete */
int 0x21
jnc DONE
mov doserr, ax
DONE:
pop dx
pop ax
}
if (doserr) {
output(fname);
output(": ");
nls_outputnl_doserr(doserr);
}
}
 
return(cmdres);
}
/svarcom/tags/svarcom-2023.1/cmd.h
0,0 → 1,50
/* 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.
*/
 
#ifndef CMD_H
#define CMD_H
 
#include "rmodinit.h"
 
/* what cmd_process may return */
enum cmd_result {
CMD_OK, /* command executed and succeeded */
CMD_FAIL, /* command executed and failed */
CMD_NOTFOUND, /* no such command (not an internal command) */
CMD_CHANGED, /* command-line transformed, please reparse it */
CMD_CHANGED_BY_CALL /* command-line transformed by CALL */
};
 
/* process internal commands */
enum cmd_result cmd_process(struct rmod_props far *rmod, unsigned short env_seg, const char *cmdline, void *BUFFER, unsigned short BUFFERSZ, const struct redir_data *r, unsigned char delstdin);
 
/* explodes a command into an array of arguments where last arg is NULL.
* if argvlist is not NULL, it will be filled with pointers that point to buff
* locations. buff is filled with all the arguments, each argument being
* zero-separated. buff is terminated with an empty argument to mark the end
* of arguments.
* returns number of args */
unsigned short cmd_explode(char *buff, const char far *s, char const **argvlist);
 
#endif
/svarcom/tags/svarcom-2023.1/command.c
0,0 → 1,1158
/* 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.
*/
 
#include <i86.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "svarlang.lib/svarlang.h"
 
#include "cmd.h"
#include "env.h"
#include "helpers.h"
#include "redir.h"
#include "rmodinit.h"
#include "sayonara.h"
 
#include "rmodcore.h" /* rmod binary inside a BUFFER array */
 
/* this version byte is used to tag RMOD so I can easily make sure that
* the RMOD struct I find in memory is one that I know. Should the version
* mismatch, then it would likely mean that SvarCOM has been upgraded and
* RMOD should not be accessed as its structure might no longer be in sync
* with what I think it is.
* *** INCREMENT THIS AT EACH NEW SVARCOM RELEASE! *** */
#define BYTE_VERSION 4
 
 
struct config {
unsigned char flags; /* command.com flags, as defined in rmodinit.h */
char *execcmd;
unsigned short envsiz;
};
 
/* max length of the cmdline storage (bytes) - includes also max length of
* line loaded from a BAT file (no more than 255 bytes!) */
#define CMDLINE_MAXLEN 255
 
 
/* sets guard values at a few places in memory for later detection of
* overflows via memguard_check() */
static void memguard_set(char *cmdlinebuf) {
BUFFER[sizeof(BUFFER) - 1] = 0xC7;
cmdlinebuf[CMDLINE_MAXLEN] = 0xC7;
}
 
 
/* checks for valguards at specific memory locations, returns 0 on success */
static int memguard_check(unsigned short rmodseg, char *cmdlinebuf) {
/* check RMOD signature (would be overwritten in case of stack overflow */
static char msg[] = "!! MEMORY CORRUPTION ## DETECTED !!";
unsigned short far *rmodsig = MK_FP(rmodseg, 0x100 + 6);
unsigned char far *rmod = MK_FP(rmodseg, 0);
 
if (*rmodsig != 0x2019) {
msg[22] = '1';
goto FAIL;
}
 
/* check last BUFFER byte */
if (BUFFER[sizeof(BUFFER) - 1] != 0xC7) {
msg[22] = '2';
goto FAIL;
}
 
/* check last cmdlinebuf byte */
if (cmdlinebuf[CMDLINE_MAXLEN] != 0xC7) {
msg[22] = '3';
goto FAIL;
}
 
/* check rmod exec buf */
if (rmod[RMOD_OFFSET_EXECPROG + 127] != 0) {
msg[22] = '4';
goto FAIL;
}
 
/* check rmod exec stdin buf */
if (rmod[RMOD_OFFSET_STDINFILE + 127] != 0) {
msg[22] = '5';
goto FAIL;
}
 
/* check rmod exec stdout buf */
if (rmod[RMOD_OFFSET_STDOUTFILE + 127] != 0) {
msg[22] = '6';
goto FAIL;
}
 
/* else all good */
return(0);
 
/* error handling */
FAIL:
outputnl(msg);
return(1);
}
 
 
/* parses command line the hard way (directly from PSP) */
static void parse_argv(struct config *cfg) {
const unsigned char *cmdlinelen = (void *)0x80;
char *cmdline = (void *)0x81;
 
memset(cfg, 0, sizeof(*cfg));
 
/* set a NULL terminator on cmdline */
cmdline[*cmdlinelen] = 0;
 
while (*cmdline != 0) {
 
/* skip over any leading spaces */
if (*cmdline == ' ') {
cmdline++;
continue;
}
 
if (*cmdline != '/') {
nls_output(0,6); /* "Invalid parameter" */
output(": ");
outputnl(cmdline);
goto SKIP_TO_NEXT_ARG;
}
 
/* got a slash */
cmdline++; /* skip the slash */
switch (*cmdline) {
case 'c': /* /C = execute command and quit */
case 'C':
cfg->flags |= FLAG_EXEC_AND_QUIT;
/* FALLTHRU */
case 'k': /* /K = execute command and keep running */
case 'K':
cmdline++;
cfg->execcmd = cmdline;
return; /* further arguments are for the executed program, not for me */
 
case 'y': /* /Y = execute batch file step-by-step (with /P, /K or /C) */
case 'Y':
cfg->flags |= FLAG_STEPBYSTEP;
break;
 
case 'd': /* /D = skip autoexec.bat processing */
case 'D':
cfg->flags |= FLAG_SKIP_AUTOEXEC;
break;
 
case 'e': /* preset the initial size of the environment block */
case 'E':
cmdline++;
if (*cmdline == ':') cmdline++; /* could be /E:size */
atous(&(cfg->envsiz), cmdline);
if (cfg->envsiz < 64) cfg->envsiz = 0;
break;
 
case 'p': /* permanent shell (can't exit + run autoexec.bat) */
case 'P':
cfg->flags |= FLAG_PERMANENT;
break;
 
case '?':
nls_outputnl(1,0); /* "Starts the SvarCOM command interpreter" */
outputnl("");
nls_outputnl(1,1); /* "COMMAND /E:nnn [/[C|K] [/P] [/D] command]" */
outputnl("");
nls_outputnl(1,2); /* "/D Skip AUTOEXEC.BAT processing (makes sense only with /P)" */
nls_outputnl(1,3); /* "/E:nnn Sets the environment size to nnn bytes" */
nls_outputnl(1,4); /* "/P Makes the new command interpreter permanent and run AUTOEXEC.BAT" */
nls_outputnl(1,5); /* "/C Executes the specified command and returns" */
nls_outputnl(1,6); /* "/K Executes the specified command and continues running" */
nls_outputnl(1,7); /* "/Y Executes the batch program step by step" */
exit(1);
break;
 
default:
nls_output(0,2); /* invalid switch */
output(": /");
outputnl(cmdline);
break;
}
 
/* move to next argument or quit processing if end of cmdline */
SKIP_TO_NEXT_ARG:
while ((*cmdline != 0) && (*cmdline != ' ') && (*cmdline != '/')) cmdline++;
}
}
 
 
/* builds the prompt string and displays it. buff is filled with a zero-terminated copy of the prompt. */
static void build_and_display_prompt(char *buff, unsigned short envseg) {
char *s = buff;
/* locate the prompt variable or use the default pattern */
const char far *fmt = env_lookup_val(envseg, "PROMPT");
if ((fmt == NULL) || (*fmt == 0)) fmt = "$p$g"; /* fallback to default if empty */
/* build the prompt string based on pattern */
for (; *fmt != 0; fmt++) {
if (*fmt != '$') {
*s = *fmt;
s++;
continue;
}
/* escape code ($P, etc) */
fmt++;
switch (*fmt) {
case 'Q': /* $Q = = (equal sign) */
case 'q':
*s = '=';
s++;
break;
case '$': /* $$ = $ (dollar sign) */
*s = '$';
s++;
break;
case 'T': /* $t = current time */
case 't':
s += sprintf(s, "00:00"); /* TODO */
break;
case 'D': /* $D = current date */
case 'd':
s += sprintf(s, "1985-07-29"); /* TODO */
break;
case 'P': /* $P = current drive and path */
case 'p':
_asm {
mov ah, 0x19 /* DOS 1+ - GET CURRENT DRIVE */
int 0x21
mov bx, s
mov [bx], al /* AL = drive (00 = A:, 01 = B:, etc */
}
*s += 'A';
s++;
*s = ':';
s++;
*s = '\\';
s++;
_asm {
mov ah, 0x47 /* DOS 2+ - CWD - GET CURRENT DIRECTORY */
xor dl,dl /* DL = drive number (00h = default, 01h = A:, etc) */
mov si, s /* DS:SI -> 64-byte buffer for ASCIZ pathname */
int 0x21
jc DONE /* leave path empty on error */
/* move s ptr forward to end (0-termintor) of pathname */
NEXTBYTE:
mov si, s
cmp byte ptr [si], 0
je DONE
inc s
jmp NEXTBYTE
DONE:
}
break;
case 'V': /* $V = DOS version number */
case 'v':
s += sprintf(s, "VER"); /* TODO */
break;
case 'N': /* $N = current drive */
case 'n':
_asm {
mov ah, 0x19 /* DOS 1+ - GET CURRENT DRIVE */
int 0x21
mov bx, s
mov [bx], al /* AL = drive (00 = A:, 01 = B:, etc */
}
*s += 'A';
s++;
break;
case 'G': /* $G = > (greater-than sign) */
case 'g':
*s = '>';
s++;
break;
case 'L': /* $L = < (less-than sign) */
case 'l':
*s = '<';
s++;
break;
case 'B': /* $B = | (pipe) */
case 'b':
*s = '|';
s++;
break;
case 'H': /* $H = backspace (erases previous character) */
case 'h':
*s = '\b';
s++;
break;
case 'E': /* $E = Escape code (ASCII 27) */
case 'e':
*s = 27;
s++;
break;
case '_': /* $_ = CR+LF */
*s = '\r';
s++;
*s = '\n';
s++;
break;
}
}
*s = 0;
output(buff);
}
 
 
static void dos_fname2fcb(char far *fcb, const char *cmd) {
unsigned short fcb_seg, fcb_off;
fcb_seg = FP_SEG(fcb);
fcb_off = FP_OFF(fcb);
_asm {
push ax
push bx
push cx
push dx
push es
push si
 
mov ax, 0x2900 /* DOS 1+ - parse filename into FCB (DS:SI=fname, ES:DI=FCB) */
mov si, cmd
mov es, fcb_seg
mov di, fcb_off
int 0x21
 
pop si
pop es
pop dx
pop cx
pop bx
pop ax
}
}
 
 
/* parses cmdtail and fills fcb1 and fcb2 with first and second arguments,
* respectively. an FCB is 12 bytes long:
* drive (0=default, 1=A, 2=B, etc)
* fname (8 chars, blank-padded)
* fext (3 chars, blank-padded) */
static void cmdtail_to_fcb(char far *fcb1, char far *fcb2, const char *cmdtail) {
 
/* skip any leading spaces */
while (*cmdtail == ' ') cmdtail++;
 
/* convert first arg */
dos_fname2fcb(fcb1, cmdtail);
 
/* skip to next arg */
while ((*cmdtail != ' ') && (*cmdtail != 0)) cmdtail++;
while (*cmdtail == ' ') cmdtail++;
 
/* convert second arg */
dos_fname2fcb(fcb2, cmdtail);
}
 
 
/* a few internal flags */
#define DELETE_STDIN_FILE 1
#define CALL_FLAG 2
 
static void run_as_external(char *buff, const char *cmdline, unsigned short envseg, struct rmod_props far *rmod, struct redir_data *redir, unsigned char flags) {
char *cmdfile = buff + 512;
const char far *pathptr;
int lookup;
unsigned short i;
const char *ext;
char *cmd = buff + 1024;
const char *cmdtail;
char far *rmod_execprog = MK_FP(rmod->rmodseg, RMOD_OFFSET_EXECPROG);
char far *rmod_cmdtail = MK_FP(rmod->rmodseg, 0x81);
_Packed struct {
unsigned short envseg;
unsigned long cmdtail;
unsigned long fcb1;
unsigned long fcb2;
} far *ExecParam = MK_FP(rmod->rmodseg, RMOD_OFFSET_EXECPARAM);
 
/* find cmd and cmdtail */
i = 0;
cmdtail = cmdline;
while (*cmdtail == ' ') cmdtail++; /* skip any leading spaces */
while ((*cmdtail != ' ') && (*cmdtail != '/') && (*cmdtail != '+') && (*cmdtail != 0)) {
cmd[i++] = *cmdtail;
cmdtail++;
}
cmd[i] = 0;
 
/* is this a command in curdir? */
lookup = lookup_cmd(cmdfile, cmd, NULL, &ext);
if (lookup == 0) {
/* printf("FOUND LOCAL EXEC FILE: '%s'\r\n", cmdfile); */
goto RUNCMDFILE;
} else if (lookup == -2) {
/* puts("NOT FOUND"); */
return;
}
 
/* try matching something in PATH */
pathptr = env_lookup_val(envseg, "PATH");
 
/* try each path in %PATH% */
while (pathptr) {
for (i = 0;; i++) {
buff[i] = *pathptr;
if ((buff[i] == 0) || (buff[i] == ';')) break;
pathptr++;
}
buff[i] = 0;
lookup = lookup_cmd(cmdfile, cmd, buff, &ext);
if (lookup == 0) goto RUNCMDFILE;
if (lookup == -2) return;
if (*pathptr == ';') {
pathptr++;
} else {
break;
}
}
 
/* last chance: is it an executable link? (trim extension from cmd first) */
for (i = 0; (cmd[i] != 0) && (cmd[i] != '.') && (i < 9); i++) buff[128 + i] = cmd[i];
buff[128 + i] = 0;
if ((i < 9) && (link_computefname(buff, buff + 128, envseg) == 0)) {
/* try opening the link file (if it exists) and read it into buff */
i = 0;
_asm {
push ax
push bx
push cx
push dx
 
mov ax, 0x3d00 /* DOS 2+ - OPEN EXISTING FILE, READ-ONLY */
mov dx, buff /* file name */
int 0x21
jc ERR_FOPEN
/* file handle in AX, read from file now */
mov bx, ax /* file handle */
mov ah, 0x3f /* Read from file via handle bx */
mov cx, 128 /* up to 128 bytes */
/* mov dx, buff */ /* dest buffer (already set) */
int 0x21 /* read up to 256 bytes from file and write to buff */
jc ERR_READ
mov i, ax
ERR_READ:
mov ah, 0x3e /* close file handle in BX */
int 0x21
ERR_FOPEN:
 
pop dx
pop cx
pop bx
pop ax
}
 
/* did I read anything? */
if (i != 0) {
buff[i] = 0;
/* trim buff at first \n or \r, just in case someone fiddled with the
* link file using a text editor */
for (i = 0; (buff[i] != 0) && (buff[i] != '\r') && (buff[i] != '\n'); i++);
buff[i] = 0;
/* lookup check */
if (buff[0] != 0) {
lookup = lookup_cmd(cmdfile, cmd, buff, &ext);
if (lookup == 0) goto RUNCMDFILE;
}
}
}
 
/* all failed (ie. executable file not found) */
return;
 
RUNCMDFILE:
 
/* special handling of batch files */
if ((ext != NULL) && (imatch(ext, "bat"))) {
struct batctx far *newbat;
 
/* remember the echo flag (in case bat file disables echo, only when starting first bat) */
if (rmod->bat == NULL) {
rmod->flags &= ~FLAG_ECHO_BEFORE_BAT;
if (rmod->flags & FLAG_ECHOFLAG) rmod->flags |= FLAG_ECHO_BEFORE_BAT;
}
 
/* if bat is not called via a CALL, then free the bat-context linked list */
if ((flags & CALL_FLAG) == 0) rmod_free_bat_llist(rmod);
 
/* allocate a new bat context */
newbat = rmod_fcalloc(sizeof(struct batctx), rmod->rmodseg, "SVBATCTX");
if (newbat == NULL) {
nls_outputnl_doserr(8); /* insufficient memory */
return;
}
 
/* fill the newly allocated batctx structure */
_fstrcpy(newbat->fname, cmdfile); /* truename of the BAT file */
newbat->flags = flags & FLAG_STEPBYSTEP;
/* explode args of the bat file and store them in rmod buff */
cmd_explode(buff, cmdline, NULL);
_fmemcpy(newbat->argv, buff, sizeof(newbat->argv));
 
/* push the new bat to the top of rmod's linked list */
newbat->parent = rmod->bat;
rmod->bat = newbat;
 
return;
}
 
/* copy full filename to execute, along with redirected files (if any) */
_fstrcpy(rmod_execprog, cmdfile);
 
/* copy stdin file if a redirection is needed */
if (redir->stdinfile) {
char far *farptr = MK_FP(rmod->rmodseg, RMOD_OFFSET_STDINFILE);
char far *delstdin = MK_FP(rmod->rmodseg, RMOD_OFFSET_STDIN_DEL);
_fstrcpy(farptr, redir->stdinfile);
if (flags & DELETE_STDIN_FILE) {
*delstdin = redir->stdinfile[0];
} else {
*delstdin = 0;
}
}
 
/* same for stdout file */
if (redir->stdoutfile) {
char far *farptr = MK_FP(rmod->rmodseg, RMOD_OFFSET_STDOUTFILE);
unsigned short far *farptr16 = MK_FP(rmod->rmodseg, RMOD_OFFSET_STDOUTAPP);
_fstrcpy(farptr, redir->stdoutfile);
/* openflag */
*farptr16 = redir->stdout_openflag;
}
 
/* copy cmdtail to rmod's PSP and compute its len */
for (i = 0; cmdtail[i] != 0; i++) rmod_cmdtail[i] = cmdtail[i];
rmod_cmdtail[i] = '\r';
rmod_cmdtail[-1] = i;
 
/* set up rmod to execute the command */
 
ExecParam->envseg = envseg;
ExecParam->cmdtail = (unsigned long)MK_FP(rmod->rmodseg, 0x80); /* farptr, must be in PSP format (lenbyte args \r) */
/* far pointers to unopened FCB entries (stored in RMOD's own PSP) */
{
char far *farptr;
/* prep the unopened FCBs */
farptr = MK_FP(rmod->rmodseg, 0x5C);
_fmemset(farptr, 0, 36); /* first FCB is 16 bytes long, second is 20 bytes long */
cmdtail_to_fcb(farptr, farptr + 16, cmdtail);
/* set (far) pointers in the ExecParam block */
ExecParam->fcb1 = (unsigned long)MK_FP(rmod->rmodseg, 0x5C);
ExecParam->fcb2 = (unsigned long)MK_FP(rmod->rmodseg, 0x6C);
}
exit(0); /* let rmod do the job now */
}
 
 
static void set_comspec_to_self(unsigned short envseg) {
unsigned short *psp_envseg = (void *)(0x2c); /* pointer to my env segment field in the PSP */
char far *myenv = MK_FP(*psp_envseg, 0);
unsigned short varcount;
char buff[256] = "COMSPEC=";
char *buffptr = buff + 8;
/* who am i? look into my own environment, at the end of it should be my EXEPATH string */
while (*myenv != 0) {
/* consume a NULL-terminated string */
while (*myenv != 0) myenv++;
/* move to next string */
myenv++;
}
/* get next word, if 1 then EXEPATH follows */
myenv++;
varcount = *myenv;
myenv++;
varcount |= (*myenv << 8);
myenv++;
if (varcount != 1) return; /* NO EXEPATH FOUND */
while (*myenv != 0) {
*buffptr = *myenv;
buffptr++;
myenv++;
}
*buffptr = 0;
/* printf("EXEPATH: '%s'\r\n", buff); */
env_setvar(envseg, buff);
}
 
 
/* wait for user input */
static void cmdline_getinput(unsigned short inpseg, unsigned short inpoff) {
_asm {
push ax
push bx
push cx
push dx
push ds
 
/* is DOSKEY support present? (INT 2Fh, AX=4800h, returns non-zero in AL if present) */
mov ax, 0x4800
int 0x2f
mov bl, al /* save doskey status in BL */
 
/* set up buffered input to inpseg:inpoff */
mov ax, inpseg
push ax
pop ds
mov dx, inpoff
 
/* execute either DOS input or DOSKEY */
test bl, bl /* zf set if no DOSKEY present */
jnz DOSKEY
 
mov ah, 0x0a
int 0x21
jmp short DONE
 
DOSKEY:
mov ax, 0x4810
int 0x2f
 
DONE:
/* terminate command with a CR/LF */
mov ah, 0x02 /* display character in dl */
mov dl, 0x0d
int 0x21
mov dl, 0x0a
int 0x21
 
pop ds
pop dx
pop cx
pop bx
pop ax
}
}
 
 
/* fetches a line from batch file and write it to buff (NULL-terminated),
* increments rmod counter and returns 0 on success. */
static int getbatcmd(char *buff, unsigned char buffmaxlen, struct rmod_props far *rmod) {
unsigned short i;
unsigned short batname_seg = FP_SEG(rmod->bat->fname);
unsigned short batname_off = FP_OFF(rmod->bat->fname);
unsigned short filepos_cx = rmod->bat->nextline >> 16;
unsigned short filepos_dx = rmod->bat->nextline & 0xffff;
unsigned char blen = 0;
unsigned short errv = 0;
 
/* open file, jump to offset filpos, and read data into buff.
* result in blen (unchanged if EOF or failure). */
_asm {
push ax
push bx
push cx
push dx
 
/* open file (read-only) */
mov bx, 0xffff /* preset BX to 0xffff to detect error conditions */
mov dx, batname_off
mov ax, batname_seg
push ds /* save DS */
mov ds, ax
mov ax, 0x3d00
int 0x21 /* handle in ax on success */
pop ds /* restore DS */
jc ERR
mov bx, ax /* save handle to bx */
 
/* jump to file offset CX:DX */
mov ax, 0x4200
mov cx, filepos_cx
mov dx, filepos_dx
int 0x21 /* CF clear on success, DX:AX set to cur pos */
jc ERR
 
/* read the line into buff */
mov ah, 0x3f
xor ch, ch
mov cl, buffmaxlen
mov dx, buff
int 0x21 /* CF clear on success, AX=number of bytes read */
jc ERR
mov blen, al
jmp CLOSEANDQUIT
 
ERR:
mov errv, ax
 
CLOSEANDQUIT:
/* close file (if bx contains a handle) */
cmp bx, 0xffff
je DONE
mov ah, 0x3e
int 0x21
 
DONE:
pop dx
pop cx
pop bx
pop ax
}
 
/* printf("blen=%u filepos_cx=%u filepos_dx=%u\r\n", blen, filepos_cx, filepos_dx); */
 
if (errv != 0) nls_outputnl_doserr(errv);
 
/* on EOF - abort processing the bat file */
if (blen == 0) goto OOPS;
 
/* find nearest \n to inc batch offset and replace \r by NULL terminator
* I support all CR/LF, CR- and LF-terminated batch files */
for (i = 0; i < blen; i++) {
if ((buff[i] == '\r') || (buff[i] == '\n')) {
if ((buff[i] == '\r') && ((i+1) < blen) && (buff[i+1] == '\n')) rmod->bat->nextline += 1;
break;
}
}
buff[i] = 0;
rmod->bat->nextline += i + 1;
 
return(0);
 
OOPS:
rmod->bat->fname[0] = 0;
rmod->bat->nextline = 0;
return(-1);
}
 
 
/* replaces %-variables in a BAT line with resolved values:
* %PATH% -> replaced by the contend of the PATH env variable
* %UNDEFINED% -> undefined variables are replaced by nothing ("")
* %NOTCLOSED -> NOTCLOSED
* %1 -> first argument of the batch file (or nothing if no arg) */
static void batpercrepl(char *res, unsigned short ressz, const char *line, const struct rmod_props far *rmod, unsigned short envseg) {
unsigned short lastperc = 0xffff;
unsigned short reslen = 0;
 
if (ressz == 0) return;
ressz--; /* reserve one byte for the NULL terminator */
 
for (; (reslen < ressz) && (*line != 0); line++) {
/* if not a percent, I don't care */
if (*line != '%') {
res[reslen++] = *line;
continue;
}
 
/* *** perc char handling *** */
 
/* closing perc? */
if (lastperc != 0xffff) {
/* %% is '%' */
if (lastperc == reslen) {
res[reslen++] = '%';
} else { /* otherwise variable name */
const char far *ptr;
res[reslen] = 0;
reslen = lastperc;
nls_strtoup(res + reslen); /* turn varname uppercase before lookup */
ptr = env_lookup_val(envseg, res + reslen);
if (ptr != NULL) {
while ((*ptr != 0) && (reslen < ressz)) {
res[reslen++] = *ptr;
ptr++;
}
}
}
lastperc = 0xffff;
continue;
}
 
/* digit? (bat arg) */
if ((line[1] >= '0') && (line[1] <= '9')) {
unsigned short argid = line[1] - '0';
unsigned short i;
const char far *argv = "";
if ((rmod != NULL) && (rmod->bat != NULL)) argv = rmod->bat->argv;
 
/* locate the proper arg */
for (i = 0; i != argid; i++) {
/* if string is 0, then end of list reached */
if (*argv == 0) break;
/* jump to next arg */
while (*argv != 0) argv++;
argv++;
}
 
/* copy the arg to result */
for (i = 0; (argv[i] != 0) && (reslen < ressz); i++) {
res[reslen++] = argv[i];
}
line++; /* skip the digit */
continue;
}
 
/* opening perc */
lastperc = reslen;
 
}
 
res[reslen] = 0;
}
 
 
/* process the ongoing forloop, returns 0 on success, non-zero otherwise (no
more things to process) */
static int forloop_process(char *res, struct forctx far *forloop) {
unsigned short i, t;
struct DTA *dta = (void *)0x80; /* default DTA at 80h in PSP */
char *fnameptr = dta->fname;
char *pathprefix = BUFFER + 256;
 
*pathprefix = 0;
 
TRYAGAIN:
 
/* dta_inited: FindFirst() or FindNext()? */
if (forloop->dta_inited == 0) {
 
/* copy next awaiting pattern to BUFFER (and skip all delimiters until
* next pattern or end of list) */
t = 0;
for (i = 0;; i++) {
BUFFER[i] = forloop->cmd[forloop->nextpat + i];
/* is this a delimiter? (all delimiters are already normalized to a space here) */
if (BUFFER[i] == ' ') {
BUFFER[i] = 0;
t = 1;
} else if (BUFFER[i] == 0) {
/* end of patterns list */
break;
} else {
/* quit if I got a pattern already */
if (t == 1) break;
}
}
 
if (i == 0) return(-1);
 
/* remember position of current pattern */
forloop->curpat = forloop->nextpat;
 
/* move nextpat forward to next pattern */
i += forloop->nextpat;
forloop->nextpat = i;
 
/* if this is a string and not a pattern, skip all the FindFirst business
* a file pattern has a wildcard (* or ?), a message doesn't */
for (i = 0; (BUFFER[i] != 0) && (BUFFER[i] != '?') && (BUFFER[i] != '*'); i++);
if (BUFFER[i] == 0) {
fnameptr = BUFFER;
goto SKIP_DTA;
}
 
/* FOR in MSDOS 6 includes hidden and system files, but not directories nor volumes */
if (findfirst(dta, BUFFER, DOS_ATTR_RO | DOS_ATTR_HID | DOS_ATTR_SYS | DOS_ATTR_ARC) != 0) {
goto TRYAGAIN;
}
forloop->dta_inited = 1;
} else { /* dta in progress */
 
/* copy forloop DTA to my local copy */
_fmemcpy(dta, &(forloop->dta), sizeof(*dta));
 
/* findnext() call */
if (findnext(dta) != 0) {
forloop->dta_inited = 0;
goto TRYAGAIN;
}
}
 
/* copy updated DTA to rmod */
_fmemcpy(&(forloop->dta), dta, sizeof(*dta));
 
/* prefill pathprefix with the prefix (path) of the files */
{
short lastbk = -1;
char far *c = forloop->cmd + forloop->curpat;
for (i = 0;; i++) {
pathprefix[i] = c[i];
if (pathprefix[i] == '\\') lastbk = i;
if ((pathprefix[i] == ' ') || (pathprefix[i] == 0)) break;
}
pathprefix[lastbk+1] = 0;
}
 
SKIP_DTA:
 
/* fill res with command, replacing varname by actual filename */
/* full filename is to be built with path of curpat and fname from dta */
t = 0;
i = 0;
for (;;) {
if ((forloop->cmd[forloop->exec + t] == '%') && (forloop->cmd[forloop->exec + t + 1] == forloop->varname)) {
strcpy(res + i, pathprefix);
strcat(res + i, fnameptr);
for (; res[i] != 0; i++);
t += 2;
} else {
res[i] = forloop->cmd[forloop->exec + t];
t++;
if (res[i++] == 0) break;
}
}
 
return(0);
}
 
 
int main(void) {
static struct config cfg;
static unsigned short far *rmod_envseg;
static unsigned short far *lastexitcode;
static struct rmod_props far *rmod;
static char cmdlinebuf[CMDLINE_MAXLEN + 2]; /* 1 extra byte for 0-terminator and another for memguard */
static char *cmdline;
static struct redir_data redirprops;
static enum cmd_result cmdres;
static unsigned short i; /* general-purpose variable for short-lived things */
static unsigned char flags;
 
rmod = rmod_find(BUFFER_len);
if (rmod == NULL) {
/* look at command line parameters (in case env size if set there) */
parse_argv(&cfg);
rmod = rmod_install(cfg.envsiz, BUFFER, BUFFER_len);
if (rmod == NULL) {
nls_outputnl_err(2,1); /* "FATAL ERROR: rmod_install() failed" */
return(1);
}
/* copy flags to rmod's storage (and enable ECHO) */
rmod->flags = cfg.flags | FLAG_ECHOFLAG;
/* printf("rmod installed at %Fp\r\n", rmod); */
rmod->version = BYTE_VERSION;
} else {
/* printf("rmod found at %Fp\r\n", rmod); */
/* if I was spawned by rmod and FLAG_EXEC_AND_QUIT is set, then I should
* die asap, because the command has been executed already, so I no longer
* have a purpose in life */
if (rmod->flags & FLAG_EXEC_AND_QUIT) sayonara(rmod);
/* */
if (rmod->version != BYTE_VERSION) {
nls_outputnl_err(2,0);
_asm {
HALT:
hlt
jmp HALT
}
}
}
 
/* install a few guardvals in memory to detect some cases of overflows */
memguard_set(cmdlinebuf);
 
rmod_envseg = MK_FP(rmod->rmodseg, RMOD_OFFSET_ENVSEG);
lastexitcode = MK_FP(rmod->rmodseg, RMOD_OFFSET_LEXITCODE);
 
/* make COMPSEC point to myself */
set_comspec_to_self(*rmod_envseg);
 
/* on /P check for the presence of AUTOEXEC.BAT and execute it if found,
* but skip this check if /D was also passed */
if ((cfg.flags & (FLAG_PERMANENT | FLAG_SKIP_AUTOEXEC)) == FLAG_PERMANENT) {
if (file_getattr("AUTOEXEC.BAT") >= 0) cfg.execcmd = "AUTOEXEC.BAT";
}
 
do {
 
/* terminate previous command with a CR/LF if ECHO ON (but not during BAT processing) */
if ((rmod->flags & FLAG_ECHOFLAG) && (rmod->bat == NULL)) outputnl("");
 
SKIP_NEWLINE:
 
/* memory check */
memguard_check(rmod->rmodseg, cmdlinebuf);
 
/* preset cmdline to point at the dedicated buffer */
cmdline = cmdlinebuf;
 
/* (re)load translation strings if needed */
nls_langreload(BUFFER, *rmod_envseg);
 
/* am I inside a FOR loop? */
if (rmod->forloop) {
if (forloop_process(cmdlinebuf, rmod->forloop) != 0) {
rmod_ffree(rmod->forloop);
rmod->forloop = NULL;
} else {
/* output prompt and command on screen if echo on and command is not
* inhibiting it with the @ prefix */
if (rmod->flags & FLAG_ECHOFLAG) {
build_and_display_prompt(BUFFER, *rmod_envseg);
outputnl(cmdline);
}
/* jump to command processing */
goto EXEC_CMDLINE;
}
}
 
/* load awaiting command, if any (used to run piped commands) */
if (rmod->awaitingcmd[0] != 0) {
_fstrcpy(cmdline, rmod->awaitingcmd);
rmod->awaitingcmd[0] = 0;
flags |= DELETE_STDIN_FILE;
goto EXEC_CMDLINE;
} else {
flags &= ~DELETE_STDIN_FILE;
}
 
/* skip user input if I have a command to exec (/C or /K or /P) */
if (cfg.execcmd != NULL) {
cmdline = cfg.execcmd;
cfg.execcmd = NULL;
/* */
if (cfg.flags & FLAG_STEPBYSTEP) flags |= FLAG_STEPBYSTEP;
goto EXEC_CMDLINE;
}
 
/* if batch file is being executed -> fetch next line */
if (rmod->bat != NULL) {
if (getbatcmd(BUFFER, CMDLINE_MAXLEN, rmod) != 0) { /* end of batch */
struct batctx far *victim = rmod->bat;
rmod->bat = rmod->bat->parent;
rmod_ffree(victim);
/* end of batch? then restore echo flag as it was before running the (first) bat file */
if (rmod->bat == NULL) {
rmod->flags &= ~FLAG_ECHOFLAG;
if (rmod->flags & FLAG_ECHO_BEFORE_BAT) rmod->flags |= FLAG_ECHOFLAG;
}
continue;
}
/* %-decoding of variables (%PATH%, %1, %%...), result in cmdline */
batpercrepl(cmdline, CMDLINE_MAXLEN, BUFFER, rmod, *rmod_envseg);
/* skip any leading spaces */
while (*cmdline == ' ') cmdline++;
/* skip batch labels */
if (*cmdline == ':') continue;
/* step-by-step execution? */
if (rmod->bat->flags & FLAG_STEPBYSTEP) {
if (*cmdline == 0) continue; /* skip empty lines */
if (askchoice(cmdline, svarlang_str(0,10)) != 0) continue;
}
/* output prompt and command on screen if echo on and command is not
* inhibiting it with the @ prefix */
if ((rmod->flags & FLAG_ECHOFLAG) && (cmdline[0] != '@')) {
build_and_display_prompt(BUFFER, *rmod_envseg);
outputnl(cmdline);
}
/* skip the @ prefix if present, it is no longer useful */
if (cmdline[0] == '@') cmdline++;
} else {
unsigned char far *rmod_inputbuf = MK_FP(rmod->rmodseg, RMOD_OFFSET_INPUTBUF);
/* invalidate input history if it appears to be damaged (could occur
* because of a stack overflow, for example if some stack-hungry TSR is
* being used) */
if ((rmod_inputbuf[0] != 128) || (rmod_inputbuf[rmod_inputbuf[1] + 2] != '\r') || (rmod_inputbuf[rmod_inputbuf[1] + 3] != 0xCA) || (rmod_inputbuf[rmod_inputbuf[1] + 4] != 0xFE)) {
rmod_inputbuf[0] = 128; /* max allowed input length */
rmod_inputbuf[1] = 0; /* string len stored in buffer */
rmod_inputbuf[2] = '\r'; /* string terminator */
rmod_inputbuf[3] = 0xCA; /* trailing signature */
rmod_inputbuf[4] = 0xFE; /* trailing signature */
nls_outputnl_err(2,2); /* "stack overflow detected, command history flushed" */
}
/* interactive mode: display prompt (if echo enabled) and wait for user
* command line */
if (rmod->flags & FLAG_ECHOFLAG) build_and_display_prompt(BUFFER, *rmod_envseg);
/* collect user input */
cmdline_getinput(rmod->rmodseg, RMOD_OFFSET_INPUTBUF);
/* append stack-overflow detection signature to the end of the input buffer */
rmod_inputbuf[rmod_inputbuf[1] + 3] = 0xCA; /* trailing signature */
rmod_inputbuf[rmod_inputbuf[1] + 4] = 0xFE; /* trailing signature */
/* copy it to local cmdline */
if (rmod_inputbuf[1] != 0) _fmemcpy(cmdline, rmod_inputbuf + 2, rmod_inputbuf[1]);
cmdline[rmod_inputbuf[1]] = 0; /* zero-terminate local buff (original is '\r'-terminated) */
}
 
/* if nothing entered, loop again (but without appending an extra CR/LF) */
if (cmdline[0] == 0) goto SKIP_NEWLINE;
 
/* I jump here when I need to exec an initial command (/C or /K) */
EXEC_CMDLINE:
 
/* move pointer forward to skip over any leading spaces */
while (*cmdline == ' ') cmdline++;
 
/* sanitize separators into spaces */
for (i = 0; cmdline[i] != 0; i++) {
switch (cmdline[i]) {
case '\t':
cmdline[i] = ' ';
}
}
 
/* update rmod's ptr to COMPSPEC so it is always up to date */
rmod_updatecomspecptr(rmod->rmodseg, *rmod_envseg);
 
/* handle redirections (if any) */
i = redir_parsecmd(&redirprops, cmdline, rmod->awaitingcmd, *rmod_envseg);
if (i != 0) {
nls_outputnl_doserr(i);
rmod->awaitingcmd[0] = 0;
continue;
}
 
/* try matching (and executing) an internal command */
cmdres = cmd_process(rmod, *rmod_envseg, cmdline, BUFFER, sizeof(BUFFER), &redirprops, flags & DELETE_STDIN_FILE);
if ((cmdres == CMD_OK) || (cmdres == CMD_FAIL)) {
/* internal command executed */
} else if (cmdres == CMD_CHANGED) { /* cmdline changed, needs to be reprocessed */
goto EXEC_CMDLINE;
} else if (cmdres == CMD_CHANGED_BY_CALL) { /* cmdline changed *specifically* by CALL */
/* the distinction is important since it changes the way batch files are processed */
flags |= CALL_FLAG;
goto EXEC_CMDLINE;
} else if (cmdres == CMD_NOTFOUND) {
/* this was not an internal command, try matching an external command */
run_as_external(BUFFER, cmdline, *rmod_envseg, rmod, &redirprops, flags);
 
/* is it a newly launched BAT file? */
if ((rmod->bat != NULL) && (rmod->bat->nextline == 0)) goto SKIP_NEWLINE;
/* run_as_external() does not return on success, if I am still alive then
* external command failed to execute */
nls_outputnl(0,5); /* "Bad command or file name" */
} else {
/* I should never ever land here */
outputnl("INTERNAL ERR: INVALID CMDRES");
}
 
/* reset one-time only flags */
flags &= ~CALL_FLAG;
flags &= ~FLAG_STEPBYSTEP;
 
/* repeat unless /C was asked - but always finish running an ongoing batch
* file (otherwise only first BAT command would be executed with /C) */
} while (((rmod->flags & FLAG_EXEC_AND_QUIT) == 0) || (rmod->bat != NULL) || (rmod->forloop != NULL));
 
sayonara(rmod);
return(0);
}
/svarcom/tags/svarcom-2023.1/env.c
0,0 → 1,167
/* 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.
*/
 
/*
* routines used to manipulate the environment block
*/
 
#include <i86.h>
#include <string.h>
 
#include "env.h"
 
/* looks for varname in environment block and returns a far ptr to it if
* found, NULL otherwise. varname MUST be in upper-case and MUST be terminated
* by either a = sign or a NULL terminator */
char far *env_lookup(unsigned short env_seg, const char *varname) {
char far *env = MK_FP(env_seg, 0);
int i;
for (;;) {
/* is this it? */
for (i = 0;; i++) {
if ((varname[i] == '=') || (varname[i] == 0)) {
if (env[i] == '=') return(env); /* FOUND! */
break; /* else look for next string */
}
if (varname[i] != env[i]) break;
}
/* move env to end of current string */
while (*env != 0) env++;
/* if there's another trailing zero, then that is the end of environment */
env++;
if (*env == 0) return(NULL);
}
}
 
 
/* almost identical to env_lookup(), but instead of returning a pointer
* to the 'NAME=value' string, it returns a pointer to value (or NULL if
* var not found) */
char far *env_lookup_val(unsigned short env_seg, const char *varname) {
char far *r = env_lookup(env_seg, varname);
if (r == NULL) return(NULL);
/* find '=' or end of string */
for (;;) {
if (*r == '=') return(r + 1);
if (*r == 0) return(r);
r++;
}
}
 
 
/* locates the value of env variable varname and copies it to result, up to
* ressz bytes (incl. the NULL terminator). returns the length of the value on
* success, 0 if var not found or couldn't fit in ressz). */
unsigned short env_lookup_valcopy(char *res, unsigned short ressz, unsigned short env_seg, const char *varname) {
unsigned short i;
char far *v = env_lookup_val(env_seg, varname);
if (v == NULL) return(0);
for (i = 0;; i++) {
if (ressz-- == 0) return(0);
res[i] = v[i];
if (res[i] == 0) return(i);
}
}
 
 
/* returns the size, in bytes, of the allocated environment block */
unsigned short env_allocsz(unsigned short env_seg) {
unsigned short far *mcbsz = MK_FP(env_seg - 1, 3); /* block size is a word at offset +3 in the MCB */
return(*mcbsz * 16); /* return size in bytes, not paragraphs */
}
 
 
/* remove a variable from environment, if present. returns 0 on success, non-zero if variable not found */
int env_dropvar(unsigned short env_seg, const char *varname) {
unsigned short blocksz, traillen;
unsigned short len;
char far *varptr = env_lookup(env_seg, varname);
 
/* if variable not found in environment, quit now */
if (varptr == NULL) return(-1);
 
for (len = 0; varptr[len] != 0; len++); /* compute length of variable (without trailing null) */
blocksz = env_allocsz(env_seg); /* total environment size */
traillen = blocksz - (FP_OFF(varptr) + len + 1); /* how much bytes are present after the variable */
_fmemset(varptr, 0, len); /* zero out the variable */
if (traillen != 0) {
_fmemmove(varptr, varptr + len + 1, traillen); /* move rest of memory */
}
return(0);
}
 
 
/* Writes a variable to environment block. The variable must in the form
* "VARNAME=value". If variable is already present in the environment block,
* then the value will be updated. If the new value is empty, then the
* existing variable (if any) is removed.
* VARNAME *MUST* be all-uppercase.
*
* This function returns:
* ENV_SUCCESS = success
* ENV_NOTENOM = not enough available space in memory block
* ENV_INVSYNT = invalid syntax
*/
int env_setvar(unsigned short env_seg, const char *v) {
unsigned short envlen;
unsigned short envfree;
unsigned short vlen, veqpos;
char far *env = MK_FP(env_seg, 0);
 
/* remove variable from environment, if already set */
env_dropvar(env_seg, v);
 
/* compute v length and find the position of the eq sign */
veqpos = 0xffff;
for (vlen = 0; v[vlen] != 0; vlen++) {
if (v[vlen] == '=') {
if (veqpos != 0xffff) return(ENV_INVSYNT); /* equal sign is forbidden in value */
veqpos = vlen;
}
}
 
/* if variable empty, stop here */
if (veqpos == vlen - 1) return(ENV_SUCCESS);
 
/* compute current size of the environment */
for (envlen = 0; env[envlen] != 0; envlen++) {
while (env[envlen] != 0) envlen++; /* consume a string */
}
 
/* compute free space available in environment */
envfree = env_allocsz(env_seg);
envfree -= envlen;
envfree -= 1; /* 1 byte for the environment's NULL terminator */
 
/* do I have enough env space for the new var? */
if (envfree < vlen + 1) return(ENV_NOTENOM);
 
/* write the new variable (with its NULL terminator) to environment tail */
_fmemcpy(env + envlen, v, vlen + 1);
 
/* add the environment's NULL terminator */
env[envlen + vlen + 1] = 0;
 
return(ENV_SUCCESS);
}
/svarcom/tags/svarcom-2023.1/env.h
0,0 → 1,69
/* 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.
*/
 
/*
* routines used to manipulate the environment block
*/
 
#ifndef ENV_H
#define ENV_H
 
/* looks for varname in environment block and returns a far ptr to it if
* found, NULL otherwise. varname MUST be in upper-case and MUST be terminated
* by either a = sign or a NULL terminator */
char far *env_lookup(unsigned short env_seg, const char *varname);
 
/* almost identical to env_lookup(), but instead of returning a pointer
* to the 'NAME=value' string, it returns a pointer to value (or NULL if
* var not found) */
char far *env_lookup_val(unsigned short env_seg, const char *varname);
 
/* locates the value of env variable varname and copies it to result, up to
* ressz bytes (incl. the NULL terminator). returns the length of the value on
* success, 0 if var not found or couldn't fit in ressz). */
unsigned short env_lookup_valcopy(char *res, unsigned short ressz, unsigned short env_seg, const char *varname);
 
/* returns the size, in bytes, of the allocated environment block */
unsigned short env_allocsz(unsigned short env_seg);
 
/* remove a variable from environment, if present. returns 0 on success, non-zero if variable not found */
int env_dropvar(unsigned short env_seg, const char *varname);
 
#define ENV_SUCCESS 0
#define ENV_NOTENOM -1
#define ENV_INVSYNT -2
 
/* Writes a variable to environment block. The variable must in the form
* "varname=value". If variable is already present in the environment block,
* then the value will be updated. If the new value is empty, then the
* existing variable (if any) is removed.
*
* This function returns:
* ENV_SUCCESS = success
* ENV_NOTENOM = not enough available space in memory block
* ENV_INVSYNT = invalid syntax
*/
int env_setvar(unsigned short env_seg, const char *v);
 
#endif
/svarcom/tags/svarcom-2023.1/file2c.c
0,0 → 1,93
/*
* translates a binary file to a C include.
* used by the SvarCOM build process to embedd rcom inside COMMAND.COM
*
* Copyright (C) 2021 Mateusz Viste
*/
 
#include <stdio.h>
 
 
static void help(void) {
puts("usage: file2c [/c] [/lxxx] infile.dat outfile.c varname");
puts("");
puts("/c - define the output array as CONST");
puts("/s - define the output array as STATIC");
puts("/lxxx - enforces the output array to be xxx bytes big");
}
 
 
int main(int argc, char **argv) {
char *fnamein = NULL, *fnameout = NULL, *varname = NULL;
char stortype = 0; /* 'c' = const ; 's' = static */
char *flag_l = "";
FILE *fdin, *fdout;
unsigned long len;
int c;
 
for (c = 1; c < argc; c++) {
if ((argv[c][0] == '/') && (argv[c][1] == 'l')) {
flag_l = argv[c] + 2;
continue;
}
if ((argv[c][0] == '/') && (argv[c][1] == 'c')) {
stortype = 'c';
continue;
}
if ((argv[c][0] == '/') && (argv[c][1] == 's')) {
stortype = 's';
continue;
}
if (argv[c][0] == '/') {
help();
return(1);
}
/* not a switch - so it's either infile, outfile or varname */
if (fnamein == NULL) {
fnamein = argv[c];
} else if (fnameout == NULL) {
fnameout = argv[c];
} else if (varname == NULL) {
varname = argv[c];
} else {
help();
return(1);
}
}
 
if (varname == NULL) {
help();
return(1);
}
 
fdin = fopen(fnamein, "rb");
if (fdin == NULL) {
puts("ERROR: failed to open input file");
return(1);
}
 
fdout = fopen(fnameout, "wb");
if (fdout == NULL) {
fclose(fdin);
puts("ERROR: failed to open output file");
return(1);
}
 
if (stortype == 'c') fprintf(fdout, "const ");
if (stortype == 's') fprintf(fdout, "static ");
fprintf(fdout, "char %s[%s] = {", varname, flag_l);
 
for (len = 0;; len++) {
c = getc(fdin);
if (c == EOF) break;
if (len > 0) fprintf(fdout, ",");
if ((len & 15) == 0) fprintf(fdout, "\r\n");
fprintf(fdout, "%3u", c);
}
fprintf(fdout, "};\r\n");
fprintf(fdout, "#define %s_len %lu\r\n", varname, len);
 
fclose(fdin);
fclose(fdout);
return(0);
}
/svarcom/tags/svarcom-2023.1/freecom.txt
0,0 → 1,73
 
=== SVARCOM vs FREECOM ===
 
 
SvarCOM is a DOS command interpreter (shell), similar to COMMAND.COM in MS-DOS
and FreeCOM in FreeDOS. But why not using FreeCOM in the first place?
 
The FreeCOM project is an impressive piece of software, but there are a few
things that I do not like about it. SvarCOM is my attempt at addressing these
issues through a completely new implementation. SvarCOM is composed of
entirely original code and does not borrow any code from MS-DOS or FreeCOM.
 
 
=== MEMORY FOOTPRINT =========================================================
 
FreeCOM is not suitable for low-memory machines. It takes about 55K of
conventional memory when XMS is unavailable. XMS being a 386+ thing, FreeCOM
is a poor fit for pre-386 machines. There is the KSSF hack, but it is a kludge
with many limitations. As pointed out by one of the FreeCOM authors, FreeCOM
is designed with 21'st century machines in mind and not IBM PC compatibles.
 
SvarCOM does not rely on XMS and performs runtime swapping that works on any
IBM PC compatible machine. Its resident size is about 2K.
 
 
=== NLS RESSOURCES ===========================================================
 
FreeCOM requires custom NLS ressources. While the vast majority of FreeDOS
programs use a single "standard" (CATS), FreeCOM uses a different approach
with NLS strings built into the binary. This makes it necessary to distribute
as many binary blobs as there are supported languages. Another consequence is
that FreeCOM is unable to switch its language dynamically (ie. following
changes made to the LANG environment variable). It also makes the translation
more difficult.
 
SvarCOM uses CATS-style translations and supports dynamic language changes
through the %LANG% environment variable.
 
 
=== CODE COMPLEXITY ==========================================================
 
FreeCOM is a complex beast: it aims for compatibility with multiple compilers
and supports many embedded features. This makes the code uneasy to follow and
changes require careful testing on all supported compilers and all possible
build variants.
 
SvarCOM, on the other hand, is meant to be simple and universal. It is
compiled with OpenWatcom only, which makes a ton of IFDEF's go away. It also
does not integrate extra features that can be reasonably implemented through
external tools (typically: DOSKEY). It strives to reimplement the baseline
functionality of MS-DOS 5/6.
 
 
=== NON-FREE LICENSE =========================================================
 
FreeCOM code is released under the terms of a license that restrains the
freedom of its users due to its virality (GPL).
 
SvarCOM is released under the terms of a liberal and permissive (MIT) license
that does not impose limitations on how users may or may not use the software,
it only asks for credits to be provided where credit is due.
 
I am aware that this section, and its slightly provocating title, may trigger
reactions from GPL enthusiasts. Let me explain with more words. I enjoy
creating software and I publish it for others to use for free. Should someone
wish to extend SvarCOM with an extra feature and decide not to publish the
source code along with the modified version, that's fine by me. My code is
still open and free. Theirs is not, but its their work, so I find it fair that
they have the freedom to decide how to distribute it. I certainly do not want
to impose my views on others.
 
 
====================================================================== EOF ===
/svarcom/tags/svarcom-2023.1/helpers.c
0,0 → 1,810
/* 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.
*/
 
/*
* a variety of helper functions
*/
 
#include <i86.h> /* MK_FP() */
#include <stdio.h> /* sprintf() */
#include <string.h> /* memcpy() */
 
#include "svarlang.lib\svarlang.h"
 
#include "env.h"
 
#include "helpers.h"
 
 
 
/* case-insensitive comparison of strings, compares up to maxlen characters.
* returns non-zero on equality. */
int imatchlim(const char *s1, const char *s2, unsigned short maxlen) {
while (maxlen--) {
char c1, c2;
c1 = *s1;
c2 = *s2;
if ((c1 >= 'a') && (c1 <= 'z')) c1 -= ('a' - 'A');
if ((c2 >= 'a') && (c2 <= 'z')) c2 -= ('a' - 'A');
/* */
if (c1 != c2) return(0);
if (c1 == 0) break;
s1++;
s2++;
}
return(1);
}
 
 
/* returns zero if s1 starts with s2 */
int strstartswith(const char *s1, const char *s2) {
while (*s2 != 0) {
if (*s1 != *s2) return(-1);
s1++;
s2++;
}
return(0);
}
 
 
/* outputs a NULL-terminated string to handle (1=stdout 2=stderr) */
void output_internal(const char *s, unsigned char nl, unsigned char handle) {
const static unsigned char *crlf = "\r\n";
_asm {
push ds
pop es /* make sure es=ds (scasb uses es) */
/* get length of s into CX */
mov ax, 0x4000 /* ah=DOS "write to file" and AL=0 for NULL matching */
mov dx, s /* set dx to string (required for later) */
mov di, dx /* set di to string (for NULL matching) */
mov cx, 0xffff /* preset cx to 65535 (-1) */
cld /* clear DF so scasb increments DI */
repne scasb /* cmp al, es:[di], inc di, dec cx until match found */
/* CX contains (65535 - strlen(s)) now */
not cx /* reverse all bits so I get (strlen(s) + 1) */
dec cx /* this is CX length */
jz WRITEDONE /* do nothing for empty strings */
 
/* output by writing to stdout */
/* mov ah, 0x40 */ /* DOS 2+ -- write to file via handle */
xor bh, bh
mov bl, handle /* set handle (1=stdout 2=stderr) */
/* mov cx, xxx */ /* write CX bytes */
/* mov dx, s */ /* DS:DX is the source of bytes to "write" */
int 0x21
WRITEDONE:
 
/* print out a CR/LF trailer if nl set */
test byte ptr [nl], 0xff
jz FINITO
/* bx still contains handle */
mov ah, 0x40 /* "write to file" */
mov cx, 2
mov dx, crlf
int 0x21
FINITO:
}
}
 
 
void nls_output_internal(unsigned short id, unsigned char nl, unsigned char handle) {
const char *NOTFOUND = "NLS_STRING_NOT_FOUND";
const char *ptr = svarlang_strid(id);
if ((ptr == NULL) || (ptr[0]) == 0) ptr = NOTFOUND;
output_internal(ptr, nl, handle);
}
 
 
/* output DOS error e to stdout, if stdout is redirected then *additionally*
* also to stderr */
void nls_outputnl_doserr(unsigned short e) {
static char errstr[16];
const char *ptr = NULL;
unsigned char redirflag = 0;
/* find string in nls block */
if (e < 0xff) ptr = svarlang_strid(0xff00 | e);
/* if not found, use a fallback */
if ((ptr == NULL) || (ptr[0] == 0)) {
sprintf(errstr, "DOS ERR %u", e);
ptr = errstr;
}
 
/* display to stdout */
output_internal(ptr, 1, hSTDOUT);
 
/* is stdout redirected? */
_asm {
push bx
push dx
 
mov ax, 0x4400 /* query device flags */
mov bx, 1 /* stdout */
int 0x21
/* CF set on error and AX filled with DOS error,
* returns flags in DX on succes:
* bit 7 reset if handle points to a file, set if handle points to a device */
jc FAIL
mov redirflag, dl
and redirflag, 128
 
FAIL:
pop dx
pop bx
}
 
if (redirflag == 0) output_internal(ptr, 1, hSTDERR);
}
 
 
/* find first matching files using a FindFirst DOS call
* returns 0 on success or a DOS err code on failure */
unsigned short findfirst(struct DTA *dta, const char *pattern, unsigned short attr) {
unsigned short res = 0;
_asm {
/* set DTA location */
mov ah, 0x1a
mov dx, dta
int 0x21
/* */
mov ah, 0x4e /* FindFirst */
mov dx, pattern
mov cx, attr
int 0x21 /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
jnc DONE
mov [res], ax
DONE:
}
return(res);
}
 
 
/* find next matching, ie. continues an action intiated by findfirst() */
unsigned short findnext(struct DTA *dta) {
unsigned short res = 0;
_asm {
mov ah, 0x4f /* FindNext */
mov dx, dta
int 0x21 /* CF set on error + err code in AX, DTA filled with FileInfoRec on success */
jnc DONE
mov [res], ax
DONE:
}
return(res);
}
 
 
/* print s string and wait for a single key press from stdin. accepts only
* key presses defined in the c ASCIIZ string. returns offset of pressed key
* in string. keys in c MUST BE UPPERCASE! */
unsigned short askchoice(const char *s, const char *c) {
unsigned short res;
char cstr[2] = {0,0};
char key = 0;
 
AGAIN:
output(s);
output(" ");
output("(");
for (res = 0; c[res] != 0; res++) {
if (res != 0) output("/");
cstr[0] = c[res];
output(cstr);
}
output(") ");
 
_asm {
push ax
push dx
 
mov ax, 0x0c01 /* clear input buffer and execute getchar (INT 21h,AH=1) */
int 0x21
/* if AL == 0 then this is an extended character */
test al, al
jnz GOTCHAR
mov ah, 0x08 /* read again to flush extended char from input buffer */
int 0x21
xor al, al /* all extended chars are ignored */
GOTCHAR: /* received key is in AL now */
mov [key], al /* save key */
 
/* print a cr/lf */
mov ah, 0x02
mov dl, 0x0D
int 0x21
mov dl, 0x0A
int 0x21
 
pop dx
pop ax
}
 
/* ucase() result */
if ((key >= 'a') && (key <= 'z')) key -= ('a' - 'A');
 
/* is there a match? */
for (res = 0; c[res] != 0; res++) if (c[res] == key) return(res);
 
goto AGAIN;
}
 
 
/* converts a path to its canonic representation, returns 0 on success
* or DOS err on failure (invalid drive) */
unsigned short file_truename(const char *src, char *dst) {
unsigned short res = 0;
_asm {
push es
mov ah, 0x60 /* query truename, DS:SI=src, ES:DI=dst */
push ds
pop es
mov si, src
mov di, dst
int 0x21
jnc DONE
mov [res], ax
DONE:
pop es
}
return(res);
}
 
 
/* returns DOS attributes of file, or -1 on error */
int file_getattr(const char *fname) {
int res = -1;
_asm {
mov ax, 0x4300 /* query file attributes, fname at DS:DX */
mov dx, fname
int 0x21 /* CX=attributes if CF=0, otherwise AX=errno */
jc DONE
mov [res], cx
DONE:
}
return(res);
}
 
 
/* returns screen's width (in columns) */
unsigned short screen_getwidth(void) {
/* BIOS 0040:004A = word containing screen width in text columns */
unsigned short far *scrw = MK_FP(0x40, 0x4a);
return(*scrw);
}
 
 
/* returns screen's height (in rows) */
unsigned short screen_getheight(void) {
/* BIOS 0040:0084 = byte containing maximum valid row value (EGA ONLY) */
unsigned char far *scrh = MK_FP(0x40, 0x84);
if (*scrh == 0) return(25); /* pre-EGA adapter */
return(*scrh + 1);
}
 
 
/* displays the "Press any key to continue" msg and waits for a keypress */
void press_any_key(void) {
nls_output(15, 1); /* Press any key to continue... */
_asm {
mov ah, 0x08 /* no echo console input */
int 0x21 /* pressed key in AL now (0 for extended keys) */
test al, al
jnz DONE
int 0x21 /* executed ah=8 again to read the rest of extended key */
DONE:
/* output CR/LF */
mov ah, 0x02
mov dl, 0x0D
int 0x21
mov dl, 0x0A
int 0x21
}
}
 
 
/* validate a drive (A=0, B=1, etc). returns 1 if valid, 0 otherwise */
int isdrivevalid(unsigned char drv) {
_asm {
mov ah, 0x19 /* query default (current) disk */
int 0x21 /* drive in AL (0=A, 1=B, etc) */
mov ch, al /* save current drive to ch */
/* try setting up the drive as current */
mov ah, 0x0E /* select default drive */
mov dl, [drv] /* 0=A, 1=B, etc */
int 0x21
/* this call does not set CF on error, I must check cur drive to look for success */
mov ah, 0x19 /* query default (current) disk */
int 0x21 /* drive in AL (0=A, 1=B, etc) */
mov [drv], 1 /* preset result as success */
cmp al, dl /* is eq? */
je DONE
mov [drv], 0 /* fail */
jmp FAILED
DONE:
/* set current drive back to what it was initially */
mov ah, 0x0E
mov dl, ch
int 0x21
FAILED:
}
return(drv);
}
 
 
/* converts a 8+3 filename into 11-bytes FCB format (MYFILE EXT) */
void file_fname2fcb(char *dst, const char *src) {
unsigned short i;
 
/* fill dst with 11 spaces and a NULL terminator */
for (i = 0; i < 11; i++) dst[i] = ' ';
dst[11] = 0;
 
/* copy fname until dot (.) or 8 characters */
for (i = 0; i < 8; i++) {
if ((src[i] == '.') || (src[i] == 0)) break;
dst[i] = src[i];
}
 
/* advance src until extension or end of string */
src += i;
for (;;) {
if (*src == '.') {
src++; /* next character is extension */
break;
}
if (*src == 0) break;
}
 
/* copy extension to dst (3 chars max) */
dst += 8;
for (i = 0; i < 3; i++) {
if (src[i] == 0) break;
dst[i] = src[i];
}
}
 
 
/* converts a 11-bytes FCB filename (MYFILE EXT) into 8+3 format (MYFILE.EXT) */
void file_fcb2fname(char *dst, const char *src) {
unsigned short i, end = 0;
 
for (i = 0; i < 8; i++) {
dst[i] = src[i];
if (dst[i] != ' ') end = i + 1;
}
 
/* is there an extension? */
if (src[8] == ' ') {
dst[end] = 0;
} else { /* found extension: copy it until first space */
dst[end++] = '.';
for (i = 8; i < 11; i++) {
if (src[i] == ' ') break;
dst[end++] = src[i];
}
dst[end] = 0;
}
}
 
 
/* converts an ASCIIZ string into an unsigned short. returns 0 on success.
* on error, result will contain all valid digits that were read until
* error occurred (0 on overflow or if parsing failed immediately) */
int atous(unsigned short *r, const char *s) {
int err = 0;
 
_asm {
mov si, s
xor ax, ax /* general purpose register */
xor cx, cx /* contains the result */
mov bx, 10 /* used as a multiplicative step */
 
NEXTBYTE:
xchg cx, ax /* move result into cx temporarily */
lodsb /* AL = DS:[SI++] */
/* is AL 0? if so we're done */
test al, al
jz DONE
/* validate that AL is in range '0'-'9' */
sub al, '0'
jc FAIL /* invalid character detected */
cmp al, 9
jg FAIL /* invalid character detected */
/* restore result into AX (CX contains the new digit) */
xchg cx, ax
/* multiply result by 10 and add cl */
mul bx /* DX AX = AX * BX(10) */
jc OVERFLOW /* overflow */
add ax, cx
/* if CF is set then overflow occurred (overflow part lands in DX) */
jnc NEXTBYTE
 
OVERFLOW:
xor cx, cx /* make sure result is zeroed in case overflow occured */
 
FAIL:
inc [err]
 
DONE: /* save result (CX) into indirect memory address r */
mov bx, [r]
mov [bx], cx
}
return(err);
}
 
 
/* appends a backslash if path is a directory
* returns the (possibly updated) length of path */
unsigned short path_appendbkslash_if_dir(char *path) {
unsigned short len;
int attr;
for (len = 0; path[len] != 0; len++);
if (len == 0) return(0);
if (path[len - 1] == '\\') return(len);
/* */
attr = file_getattr(path);
if ((attr > 0) && (attr & DOS_ATTR_DIR)) {
path[len++] = '\\';
path[len] = 0;
}
return(len);
}
 
 
/* get current path drive d (A=1, B=2, etc - 0 is "current drive")
* returns 0 on success, doserr otherwise */
unsigned short curpathfordrv(char *buff, unsigned char d) {
unsigned short r = 0;
 
_asm {
/* is d == 0? then I need to resolve current drive */
cmp byte ptr [d], 0
jne GETCWD
/* resolve cur drive */
mov ah, 0x19 /* get current default drive */
int 0x21 /* al = drive (00h = A:, 01h = B:, etc) */
inc al /* convert to 1=A, 2=B, etc */
mov [d], al
 
GETCWD:
/* prepend buff with drive:\ */
mov si, buff
mov dl, [d]
mov [si], dl
add byte ptr [si], 'A' - 1
inc si
mov [si], ':'
inc si
mov [si], '\\'
inc si
 
mov ah, 0x47 /* get current directory of drv DL into DS:SI */
int 0x21
jnc DONE
mov [r], ax /* copy result from ax */
 
DONE:
}
 
return(r);
}
 
 
/* fills a nls_patterns struct with current NLS patterns, returns 0 on success, DOS errcode otherwise */
unsigned short nls_getpatterns(struct nls_patterns *p) {
unsigned short r = 0;
 
_asm {
mov ax, 0x3800 /* DOS 2+ -- Get Country Info for current country */
mov dx, p /* DS:DX points to the CountryInfoRec buffer */
int 0x21
jnc DONE
mov [r], ax /* copy DOS err code to r */
DONE:
}
 
return(r);
}
 
 
/* computes a formatted date based on NLS patterns found in p
* returns length of result */
unsigned short nls_format_date(char *s, unsigned short yr, unsigned char mo, unsigned char dy, const struct nls_patterns *p) {
unsigned short items[3];
/* preset date/month/year in proper order depending on date format */
switch (p->dateformat) {
case 0: /* USA style: m d y */
items[0] = mo;
items[1] = dy;
items[2] = yr;
break;
case 1: /* EU style: d m y */
items[0] = dy;
items[1] = mo;
items[2] = yr;
break;
case 2: /* Japan-style: y m d */
default:
items[0] = yr;
items[1] = mo;
items[2] = dy;
break;
}
/* compute the string */
return(sprintf(s, "%02u%s%02u%s%02u", items[0], p->datesep, items[1], p->datesep, items[2]));
}
 
 
/* computes a formatted time based on NLS patterns found in p, sc are ignored if set 0xff
* returns length of result */
unsigned short nls_format_time(char *s, unsigned char ho, unsigned char mn, unsigned char sc, const struct nls_patterns *p) {
char ampm = 0;
unsigned short res;
 
if (p->timefmt == 0) {
if (ho == 12) {
ampm = 'p';
} else if (ho > 12) {
ho -= 12;
ampm = 'p';
} else { /* ho < 12 */
if (ho == 0) ho = 12;
ampm = 'a';
}
res = sprintf(s, "%2u", ho);
} else {
res = sprintf(s, "%02u", ho);
}
 
/* append separator and minutes */
res += sprintf(s + res, "%s%02u", p->timesep, mn);
 
/* if seconds provided, append them, too */
if (sc != 0xff) res += sprintf(s + res, "%s%02u", p->timesep, sc);
 
/* finally append AM/PM char */
if (ampm != 0) s[res++] = ampm;
s[res] = 0;
 
return(res);
}
 
 
/* computes a formatted integer number based on NLS patterns found in p
* returns length of result */
unsigned short nls_format_number(char *s, unsigned long num, const struct nls_patterns *p) {
unsigned short sl = 0, i;
unsigned char thcount = 0;
 
/* write the value (reverse) with thousand separators (if any defined) */
do {
if ((thcount == 3) && (p->thousep[0] != 0)) {
s[sl++] = p->thousep[0];
thcount = 0;
}
s[sl++] = '0' + num % 10;
num /= 10;
thcount++;
} while (num > 0);
 
/* terminate the string */
s[sl] = 0;
 
/* reverse the string now (has been built in reverse) */
for (i = sl / 2 + (sl & 1); i < sl; i++) {
thcount = s[i];
s[i] = s[sl - (i + 1)]; /* abc'de if i=3 then ' <-> c */
s[sl - (i + 1)] = thcount;
}
 
return(sl);
}
 
 
/* capitalize an ASCIZ string following country-dependent rules */
void nls_strtoup(char *buff) {
unsigned short errcode = 0;
/* requires DOS 4+ */
_asm {
push ax
push dx
 
mov ax, 0x6522 /* country-dependent capitalize string (DOS 4+) */
mov dx, buff /* DS:DX -> string to capitalize */
int 0x21
jnc DONE
 
mov errcode, ax /* set errcode on failure */
DONE:
 
pop dx
pop ax
}
 
/* rely on OpenWatcom's strupr() if DOS has no NLS support */
if (errcode != 0) strupr(buff);
}
 
 
/* reload nls ressources from svarcom.lng into svarlang_mem */
void nls_langreload(char *buff, unsigned short env) {
const char far *nlspath;
const char far *lang;
static unsigned short lastlang;
 
/* look up the LANG env variable, upcase it and copy to lang */
lang = env_lookup_val(env, "LANG");
if ((lang == NULL) || (lang[0] == 0)) return;
_fmemcpy(buff, lang, 2);
buff[2] = 0;
 
/* check if there is need to reload at all */
if (memcmp(&lastlang, buff, 2) == 0) return;
 
buff[4] = 0;
nlspath = env_lookup_val(env, "NLSPATH");
if (nlspath != NULL) _fstrcpy(buff + 4, nlspath);
 
if (svarlang_load("SVARCOM", buff, buff + 4) != 0) return;
 
_fmemcpy(&lastlang, lang, 2);
}
 
 
/* locates executable fname in path and fill res with result. returns 0 on success,
* -1 on failed match and -2 on failed match + "don't even try with other paths"
* extptr is filled with a ptr to the extension in fname (NULL if no extension) */
int lookup_cmd(char *res, const char *fname, const char *path, const char **extptr) {
unsigned short lastbslash = 0;
unsigned short i, len;
unsigned char explicitpath = 0;
const char *exec_ext[] = {"COM", "EXE", "BAT", NULL};
 
/* does the original fname has an explicit path prefix or explicit ext? */
*extptr = NULL;
for (i = 0; fname[i] != 0; i++) {
switch (fname[i]) {
case ':':
case '\\':
explicitpath = 1;
*extptr = NULL; /* extension is the last dot AFTER all path delimiters */
break;
case '.':
*extptr = fname + i + 1;
break;
}
}
 
/* if explicit ext found, make sure it is executable */
if (*extptr != NULL) {
for (i = 0; exec_ext[i] != NULL; i++) if (imatch(*extptr, exec_ext[i])) break;
if (exec_ext[i] == NULL) return(-2); /* bad extension - don't try running it ever */
}
 
/* normalize filename */
if (file_truename(fname, res) != 0) return(-2);
 
/* printf("truename: %s\r\n", res); */
 
/* figure out where the command starts */
for (len = 0; res[len] != 0; len++) {
switch (res[len]) {
case '?': /* abort on any wildcard character */
case '*':
return(-2);
case '\\':
lastbslash = len;
break;
}
}
 
/* printf("lastbslash=%u\r\n", lastbslash); */
 
/* if no path prefix was found in fname (no colon or backslash) AND we have
* a path arg, then assemble path+filename */
if ((!explicitpath) && (path != NULL) && (path[0] != 0)) {
i = strlen(path);
if (path[i - 1] != '\\') i++; /* add a byte for inserting a bkslash after path */
/* move the filename at the place where path will end */
memmove(res + i, res + lastbslash + 1, len - lastbslash);
/* copy path in front of the filename and make sure there is a bkslash sep */
memmove(res, path, i);
res[i - 1] = '\\';
}
 
/* if no extension was initially provided, try matching COM, EXE, BAT */
if (*extptr == NULL) {
int attr;
len = strlen(res);
res[len++] = '.';
for (i = 0; exec_ext[i] != NULL; i++) {
strcpy(res + len, exec_ext[i]);
/* printf("? '%s'\r\n", res); */
*extptr = exec_ext[i];
attr = file_getattr(res);
if (attr < 0) continue; /* file not found */
if (attr & DOS_ATTR_DIR) continue; /* this is a directory */
if (attr & DOS_ATTR_VOL) continue; /* this is a volume */
return(0);
}
} else { /* try finding it as-is */
/* printf("? '%s'\r\n", res); */
int attr = file_getattr(res);
if ((attr >= 0) && /* file exists */
((attr & DOS_ATTR_DIR) == 0) && /* is not a directory */
((attr & DOS_ATTR_VOL) == 0)) { /* is not a volume */
return(0);
}
}
 
/* not found */
if (explicitpath) return(-2); /* don't bother trying other paths, the caller had its own path preset anyway */
return(-1);
}
 
 
/* fills fname with the path and filename to the linkfile related to the
* executable link "linkname". returns 0 on success. */
int link_computefname(char *fname, const char *linkname, unsigned short env_seg) {
unsigned short pathlen, doserr = 0;
 
/* fetch %DOSDIR% */
pathlen = env_lookup_valcopy(fname, 128, env_seg, "DOSDIR");
if (pathlen == 0) {
nls_outputnl(29,5); /* "%DOSDIR% not defined" */
return(-1);
}
 
/* prep filename: %DOSDIR%\LINKS\PKG.LNK */
if (fname[pathlen - 1] == '\\') pathlen--;
pathlen += sprintf(fname + pathlen, "\\LINKS");
/* create \LINKS if not exists */
if (file_getattr(fname) < 0) {
_asm {
push dx
mov ah, 0x39
mov dx, fname
int 0x21
jnc DONE
mov doserr, ax
DONE:
pop dx
}
if (doserr) {
output(fname);
output(" - ");
nls_outputnl(255, doserr);
return(-1);
}
}
/* quit early if dir does not exist (or is not a dir) */
if (file_getattr(fname) != DOS_ATTR_DIR) {
output(fname);
output(" - ");
nls_outputnl(255,3); /* path not found */
return(-1);
}
sprintf(fname + pathlen, "\\%s.LNK", linkname);
 
return(0);
}
/svarcom/tags/svarcom-2023.1/helpers.h
0,0 → 1,200
/* 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.
*/
 
#ifndef HELPERS_H
#define HELPERS_H
 
/* case-insensitive comparison of strings, compares up to maxlen characters.
* returns non-zero on equality. */
int imatchlim(const char *s1, const char *s2, unsigned short maxlen);
 
#define imatch(a,b) imatchlim(a,b,0xffff)
 
/* returns zero if s1 starts with s2 */
int strstartswith(const char *s1, const char *s2);
 
/* outputs a NULL-terminated string to handle (hSTDOUT or hSTDERR) */
void output_internal(const char *s, unsigned char nl, unsigned char handle);
 
/* outputs a NULL-terminated NLS string to stdout */
void nls_output_internal(unsigned short id, unsigned char nl, unsigned char handle);
 
#define hSTDOUT 1
#define hSTDERR 2
 
#define output(x) output_internal(x, 0, hSTDOUT)
#define outputnl(x) output_internal(x, 1, hSTDOUT)
#define nls_output(x,y) nls_output_internal((x << 8) | y, 0, hSTDOUT)
#define nls_outputnl(x,y) nls_output_internal((x << 8) | y, 1, hSTDOUT)
#define nls_outputnl_err(x,y) nls_output_internal((x << 8) | y, 1, hSTDERR)
 
/* output DOS error e to stderr */
void nls_outputnl_doserr(unsigned short e);
 
/*
* FileInfoRec (DTA) format:
* offset size desc
* +0 21 reserved
* +15h 1 file attr (1=RO 2=Hidden 4=System 8=VOL 16=DIR 32=Archive
* +16h 2 time: bits 0-4=bi-seconds (0-30), bits 5-10=minutes (0-59), bits 11-15=hour (0-23)
* +18h 2 date: bits 0-4=day(0-31), bits 5-8=month (1-12), bits 9-15=years since 1980
* +1ah 4 DWORD file size, in bytes
* +1eh 13 13-bytes max ASCIIZ filename
*/
_Packed struct DTA {
char reserved[21];
unsigned char attr;
unsigned short time_sec2:5;
unsigned short time_min:6;
unsigned short time_hour:5;
unsigned short date_dy:5;
unsigned short date_mo:4;
unsigned short date_yr:7;
unsigned long size;
char fname[13];
};
 
 
/* this is also known as the "Country Info Block" or "CountryInfoRec":
* offset size desc
* +0 2 wDateFormat 0=USA (m d y), 1=Europe (d m y), 2=Japan (y m d)
* +2 5 szCrncySymb currency symbol (ASCIIZ)
* +7 2 szThouSep thousands separator (ASCIIZ)
* +9 2 szDecSep decimal separator (ASCIIZ)
* +0bH 2 szDateSep date separator (ASCIIZ)
* +0dH 2 szTimeSep time separator (ASCIIZ)
* +0fH 1 bCrncyFlags currency format flags
* +10H 1 bCrncyDigits decimals digits in currency
* +11H 1 bTimeFormat time format 0=12h 1=24h
* +12H 4 pfCasemap Casemap FAR call address
* +16H 2 szDataSep data list separator (ASCIIZ)
* +18H 10 res reserved zeros
* 34 total length
*/
_Packed struct nls_patterns {
unsigned short dateformat;
char currency[5];
char thousep[2];
char decsep[2];
char datesep[2];
char timesep[2];
unsigned char currflags;
unsigned char currdigits;
unsigned char timefmt;
void far *casemapfn;
char datalistsep[2];
char reserved[10];
};
 
 
#define DOS_ATTR_RO 1
#define DOS_ATTR_HID 2
#define DOS_ATTR_SYS 4
#define DOS_ATTR_VOL 8
#define DOS_ATTR_DIR 16
#define DOS_ATTR_ARC 32
 
/* find first matching files using a FindFirst DOS call
* attr contains DOS attributes that files MAY have (ie attr=0 will match only
* files that have no attributes at all)
* returns 0 on success or a DOS err code on failure */
unsigned short findfirst(struct DTA *dta, const char *pattern, unsigned short attr);
 
/* find next matching, ie. continues an action intiated by findfirst() */
unsigned short findnext(struct DTA *dta);
 
/* print s string and wait for a single key press from stdin. accepts only
* key presses defined in the c ASCIIZ string. returns offset of pressed key
* in string. keys in c MUST BE UPPERCASE! */
unsigned short askchoice(const char *s, const char *c);
 
/* converts a path to its canonic representation, returns 0 on success
* or DOS err on failure (invalid drive) */
unsigned short file_truename(const char *src, char *dst);
 
/* returns DOS attributes of file, or -1 on error */
int file_getattr(const char *fname);
 
/* returns screen's width (in columns) */
unsigned short screen_getwidth(void);
 
/* returns screen's height (in rows) */
unsigned short screen_getheight(void);
 
/* displays the "Press any key to continue" msg and waits for a keypress */
void press_any_key(void);
 
/* validate a drive (A=0, B=1, etc). returns 1 if valid, 0 otherwise */
int isdrivevalid(unsigned char drv);
 
/* converts a filename into FCB format (FILENAMEEXT) */
void file_fname2fcb(char *dst, const char *src);
 
/* converts a FCB filename (FILENAMEEXT) into normal format (FILENAME.EXT) */
void file_fcb2fname(char *dst, const char *src);
 
/* converts an ASCIIZ string into an unsigned short. returns 0 on success.
* on error, result will contain all valid digits that were read until
* error occurred (0 on overflow or if parsing failed immediately) */
int atous(unsigned short *r, const char *s);
 
/* appends a backslash if path is a directory
* returns the (possibly updated) length of path */
unsigned short path_appendbkslash_if_dir(char *path);
 
/* get current path drive d (A=1, B=2, etc - 0 is "current drive")
* returns 0 on success, doserr otherwise */
unsigned short curpathfordrv(char *buff, unsigned char d);
 
/* fills a nls_patterns struct with current NLS patterns, returns 0 on success, DOS errcode otherwise */
unsigned short nls_getpatterns(struct nls_patterns *p);
 
/* computes a formatted date based on NLS patterns found in p
* returns length of result */
unsigned short nls_format_date(char *s, unsigned short yr, unsigned char mo, unsigned char dy, const struct nls_patterns *p);
 
/* computes a formatted time based on NLS patterns found in p, sc are ignored if set 0xff
* returns length of result */
unsigned short nls_format_time(char *s, unsigned char ho, unsigned char mn, unsigned char sc, const struct nls_patterns *p);
 
/* computes a formatted integer number based on NLS patterns found in p
* returns length of result */
unsigned short nls_format_number(char *s, unsigned long num, const struct nls_patterns *p);
 
/* capitalize an ASCIZ string following country-dependent rules */
void nls_strtoup(char *buff);
 
/* reload nls ressources from svarcom.lng into langblock */
void nls_langreload(char *buff, unsigned short env);
 
/* locates executable fname in path and fill res with result. returns 0 on success,
* -1 on failed match and -2 on failed match + "don't even try with other paths"
* extptr is filled with a ptr to the extension in fname (NULL if no extension) */
int lookup_cmd(char *res, const char *fname, const char *path, const char **extptr);
 
/* fills fname with the path and filename to the linkfile related to the
* executable link "linkname". returns 0 on success. */
int link_computefname(char *fname, const char *linkname, unsigned short env_seg);
 
#endif
/svarcom/tags/svarcom-2023.1/history.txt
0,0 → 1,89
 
 
=== SvarCOM's history / changelog ===
 
 
(ticket numbers at https://osdn.net/projects/svardos/ticket/ in [] brackets)
 
 
=== ver 2023.1 (17.02.2023) ==================================================
 
- improved BR translations (courtesy of Luzemario Dantes)
 
 
=== ver 2023.0 (06.02.2023) ==================================================
 
- added a dummy INT 0x2E handler
- added BR translations (courtesy of Luzemario Dantes)
 
 
=== ver 2022.4 (12.04.2022) ==================================================
 
- SET command: fixed upcasing of var names with high-ASCII chars [#44145]
- PATH command: path is always upcased [#44146]
- DIR command: output adapted to 40-columns screen modes [#44153]
- DIR command: make use of thousands separator for file sizes [#44151]
- tabs are accepted as command-line separators (part of [#44145])
- PSP FCB fields of launched apps are filled with cmdline arguments [#44268]
 
 
=== ver 2022.3 (13.03.2022) ==================================================
 
- fixed stdin redirection handling (was broken since 2022.1) [#44027]
- only COM, EXE and BAT files are allowed for execution [#44068]
- FOR command: accepts control characters as pattern delimiters [#44058]
- FOR command: patterns without wildcards are processed as messages [#44058]
- implemented the TRUENAME command [#44051]
- DIR command: /a:xxx is supported like an equivalent to /axxx [#44077]
- VER command: displays DOS memory location (low, HMA, ROM...) [#44050]
- VER command: displays true DOS version and DOS rev (bttr) [#44050]
- REN command: allows renaming directory names [#44060]
- implemented CTTY and LOADHIGH/LH as no-ops (LH loads programs low)
- LN creates %DOSDIR%\LINKS directory when needed and warns on error [#44042]
- LN ADD outputs an error message when link already exists [#44043]
- added Polish translations
- added German translations, courtesy of Robert Riebisch (bttr)
- added French translations, kindly contributed by Berki Yenigun (thraex)
- added Turkish translations, submitted by Berki Yenigun (thraex)
- fixed and improved English help screens
 
 
=== ver 2022.2 (04.03.2022) ==================================================
 
- added support for the internal FOR command
- step-by-step execution of batch files (/Y)
- fixed parsing of /C and /K arguments that was leading to spurious warnings
- fixed %var% matching within batch files to be case-insensitive [#44000]
 
 
=== ver 2022.1 (28.02.2022) ==================================================
 
- added GOTO support (jumps to a labelled line within a batch file)
- added CALL support (calls batch files from within batch files)
- DOS errors are output to stdout, and also to stderr if stdout is redirected
- fixed batch processing with /C (was executing only first command)
- stack overflow detection degrades gracefully by invalidating command-line
history (useful if a stack-hungry TSR overflows the RMOD stack)
- multi-lang support relies on SvarLANG.lib instead of its own routines
- made all SvarCOM strings localizable
- added partial German translations (kindly provided by Robert Riebisch)
 
 
=== ver 2022.0 (01.02.2022) ==================================================
 
- added "global executable links" support (new command: LN)
- prompt fixed when current drive becomes invalid (eg. empty diskette drive)
- piping support (like dir/b | sort)
- DIR: fixed /P pagination in wide mode
- DIR: implemented /A
- implemented IF command (IF EXIST, IF ERRORLEVEL, IF str==str)
- added a break handler (running application can be aborted with CTRL+C)
- DOS error messages are output to stderr
 
 
=== ver 2021.0 (24.11.2021) ==================================================
 
- first public release, after roughly a month of work
 
 
====================================================================== EOF ===
/svarcom/tags/svarcom-2023.1/int24.asm
0,0 → 1,93
;
; WORK IN PROGRESS TEMPLATE! NOT USED YET
;
; int 24h handler, part of SvarCOM. MIT license.
; Copyright (C) 2022 Mateusz Viste
;
; this is an executable image that can be set up as the critical error handler
; interrupt (int 24h). It displays the usual "Abort, retry, fail" prompt.
;
 
org 0 ; this code does not have a PSP, it is loaded as-is into a memory
; segment
 
; === CRIT HANDLER DETAILS ====================================================
;
; *** ON ENTRY ***
;
; upon entry to the INT 24h handler, the registers are as follows:
; BP:SI = addr of a "device header" that identifies the failing device
; DI = error code in lower 8 bits (only for non-disk errors)
; AL = drive number, but only if AH bit 7 is reset
; AH = error flags
; 0x80 = reset if device is a disk, set otherwise
; all the following are valid ONLY for disks (0x80 reset):
; 0x20 = set if "ignore" action allowed
; 0x10 = set if "retry" action allowed
; 0x08 = set if "fail" action allowed
; 0x06 = disk area, 0=sys files, 1=fat, 10=directory, 11=data
; 0x01 = set if failure is a write, reset if read
;
; within the int 24h handler, only these DOS functions are allowed:
; 01H-0CH (DOS character I/O)
; 33H (all subfns are OK, including 3306H get DOS version)
; 50H (set PSP address)
; 51H and 62H (query PSP address)
; 59H (get extended error information)
;
;
; *** ON EXIT ***
;
; After handling the error, AL should be set with an action code and get back
; to DOS. Available actions are defined in AH at entry (see above). Possible
; values on exit are:
; AL=0 ignore error (pretend nothing happenned)
; AL=1 retry operation
; AL=2 abort (terminates the failed program via int 23h, like ctrl+break)
; AL=3 return to application indicating a failure of the DOS function
;
; A very basic "always fail" handler would be as simple as this:
; mov al, 3
; iret
; =============================================================================
 
 
; save registers so I can restore them later
push ah
push bx
push cx
push dx
pushf
 
; disk errors product this message:
; CRITICAL ERROR - DRIVE A: - READ|WRITE FAILURE
; (A)bort, (R)etry, (F)ail
;
; non-disk errors produce this:
; CRITICAL ERROR #errno
 
 
; restore registers and quit the handler
popf
pop dx
pop cx
pop bx
pop ah
 
iret
 
 
; write DX string to stderr
write_dx_str_to_stderr:
push ax
push bx
push cx
 
mov ah, 0x40 ; write to file -- am I sure I can use this function safely?
mov bx, 2 ; stderr
mov cx, 1 ; one byte
int 0x21
 
pop cx
pop bx
pop ax
/svarcom/tags/svarcom-2023.1/internal.txt
0,0 → 1,103
 
 
=== SvarCOM implementation notes ===
 
 
=== SWAPPING =================================================================
 
Conventional RAM is scarce, that is why a command line interpreter must make
efforts to reduce its memory footprint when launching applications. SvarCOM
does that by installing a small executable module in memory, called RMOD (for
Resident MODule). SvarCOM pre-sets RMOD so it knows how to execute the external
program and removes itself from memory, letting RMOD do the job. RMOD executes
the application, waits for it to finish and then calls back SvarCOM. All
necessary contextual data is kept in a resident, RMOD-owned memory structure.
 
 
=== NLS STRINGS ==============================================================
 
SvarCOM can output information in many languages. To do so, it relies on a
precompiled resource file named SVARCOM.LNG. When SvarCOM starts, it looks
for this file in the %NLSPATH% directory and loads from it the part that
contains the %LANG% language. All this is done by nls_langreload().
 
The SVARCOM.LNG file is compiled by TLUMACZ (from the SvarLANG.lib suite). It
takes CATS-style language files as input and compiles them into a single
SVARCOM.LNG resource file. It also produces a DEFLANG.C file with english
strings only, this one is embedded into the SvarCOM executable to display
English text in case SVARCOM.LNG is unavailable.
 
 
=== BATCH FILES SUPPORT ======================================================
 
When SvarCOM executes a command, it checks first if it has a *.BAT extension.
If so, it switches into 'batch-processing' mode:
 
- allocates a "batch context" structure and attach it to rmod
- writes the batch filename into the batch context (rmod-owned) memory, along
with a counter that holds the offset of the next line to be executed.
- a batch context has a "parent" pointer that may point to another batch
context (owned by a different batch instance), it is, in essence, a linked
list that allows batch files to call one another (typicall through the CALL
command) allowing SvarCOM to get back to the parent batch once the child
terminates.
 
When the rmod batch context pointer non-NULL, SvarCOM does not ask the user for
a command. Instead, it opens the batch file, jumps to the "next line to be
executed" and loads the command from there, incrementing the line counter in
the process.
 
 
=== PIPING COMMANDS ==========================================================
 
Piping a command means redirecting its standard output (stdout) to the
standard input (stdin) of another command. While redirection of file handles
is a concept well supported by the DOS kernels, piping is not, in part due to
the mono-task nature of DOS. SvarCOM provides piping support through following
logic:
1. user-entered (or batch-acquired) command line is analyzed for any kind of
redirections (incl. pipes) by redir_parsecmd(). If the command appears to
be piped, then redir_parsecmd() enforces a stdout redirection to a
temporary file and moves all the pipe chain to an RMOD-owned buffer named
"awaitingcmd", appending an stdin redirection so the next command's stdin
is fed from the temporary file. The command is then executed.
2. before further execution, SvarCOM looks into its "awaitingcmd" buffer, and
if it is non-empty, it runs its content.
3. when loading commands from the awaitingcmd, SvarCOM sets a special
"delete_stdin_file" flag and passes it to command-executing functions so
these remember to delete the stdin-redirected file.
 
 
=== GLOBAL EXECUTABLE LINKS ==================================================
 
SvarCOM features special support for "global executable links". This allows to
run selected programs from any directory, without the need to copy these
programs to a directory in %PATH%. Executable links are flat files written in
%DOSDIR%\LINKS\. Each file there contains the directory where the matching
program should be looked for.
 
 
=== STACK-OVERFLOW PROTECTION =================================================
 
RMOD reserves a 64-bytes memory buffer for its private stack. This is more than
enough for RMOD itself, as well as for the DOS exec function INT 21h,AX=4B00h.
 
There may be, however, exotic configurations where this stack is not enough,
typically if some stack-hungry TSR kicks in while RMOD is being active, or some
large interrupt handlers are used, etc. In such situation the 64-bytes stack
could be overflowed. RMOD copes with this by placing the stack right on top of
its command history buffer, and terminates the history string with a specific
signature. This way, if a stack overflow occurs and damages the command history
buffer, SvarCOM is able to easily detect it and invalidates the history buffer,
causing no risk of system instability. The user is notified about it, and the
only inconvenience is that he cannot recall the previous command.
 
Below the input buffer is RMOD's own memory signature, followed by its PSP.
This means that should the stack overflow become truly severe (more than 192
bytes and less than 326 bytes), RMOD signature will be overwritten and SvarCOM
won't be able to locate it, so a new copy of RMOD will be recreated. In case of
of a stack overflow that tries to use more than 326 bytes of memory, all hope
is lost and everything becomes possible.
 
 
===================================================================== EOF ====
/svarcom/tags/svarcom-2023.1/lang/br-utf8.txt
0,0 → 1,298
#
# SvarCOM translation file
#
# Language...: Portuguese Brazil
# Authors....: Luzemário Dantas
# Last update: 17 Feb 2023
#
 
# GENERIC MESSAGES USED BY MULTIPLE INTERNAL COMMANDS
0.1:Sintaxe Inválida
0.2:Opção onválida
0.3:Formato de parâmetro inválido
0.4:Excesso de parâmetros
0.5:Comando ou nome de arquivo inválido
0.6:Parâmetro inválido
0.7:Parâmero obrigatório ausente
0.8:Destino inválido
0.9:Este comando não foi implementado
 
# the message below MUST be a two-letter UPPER-CASE string for "Yes/No" keys
# that user can press to answer interactive "Yes/No" questions
0.10:SN
 
# SVARCOM HELP SCREEN
1.0:Inicia o interpretador de comandos SvarCOM.
1.1:COMMAND /E:nnn [/P] [/D] [/Y] [/[C|K] commando]
1.2:/D Pula o processamento do AUTOEXEC.BAT (faz sentido só com /P)
1.3:/E:nnn define o tamanho do ambiente para nnn bytes
1.4:/P Torna o novo interpretador de comandos permanente e roda o AUTOEXEC.BAT
1.5:/C Executa o comando especificado e retorna
1.6:/K Executa o comando especificado e continua rodando
1.7:/Y Executa o programa em lote passo a passo (só com /P, /K or /C)
 
# VARIOUS SVARCOM MESSAGES
2.0:A VERSÃO DO SVARCOM MUDOU. SISTEMA INTERROMPIDO. POR FAVOR REINICIE SEU COMPUTADOR.
2.1:ERRO FATAL: rmod_install() falhou
2.2:SvarCOM: estouro de pilha detectado, histórico de comandos esvaziado (isso\r\nnão é um bug)
 
# CLS
10.0:Limpa a tela.
 
# CHCP
11.0:Mostra ou define o número de página de código ativo.
11.1:CHCP [nnn]
11.2:nnn Especifica um número de página de código
11.3:Digite CHCP sem parâmetros para mostrar o número de página de código atual.
11.4:Número de página de código inválido
11.5:NLSFUNC não instalado
11.6:Falha na mudança de página de código
11.7:Página de código ativa:
 
# CD / CHDIR
12.0:Mostra o nome ou muda o diretório atual.
12.1:CHDIR [drive:][caminho]
12.2:CHDIR[..]
12.3:CD [drive:][caminho]
12.4:CD[..]
12.5:.. Especifica que você quer mudar para o diretório pai (anterior).
12.6:Digite CD drive: para motrar o diretório atual no disco especificado.
12.7:Digite CD sem parâmetros para mostrar o drive e diretório atuais.
 
# CALL
13.0:Chama um programa em lote à partir de outro.
13.1:CALL [drive:][caminho]arquivo [parâmetros-do-arquivo-batch]
 
# BREAK
14.0:Ativa ou desativa a verificação extendida de CTRL+C.
14.1:Digite BREAK sem parâmetros para mostrar o status atual.
14.2:BREAK está desligado
14.3:BREAK está ligado
 
# PAUSE
15.0:Suspende a execução de um arquivo de comandos em lote.
15.1:Pressione qualquer tecla para continuar...
 
# SHIFT
16.0:Muda a posição dos argumentos em um arquivo de comandos em lote:
16.1:Argumento %1 se torna %0, argumento %2 se torna %1, etc.
 
# GOTO
17.0:Direciona o processamento de comandos em lote para uma linha com um rótulo\r\nno programa.
17.1:GOTO LABEL
17.2:LABEL especifica uma sequência de texto useda no programa em lote como se\r\nfosse um rótulo.
17.3:Um rótulo fica sozinho na linha e deve ser precedido por dois pontos ":".
17.10:Rótulo não encontrado
 
# FOR
18.0:Roda um comando especificado para cada elemento em uma lista.
18.1:FOR %variável IN (lista) DO comando [parâmetros]
18.2:%variável Variável de única letra (a-z ou A-Z).
18.3:(lista) Uma ou mais sequências separadas por espaços ou curingas de\r\nnomes de arquivos.
18.4:comando O comando para executar para cada elemento. %variável\r\npermitida.
18.5:parâmetros Parâmetros ou opções para o comando especificado.
18.6:Para usar o FOR em um programa de lote, use %%variável invés de %variável
18.7:O FOR não pode ser aninhado (dentro de outro FOR)
 
# VERIFY
19.0:Diz ao DOS se deve verificar se os arquivos foram corretamente gravados no\r\ndisco.
19.1:Digite VERIFY sem parâmetros para mostrar o status atual.
19.2:VERIFY está desligado
19.3:VERIFY está ligado
19.4:É necessário especificar ON ou OFF
 
# VER
20.0:Mostra as versões do kernel do DOS e do shell SvarCOM.
20.1:Versão do kernel DOS %u.%u
20.2:Shell SvarCOM ver
20.3:O SvarCOM é um interpretador shell para kernels do DOS compatível com\r\nMS-DOS 5+.
20.4:Este software é distribuído nos termos da licença MIT.
20.5:Revisão %c
20.6:O DOS está em %s
20.7:memória convencional
20.8:HMA
20.9:ROM
20.10:versão verdadeira %u.%u
 
# TYPE
21.0:Mostra o conteúdo de um arquivo de texto.
21.1:TYPE [drive:][caminho]arquivo
 
# TIME
22.0:Mostra ou define as horas no relógio do sistema.
22.1:TIME [horas]
22.2:Digite TIME sem parâmetros para mostrar a hora atual e um prompt para uma\r\nnova hora. Pressione ENTER para manter a hora atual.
22.3:A hora atual é
22.4:Hora inválida
22.5:Entre a nova hora:
 
# SET
23.0:Mostra, define, ou remove variáveis de ambiente do DOS.
23.1:SET [variável=[string]]
23.2:variável Especifica o nome da variável de ambiente
23.3:string Especifica uma sequência de caracteres para atribuir à variável
23.4:Digite SET sem parâmetros para mostrar as variáveis de ambiente atuais.
23.5:Não há mais espaço disponível no bloco de ambiente
 
# RD / RMDIR
24.0:Remove (apaga) um diretório.
24.1:RMDIR [drive:]caminho
24.2:RD [drive:]caminho
 
# REN / RENAME
25.0:Renomeia um ou mais arquivos ou diretórios.
25.1:RENAME [drive:][caminho]nomevelho nomenovo
25.2:REN [drive:][caminho]nomevelho nomenovo
25.3:Note que você não pode especificar um novo drive ou caminho para nomenovo.\r\nUse MOVE para mover arquivos de um diretório para outro.
 
# REM
26.0:Salva comentários (lembretes) em um arquivo de comandos em lote.
26.1:REM [comentário]
 
# PATH
27.0:Mostra ou define um caminho de pesquisa para arquivos executáveis.
27.1:PATH [[drive:]caminho[;...]]
27.2:Digite PATH ; para apagar todas as configurações de pesquisa de caminho e\r\ndirecionar o DOS para pesquisar somente no diretório atual.
27.3:Digite PATH sem parâmetros para mostrar o caminho atual.
27.4:Nenhum caminho
 
# MD / MKDIR
28.0:Cria um diretório.
28.1:MKDIR [drive:]caminho
28.2:MD [drive:]caminho
 
# LN
29.0:Adiciona, apaga ou mostra links executáveis.
29.1:LN ADD nomedolink diretóriodestino
29.2:LN DEL nomedolink
29.3:LN LIST [padrão]
29.4:Nenhum executável correspondente encontrado no caminho fornecido.
29.5:%DOSDIR% não definido
 
# EXIT
30.0:Sai do programa COMMAND.COM (interpretador de comandos).
 
# ECHO
31.0:Mostra mensagens, ou liga e desliga o eco de comandos.
31.1:ECHO [mensagem]
31.2:Digite ECHO sem parâmetros para mostrar a configuração atual.
31.3:ECHO está ligado
31.4:ECHO está desligado
 
# DATE
32.0:Mostra ou define a data do sistema.
32.1:DATE [data]
32.2:Digite DATE sem parâmetros para mostrar a data atual e um prompt para uma\r\nnova data. Pressione ENTER para manter a data atual.
32.3:Data inválida
32.4:A data atual é
32.5:Entre nova data:
 
# PROMPT
33.0:Muda o prompt de comando do DOS.
33.1:PROMPT [nova especificação de prompt de comando]
 
# VOL
34.0:Mostra o rótulo do volume do disco e o número de série, se existir.
34.1:VOL [drive:]
34.2:O volume no drive %c não tem nome
34.3:O volume no drive %c é %s
34.4:O número de série do volume é %04X-%04X
 
# IF
35.0:Executa processamento condicional em programas de lote.
35.1:IF [NOT] ERRORLEVEL número comando
35.2:IF [NOT] string1==string2 comando
35.3:IF [NOT] EXIST arquivo comando
35.4:NOT o comando é executado somente se a condição NÃO for\r\nsatisfeita
35.5:ERRORLEVEL num condição: o último programa retornou um código de saída\r\n>= número
35.6:string1==string2 condição: ambos os strings tem de ser iguais
35.7:EXIST arquivo condição: o nome do arquivo existe (curingas aceitos)
35.8:comando comando para executar se a condição for satisfeita
 
# DEL / ERASE
36.0:Remove (apaga) um ou mais arquivos.
36.1:DEL [drive:][caminho]arquivo [/P]
36.2:ERASE [drive:][caminho]arquivo [/P]
36.3:[drive:][caminho]arquivo Especifica os arquivos a apagar.
36.4:/P Pergunta confirmação antes de apagar cada arquivo.
36.5:Todos os arquivos no diretório serão apagados!
36.6:Tem certeza?
36.7:Apagar?
 
# DIR
37.0:Mostra uma lista de arquivos e subdiretórios em um diretório.
37.1:DIR [drive:][caminho][arquivo] [/P] [/W] [/A[:]atributos] [/O[[:]ordem]]\r\n [/S] [/B] [/L]
37.2:/P Pausa após cada preenchimento da tela
37.3:/W Usa formato de lista longo
37.4:/A Mostra arquivos com atributos específicos:
37.5: D Diretórios R Arquivos só leitura H Arquivos ocultos
37.6: A Pronto para arquivar S Arquivos de sistema - prefixo "não"
37.7:/O Lista arquivos com ordenação:
37.8: N por nome S por tamanho E por extensão
37.9: D por data G agrupa dirs primeiro - inverter a ordem
37.10:/S Mostra arquivos no diretório especificado e todos os subdiretórios
37.11:/B Usa formato simples (sem cabeçalho ou sumário)
37.12:/L Usa minúsculas
37.20:Diretório de %s
37.21:<DIR>
37.22:arquivo(s)
37.23:bytes
37.24:bytes livres
 
# COPY
38.0:Copia um ou mais arquivos para outro lugar.
38.1:COPY [/A|/B] origem [/A|/B] [+origem [/A|/B] [+...]] [destino [/A|/B]] [/V]
38.2:origem Especifica o arquivo ou arquivos para copiar
38.3:/A Indica um arquivo de texto ASCII
38.4:/B Indica um arquivo binário
38.5:destino Especifica o diretório e/ou arquivo para os novos arquivo(s)
38.6:/V Verifica se os novos arquivos são gravados corretamente
38.7:Para concatenar arquivos, especifique um único arquivo para o destino, mas\r\nmúltiplos arquivos de origem (usando curingas ou o formato\r\narquivo1+arquivo2+arquivo3).
38.8:NOTE: /A e /B não são opções válidas (são ignoradas), providos somente\r\npor motivos de compatibilidade. COPY sempre assume que os arquivos são binários.
38.9:%u arquivos(s) copiado(s)
 
# TRUENAME
39.0:Returna um caminho ou nome de arquivo totalmente qualificado.
39.1:TRUENAME [[drive:][caminho][arquivo]]
 
# DOS ERRORS
255.1:Número de função inválida
255.2:Arquivo não encontrado
255.3:Caminho não encontrado
255.4:Excesso de arquivos abertos (sem manipuladores disponíveis)
255.5:Acesso negado
255.6:Manipulador inválido
255.7:Bloco de Controle de Memória destruído
255.8:Memória insuficiente
255.9:Endereço de bloco de memória inválido
255.10:Ambiente inválido
255.11:Formato inválido
255.12:Código de acesso inválido
255.13:Dados inválidos
255.15:Drive inválido
255.16:Tentativa de remover o diretório atual
255.17:Não é o mesmo dispositivo
255.18:Não há mais arquivos
255.19:Disco protegido contra gravação
255.20:Unidade desconhecida
255.21:Drive não pronto
255.22:Comando desconhecido
255.23:Erro de dados (CRC)
255.24:Tamanho da estrutura de solicitação errada
255.25:Erro de busca
255.26:Tipo de mídia desconhecido (disco não-DOS)
255.27:Setor não encontrado
255.28:Impressora sem papel
255.29:Falha de gravação
255.30:Falha de leitura
255.31:Falha geral
255.32:Volação de compartilhamento
255.33:Violação de bloqueio
255.34:Mudança de disco inválida
255.35:FCB indisponível
255.36:Overflow no buffer de compartilhamento
255.37:Página de código errada
255.38:Impossível completar operações de arquivo (EOF / fora da entrada)
255.39:Espaço em disco insuficiente
255.80:Arquivo já existe
 
/svarcom/tags/svarcom-2023.1/lang/de-utf8.txt
0,0 → 1,298
#
# SvarCOM language file
#
# Language...........: German
# Authors............: Robert Riebisch
# Last update........: 12 Mar 2022
# In sync with EN rev: 1095
#
 
# GENERIC MESSAGES USED BY MULTIPLE INTERNAL COMMANDS
0.1:Ungültige Syntax
0.2:Ungültiger Schalter
0.3:Ungültiges Parameterformat
0.4:Zu viele Parameter
0.5:Befehl oder Dateiname nicht gefunden
0.6:Ungültiger Parameter
0.7:Erforderlicher Parameter fehlt
0.8:Ungültiges Ziel
0.9:Dieser Befehl ist nicht implementiert.
 
# the message below MUST be a two-letter UPPER-CASE string for "Yes/No" keys
# that user can press to answer interactive "Yes/No" questions
0.10:JN
 
# SVARCOM HELP SCREEN
1.0:Startet den SvarCOM-Befehlsinterpreter.
1.1:COMMAND /E:nnn [/P] [/D] [/Y] [/[C|K] Befehl]
1.2:/D Überspringt die Abarbeitung von AUTOEXEC.BAT (nur sinnvoll mit /P)
1.3:/E:nnn Legt die Umgebungsgröße auf nnn Byte fest
1.4:/P Macht den neuen Befehlsinterpreter permanent und startet AUTOEXEC.BAT
1.5:/C Führt den angegebenen Befehl aus und kehrt dann zurück
1.6:/K Führt den angegebenen Befehl aus und läuft dann weiter
1.7:/Y Führt das Stapelprogramm schrittweise aus (nur mit /P, /K oder /C)
 
# VARIOUS SVARCOM MESSAGES
2.0:SVARCOM-VERSION VERÄNDERT. SYSTEM ANGEHALTEN. STARTEN SIE DEN COMPUTER NEU.
2.1:SCHWERWIEGENDER FEHLER: rmod_install() fehlgeschlagen
2.2:SvarCOM: Stacküberlauf bemerkt, Befehlsverlauf geleert (Das ist kein Fehler.)
 
# CLS
10.0:Löscht den Bildschirminhalt.
 
# CHCP
11.0:Zeigt die Nummer der aktiven Codeseite an oder legt letztere fest.
11.1:CHCP [nnn]
11.2:nnn Gibt die Nummer einer Codeseite an
11.3:Der Befehl CHCP ohne Parameter zeigt die Nummer der aktuellen Codeseite an.
11.4:Ungültige Codeseitennummer
11.5:NLSFUNC nicht installiert
11.6:Ändern der Codeseite fehlgeschlagen
11.7:Aktive Codeseite:
 
# CD / CHDIR
12.0:Zeigt den Namen des aktuellen Verzeichnisses an oder wechselt es.
12.1:CHDIR [Laufwerk:][Pfad]
12.2:CHDIR[..]
12.3:CD [Laufwerk:][Pfad]
12.4:CD[..]
12.5:.. Gibt an, dass Sie ins übergeordnete Verzeichnis wechseln wollen.
12.6:CD Laufwerk: zeigt das aktuelle Verzeichnis auf dem angegebenen Laufwerk an.
12.7:Der Befehl CD ohne Parameter zeigt das aktuelle Laufwerk und Verzeichnis an.
 
# CALL
13.0:Ruft ein Stapelprogramm von einem anderen aus auf.
13.1:CALL [Laufwerk:][Pfad]Dateiname [Parameter]
 
# BREAK
14.0:Schaltet erweiterte Prüfung für STRG+C ein (ON) oder aus (OFF).
14.1:Der Befehl BREAK ohne Parameter zeigt die aktuelle Einstellung von BREAK an.
14.2:BREAK ist ausgeschaltet (OFF)
14.3:BREAK ist eingeschaltet (ON)
 
# PAUSE
15.0:Pausiert die Ausführung eines Stapelskripts.
15.1:Drücken Sie eine beliebige Taste, um fortzusetzen.
 
# SHIFT
16.0:Ändert die Position der Argumente in einer Stapeldatei:
16.1:Argument %1 wird zu %0, Argument %2 wird zu %1 usw.
 
# GOTO
17.0:Lenkt die Stapelverarbeitung zu einer Sprungmarke im Stapelprogramm.
17.1:GOTO MARKE
17.2:MARKE gibt eine Zeichenfolge an, die im Stapelprogramm als Sprungmarke\r\nverwendet wird.
17.3:Eine Sprungmarke steht in einer eigenen Zeile und muss mit einem Doppelpunkt\r\neingeleitet werden.
17.10:Sprungmarke nicht gefunden
 
# FOR
18.0:Führt einen angegebenen Befehl für jedes Element einer Liste aus.
18.1:FOR %Variable IN (Liste) DO Befehl [Parameter]
18.2:%Variable Einzelner Buchstaben als Variable (a-z oder A-Z)
18.3:(Liste) Eine oder mehrere durch Leerzeichen getrennte Zeichenfolgen oder\r\n Platzhalter für Dateinamen
18.4:Befehl Für jedes Element auszuführender Befehl. %Variable erlaubt
18.5:Parameter Parameter oder Schalter für den angegebenen Befehl
18.6:In einem Stapelprogramm verwenden Sie %%Variable statt %Variable für FOR.
18.7:FOR kann nicht verschachtelt werden
 
# VERIFY
19.0:Teilt DOS mit, ob es überprüfen soll, dass Dateien korrekt auf Datenträger\r\n geschrieben werden.
19.1:Der Befehl VERIFY ohne Parameter zeigt die aktuelle Einstellung von VERIFY an.
19.2:VERIFY ist ausgeschaltet (OFF)
19.3:VERIFY ist eingeschaltet (ON)
19.4:ON oder OFF muß angegeben werden
 
# VER
20.0:Zeigt die Versionen von DOS-Kernel und SvarCOM-Shell an.
20.1:DOS-Kernel-Version %u.%u
20.2:SvarCOM-Shell-Version
20.3:SvarCOM ist ein Shell-Interpreter für DOS-Kernel kompatibel mit MS-DOS 5+.
20.4:Diese Software wird unter den Bedingungen der MIT-Lizenz verbreitet.
20.5:Revision %c
20.6:DOS ist im %s
20.7:unteren Speicherbereich
20.8:oberen Speicherbereich (High Memory Area)
20.9:ROM
20.10:wahre Version %u.%u
 
# TYPE
21.0:Zeigt den Inhalt einer Textdatei an.
21.1:TYPE [Laufwerk:][Pfad]Dateiname
 
# TIME
22.0:Zeigt die Systemzeit an oder legt sie fest.
22.1:TIME [Zeit]
22.2:Der Befehl TIME ohne Parameter zeigt die aktuelle Zeit an und fragt\r\nnach einer neuen. Drücken Sie die EINGABETASTE, um die bisherige zu behalten.
22.3:Aktuelle Zeit:
22.4:Ungültige Zeit
22.5:Geben Sie die neue Zeit ein:
 
# SET
23.0:Zeigt DOS-Umgebungsvariablen an, legt sie fest oder entfernt sie.
23.1:SET [Variable=[Zeichenfolge]]
23.2:Variable Gibt den Namen der Umgebungsvariable an
23.3:Zeichenfolge Eine Zeichenfolge, die der Variablen zugewiesen werden soll
23.4:Der Befehl SET ohne Parameter zeigt die aktuellen Umgebungsvariablen an.
23.5:Nicht genügend Platz innerhalb des Umgebungsblocks verfügbar
 
# RD / RMDIR
24.0:Entfernt (löscht) ein Verzeichnis.
24.1:RMDIR [Laufwerk:]Pfad
24.2:RD [Laufwerk:]Pfad
 
# REN / RENAME
25.0:Benennt eine oder mehrere Dateien oder Verzeichnisse um.
25.1:RENAME [Laufwerk:][Pfad]Alter_Name Neuer_Name
25.2:REN [Laufwerk:][Pfad]Alter_Name Neuer_Name
25.3:Beachten Sie, Sie können keinen neuen Laufwerkspfad für Neuer_Name angeben.\r\nVerwenden Sie MOVE, um Dateien von einem Verzeichnis in ein anderes\r\nzu verschieben.
 
# REM
26.0:Leitet Kommentare in einer Stapeldatei ein.
26.1:REM [Kommentar]
 
# PATH
27.0:Zeigt den Suchpfad für ausführbare Dateien an oder legt ihn fest.
27.1:PATH [[Laufwerk:]Pfad[;...]]
27.2:Geben Sie "PATH ;" ein, um alle Suchpfadeinstellungen zu löschen und DOS\r\nanzuweisen, nur im aktuellen Verzeichnis zu suchen.
27.3:Der Befehl PATH ohne Parameter zeigt den aktuellen Suchpfad an.
27.4:Kein Pfad
 
# MD / MKDIR
28.0:Erstellt ein Verzeichnis.
28.1:MKDIR [Laufwerk:]Pfad
28.2:MD [Laufwerk:]Pfad
 
# LN
29.0:Fügt Verknüpfungen für ausführbare Dateien hinzu, löscht oder zeigt sie an.
29.1:LN ADD Verknüpfungsname Zielverzeichnis
29.2:LN DEL Verknüpfungsname
29.3:LN LIST [Muster]
29.4:Keine passende ausführbare Datei in angegebenem Pfad gefunden.
29.5:%DOSDIR% nicht definiert
 
# EXIT
30.0:Verlässt das COMMAND.COM-Programm (Befehlsinterpreter).
 
# ECHO
31.0:Zeigt Meldungen an oder schaltet die Befehlsanzeige ein (ON) oder aus (OFF).
31.1:ECHO [Meldung]
31.2:ECHO ohne Parameter zeigt die aktuelle Einstellung der Befehlsanzeige an.
31.3:ECHO ist eingeschaltet (ON)
31.4:ECHO ist ausgeschaltet (OFF)
 
# DATE
32.0:Zeigt das Systemdatum an oder legt es fest.
32.1:DATE [Datum]
32.2:Der Befehl DATE ohne Parameter zeigt das aktuelle Datum an und fragt\r\nnach einem neuen. Drücken Sie die EINGABETASTE, um das bisherige zu behalten.
32.3:Ungültiges Datum
32.4:Aktuelles Datum:
32.5:Geben Sie das neue Datum ein:
 
# PROMPT
33.0:Ändert die DOS-Eingabeaufforderung.
33.1:PROMPT [neue Eingabeaufforderungspezifikation]
 
# VOL
34.0:Zeigt die Datenträgerbezeichnung und -seriennummer an, falls vorhanden.
34.1:VOL [Laufwerk:]
34.2:Datenträger in Laufwerk %c hat keine Bezeichnung
34.3:Datenträger in Laufwerk %c ist %s
34.4:Datenträgerseriennummer: %04X-%04X
 
# IF
35.0:Führt eine bedingte Verarbeitung in Batchprogrammen durch.
35.1:IF [NOT] ERRORLEVEL Zahl Befehl
35.2:IF [NOT] Zeichenfolge1==Zeichenfolge2 Befehl
35.3:IF [NOT] EXIST Dateiname Befehl
35.4:NOT Den Befehl nur ausführen, falls Bedingung NICHT erfüllt ist
35.5:ERRORLEVEL Zahl Bedingung: Letztes Programm hatte einen Rückgabewert >= Zahl
35.6:Zeichenfolge1==Zeichenfolge2\r\n Bedingung: Beide Zeichenfolgen müssen gleich sein
35.7:EXIST Dateiname Bedingung: Dateiname existiert (Platzhalter erlaubt)
35.8:Befehl Auszuführender Befehl, falls die Bedingung erfüllt ist
 
# DEL / ERASE
36.0:Löscht eine oder mehrere Dateien.
36.1:DEL [Laufwerk:][Pfad]Dateiname [/P]
36.2:ERASE [Laufwerk:][Pfad]Dateiname [/P]
36.3:[Laufwerk:][Pfad]Dateiname Gibt die zu löschende(n) Datei(en) an.
36.4:/P Fordert vor dem Löschen jeder Datei zur Bestätigung auf.
36.5:Alle Dateien im Verzeichnis werden gelöscht!
36.6:Sind Sie sicher?
36.7:Löschen?
 
# DIR
37.0:Zeigt eine Liste von Dateien und Unterverzeichnissen eines Verzeichnisses an.
37.1:DIR [Laufwerk:][Pfad][Dateiname] [/P] [/W] [/A[:]Attribute] [/O[[:]Sortierung]]\r\n [/S] [/B] [/L]
37.2:/P Pausiert nach jeder Bildschirmseite
37.3:/W Verwendet breites Listenformat
37.4:/A Zeigt Dateien mit angegebenen Attributen an:
37.5: D Verzeichnisse R Schreibgeschützte Dateien H Versteckte Dateien
37.6: S Systemdateien A Zu archivierende Dateien - davor = "nicht"
37.7:/O Listet Dateien aufsteigend sortiert auf:
37.8: N Name S Größe E Erweiterung
37.9: D Datum G Verzeichnisse zuerst - davor = absteigend
37.10:/S Zeigt Dateien im angegebenen Verzeichnis und allen Unterverzeichnissen
37.11:/B Verwendet knappes Format (kein Vorspann und keine Zusammenfassung)
37.12:/L Verwendet Kleinschreibung
37.20:Verzeichnis von %s
37.21:<DIR>
37.22:Datei(en)
37.23:Byte
37.24:Byte frei
 
# COPY
38.0:Kopiert eine oder mehrere Dateien an eine andere Stelle.
38.1:COPY [/A|/B] Quelle [/A|/B] [+Quelle [/A|/B] [+...]] [Ziel [/A|/B]] [/V]
38.2:Quelle Gibt die zu kopierende(n) Datei(en) an
38.3:/A Weist auf eine ASCII-Textdatei hin
38.4:/B Weist auf eine Binärdatei hin
38.5:Ziel Bezeichnet das Verzeichnis und/oder Dateiname der neuen Datei(en)
38.6:/V Überprüft, dass neue Dateien korrekt geschrieben werden
38.7:Um Dateien aneinanderzuhängen, geben Sie eine einzelne Datei als Ziel an, aber\r\nmehrere Dateien als Quelle (per Platzhalter oder Format Datei1+Datei2+Datei3).
38.8:HINWEIS: /A und /B sind ohne Wirkung. Sie werden nur aus Gründen der\r\nKompatibilität angeboten. COPY nimmt immer binär an.
38.9:%u Datei(en) kopiert
 
# TRUENAME
39.0:Gibt einen vollständig qualifizierten Pfad oder Dateinamen zurück.
39.1:TRUENAME [[Laufwerk:][Pfad][Dateiname]]
 
# DOS ERRORS
255.1:Funktionsnummer ungültig
255.2:Datei nicht gefunden
255.3:Pfad nicht gefunden
255.4:Zu viele offene Dateien (keine Handles verfügbar)
255.5:Zugriff verweigert
255.6:Ungültiges Handle
255.7:Speichersteuerblock zerstört
255.8:Unzureichender Speicher
255.9:Speicherblockadresse ungültig
255.10:Umgebung ungültig
255.11:Format ungültig
255.12:Zugriffscode ungültig
255.13:Daten ungültig
255.15:Ungültiges Laufwerk
255.16:Es wurde versucht, das aktuelle Verzeichnis zu entfernen
255.17:Nicht dasselbe Gerät
255.18:Keine weiteren Dateien
255.19:Datenträger schreibgeschützt
255.20:Unbekanntes Gerät
255.21:Laufwerk nicht bereit
255.22:Unbekannter Befehl
255.23:Datenfehler (CRC)
255.24:Falsche Länge der Anforderungsstruktur
255.25:Positionierungsfehler
255.26:Unbekannter Datenträgertyp (Nicht-DOS-Datenträger)
255.27:Sektor nicht gefunden
255.28:Drucker ohne Papier
255.29:Schreibfehler
255.30:Lesefehler
255.31:Allgemeiner Fehler
255.32:Freigabeverletzung
255.33:Sperrverletzung
255.34:Datenträgerwechsel ungültig
255.35:FCB nicht verfügbar
255.36:Freigabepufferüberlauf
255.37:Nichtübereinstimmung der Codeseite
255.38:Kann Dateivorgänge nicht abschließen (EOF / keine Eingabe mehr)
255.39:Unzureichender Datenträgerplatz
255.80:Datei bereits vorhanden
/svarcom/tags/svarcom-2023.1/lang/en-utf8.txt
0,0 → 1,297
#
# SvarCOM language file
#
# Language...: English
# Authors....: Mateusz Viste, Robert Riebisch
# Last update: 12 Mar 2022
#
 
# GENERIC MESSAGES USED BY MULTIPLE INTERNAL COMMANDS
0.1:Invalid syntax
0.2:Invalid switch
0.3:Invalid parameter format
0.4:Too many parameters
0.5:Bad command or file name
0.6:Invalid parameter
0.7:Required parameter missing
0.8:Invalid destination
0.9:This command is not implemented
 
# the message below MUST be a two-letter UPPER-CASE string for "Yes/No" keys
# that user can press to answer interactive "Yes/No" questions
0.10:YN
 
# SVARCOM HELP SCREEN
1.0:Starts the SvarCOM command interpreter.
1.1:COMMAND /E:nnn [/P] [/D] [/Y] [/[C|K] command]
1.2:/D Skip AUTOEXEC.BAT processing (makes sense only with /P)
1.3:/E:nnn Sets the environment size to nnn bytes
1.4:/P Makes the new command interpreter permanent and run AUTOEXEC.BAT
1.5:/C Executes the specified command and returns
1.6:/K Executes the specified command and continues running
1.7:/Y Executes the batch program step by step (only with /P, /K or /C)
 
# VARIOUS SVARCOM MESSAGES
2.0:SVARCOM VERSION CHANGED. SYSTEM HALTED. PLEASE REBOOT YOUR COMPUTER.
2.1:FATAL ERROR: rmod_install() failed
2.2:SvarCOM: stack overflow detected, command history flushed (this is not a bug)
 
# CLS
10.0:Clears the screen.
 
# CHCP
11.0:Displays or sets the active code page number.
11.1:CHCP [nnn]
11.2:nnn Specifies a code page number
11.3:Type CHCP without a parameter to display the active code page number.
11.4:Invalid code page number
11.5:NLSFUNC not installed
11.6:Failed to change code page
11.7:Active code page:
 
# CD / CHDIR
12.0:Displays the name of or changes the current directory.
12.1:CHDIR [drive:][path]
12.2:CHDIR[..]
12.3:CD [drive:][path]
12.4:CD[..]
12.5:.. Specifies that you want to change to the parent directory.
12.6:Type CD drive: to display the current directory in the specified drive.
12.7:Type CD without parameters to display the current drive and directory.
 
# CALL
13.0:Calls one batch program from another.
13.1:CALL [drive:][path]filename [batch-parameters]
 
# BREAK
14.0:Sets or clears extended CTRL+C checking.
14.1:Type BREAK without a parameter to display the current BREAK setting.
14.2:BREAK is off
14.3:BREAK is on
 
# PAUSE
15.0:Suspends the execution of a batch script.
15.1:Press any key to continue...
 
# SHIFT
16.0:Changes the position of arguments in a batch file:
16.1:Argument %1 becomes %0, argument %2 becomes %1, etc.
 
# GOTO
17.0:Directs batch processing to a labelled line in the batch program.
17.1:GOTO LABEL
17.2:LABEL specifies a text string used in the batch program as a label.
17.3:A label is on a line by itself and must be preceded by a colon.
17.10:Label not found
 
# FOR
18.0:Runs a specified command for each element in a list.
18.1:FOR %variable IN (list) DO command [parameters]
18.2:%variable Single-letter variable (a-z or A-Z).
18.3:(list) One or more space-separated strings or filename wildcards.
18.4:command The command to carry out for each element. %variable allowed.
18.5:parameters Parameters or switches for the specified command.
18.6:To use FOR in a batch program, use %%variable instead of %variable.
18.7:FOR cannot be nested
 
# VERIFY
19.0:Tells DOS whether to verify that files are written correctly to disk.
19.1:Type VERIFY without a parameter to display its current setting.
19.2:VERIFY is off
19.3:VERIFY is on
19.4:Must specify ON or OFF
 
# VER
20.0:Displays the DOS kernel and SvarCOM shell versions.
20.1:DOS kernel version %u.%u
20.2:SvarCOM shell ver
20.3:SvarCOM is a shell interpreter for DOS kernels compatible with MS-DOS 5+.
20.4:This software is distributed under the terms of the MIT license.
20.5:Revision %c
20.6:DOS is in %s
20.7:low memory
20.8:HMA
20.9:ROM
20.10:true version %u.%u
 
# TYPE
21.0:Displays the contents of a text file.
21.1:TYPE [drive:][path]filename
 
# TIME
22.0:Displays or sets the system time.
22.1:TIME [time]
22.2:Type TIME with no parameters to display the current time and a prompt for a\r\nnew one. Press ENTER to keep the same time.
22.3:Current time is
22.4:Invalid time
22.5:Enter new time:
 
# SET
23.0:Displays, sets, or removes DOS environment variables.
23.1:SET [variable=[string]]
23.2:variable Specifies the environment-variable name
23.3:string Specifies a series of characters to assign to the variable
23.4:Type SET without parameters to display the current environment variables.
23.5:Not enough available space within the environment block
 
# RD / RMDIR
24.0:Removes (deletes) a directory.
24.1:RMDIR [drive:]path
24.2:RD [drive:]path
 
# REN / RENAME
25.0:Renames one or more files or directories.
25.1:RENAME [drive:][path]oldname newname
25.2:REN [drive:][path]oldname newname
25.3:Note that you cannot specify a new drive or path for newname.\r\nUse MOVE to move files from one directory to another.
 
# REM
26.0:Records comments (remarks) in a batch file.
26.1:REM [comment]
 
# PATH
27.0:Displays or sets a search path for executable files.
27.1:PATH [[drive:]path[;...]]
27.2:Type PATH ; to clear all search-path settings and direct DOS to search\r\nonly in the current directory.
27.3:Type PATH without parameters to display the current path.
27.4:No Path
 
# MD / MKDIR
28.0:Creates a directory.
28.1:MKDIR [drive:]path
28.2:MD [drive:]path
 
# LN
29.0:Adds, deletes or displays executable links.
29.1:LN ADD linkname targetdir
29.2:LN DEL linkname
29.3:LN LIST [pattern]
29.4:No matching executable found in given path.
29.5:%DOSDIR% not defined
 
# EXIT
30.0:Quits the COMMAND.COM program (command interpreter).
 
# ECHO
31.0:Displays messages, or turns command-echoing on or off.
31.1:ECHO [message]
31.2:Type ECHO without parameters to display the current echo setting.
31.3:ECHO is on
31.4:ECHO is off
 
# DATE
32.0:Displays or sets the system date.
32.1:DATE [date]
32.2:Type DATE with no parameters to display the current date and a prompt for a\r\nnew one. Press ENTER to keep the same date.
32.3:Invalid date
32.4:Current date is
32.5:Enter new date:
 
# PROMPT
33.0:Changes the DOS command prompt.
33.1:PROMPT [new command prompt specification]
 
# VOL
34.0:Displays the disk volume label and serial number, if they exist.
34.1:VOL [drive:]
34.2:Volume in drive %c has no label
34.3:Volume in drive %c is %s
34.4:Volume Serial Number is %04X-%04X
 
# IF
35.0:Performs conditional processing in batch programs.
35.1:IF [NOT] ERRORLEVEL num command
35.2:IF [NOT] string1==string2 command
35.3:IF [NOT] EXIST filename command
35.4:NOT command is executed only if condition is NOT met
35.5:ERRORLEVEL num condition: last program returned an exit code >= num
35.6:string1==string2 condition: both strings must be equal
35.7:EXIST filename condition: file filename exists (wildcards accepted)
35.8:command command to carry out if condition is met
 
# DEL / ERASE
36.0:Deletes one or more files.
36.1:DEL [drive:][path]filename [/P]
36.2:ERASE [drive:][path]filename [/P]
36.3:[drive:][path]filename Specifies the file(s) to delete.
36.4:/P Prompts for confirmation before deleting each file.
36.5:All files in directory will be deleted!
36.6:Are you sure?
36.7:Delete?
 
# DIR
37.0:Displays a list of files and subdirectories in a directory.
37.1:DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]]\r\n [/S] [/B] [/L]
37.2:/P Pauses after each screenful of information
37.3:/W Uses wide list format
37.4:/A Displays files with specified attributes:
37.5: D Directories R Read-only files H Hidden files
37.6: A Ready for archiving S System files - prefix meaning "not"
37.7:/O List files in sorted order:
37.8: N by name S by size E by extension
37.9: D by date G group dirs first - prefix to reverse order
37.10:/S Displays files in specified directory and all subdirectories
37.11:/B Uses bare format (no heading information or summary)
37.12:/L Uses lowercases
37.20:Directory of %s
37.21:<DIR>
37.22:file(s)
37.23:bytes
37.24:bytes free
 
# COPY
38.0:Copies one or more files to another location.
38.1:COPY [/A|/B] source [/A|/B] [+source [/A|/B] [+...]] [destination [/A|/B]] [/V]
38.2:source Specifies the file or files to be copied
38.3:/A Indicates an ASCII text file
38.4:/B Indicates a binary file
38.5:destination Specifies the directory and/or filename for the new file(s)
38.6:/V Verifies that new files are written correctly
38.7:To append files, specify a single file for destination, but multiple files\r\nfor source (using wildcards or file1+file2+file3 format).
38.8:NOTE: /A and /B are no-ops (ignored), provided only for compatibility reasons.\r\nCOPY assumes binary always.
38.9:%u file(s) copied
 
# TRUENAME
39.0:Returns a fully qualified path or filename.
39.1:TRUENAME [[drive:][path][filename]]
 
# DOS ERRORS
255.1:Function number invalid
255.2:File not found
255.3:Path not found
255.4:Too many open files (no handles available)
255.5:Access denied
255.6:Invalid handle
255.7:Memory control block destroyed
255.8:Insufficient memory
255.9:Memory block address invalid
255.10:Environment invalid
255.11:Format invalid
255.12:Access code invalid
255.13:Data invalid
255.15:Invalid drive
255.16:Attempted to remove current directory
255.17:Not same device
255.18:No more files
255.19:Disk write-protected
255.20:Unknown unit
255.21:Drive not ready
255.22:Unknown command
255.23:Data error (CRC)
255.24:Bad request structure length
255.25:Seek error
255.26:Unknown media type (non-DOS disk)
255.27:Sector not found
255.28:Printer out of paper
255.29:Write fault
255.30:Read fault
255.31:General failure
255.32:Sharing violation
255.33:Lock violation
255.34:Disk change invalid
255.35:FCB unavailable
255.36:Sharing buffer overflow
255.37:Code page mismatch
255.38:Cannot complete file operations (EOF / out of input)
255.39:Insufficient disk space
255.80:File already exists
/svarcom/tags/svarcom-2023.1/lang/fr-utf8.txt
0,0 → 1,297
#
# SvarCOM translation file
#
# Language.....: French
# Authors......: Berki Yenigün + fixes and adaptations by Mateusz Viste
# Last update..: 17 Feb 2023
#
 
# GENERIC MESSAGES USED BY MULTIPLE INTERNAL COMMANDS
0.1:Syntaxe invalide
0.2:Commutateur invalide
0.3:Format de paramètres invalide
0.4:Trop de paramètres
0.5:Mauvaise commande ou nom de fichier
0.6:Paramètre invalide
0.7:Paramètre requis manquant
0.8:Destination invalide
0.9:Cette commande n'est pas disponible
 
# the message below MUST be a two-letter UPPER-CASE string for "Yes/No" keys
# that user can press to answer interactive "Yes/No" questions
0.10:ON
 
# SVARCOM HELP SCREEN
1.0:Démarre l'interpréteur de commandes SvarCOM.
1.1:COMMAND /E:nnn [/P] [/D] [/Y] [/[C|K] commande]
1.2:/D Sauter le traitement d'AUTOEXEC.BAT (n'a de sens que avec /P)
1.3:/E:nnn Définit la taille de l'environnement sur nnn octets
1.4:/P Rend le nouvel interpréteur permanent et exécute AUTOEXEC.BAT
1.5:/C Exécute la commande spécifiée et retourne
1.6:/K Exécute la commande spécifiée et continue à fonctionner
1.7:/Y Exécute le programme batch pas à pas (seulement avec /P, /K ou /C)
 
# VARIOUS SVARCOM MESSAGES
2.0:LA VERSION DE SVARCOM A CHANGÉ. SYSTÈME ARRÊTÉ. REDÉMARREZ VOTRE ORDINATEUR.
2.1:ERREUR FATALE : rmod_install() a échoué
2.2:SvarCOM: débordem. de pile détecté, historique effacée (ce n'est pas un bug)
 
# CLS
10.0:Efface l'écran.
 
# CHCP
11.0:Affiche ou définit le numéro de page de code active.
11.1:CHCP [nnn]
11.2:nnn Spécifie un numéro de page de code
11.3:Tapez CHCP sans paramètres pour afficher la page de code active.
11.4:Numéro de page de code invalide
11.5:NLSFUNC n'est pas installé
11.6:Échec du changement de la page de code
11.7:Page de code active :
 
# CD / CHDIR
12.0:Affiche le nom ou modifie le répertoire courant.
12.1:CHDIR [lecteur:][chemin]
12.2:CHDIR[..]
12.3:CD [lecteur:][chemin]
12.4:CD[..]
12.5:.. Spécifique que vous voulez aller au répertoire parent.
12.6:Tapez CD lecteur: pour afficher le dossier courant dans le lecteur spécifié.
12.7:Tapez CD sans paramètre pour afficher le lecteur et dossier courants.
 
# CALL
13.0:Appelle un programme batch depuis un autre programme batch.
13.1:CALL [lecteur:][chemin]nomfichier [paramètres-batch]
 
# BREAK
14.0:Définit ou efface la vérification de CTRL+C étendu.
14.1:Tapez BREAK sans paramètres pour afficher le réglage actuel de BREAK.
14.2:BREAK est désactivé
14.3:BREAK est activé
 
# PAUSE
15.0:Suspend l'exécution d'un script batch.
15.1:Appuyez sur une touche pour continuer...
 
# SHIFT
16.0:Modifie la position des arguments dans un fichier batch :
16.1:Argument %1 devient %0, argument %2 devient %1, etc.
 
# GOTO
17.0:Dirige le traitement batch vers une ligne étiquetée dans le script batch.
17.1:GOTO LABEL
17.2:LABEL spécifie une chaîne texte utilisée dans le script batch comme étiquette.
17.3:Une étiquette est sur une ligne propre et doit être précédée par deux-points.
17.10:Étiquette introuvable
 
# FOR
18.0:Exécute une commande spécifiée pour chaque fichier dans un jeu de fichiers.
18.1:FOR %variable IN (set) DO commande [paramètres]
18.2:%variable un nom de paramètre remplaçable.
18.3:(set) une ou plusieurs expressions séparés par des espaces.
18.4:commande la commande à exécuter pour chaque fichier correspondant.
18.5:paramètres paramètres ou options pour la commande spécifiée.
18.6:Pour utiliser FOR dans un programme batch, utilisez %%variable au lieu de\r\n%variable.
18.7:FOR ne peut pas être imbriqué
 
# VERIFY
19.0:Indique à DOS s'il faut vérifier que les fichiers ont été écrits correctement.
19.1:Tapez VERIFY sans paramètres pour vérifier son réglage actuel.
19.2:VERIFY est désactivé
19.3:VERIFY est activé
19.4:Vous devez spécifier ON ou OFF
 
# VER
20.0:Affiche la version de DOS.
20.1:Version du noyau DOS %u.%u
20.2:Version du shell SvarCOM
20.3:SvarCOM est un interpréteur pour les noyaux DOS compatibles avec MS-DOS 5+.
20.4:Ce logiciel est distribué sous les termes de la licence MIT.
20.5:Révision %c
20.6:DOS est en %s
20.7:mémoire basse
20.8:HMA (zone mémoire haute)
20.9:ROM
20.10:vraie version %u.%u
 
# TYPE
21.0:Affiche le contenu d'un fichier texte.
21.1:TYPE [lecteur:][chemin]nomfichier
 
# TIME
22.0:Affiche ou définit l'heure du système.
22.1:TIME [heure]
22.2:Tapez TIME sans paramètre pour afficher l'heure actuelle et une invite pour\r\nune nouvelle heure. Appuyez sur ENTRÉE pour conserver.
22.3:L'heure actuelle est
22.4:Heure invalide
22.5:Entrez une nouvelle heure :
 
# SET
23.0:Affiche, définit ou enlève des variables d'environnement DOS.
23.1:SET [variable=[chaîne]]
23.2:variable Spécifie le nom de la variable d'environnement
23.3:chaîne Spécifie une série de caractères à attribuer à la variable
23.4:Tapez SET sans paramètre pour afficher la variable actuelle.
23.5:Pas assez d'espace disponible dans le bloc d'environnement
 
# RD / RMDIR
24.0:Enlève (efface) un répertoire.
24.1:RMDIR [lecteur:]chemin
24.2:RD [lecteur:]chemin
 
# REN / RENAME
25.0:Renomme un ou plusieurs fichiers, ou un répertoire.
25.1:RENAME [lecteur:][chemin]nomfichier1 nomfichier2
25.2:REN [lecteur:][chemin]nomfichier1 nomfichier2
25.3:Notez que vous ne pouvez pas spécifier un nouveau lecteur ou chemin pour votre\r\nfichier de destination. Utilisez MOVE pour déplacer des fichiers d'un\r\nrépertoire à un autre.
 
# REM
26.0:Enregistre des commentaires (remarques) dans un fichier batch.
26.1:REM [commentaire]
 
# PATH
27.0:Affiche ou définit un chemin de recherche pour les fichiers exécutables.
27.1:PATH [[lecteur:]chemin[;...]]
27.2:Tapez PATH ; pour effacer tous les réglages de chemin de recherche et indiquer\r\nà DOS de ne rechercher que dans le répertoire courant.
27.3:Tapez PATH sans paramètre pour afficher le chemin actuel.
27.4:Pas de chemin
 
# MD / MKDIR
28.0:Crée un répertoire.
28.1:MKDIR [lecteur:]chemin
28.2:MD [lecteur:]chemin
 
# LN
29.0:Ajoute, efface ou affiche des liens exécutables.
29.1:LN ADD nomlien dossiercible
29.2:LN DEL nomlien
29.3:LN LIST [pattern]
29.4:Aucun exécutable correspondant n'a été trouvé sur le chemin indiqué.
29.5:%DOSDIR% n'est pas défini
 
# EXIT
30.0:Quitte le programme COMMAND.COM (interpréteur de commandes).
 
# ECHO
31.0:Affiche des messages ou active ou désactive les échos des commandes.
31.1:ECHO [message]
31.2:Tapez ECHO sans paramètres pour afficher le réglage actuel d'echo.
31.3:ECHO est activé
31.4:ECHO est désactivé
 
# DATE
32.0:Affiche ou définit la date du système.
32.1:DATE [date]
32.2:Tapez DATE sans paramètre pour afficher la date actuelle et une invite pour\r\nune nouvelle. Appuyez sur ENTRÉE pour conserver la date actuelle.
32.3:Date invalide
32.4:La date actuelle est
32.5:Entrez une nouvelle date :
 
# PROMPT
33.0:Modifie l'invite de commandes de DOS.
33.1:PROMPT [nouvelle spécification d'invite de commandes]
 
# VOL
34.0:Affiche l'étiquette du volume de disque et le numéro de série, s'il existent.
34.1:VOL [lecteur:]
34.2:Volume dans le lecteur %c n'a pas d'étiquette
34.3:Volume dans le lecteur %c est %s
34.4:Le numéro de série du volume est %04X-%04X
 
# IF
35.0:Effectue des traitements conditionnels dans les programmes batch.
35.1:IF [NOT] ERRORLEVEL num commande
35.2:IF [NOT] chaîne1==chaîne2 commande
35.3:IF [NOT] EXIST nomfichier commande
35.4:NOT la commande est exécutée si la condition n'est PAS remplie
35.5:ERRORLEVEL num condition : le dernier programme a retourné un code >= num
35.6:string1==string2 condition : les deux chaînes doivent être identiques
35.7:EXIST filename condition : le nom de fichier existe (jokers acceptés)
35.8:command commande à exécuter si la condition est remplie
 
# DEL
36.0:Efface un ou plusieurs fichiers.
36.1:DEL [lecteur:][chemin]nomfichier [/P]
36.2:ERASE [lecteur:][chemin]nomfichier [/P]
36.3:[lecteur:][chemin]nomfichier Spécifie le(s) fichier(s) à effacer.
36.4:/P Demande confirmation avant d'effacer chaque fichier.
36.5:Tous les fichiers contenus dans le répertoire seront effacés !
36.6:Êtes-vous sûr ?
36.7:Effacer ?
 
# DIR
37.0:Affiche une liste de fichiers et de sous-répertoires dans un répertoire.
37.1:DIR [lecteur:][chemin][nomfichier] [/P] [/W] [/A[:]attributs]\r\n [/O[[:]ordredetri]] [/S] [/B] [/L]
37.2:/P Effectue une pause après chaque écran d'information
37.3:/W Utilise le format de liste large
37.4:/A Affiche les fichiers avec les attributs spécifiés :
37.5: D Répertoires R Fichiers lecture seule H Fichiers cachés
37.6: A Prêt pour archivage S Fichiers système - préfixe signifiant "non"
37.7:/O Liste les fichiers dans l'ordre indiqué :
37.8: N par nom S par taille E par extension
37.9: D par date G grouper les rép - préfixe inverser ordre"
37.10:/S Afficher les fichiers dans le dossier spécifié et tous les sous-dossiers
37.11:/B Utilise le fomat dépouillé (pas d'informations d'en-tête ou de résumé)
37.12:/L Utilise des caractères minuscules
37.20:Répertoire de %s
37.21:<RÉP>
37.22:fichier(s)
37.23:octets
37.24:octets libres
 
# COPY
38.0:Copie un ou davantage de fichiers à un autre endroit.
38.1:COPY [/A|/B] source [/A|/B] [+source [/A|/B] [+...]] [destination [/A|/B]] [/V]
38.2:source Spécifie le ou les fichiers à copier
38.3:/A Indique un fichier texte ASCII
38.4:/B Indique un fichier binaire
38.5:destination Spécifie le dossier et/ou nom de fichier pour le nouveau fichier
38.6:/V Vérifie que les nouveaux fichiers sont écrits correctement
38.7:Pour concatener des fichiers, spécifiez un seul fichier de destination, mais de\r\nmultiples fichiers source (en utilisant soit des jokers, soit le format\r\nfichier1+fichier2+fichier3).
38.8:NOTE: /A et /B sont des no-ops (ignorés), fournis pour la compatibilité.\r\nCOPY considère toujours les fichiers comme étant des binaires.
38.9:%u fichier(s) copié(s)
 
# TRUENAME
39.0:Retourne un chemin ou un nom de fichier pleinement qualifié.
39.1:TRUENAME [[lecteur:][chemin][nomfichier]]
 
# DOS ERRORS
255.1:Numéro de fonction invalide
255.2:Fichier introuvable
255.3:Chemin introuvable
255.4:Trop de fichiers ouverts (plus d'indicateur disponible)
255.5:Accès refusé
255.6:Indicateur invalide
255.7:Bloc de contrôle de mémoire détruit
255.8:Mémoire insuffisante
255.9:Adresse de bloc de mémoire invalide
255.10:Environnement invalide
255.11:Format invalide
255.12:Code d'accès invalide
255.13:Données invalides
255.15:Lecteur invalide
255.16:Tentative d'effacement du répertoire courant
255.17:Pas le même appareil
255.18:Plus de fichier
255.19:Le disque est protégé en écriture
255.20:Unité inconnue
255.21:Le lecteur n'est pas prêt
255.22:Commande inconnue
255.23:Erreur de données (CRC)
255.24:Mauvaise taille de structure de requête
255.25:Erreur de recherche
255.26:Type de media inconnu (disque non-DOS)
255.27:Secteur introuvable
255.28:Imprimante à court de papier
255.29:Défaut d'écriture
255.30:Défaut de lecture
255.31:Échec général
255.32:Violation de partage
255.33:Violation de verrou
255.34:Changement de disque invalide
255.35:FCB indisponible
255.36:Dépassement de tampon de partage
255.37:Défaut de correspondance des pages de code
255.38:Impossible de terminer les opérations de fichier (EOF / entrée terminée)
255.39:Espace disque insuffisant
255.80:Ce fichier existe déjà
/svarcom/tags/svarcom-2023.1/lang/pl-utf8.txt
0,0 → 1,297
#
# SvarCOM translation file
#
# Language...: Polish
# Author.....: Mateusz Viste
# Last update: 17 Feb 2023
#
 
# GENERIC MESSAGES USED BY MULTIPLE INTERNAL COMMANDS
0.1:Nieprawidłowa składnia
0.2:Nieprawidłowy przełącznik
0.3:Nieprawidłowy format parametru
0.4:Zbyt duża ilość parametrów
0.5:Złe polecenie lub nazwa pliku
0.6:Nieprawidłowy parametr
0.7:Brak wymaganego parametru
0.8:Nieprawidłowy cel
0.9:To polecenie nie jest dostępne
 
# the message below MUST be a two-letter upper-case string for "Yes/No" keys
# that user can press to answer interactive "Yes/No" questions
0.10:TN
 
# SVARCOM HELP SCREEN
1.0:Uruchamia interpreter poleceń SvarCOM.
1.1:COMMAND /E:nnn [/[C|K] [/P] [/D] polecenie]
1.2:/D Ignoruje AUTOEXEC.BAT (ma sens tylko przy /P)
1.3:/E:nnn Ustawia rozmiar środowiska na nnn bajtów
1.4:/P Ustala nowy interpreter poleceń i wykonuje AUTOEXEC.BAT
1.5:/C Wykonuje podane polecenie i kończy się
1.6:/K Wykonuje podane polecenie i działa dalej
1.7:/Y Wykonuje program wsadowy krok po kroku (tylko z /P, /K lub /C)
 
# VARIOUS SVARCOM MESSAGES
2.0:WERSJA SVARCOM ULEGŁA ZMIANIE. SYSTEM ZATRZYMANY. ZRESTARTUJ KOMPUTER.
2.1:BŁĄD KRYTYCZNY: rmod_install() nie powiodło się
2.2:SvarCOM: wykryto przepełnienie stosu, usunięto historię poleceń (to nie bug)
 
# CLS
10.0:Czyści ekran.
 
# CHCP
11.0:Wyświetla lub ustawia aktywną stronę kodową.
11.1:CHCP [nnn]
11.2:nnn Numer strony kodowej
11.3:Uruchom CHCP bez parametrów aby wyświetlić numer bieżącej strony kodowej.
11.4:Nieprawidłowy numer strony kodowej
11.5:NLSFUNC nie jest zainstalowany
11.6:Nie zdołano zmienić strony kodowej
11.7:Aktualna strona kodowa:
 
# CD / CHDIR
12.0:Wyświetla lub zmienia bieżący katalog.
12.1:CHDIR [dysk:][ścieżka]
12.2:CHDIR[..]
12.3:CD [dysk:][ścieżka]
12.4:CD[..]
12.5:.. Wskazuje, że chcesz przejść do katalogu nadrzędnego.
12.6:Wpisz CD dysk: to display the current directory in the specified drive.
12.7:Wpisz CD bez parametrów aby wyświetlić bieżący dysk i katalog.
 
# CALL
13.0:Wywołuje program wsadowy (bat) z innego programu wsadowego.
13.1:CALL [dysk:][ścieżka]nazwapliku [parametry-batch]
 
# BREAK
14.0:Włącza lub wyłącza rozszerzone sprawdzanie CTRL+C.
14.1:Wpisz BREAK bez parametru aby wyświetlić aktualne ustawienie BREAK.
14.2:BREAK jest wyłączone
14.3:BREAK jest włączone
 
# PAUSE
15.0:Wstrzymuje przetwarzanie pliku wsadowego.
15.1:Naciśnij dowolny klawisz aby kontynuować...
 
# SHIFT
16.0:Zmienia pozycję argumentów w pliku wsadowym:
16.1:Argument %1 staje się %0, argument %2 staje się %1, itd.
 
# GOTO
17.0:Kieruje przetwarzanie programu wsadowego do wiersza o określonej etykiecie.
17.1:GOTO ETYKIETA
17.2:ETYKIETA to ciąg znaków wykorzystany przez program wsadowy jako etykieta.
17.3:Etykieta znajduje się w osobnym wierszu i jest poprzedzona dwukropkiem.
17.10:Nie znaleziono etykiety
 
# FOR
18.0:Wykonuje określone polecenie na każdym pliku sposród zestawu plików.
18.1:FOR %zmienna IN (zestaw) DO polecenie [parametry]
18.2:%zmienna nazwa zmiennej.
18.3:(zestaw) Jeden lub więcej wzorów plików lub komunikatów, oddzielone spacją.
18.4:polecenie polecenie do wykonania na każdym z pasujących plików.
18.5:parametry parametry lub przełączniki dla określonego polecenia.
18.6:Aby użyć FOR w programie wsadowym, użyj %%zmienna zamiast %zmienna.
18.7:FOR nie może być zagnieżdżone
 
# VERIFY
19.0:Włącza lub wyłącza sprawdzanie poprawności zapisu plików przez DOS.
19.1:Wpisz VERIFY bez parametru aby wyświetlić aktualne ustawienie.
19.2:VERIFY jest wyłączone
19.3:VERIFY jest włączone
19.4:Należy podać ON lub OFF
 
# VER
20.0:Wyświetla wersję DOS.
20.1:Wersja jądra DOS %u.%u
20.2:Wersja powłoki SvarCOM
20.3:SvarCOM jest interpreterem poleceń dla systemów DOS kompatybilnych z MS-DOS 5+.
20.4:To oprogramowanie jest udostępniane na zasadach licencji MIT.
20.5:Rewizja %c
20.6:DOS jest w %s
20.7:pamięci konwencjonalnej
20.8:HMA
20.9:ROM
20.10:prawdziwa wersja %u.%u
 
# TYPE
21.0:Wyświetla zawartość pliku tekstowego.
21.1:TYPE [dysk:][ścieżka]nazwapliku
 
# TIME
22.0:Wyświetla lub ustawia czas systemowy.
22.1:TIME [czas]
22.2:Wpisz TIME bez parametrów aby wyświetlić aktualną godzinę, wraz z zapytaniem\r\no podanie nowej. Wciśnij ENTER aby zachować bieżącą godzinę.
22.3:Aktualna godzina to
22.4:Nieprawidłowy czas
22.5:Podaj nową godzinę:
 
# SET
23.0:Wyświetla, ustawia lub usuwa zmienną środowiskową DOS.
23.1:SET [zmienna=[ciąg znaków]]
23.2:zmienna Nazwa zmiennej środowiskowej
23.3:ciąg zn. Ciąg znaków przypisany do zmiennej
23.4:Wpisz SET bez parametrów aby wyświetlić obecne zmienne środowiskowe.
23.5:Brak miejsca w bloku pamięci środowiskowej
 
# RD / RMDIR
24.0:Usuwa (kasuje) katalog.
24.1:RMDIR [dysk:]ścieżka
24.2:RD [dysk:]ścieżka
 
# REN / RENAME
25.0:Zmienia nazwę jednego lub wielu plików bądź katalogu.
25.1:RENAME [dysk:][ścieżka]plik1 plik2
25.2:REN [dysk:][ścieżka]plik1 plik2
25.3:Uwaga: nie możesz podać nowego dysku lub ścieżki dla pliku2\r\nUżyj MOVE aby przenieść pliki do innego katalogu.
 
# REM
26.0:Pozwala zapisać komentarze (uwagi) w pliku wsadowym.
26.1:REM [komentarz]
 
# PATH
27.0:Wyświetla lub ustawia ścieżkę wyszukiwania plików wykonywalnych.
27.1:PATH [[dysk:]ścieżka[;...]]
27.2:Wpisz PATH ; aby wyczyścić ustawienia ścieżek wyszukiwania. DOS będzie\r\nwówczas przeszukiwał wyłącznie bieżący katalog.
27.3:Wpisz PATH bez parametrów, aby wyświetlić bieżącą ścieżkę.
27.4:Brak ścieżki PATH
 
# MD / MKDIR
28.0:Tworzy katalog.
28.1:MKDIR [dysk:]ścieżka
28.2:MD [dysk:]ścieżka
 
# LN
29.0:Dodaje, usuwa lub wyświetla wykonywalne linki.
29.1:LN ADD nazwalinku katalogdocelowy
29.2:LN DEL nazwalinku
29.3:LN LIST [wzór]
29.4:Nie znaleziono pasującego pliku wykonywalnego w podanej ścieżce.
29.5:%DOSDIR% nie jest ustawione
 
# EXIT
30.0:Kończy program COMMAND.COM (interpreter poleceń).
 
# ECHO
31.0:Wyświetla komunikaty lub włącza bądź wyłącza wyświetlanie wykonywanych poleceń.
31.1:ECHO [komunikat]
31.2:Wpisz ECHO bez parametrów, aby wyświetlić bieżące ustawienie echa.
31.3:ECHO jest włączone
31.4:ECHO jest wyłączone
 
# DATE
32.0:Wyświetla lub ustawia datę systemową.
32.1:DATE [data]
32.2:Wpisz DATE bez parametrów, aby wyświetlić bieżącą datę i zapytanie o nową datę.\r\nNaciśnij ENTER, aby zachować tę samą datę.
32.3:Nieprawidłowa data
32.4:Aktualna data to
32.5:Podaj nową datę:
 
# PROMPT
33.0:Zmienia znak zachęty poleceń systemu DOS.
33.1:PROMPT [specyfikacja nowego znaku zachęty poleceń]
 
# VOL
34.0:Wyświetla etykietę woluminu dysku i numer seryjny, jeśli istnieją.
34.1:VOL [dysk:]
34.2:Wolumin w napędzie %c nie ma etykiety
34.3:Wolumin w napędzie %c to %s
34.4:Numer seryjny woluminu to %04X-%04X
 
# IF
35.0:Wykonuje przetwarzanie warunkowe w programach wsadowych.
35.1:IF [NOT] ERRORLEVEL n polecenie
35.2:IF [NOT] ciąg1=ciąg2 polecenie
35.3:IF [NOT] EXIST nazwapliku
35.4:NOT wykonaj polecenie tylko jeśli warunek NIE jest spełniony
35.5:ERRORLEVEL n warunek: ostatni program zwrócił kod zakończenia >= n
35.6:ciąg1==ciąg2 warunek: ciągi muszą być takie same
35.7:EXIST nazwapliku warunek: plik istnieje (dozwolone symbole wieloznaczne)
35.8:polecenie polecenie do wykonania, jeśli warunek jest spełniony
 
# DEL / ERASE
36.0:Usuwa jeden lub więcej plików.
36.1:DEL [dysk:][ścieżka]nazwapliku [/P]
36.2:ERASE [dysk:][ścieżka]nazwapliku [/P]
36.3:[dyske:][ścieżka]nazwapliku Określa plik(i) do skasowania.
36.4:/P Prosi o potwierdzenie przed usunięciem każdego pliku.
36.5:Wszystkie pliki w katalogu zostaną usunięte!
36.6:Czy na pewno?
36.7:Usunąć?
 
# DIR
37.0:Wyświetla listę plików i podkatalogów w katalogu.
37.1:DIR [dysk:][ścieżka][nazwapliku] [/P] [/W] [/A[:]atrybuty] [/O[:]sortowanie]]\r\n [/S] [/B] [/L]
37.2:/P Zatrzymuje się po każdej informacji na ekranie
37.3:/W Używa formatu szerokiej listy
37.4:/A Wyświetla pliki z określonymi atrybutami:
37.5: D Katalogi R Pliki tylko do odczytu H Pliki ukryte
37.6: A Pliki do archiwizacji S Pliki systemowe - przedrostek negujący
37.7:/O Listuje pliki w posortowanej kolejności:
37.8: N według nazwy S według rozmiaru E według rozszerzenia
37.9: D według daty G najpierw katalogi - przedrostek odwracający kolejność
37.10:/S Wyświetla pliki w podanym katalogu i wszystkich podkatalogach
37.11:/B Używa uproszczonego formatu (bez nagłówka i podsumowania)
37.12:/L Używa małych liter
37.20:Katalog %s
37.21:<KAT>
37.22:plik(i)
37.23:bajty
37.24:bajty wolne
 
# COPY
38.0:Kopiuje jeden lub więcej plików do innej lokalizacji.
38.1:COPY [/A|/B] źródło [/A|/B] [+źródło [/A|/B] [+...]] [cel [/A|/B]] [/V]
38.2:źródło Określa plik lub pliki, które mają być skopiowane
38.3:/A Wskazuje plik tekstowy ASCII
38.4:/B Wskazuje plik binarny
38.5:cel Określa katalog i/lub nazwę nowego pliku(ów)
38.6:/V Sprawdza, czy nowe pliki zostały poprawnie zapisane
38.7:Aby połączać pliki, należy podać pojedynczy plik jako cel, ale wiele plików\r\nźródłowych (używając symboli wieloznacznych lub formatu plik1+plik2+plik3).
38.8:UWAGA: /A i /B są ignorowane, podane tylko ze względu na kompatybilność.\r\nCOPY zakłada zawsze binaria.
38.9:skopiowano %u plik(i)
 
# TRUENAME
39.0:Zwraca w pełni kwalifikowaną ścieżkę lub nazwę pliku.
39.1:TRUENAME [dysk:][ścieżka]nazwapliku
 
# DOS ERRORS
255.1:Błędny numer funkcji
255.2:Nie znaleziono pliku
255.3:Nie znaleziono ścieżki
255.4:Zbyt wiele otwartych plików (brak dostępnych uchwytów)
255.5:Brak dostępu
255.6:Nieprawidłowy uchwyt
255.7:Zniszczony blok kontroli pamięci
255.8:Niewystarczająca pamięć
255.9:Nieprawidłowy adres bloku pamięci
255.10:Nieprawidłowe środowisko
255.11:Nieprawidłowy format
255.12:Nieprawidłowy kod dostepu
255.13:Nieprawidłowe dane
255.15:Nieprawidłowy napęd
255.16:Dokonano próby usunięcia bieżącego katalogu
255.17:Nie to samo urządzenie
255.18:Brak dalszych plików
255.19:Dysk chroniony przed zapisem
255.20:Nieznana jednostka
255.21:Napęd nie jest gotowy
255.22:Nieznane polecenie
255.23:Błąd danych (CRC)
255.24:Nieprawidłowa długość struktury zapytania
255.25:Błąd wyszukiwania
255.26:Nieznany typ nośnika (dysk niezgodny z DOS)
255.27:Nie znaleziono sektora
255.28:Brak papieru w drukarce
255.29:Błąd zapisu
255.30:Błąd odczytu
255.31:Ogólna awaria
255.32:Naruszenie zasad współdzielenia
255.33:Naruszenie blokady
255.34:Nieprawidłowa zmiana dysku
255.35:Niedostępne FCB
255.36:Przepełnienie bufora udostępniania
255.37:Niezgodność strony kodowej
255.38:Nie można ukończyć operacji na pliku (EOF / brak danych wejściowych)
255.39:Za mało miejsca na dysku
255.80:Plik już istnieje
/svarcom/tags/svarcom-2023.1/lang/tr-utf8.txt
0,0 → 1,297
#
# SvarCOM language file
#
# Language...: Turkish
# Authors....: Berki Yenigün
# Last update: 12 Mar 2022
#
 
# GENERIC MESSAGES USED BY MULTIPLE INTERNAL COMMANDS
0.1:Geçersiz sözdizimi
0.2:Geçersiz seçenek
0.3:Geçersiz parametre biçimi
0.4:Çok fazla parametre
0.5:Yanlış komut veya dosya ismi
0.6:Geçersiz parametre
0.7:Gerekli parametre eksik
0.8:Geçersiz hedef
?0.9:Bu komut mevcut değil
 
# the message below MUST be a two-letter UPPER-CASE string for "Yes/No" keys
# that user can press to answer interactive "Yes/No" questions
0.10:EH
 
# SVARCOM HELP SCREEN
1.0:SvarCOM komut yorumlayıcısını başlatır.
1.1:COMMAND /E:nnn [/P] [/D] [/Y] [/[C|K] komut]
1.2:/D AUTOEXEC.BAT işlenmesini atla (sadece /P ile bir anlamı vardır)
1.3:/E:nnn Ortamın boyutunu nnn bayt olarak ayarlar
1.4:/P Yeni komut yorumlayıcısını daimi kılar ve AUTOEXEC.BAT'i çalıştırır
1.5:/C Belirtilen komutu çalıştırır ve döner
1.6:/K Belirtilen komutu çalıştırır ve çalışmaya devam eder
1.7:/Y Toplu iş programını adım adım çalıştırır (sadece /P, /K veya /C ile)
 
# VARIOUS SVARCOM MESSAGES
2.0:SVARCOM SÜRÜMÜ DEĞİŞTİ. SİSTEM DURDURULDU. BİLGİSAYARINIZI YENİDEN BAŞLATIN.
2.1:ÖLÜMCÜL HATA: rmod_install() başarısız oldu
2.2:SvarCOM: yığın taşması tespit edildi, komut tarihçesi silindi (hata değildir)
 
# CLS
10.0:Ekranı siler.
 
# CHCP
11.0:Etkin kod sayfası sayısını görüntüler veya ayarlar.
11.1:CHCP [nnn]
11.2:nnn Kod sayfası sayısını belirtir
11.3:Faal kod sayfası sayısını görüntülemek için parametresiz CHCP yazın.
11.4:Geçersiz kod sayfa sayısı
11.5:NLSFUNC kurulu değil
11.6:Kod sayfası değişikliği başarısız oldu
11.7:Etkin kod sayfası:
 
# CD / CHDIR
12.0:Güncel dizinin ismini görüntüler veya onu değiştirir.
12.1:CHDIR [sürücü:][yol]
12.2:CHDIR[..]
12.3:CD [sürücü:][yol]
12.4:CD[..]
12.5:.. Üst dizine gitmek istediğinizi belirtir.
12.6:Belirtilen sürücüde güncel dizini görüntülemek için CD sürücü: yazın.
12.7:Güncel sürücü ve dizini görüntülemek için parametresiz CD yazın.
 
# CALL
13.0:Bir toplu iş dosyasından başka bir toplu iş dosyasını çağırır.
13.1:CALL [sürücü:][yol]dosyaismi [toplu-iş-parametreleri]
 
# BREAK
14.0:Genişletilmiş CTRL+C denetlemesini ayarlar veya temizler.
14.1:Güncel BREAK ayarını görüntülemek için parametresiz BREAK yazın.
14.2:BREAK devre dışı
14.3:BREAK etkin
 
# PAUSE
15.0:Bir toplu iş betiğinin çalıştırılmasını askıya alır.
15.1:Devam etmek için herhangi bir tuşa basın...
 
# SHIFT
16.0:Toplu iş dosyalarında argümanların konumunu değiştirir:
16.1:%1 argümanı %0 olur, %2 argümanı %1 olur, vs.
 
# GOTO
17.0:Toplu iş işlemesini toplu iş programında etiketlenen bir satıra yönlendirir.
17.1:GOTO LABEL
17.2:LABEL toplu iş programında etiket olarak kullanılan bir dizeyi belirtir.
17.3:Etiketler kendi satırlarında bulunur ve öncesinde üst üste iki nokta bulunur.
17.10:Etiket bulunamadı
 
# FOR
18.0:Bir dosya dizisinde belirtilen komutu her dosya için çalıştırır.
18.1:FOR %değişken IN (set) DO komut [parametreler]
18.2:%değişken Değiştirilebilir parametre ismi. (tek harf)
18.3:(set) Boşlukla ayrılmış desen veya mesajlardan biri.
18.4:komut Denkleşen her dosya için çalıştırılacak komut.
18.5:parametreler Belirtilen komut için parametre veya seçenekler.
18.6:FOR'u bir toplu iş dosyasında kullanmak için, %değişken yerine %%değişken kullanın.
18.7:FOR iç içe geçirilemez yani yuvalanamaz
 
# VERIFY
19.0:DOS'a dosyaların diske doğru yazılıp yazılmadıklarını denetlemesini belirtir.
19.1:Güncel ayarını görüntülemek için parametresiz VERIFY yazın.
19.2:VERIFY devre dışı
19.3:VERIFY etkin
19.4:ON veya OFF belirtilmesi gerekir
 
# VER
20.0:DOS sürümünü görüntüler.
20.1:DOS çekirdek sürümü %u.%u
20.2:SvarCOM kabuk sürümü
20.3:SvarCOM, MS-DOS 5+ ile uyumlu DOS çekirdekleri için kabuk yorumlayıcısıdır.
20.4:Bu yazılım MIT lisansı kapsamında yayınlanmıştır.
20.5:Gözden geçirme %c
20.6:DOS şuradadır: %s
20.7:düşük bellek alanı
20.8:HMA (Yüksek Bellek Alanı)
20.9:ROM
20.10:gerçek sürümü %u.%u
 
# TYPE
21.0:Metin dosyalarının içeriğini görüntüler.
21.1:TYPE [sürücü:][yol]dosyaismi
 
# TIME
22.0:Sistem zamanını görüntüler veya ayarlar.
22.1:TIME [saat]
22.2:Güncel saati görüntülemek ve yeni bir saat girmek için parametresiz TIME\r\nyazın. Saati muhafaza etmek için ENTER'a basın.
22.3:Güncel saat şudur:
22.4:Geçersiz saat
22.5:Yeni saati girin:
 
# SET
23.0:DOS ortam değişkenlerini görüntüler, ayarlar veya kaldırır.
23.1:SET [değişken=[dize]]
23.2:değişken Ortam değişkeninin ismini belirtir
23.3:dize Değişkene atanacak karakter serisini belirtir
23.4:Güncel ortam değişkenlerini görüntülemek için parametresiz SET yazın.
23.5:Ortam bloku içinde yetersiz alan
 
# RD / RMDIR
24.0:Dizinleri kaldırır (siler).
24.1:RMDIR [sürücü:]yol
24.2:RD [sürücü:]yol
 
# REN / RENAME
25.0:Bir dosyayı, dosya kümelerini veya bir dizini tekrar isimlendirir.
25.1:RENAME [sürücü:][yol]dosyaismi1 dosyaismi2
25.2:REN [sürücü:][yol]dosyaismi1 dosyaismi2
25.3:dosyaismi2 için yeni bir sürücü veya yol belirtemeyeceğinizi unutmayın.\r\nBir dizinden başkasına dosya taşımak için MOVE kullanın.
 
# REM
26.0:Toplu iş dosyasında yorum (açıklama) kaydeder.
26.1:REM [yorum]
 
# PATH
27.0:Çalıştırılabilir dosyalar için arama yolu görüntüler veya ayarlar.
27.1:PATH [[sürücü:]yol[;...]]
27.2:Tüm arama yolu ayarlarını silmek ve DOS'ı sadece güncel dizinde aramaya\r\nyönlendirmek için PATH ; yazın.
27.3:Güncel yolu görüntülemek için parametresiz PATH yazın.
27.4:Yol Yok
 
# MD / MKDIR
28.0:Dizin oluşturur.
28.1:MKDIR [sürücü:]yol
28.2:MD [sürücü:]yol
 
# LN
29.0:Çalıştırılabilir bağlantı ekler, siler veya görüntüler.
29.1:LN ADD bağlantıisimi hedefdizin
29.2:LN DEL bağlantıismi
29.3:LN LIST [desen]
29.4:Belirtilen yolda denkleşen çalıştırılabilir dosya bulunamadı.
29.5:%DOSDIR% ayarlanmamış
 
# EXIT
30.0:COMMAND.COM programından (komut yorumlayıcısı) çıkar.
 
# ECHO
31.0:Mesaj görüntüler, komut yankılamasını etkinleştirir veya devre dışı bırakır.
31.1:ECHO [mesaj]
31.2:Güncel yankı ayarını görüntülemek için parametresiz ECHO yazın.
31.3:ECHO etkin
31.4:ECHO devre dışı
 
# DATE
32.0:Sistem tarihini görüntüler veya ayarlar.
32.1:DATE [tarih]
32.2:Güncel tarihi görüntülemek ve yeni bir tarih girmek için parametresiz DATE\r\nyazın. Tarihi muhafaza etmek için ENTER'a basın.
32.3:Geçersiz tarih
32.4:Güncel tarih şudur
32.5:Yeni tarihi girin:
 
# PROMPT
33.0:DOS komut istemini değiştirir.
33.1:PROMPT [yeni komut istemi özellikleri]
 
# VOL
34.0:Mevcutsa, disk birimi etiketini ve seri numarasını görüntüler.
34.1:VOL [sürücü:]
34.2:%c sürücüsündeki birimin etiketi yok
34.3:%c sürücüsündeki birim şudur %s
34.4:Birim Seri Numarası şudur: %04X-%04X
 
# IF
35.0:Toplu iş programlarında koşullu işleme yapar.
35.1:IF [NOT] ERRORLEVEL sayı komut
35.2:IF [NOT] dize1==dize2 komut
35.3:IF [NOT] EXIST dosyaismi komut
35.4:NOT komut sadece koşul mevcut değilse çalıştırılır
35.5:ERRORLEVEL sayı koşul: son program şu çıkma kodunu döndürdü: >= sayı
35.6:dize1==dize2 koşul: iki dizenin eşit olması gerekir
35.7:EXIST dosyaismi koşul: dosya ismi mevcut (jokerlere izin verilir)
35.8:komut koşul mevcutsa çalıştırılacak komut
 
# DEL / ERASE
36.0:Bir veya daha fazla dosyayı siler.
36.1:DEL [sürücü:][yol]dosyaismi [/P]
36.2:ERASE [sürücü:][yol]dosyaismi [/P]
36.3:[sürücü:][yol]dosyaismi Silinecek dosyaları belirtir.
36.4:/P Her dosyayı silemeden önce teyit istemi görüntüler.
36.5:Dizindeki tüm dosyalar silinecek!
36.6:Emin misiniz?
36.7:Silinsin mi?
 
# DIR
37.0:Dizinlerdeki dosyaların ve alt dizinlerin listesini görüntüler.
37.1:DIR [sürücü:][yol][dosyaismi] [/P] [/W] [/A[:]özellikler] [/O[[:]sıralama]]\r\n [/S] [/B] [/L]
37.2:/P Her bilgi ekranından sonra duraklar
37.3:/W Geniş liste biçimini kullanır
37.4:/A Belirtilen özelliklere sahip dosyaları görüntüler:
37.5: D Dizinler R Salt okunur dosyalar H Gizli dosyalar
37.6: A Arşivlenmeye hazır S Sistem dosyaları - "hayır" manasına gelen ön ek
37.7:/O Dosyaları sıralanmış düzende listele:
37.8: N ada göre S boyuta göre E uzantıya göre
37.9: D tarihe göre G önce dizinleri grupla - sırlamayı tersine çevir
37.10:/S Belirtilen dizin ve tüm alt dizinlerdeki dosyaları listeler
37.11:/B Sade biçimi kullanır (başlık bilgisi veya özet görüntülenmez)
37.12:/L Küçük harfleri kullanır
37.20:%s unsurunun dizini
37.21:<DİZİN>
37.22:dosya
37.23:bayt
37.24:bayt boş
 
# COPY
38.0:Bir veya daha fazla dosyayı başka bir konuma kopyalar.
38.1:COPY [/A|/B] kaynak [/A|/B] [+kaynak [/A|/B] [+...]] [hedef [/A|/B]] [/V]
38.2:kaynak Kopyalanacak dosya veya dosyaları belirtir
38.3:/A ASCII metin dosyası belirtir
38.4:/B İkili dosya belirtir
38.5:hedef Yeni dosyalar için dizin ve/veya dosya ismini belirtir
38.6:/V Yeni dosyaların doğru olarak yazıldığını kontrol eder
38.7:Dosya eklemek için hedef olarak tek bir dosya belirtin, fakat kaynak için\r\nçoklu (joker veya dosya1+doya2+dosya3 biçimini kullanın).
38.8:NOT: /A ve /B no-op'tur (yok sayılır), sadece uyumluluk amaçlı bulunurlar.\r\nCOPY daima ikili var sayar.
38.9:%u dosya kopyalandı
 
# TRUENAME
39.0:Tam nitelikli bir yol veya dosya adı döndürür.
39.1:TRUENAME [[sürücü:][yol][dosyaismi]]
 
# DOS ERRORS
255.1:Geçersiz işlev sayısı
255.2:Dosya bulunamadı
255.3:Yol bulunamadı
255.4:Çok fazla açık dosya (tutak yani handle kalmadı)
255.5:Erişim reddedildi
255.6:Geçersiz tutak yani handle
255.7:Bellek kontrol bloku imha edildi
255.8:Yetersiz bellek
255.9:Geçersiz bellek blok adresi
255.10:Geçersiz ortam
255.11:Geçersiz biçim
255.12:Geçersiz erişim kodu
255.13:Geçersiz veri
255.15:Geçersiz sürücü
255.16:Güncel dizini silme teşebbüsü
255.17:Aynı cihaz değil
255.18:Dosya kalmadı
255.19:Disk yazmaya karşı korumalı
255.20:Bilinmeyen birim
255.21:Sürücü hazır değil
255.22:Bilinmeyen komut
255.23:Veri hatası (CRC)
255.24:Yanlış istek yapı boyutu
255.25:Arama hatası
255.26:Bilinmeyen ortam türü (DOS diski değil)
255.27:Sektör bulunamadı
255.28:Yazıcıda kağıt kalmadı
255.29:Yazma hatası
255.30:Okuma hatası
255.31:Genel başarısızlık
255.32:Paylaşım ihlali
255.33:Kilit ihlali
255.34:Geçersiz disk değişimi
255.35:FCB mevcut değil
255.36:Paylaşım tamponu taşması
255.37:Kod sayfası uyuşmazlığı
255.38:Dosya işlemleri tamamlanamaz (EOF / girdi kalmadı)
255.39:Yetersiz disk alanı
255.80:Dosya zaten mevcut
/svarcom/tags/svarcom-2023.1/makefile
0,0 → 1,99
#
# This is a makefile to build the SVARCOM command interpreter (COMMAND.COM)
# using OpenWatcom and nasm.
#
# You can use following targets:
#
# wmake - compiles the program
# wmake clean - cleans up all non-source files
#
 
FEATURES =
FEATURES += -DVERDBG
 
LDFLAGS = -0 -y -wx -mt -lr -we -d0 -ox -fm=command.map
CFLAGS = -0 -wx -ms -we -d0 -ox $(FEATURES)
# -0 generate 8086 compatible code
# -y ignore %WCL% if present
# -wx maximum warnings level
# -mt TINY memory model
# -lr real-mode target
# -we any warning is considered an error
# -d0 no debug data
# -ox maximum optimization level
#
# NOTE: wcc does not understand -mt, that is why -ms must be passed instead
 
all: command.com
 
command.com: rmodcore.h command.obj cmd.obj deflang.obj env.obj redir.obj rmodinit.obj sayonara.obj helpers.obj
# build the final executable
*wcl $(LDFLAGS) command.obj cmd.obj deflang.obj env.obj redir.obj rmodinit.obj sayonara.obj helpers.obj svarlang.lib\svarlngs.lib
 
deflang.obj: lang\*.txt
# GENERATE CODEPAGE-SPECIFIG VERSIONS OUT OF UTF-8 FILES
CD LANG
utf8tocp 850 BR-UTF8.TXT > BR.TXT
utf8tocp 850 DE-UTF8.TXT > DE.TXT
utf8tocp 437 EN-UTF8.TXT > EN.TXT
utf8tocp 850 FR-UTF8.TXT > FR.TXT
utf8tocp maz PL-UTF8.TXT > PL.TXT
utf8tocp 857 TR-UTF8.TXT > TR.TXT
..\svarlang.lib\tlumacz en br de fr pl tr > tlumacz.log
DEL ??.TXT
MOVE /Y OUT.LNG ..\SVARCOM.LNG
MOVE /Y DEFLANG.C ..
CD ..
wcc $(CFLAGS) deflang.c
 
cmd.obj: cmd.c cmd\*.c
wcc $(CFLAGS) cmd.c
 
command.obj: command.c rmodcore.h
wcc $(CFLAGS) command.c
 
helpers.obj: helpers.c
wcc $(CFLAGS) helpers.c
 
.c.obj:
wcc $(CFLAGS) $<
 
rmodcore.h: file2c.com rmod.bin
file2c /s /l4096 rmod.bin rmodcore.h BUFFER
 
file2c.com: file2c.c
wcl $(LDFLAGS) file2c.c
 
rmod.bin: rmod.asm
nasm -f bin -l rmod.lst -o rmod.bin rmod.asm
 
clean: .SYMBOLIC
del *.com
del *.obj
del rmod.bin
del rmod.lst
del rmodcore.h
del deflang.c
del command.map
 
release: command.com .SYMBOLIC
# drop old packages if present
IF EXIST svarcom.zip DEL svarcom.zip
IF EXIST svarcom.svp DEL svarcom.svp
# source package
zip -9rkDX svarcom.zip makefile *.c *.h *.txt *.asm cmd lang svarlang.lib
# SvarDOS binary package
mkdir appinfo
mkdir doc
mkdir doc\svarcom
mkdir nls
copy command.com bin
copy *.txt doc\svarcom\
copy svarcom.lsm appinfo\
copy svarcom.lng nls\
upx -9 --8086 command.com
zip -9rkDX -m svarcom.svp command.com appinfo doc nls
rmdir appinfo
rmdir nls
rmdir doc\svarcom
rmdir doc
/svarcom/tags/svarcom-2023.1/redir.c
0,0 → 1,243
/* 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.
*/
 
#include <string.h> /* memset() */
 
#include "env.h"
#include "helpers.h"
#include "rmodinit.h"
 
#include "redir.h"
 
static unsigned short oldstdout = 0xffff;
 
 
/* compute a filename to be used for pipes */
static unsigned short gentmpfile(char *s, unsigned short envseg) {
unsigned short err = 0;
unsigned short i;
 
/* do I have a %temp% path? */
i = env_lookup_valcopy(s, 116, envseg, "TEMP");
if (i > 0) {
/* make sure it is terminated by a backslash (required by int 0x21, ah=5a) */
if (s[i - 1] != '\\') {
s[i++] = '\\';
s[i] = 0;
}
} else {
/* if fails, then use truename(.\) */
if (file_truename(".\\", s) != 0) *s = 0;
}
 
/* create file */
_asm {
mov ah, 0x5a
mov dx, s
xor cx, cx /* file attributes */
int 0x21
jnc CLOSEFILE
mov err, ax
jmp DONE
/* close file handle (handle still in BX) */
CLOSEFILE:
mov bx, ax
mov ah, 0x3e
int 0x21
DONE:
}
return(err);
}
 
 
/* parse commandline and performs necessary redirections. cmdline is
* modified so all redirections are cut out.
* piped commands are moved to awaitingcmd for later execution
* returns 0 on success, DOS err on failure */
unsigned short redir_parsecmd(struct redir_data *d, char *cmdline, char far *awaitingcmd, unsigned short envseg) {
unsigned short i;
unsigned short pipescount = 0;
 
/* NOTES:
*
* 1. while it is possible to type a command with multiple
* redirections, MSDOS executes only the last redirection.
*
* 2. the order in which >, < and | are provided on the command line does
* not seem to matter for MSDOS. piped commands are executed first (in
* the order they appear) and the result of the last one is redirected to
* whenever the last > points at.
* stdin redirection (<) is (obviously) applied to the first command only
*/
 
/* preset oldstdout to 0xffff in case no redirection is required */
oldstdout = 0xffff;
 
/* clear out the redir_data struct */
memset(d, 0, sizeof(*d));
 
*awaitingcmd = 0;
 
/* parse the command line and fill struct with pointers */
for (i = 0;; i++) {
if (cmdline[i] == '>') {
cmdline[i] = 0;
if (cmdline[i + 1] == '>') {
i++;
d->stdout_openflag = 0x11; /* used during int 21h,AH=6C */
} else {
d->stdout_openflag = 0x12;
}
d->stdoutfile = cmdline + i + 1;
while (d->stdoutfile[0] == ' ') d->stdoutfile++;
} else if (cmdline[i] == '<') {
cmdline[i] = 0;
d->stdinfile = cmdline + i + 1;
while (d->stdinfile[0] == ' ') d->stdinfile++;
} else if (cmdline[i] == '|') {
cmdline[i] = 0;
if (pipescount < REDIR_MAX_PIPES) {
d->pipes[pipescount++] = cmdline + i + 1;
while (d->pipes[pipescount][0] == ' ') d->pipes[pipescount]++;
}
} else if (cmdline[i] == 0) {
break;
}
}
 
/* if pipes present, write them to awaitingcmd (and stdout redirection too) */
if (pipescount != 0) {
static char tmpfile[130];
for (i = 0; i < pipescount; i++) {
if (i != 0) _fstrcat(awaitingcmd, "|");
_fstrcat(awaitingcmd, d->pipes[i]);
}
/* append stdout redirection so I don't forget about it for the last command of the pipe queue */
if (d->stdoutfile != NULL) {
if (d->stdout_openflag == 0x11) {
_fstrcat(awaitingcmd, ">>");
} else {
_fstrcat(awaitingcmd, ">");
}
d->stdoutfile = NULL;
}
/* redirect stdin of next command from a temp file (that is used as my output) */
_fstrcat(awaitingcmd, "<");
i = gentmpfile(tmpfile, envseg);
if (i != 0) return(i);
_fstrcat(awaitingcmd, tmpfile);
/* same file is used as my stdout */
d->stdoutfile = tmpfile;
d->stdout_openflag = 0x12;
}
return(0);
}
 
 
/* apply stdout redirections defined in redir_data, returns 0 on success */
int redir_apply(const struct redir_data *d) {
 
if (d->stdoutfile != NULL) {
unsigned short openflag = d->stdout_openflag;
unsigned short errcode = 0;
unsigned short handle = 0;
const char *myptr = d->stdoutfile;
 
/* */
_asm {
push ax
push bx
push cx
push dx
push si
mov ax, 0x6c00 /* Extended Open/Create */
mov bx, 1 /* access mode (0=read, 1=write, 2=r+w */
xor cx, cx /* attributes when(if) creating the file (0=normal) */
mov dx, [openflag] /* action if file exists (0x11=open, 0x12=truncate)*/
mov si, myptr /* ASCIIZ filename */
int 0x21 /* AX=handle on success (CF clear), otherwise dos err */
mov handle, ax /* save the file handler */
jnc JMPEOF
mov errcode, ax
jmp DONE
 
JMPEOF:
cmp openflag, word ptr 0x11
jne DUPSTDOUT
/* jump to the end of the file (required for >> redirections) */
mov ax, 0x4202 /* jump to position EOF - CX:DX in handle BX */
mov bx, handle
xor cx, cx
xor dx, dx
int 0x21
 
/* save (duplicate) current stdout so I can revert it later */
DUPSTDOUT:
mov ah, 0x45 /* duplicate file handle */
mov bx, 1 /* handle to dup (1=stdout) */
int 0x21 /* ax = new file handle */
mov oldstdout, ax
/* redirect the stdout handle */
mov bx, handle /* dst handle */
mov cx, 1 /* src handle (1=stdout) */
mov ah, 0x46 /* redirect a handle */
int 0x21
/* close the original file handle (no longer needed) */
mov ah, 0x3e /* close a file handle (handle in BX) */
int 0x21
DONE:
pop si
pop dx
pop cx
pop bx
pop ax
}
if (errcode != 0) {
nls_outputnl_doserr(errcode);
return(-1);
}
}
 
return(0);
}
 
 
/* restores previous stdout handle if is has been redirected */
void redir_revert(void) {
_asm {
/* if oldstdout is 0xffff then not redirected */
mov bx, [oldstdout] /* dst handle */
cmp bx, 0xffff
je DONE
/* redirect the stdout handle (handle already in BX) */
mov cx, 1 /* src handle (1=stdout) */
mov ah, 0x46 /* redirect a handle */
int 0x21
/* close old handle (in bx already) */
mov ah, 0x3e
int 0x21
mov [oldstdout], 0xffff
DONE:
}
}
/svarcom/tags/svarcom-2023.1/redir.h
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 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.
*/
 
#ifndef REDIR_H
#define REDIR_H
 
#define REDIR_MAX_PIPES 15
 
struct redir_data {
char *pipes[REDIR_MAX_PIPES + 1];
char *stdinfile;
char *stdoutfile;
unsigned short stdout_openflag; /* 0x11 or 0x12, used for the 'extended open' call */
};
 
/* parse commandline and performs necessary redirections. cmdline is
* modified so all redirections are cut out.
* piped commands are moved to awaitingcmd for later execution and a temporary file is created (either in current directory or in %TEMP%, if the latter is defined)
* returns 0 on success, DOS err on failure */
unsigned short redir_parsecmd(struct redir_data *d, char *cmdline, char far *awaitingcmd, unsigned short envseg);
 
/* apply stdin/stdout redirections defined in redir_data, returns 0 on success */
int redir_apply(const struct redir_data *d);
 
/* restores previous stdout/stdin handlers if they have been redirected */
void redir_revert(void);
 
#endif
/svarcom/tags/svarcom-2023.1/rmod.asm
0,0 → 1,324
;
; rmod - resident module of the SvarCOM command interpreter (NASM code)
;
; Copyright (C) 2021-2022 Mateusz Viste
; MIT license
;
; this is installed in memory by the transient part of SvarCOM. it has only
; two jobs: providing a resident buffer for command history, environment, etc
; and respawning COMMAND.COM whenever necessary.
 
CPU 8086
org 0x100
 
PSP_ENVSEG equ 0x2C
 
section .text ; all goes into code segment
 
; offset
SIG1 dw 0x1983 ; +0
SIG2 dw 0x1985 ; +2
SIG3 dw 0x2017 ; +4
SIG4 dw 0x2019 ; +6 acts also as a guardval to detect severe stack overflows
 
; Buffer used to remember previous command, when SvarCOM calls the buffered
; input service at INT 21h,AH=0x0A.
; This buffer is right before the stack, so in case of a stack overflow event
; (for example because of a "too ambitious" TSR) only this buffer is damaged,
; and can be invalidated without much harm. To detect such damage, SvarCOM's
; transient part is appending a signature at the end of the buffer.
INPUTBUF: times 132 db 0 ; 130 bytes for the input buffer + 2 for signature
 
; DOS int 21h functions that I use require at least 40 bytes of stack under
; DOS-C (FreeDOS) kernel, so here I reserve 64 bytes juste to be sure
STACKBUF db "XXX SVARCOM RMOD BY MATEUSZ VISTE XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
STACKPTR dw 0
 
; offset of the COMSPEC variable in the environment block, 0 means "use
; boot drive". this value is patched by the transient part of COMMAND.COM
COMSPECPTR dw 0 ; +CEh
 
; fallback COMSPEC string used if no COMPSEC is present in the environment
; drive. drive is patched by the transient part of COMMAND.COM
COMSPECBOOT db "@:\COMMAND.COM", 0 ; +D0h
 
; exit code of last application
LEXCODE db 0 ; +DFh
 
; ExecParamRec used by INT 21h, AX=4b00 (load and execute program), 14 bytes:
; offset size content
; +0 2 segment of environment for child (0 = current)
; +2 4 address of command line to place at PSP:0080
; +6 4 address of an FCB to be placed at PSP:005c
; +0Ah 4 address of an FCB to be placed at PSP:006c
EXEC_PARAM_REC db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; +E0h
 
; Program to execute, preset by SvarCOM (128 bytes, ASCIIZ)
EXECPROG: times 128 db 0 ; +EEh
 
; File where stdin and stdout should be redirected (0 = no redirection)
REDIR_INFIL: times 128 db 0 ; +16Eh
REDIR_OUTFIL: times 128 db 0 ; +1EEh
REDIR_OUTAPPEND: dw 0 ; +26Eh
REDIR_DEL_STDIN: db 0 ; +270h indicates that the stdin file
; should be deleted (pipes). This
; MUST contain the 1st char of
; REDIR_INFIL!
 
; CTRL+BREAK (int 23h) handler
; According to the TechHelp! Manual: "If you want to abort (exit to the parent
; process), then set the carry flag and return via a FAR RET. This causes DOS
; to perform normal cleanup and exit to the parent." (otherwise use iret)
BREAK_HANDLER: ; +271h
stc
retf
 
; INT 0x2E handler
INT2E:
xor ax, ax
iret
 
skipsig: ; +276h
 
; set up CS=DS=SS and point SP to my private stack buffer
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, STACKPTR
 
; set up myself as break handler (int 0x23)
mov ax, 0x2523 ; set int vector 23h
mov dx, BREAK_HANDLER
int 0x21
 
; set up myself as int 0x2E handler ("pass command to shell")
mov ax, 0x252E
mov dx, INT2E ; TODO do something meaningful instead of a no-op
int 0x21
 
; revert stdin/stdout redirections (if any) to their initial state
call REVERT_REDIR_IF_ANY
 
; redirect stdin and/or stdout if required
call REDIR_INOUTFILE_IF_REQUIRED
 
; should I executed command.com or a pre-set application?
or [EXECPROG], byte 0
jz EXEC_COMMAND_COM
 
; TODO: perhaps I should call the DOS SetPSP function here? But if I do, the
; int 21h, ah=50h call freezes...
;mov ah, 0x50 ; DOS 2+ -- Set PSP
;mov bx, cs
;int 0x21
 
; exec an application preset (by SvarCOM) in the ExecParamRec
mov ax, 0x4B00 ; DOS 2+ - load & execute program
mov dx, EXECPROG ; DS:DX - ASCIZ program name (preset at PSP[already)
mov bx, EXEC_PARAM_REC ; ES:BX - parameter block pointer
int 0x21
mov [cs:EXECPROG], byte 0 ; do not run app again (+DS might have been changed)
 
jmp short skipsig ; enforce valid ds/ss/etc (can be lost after int 21,4b)
 
EXEC_COMMAND_COM:
 
; collect the exit code of previous application
mov ah, 0x4D
int 0x21
mov [LEXCODE], al
 
; zero out the exec param block (14 bytes)
mov al, 0 ; byte to write
mov cx, 14 ; how many times
mov di, EXEC_PARAM_REC ; ES:DI = destination
cld ; stosb must move forward
rep stosb ; repeat cx times
 
; preset the default COMSPEC pointer to ES:DX (ES is already set to DS)
mov dx, COMSPECBOOT
 
; do I have a valid COMSPEC?
or [COMSPECPTR], word 0
jz USEDEFAULTCOMSPEC
; set ES:DX to actual COMSPEC (in env segment)
mov es, [PSP_ENVSEG]
mov dx, [COMSPECPTR]
USEDEFAULTCOMSPEC:
 
; prepare the exec param block
mov ax, [PSP_ENVSEG]
mov [EXEC_PARAM_REC], ax
mov [EXEC_PARAM_REC+2], word CMDTAIL
mov [EXEC_PARAM_REC+4], cs
 
; execute command.com
mov ax, 0x4B00 ; DOS 2+ - load & execute program
push es ;
pop ds ;
;mov dx, COMSPEC ; DS:DX - ASCIZ program name (preset already)
push cs
pop es
mov bx, EXEC_PARAM_REC ; ES:BX - parameter block pointer
int 0x21
 
; if all went well, jump back to start
jnc skipsig
 
; restore DS=CS
mov bx, cs
mov ds, bx
 
; update error string so it contains the error number
add al, '0'
mov [ERRLOAD + 4], al
 
; display error message
mov ah, 0x09
mov dx, ERRLOAD
int 0x21
 
; wait for keypress
mov ah, 0x08
int 0x21
 
; back to program start
jmp skipsig
 
; command.com tail arguments, in PSP format: length byte followed by args and
; terminated with \r) - a single 0x0A byte is passed so SvarCOM knows it is
; called as respawn (as opposed to being invoked as a normal application)
; this allows multiple copies of SvarCOM to stack upon each other.
CMDTAIL db 0x01, 0x0A, 0x0D
 
ERRLOAD db "ERR x, FAILED TO LOAD COMMAND.COM", 13, 10, '$'
 
; variables used to revert stdin/stdout to their initial state
OLD_STDOUT dw 0xffff
OLD_STDIN dw 0xffff
 
 
; ****************************************************************************
; *** ROUTINES ***************************************************************
; ****************************************************************************
 
; ----------------------------------------------------------------------------
; revert stdin/stdout redirections (if any) to their initial state
REVERT_REDIR_IF_ANY:
; is stdout redirected?
mov bx, [OLD_STDOUT]
cmp bx, 0xffff
je STDOUT_DONE
; revert the stdout handle (dst in BX already)
mov cx, 1 ; src handle (1=stdout)
mov ah, 0x46 ; redirect a handle
int 0x21
; close the old handle (still in bx)
mov ah, 0x3e
int 0x21
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected"
STDOUT_DONE:
 
; is stdin redirected?
mov bx, [OLD_STDIN]
cmp bx, 0xffff
je STDIN_DONE
; revert the stdin handle (dst in BX already)
xor cx, cx ; src handle (0=stdin)
mov ah, 0x46 ; redirect a handle
int 0x21
; close the old handle (still in bx)
mov ah, 0x3e
int 0x21
mov [OLD_STDIN], word 0xffff ; mark stdin as "not redirected"
 
; delete stdin file if required
cmp [REDIR_DEL_STDIN], byte 0
je STDIN_DONE
; revert the original file and delete it
mov ah, [REDIR_DEL_STDIN]
mov [REDIR_INFIL], ah
mov ah, 0x41 ; DOS 2+ - delete file pointed at by DS:DX
mov dx, REDIR_INFIL
int 0x21
mov [REDIR_INFIL], byte 0
mov [REDIR_DEL_STDIN], byte 0
 
STDIN_DONE:
 
ret
; ----------------------------------------------------------------------------
 
 
; ----------------------------------------------------------------------------
; redirect stdout if REDIR_OUTFIL points to something
REDIR_INOUTFILE_IF_REQUIRED:
cmp [REDIR_OUTFIL], byte 0
je NO_STDOUT_REDIR
mov si, REDIR_OUTFIL ; si = output file
mov ax, 0x6c00 ; Extended Open/Create
mov bx, 1 ; access mode (0=read, 1=write, 2=r+w)
xor cx, cx ; file attribs when(if) file is created (0=normal)
mov dx, [REDIR_OUTAPPEND] ; action if file exist (0x11=open, 0x12=truncate)
int 0x21 ; ax=handle on success (CF clear)
mov [REDIR_OUTFIL], byte 0
jc NO_STDOUT_REDIR ; TODO: abort with an error message instead
 
; jump to end of file if flag was 0x11 (required for >> redirections)
cmp [REDIR_OUTAPPEND], word 0x11
jne SKIP_JMPEOF
mov bx, ax
mov ax, 0x4202 ; jump to position EOF - CX:DX in handle BX
xor cx, cx
xor dx, dx
int 0x21
mov ax, bx ; put my handle back in ax, as expected by later code
SKIP_JMPEOF:
 
; duplicate current stdout so I can revert it later
push ax ; save my file handle in stack
mov ah, 0x45 ; duplicate file handle BX
mov bx, 1 ; 1 = stdout
int 0x21 ; ax=new (duplicated) file handle
mov [OLD_STDOUT], ax ; save the old handle in memory
 
; redirect stdout to my file
pop bx ; dst handle
mov cx, 1 ; src handle (1=stdout)
mov ah, 0x46 ; "redirect a handle"
int 0x21
 
; close the original file handle, I no longer need it
mov ah, 0x3e ; close a file handle (handle in BX)
int 0x21
NO_STDOUT_REDIR:
 
; *** redirect stdin if REDIR_INFIL points to something ***
cmp [REDIR_INFIL], byte 0
je NO_STDIN_REDIR
mov dx, REDIR_INFIL ; dx:dx = file
mov ax, 0x3d00 ; open file for read
int 0x21 ; ax=handle on success (CF clear)
mov [REDIR_INFIL], byte 0
jc NO_STDIN_REDIR ; TODO: abort with an error message instead
 
; duplicate current stdin so I can revert it later
push ax ; save my file handle in stack
mov ah, 0x45 ; duplicate file handle BX
xor bx, bx ; 0=stdin
int 0x21 ; ax=new (duplicated) file handle
mov [OLD_STDIN], ax ; save the old handle in memory
 
; redirect stdout to my file
pop bx ; dst handle
xor cx, cx ; src handle (0=stdin)
mov ah, 0x46 ; "redirect a handle"
int 0x21
 
; close the original file handle, I no longer need it
mov ah, 0x3e ; close a file handle (handle in BX)
int 0x21
NO_STDIN_REDIR:
ret
; ----------------------------------------------------------------------------
/svarcom/tags/svarcom-2023.1/rmodinit.c
0,0 → 1,343
/* 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.
*/
 
#include <i86.h>
#include <string.h>
 
#include "env.h"
#include "helpers.h"
 
#include "rmodinit.h"
 
 
/* returns far pointer to rmod's settings block on success */
struct rmod_props far *rmod_install(unsigned short envsize, unsigned char *rmodcore, unsigned short rmodcore_len) {
char far *myptr, far *mcb;
unsigned short far *owner;
const unsigned short sizeof_rmodandprops_paras = (0x100 + rmodcore_len + sizeof(struct rmod_props) + 15) / 16;
unsigned short rmodseg = 0xffff;
unsigned short envseg, origenvseg;
struct rmod_props far *res;
 
/* read my current env segment from PSP and save it */
envseg = *((unsigned short *)0x2c);
origenvseg = envseg;
 
/* printf("original (PSP) env buffer at %04X\r\n", envseg); */
 
/* if envseg is zero, then enforce our own one (MSDOS 5 does not provide a default env) */
if ((envseg == 0) && (envsize == 0)) envsize = 256;
 
/* if custom envsize requested, convert it to number of paragraphs */
if (envsize != 0) {
envsize += 15;
envsize /= 16;
}
 
_asm {
/* link in the UMB memory chain for enabling high-memory allocation (and save initial status on stack) */
mov ax, 0x5802 /* GET UMB LINK STATE */
int 0x21
xor ah, ah
push ax /* save link state on stack */
mov ax, 0x5803 /* SET UMB LINK STATE */
mov bx, 1
int 0x21
/* get current allocation strategy and save it in DX */
mov ax, 0x5800
int 0x21
push ax
pop dx
/* set strategy to 'last fit, try high then low memory' */
mov ax, 0x5801
mov bx, 0x0082
int 0x21
/* ask for a memory block and save the given segment to rmodseg */
mov ah, 0x48
mov bx, sizeof_rmodandprops_paras
int 0x21
jc ALLOC_FAIL
mov rmodseg, ax
/* ask for a memory block for the environment and save it to envseg (only if custom size requested) */
mov bx, envsize
test bx, bx
jz ALLOC_FAIL
mov ah, 0x48
int 0x21
jc ALLOC_FAIL
mov envseg, ax
 
ALLOC_FAIL:
/* restore initial allocation strategy */
mov ax, 0x5801
mov bx, dx
int 0x21
/* restore initial UMB memory link state */
mov ax, 0x5803
pop bx /* pop initial UMB link state from stack */
int 0x21
}
 
if (rmodseg == 0xffff) {
outputnl("malloc error");
return(NULL);
}
 
/* copy rmod to its destination, prefixed with a copy of my own PSP */
myptr = MK_FP(rmodseg, 0);
{
unsigned short i;
char *mypsp = (void *)0;
for (i = 0; i < 0x100; i++) myptr[i] = mypsp[i];
}
myptr = MK_FP(rmodseg, 0x100);
_fmemcpy(myptr, rmodcore, rmodcore_len);
 
/* mark rmod memory as "self owned" */
mcb = MK_FP(rmodseg - 1, 0);
owner = (void far *)(mcb + 1);
*owner = rmodseg;
_fmemcpy(mcb + 8, "SVARCOM", 8);
 
/* mark env memory as "owned by rmod" */
mcb = MK_FP(envseg - 1, 0);
owner = (void far *)(mcb + 1);
*owner = rmodseg;
_fmemcpy(mcb + 8, "SVARENV", 8);
 
/* if env block is newly allocated, fill it with a few NULLs */
if (envsize != 0) {
owner = MK_FP(envseg, 0);
owner[0] = 0;
owner[1] = 0;
}
 
/* set CTRL+BREAK handler to rmod */
_asm {
push ax
push dx
push ds
mov ax, 0x2523
mov ds, rmodseg
mov dx, RMOD_OFFSET_BRKHANDLER
int 0x21
pop ds
pop dx
pop ax
}
 
/* mark the input buffer as empty */
myptr = MK_FP(rmodseg, RMOD_OFFSET_INPUTBUF);
myptr[0] = 128; /* max acceptable length */
myptr[1] = 0; /* len of currently stored history string */
myptr[2] = '\r'; /* string terminator */
myptr[3] = 0xCA; /* signature to detect stack overflow damaging the buffer */
myptr[4] = 0xFE; /* 2nd byte of the signature */
 
/* prepare result (rmod props) */
res = MK_FP(rmodseg, 0x100 + rmodcore_len);
_fmemset(res, 0, sizeof(*res)); /* zero out */
res->rmodseg = rmodseg; /* rmod segment */
res->origenvseg = origenvseg; /* original environment segment */
 
/* write env segment to rmod's PSP */
owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
*owner = envseg;
 
/* write boot drive to rmod bootdrive field */
_asm {
push ax
push bx
push dx
push ds
mov ax, 0x3305 /* DOS 4.0+ - GET BOOT DRIVE */
int 0x21 /* boot drive is in DL now (1=A:, 2=B:, etc) */
add dl, 'A'-1 /* convert to a proper ASCII letter */
/* set DS to rmodseg */
mov ax, rmodseg
mov ds, ax
/* write boot drive to rmod bootdrive field */
mov bx, RMOD_OFFSET_BOOTDRIVE
mov [bx], dl
pop ds
pop dx
pop bx
pop ax
}
 
/* save my original parent in rmod's memory */
res->origparent = *((unsigned long *)0x0a); /* original parent seg:off is at 0x0a of my PSP */
 
/* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I
* terminate and save the original handler in rmod's memory */
{
unsigned short *ptr = (void *)0x0a; /* int22 handler is at 0x0A of the PSP */
ptr[0] = RMOD_OFFSET_ROUTINE;
ptr[1] = rmodseg;
}
 
return(res);
}
 
 
/* look up my parent: if it's rmod then return a ptr to its props struct,
* otherwise return NULL
* I look at PSP[Ch] to locate RMOD (ie. the "terminate address") */
struct rmod_props far *rmod_find(unsigned short rmodcore_len) {
unsigned short *parent = (void *)0x0C;
unsigned short far *ptr;
const unsigned short sig[] = {0x1983, 0x1985, 0x2017, 0x2019};
unsigned char *cmdtail = (void *)0x80;
unsigned char i;
/* is it rmod? */
ptr = MK_FP(*parent, 0x100);
for (i = 0; i < 4; i++) if (ptr[i] != sig[i]) return(NULL);
/* match successfull (rmod is my parent) - but is it really a respawn?
* command-line tail should contain a single character '\r' */
if ((cmdtail[0] != 1) || (cmdtail[1] != '\n')) return(NULL);
cmdtail[0] = 0;
cmdtail[1] = '\r';
/* */
return(MK_FP(*parent, 0x100 + rmodcore_len));
}
 
 
/* update rmod's pointer to comspec */
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg) {
unsigned short far *comspecptr = MK_FP(rmod_seg, RMOD_OFFSET_COMSPECPTR);
char far *comspecfp = env_lookup_val(env_seg, "COMSPEC");
if (comspecfp != NULL) {
*comspecptr = FP_OFF(comspecfp);
} else {
*comspecptr = 0;
}
}
 
 
/* allocates bytes of far memory, flags it as belonging to rmod
* the new block can be optionally flagged as 'ident' (if not null) and zero
* out the newly allocated memory.
* returns a far ptr to the allocated block, or NULL on error */
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) {
unsigned short far *owner;
unsigned short newseg = 0;
 
/* ask DOS for a memory block (as high as possible) */
_asm {
push bx /* save initial value in BX so I can restore it later */
 
/* get current allocation strategy and save it on stack */
mov ax, 0x5800
int 0x21
push ax
 
/* set strategy to 'last fit, try high then low memory' */
mov ax, 0x5801
mov bx, 0x0082
int 0x21
 
/* ask for a memory block and save the given segment to rmodseg */
mov ah, 0x48 /* Allocate Memory */
mov bx, bytes
add bx, 15 /* convert bytes to paragraphs */
shr bx, 1 /* bx /= 16 */
shr bx, 1
shr bx, 1
shr bx, 1
int 0x21
 
/* error handling */
jc FAIL
 
/* save newly allocated segment to newseg */
mov newseg, ax
 
FAIL:
/* restore initial allocation strategy */
mov ax, 0x5801
pop bx
int 0x21
 
pop bx /* restore BX to its initial value */
}
 
if (newseg == 0) return(NULL);
 
/* mark memory as "owned by rmod" */
owner = (void far *)(MK_FP(newseg - 1, 1));
*owner = rmod_seg;
 
/* set the MCB description to ident, if provided */
if (ident) {
char far *mcbdesc = MK_FP(newseg - 1, 8);
int i;
_fmemset(mcbdesc, 0, 8);
for (i = 0; (i < 8) && (ident[i] != 0); i++) { /* field's length is limited to 8 bytes max */
mcbdesc[i] = ident[i];
}
}
 
/* zero out the memory before handing it out */
_fmemset(MK_FP(newseg, 0), 0, bytes);
 
return(MK_FP(newseg, 0));
}
 
 
/* free memory previously allocated by rmod_fcalloc() */
void rmod_ffree(void far *ptr) {
unsigned short ptrseg;
unsigned short myseg = 0;
unsigned short far *owner;
if (ptr == NULL) return;
ptrseg = FP_SEG(ptr);
 
/* get my own segment */
_asm {
mov myseg, cs
}
 
/* mark memory in MCB as my own, otherwise DOS might refuse to free it */
owner = MK_FP(ptrseg - 1, 1);
*owner = myseg;
 
/* free the memory block */
_asm {
push es
mov ah, 0x49 /* Free Memory Block */
mov es, ptrseg
int 0x21
pop es
}
}
 
 
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
void rmod_free_bat_llist(struct rmod_props far *rmod) {
while (rmod->bat != NULL) {
struct batctx far *victim = rmod->bat;
rmod->bat = rmod->bat->parent;
rmod_ffree(victim);
}
}
/svarcom/tags/svarcom-2023.1/rmodinit.h
0,0 → 1,100
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021-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.
*/
 
#ifndef RMODINIT_H
#define RMODINIT_H
 
#include "helpers.h" /* struct DTA definition */
 
#define FLAG_EXEC_AND_QUIT 1
#define FLAG_PERMANENT 2
#define FLAG_ECHOFLAG 4
#define FLAG_ECHO_BEFORE_BAT 8
#define FLAG_SKIP_AUTOEXEC 16
#define FLAG_STEPBYSTEP 32
 
 
/* batch context structure used to track what batch file is being executed,
* at what line, arguments, whether or not it has a parent batch... */
struct batctx {
char fname[130]; /* truename of batch file being processed */
char argv[130]; /* args of the batch call (0-separated) */
unsigned char flags; /* used for step-by-step execution */
unsigned long nextline; /* offset in file of next bat line to process */
struct batctx far *parent; /* parent context if this batch was CALLed */
};
 
/* for context structure used to track the execution of the ongoing FOR loop */
struct forctx {
char cmd[130]; /* copy of the original FOR command */
struct DTA dta; /* DTA for FindNext on current pattern */
unsigned short curpat; /* cmd offset of currently processed pattern */
unsigned short nextpat; /* cmd offset of next pattern to be processed */
unsigned short exec; /* cmd offset of the command to be executed */
char varname; /* single char of variable name */
unsigned char dta_inited; /* 0=requires FindFirst 1=FindNext */
};
 
struct rmod_props {
unsigned short rmodseg; /* segment where rmod is loaded */
unsigned long origparent; /* original parent (far ptr) of the shell */
unsigned short origenvseg; /* original environment segment */
unsigned char flags; /* command line parameters */
unsigned char version; /* used to detect mismatch between rmod and SvarCOM */
char awaitingcmd[130]; /* command to exec next time (if any) */
struct batctx far *bat; /* linked list of bat contexts, if BAT ongoing */
struct forctx far *forloop; /* a single FOR loop structure, if FOR ongoing */
};
 
#define RMOD_OFFSET_ENVSEG 0x2C /* stored in rmod's PSP */
#define RMOD_OFFSET_INPUTBUF (0x100 + 0x08)
#define RMOD_OFFSET_COMSPECPTR (0x100 + 0xCE)
#define RMOD_OFFSET_BOOTDRIVE (0x100 + 0xD0)
#define RMOD_OFFSET_LEXITCODE (0x100 + 0xDF)
#define RMOD_OFFSET_EXECPARAM (0x100 + 0xE0)
#define RMOD_OFFSET_EXECPROG (0x100 + 0xEE)
#define RMOD_OFFSET_STDINFILE (0x100 + 0x16E)
#define RMOD_OFFSET_STDOUTFILE (0x100 + 0x1EE)
#define RMOD_OFFSET_STDOUTAPP (0x100 + 0x26E)
#define RMOD_OFFSET_STDIN_DEL (0x100 + 0x270)
#define RMOD_OFFSET_BRKHANDLER (0x100 + 0x271)
#define RMOD_OFFSET_ROUTINE (0x100 + 0x276)
 
struct rmod_props far *rmod_install(unsigned short envsize, unsigned char *rmodcore, unsigned short rmodcore_len);
struct rmod_props far *rmod_find(unsigned short rmodcore_len);
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg);
 
/* allocates bytes of far memory, flags it as belonging to rmod
* the new block can be optionally flagged as 'ident' (if not null) and zero
* out the newly allocated memory.
* returns a far ptr to the allocated block, or NULL on error */
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident);
 
/* free memory previously allocated by rmod_fcalloc() */
void rmod_ffree(void far *ptr);
 
/* free the entire linked list of bat ctx nodes (and set its rmod ptr to NULL) */
void rmod_free_bat_llist(struct rmod_props far *rmod);
 
#endif
/svarcom/tags/svarcom-2023.1/sayonara.c
0,0 → 1,63
/* 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.
*/
 
#include <i86.h>
 
#include "rmodinit.h"
 
#include "sayonara.h"
 
 
/* rewires my parent pointer, uninstalls rmod let DOS terminate me, UNLESS
* my parent is unknown */
void sayonara(struct rmod_props far *rmod) {
unsigned short rmodseg = rmod->rmodseg;
unsigned long *myparent = (void *)0x0A;
unsigned short far *rmodenv_ptr = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
unsigned short rmodenv = *rmodenv_ptr;
 
/* detect "I am the origin shell" situations */
if (rmod->flags & FLAG_PERMANENT) return; /* COMMAND.COM /P */
if ((rmod->origparent >> 16) == 0xffff) return; /* original parent seg set to 0xffff (DOS-C / FreeDOS) */
if (rmod->origenvseg == 0) return; /* no original environment (MSDOS 5/6) */
 
/* set my parent back to original value */
*myparent = rmod->origparent;
 
_asm {
/* free RMOD's code segment and env segment */
mov ah, 0x49 /* DOS 2+ -- Free Memory Block */
mov es, [rmodseg]
int 0x21
 
/* free RMOD's env segment */
mov ah, 0x49 /* DOS 2+ -- Free Memory Block */
mov es, [rmodenv]
int 0x21
 
/* gameover */
mov ax, 0x4C00 /* DOS 2+ -- Terminate with exit code 0 */
int 0x21
}
}
/svarcom/tags/svarcom-2023.1/sayonara.h
0,0 → 1,34
/* 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.
*/
 
#ifndef SAYONARA_H
#define SAYONARA_H
 
#include "rmodinit.h"
 
/* rewires my parent pointer, uninstalls rmod let DOS terminate me, UNLESS
* my parent is unknown */
void sayonara(struct rmod_props far *rmod);
 
#endif
/svarcom/tags/svarcom-2023.1/svarcom.lsm
0,0 → 1,2
Description: the SvarDOS command line interpreter (COMMAND.COM shell)
Version: 2023.1
/svarcom/tags/svarcom-2023.1/svarcom.txt
0,0 → 1,105
 
 
=== SVARCOM ===
 
 
SvarCOM is the SvarDOS command line interpreter, known usually under the name
"COMMAND.COM". It is designed and maintained by Mateusz Viste, and distributed
under the terms of the MIT license.
 
SvarCOM is minimalist and I'd like to keep it that way. It aims to be
functionaly equivalent to COMMAND.COM from MS-DOS 5.x/6.x. No LFN support.
 
SvarCOM's resident footprint is under 2 KiB.
 
Translation strings are stored in the file SVARCOM.LNG, which should be
placed in a directory pointed at by %NLSPATH% for SvarCOM to be able to output
messages in non-english languages. SvarCOM's language is controlled by the
%LANG% environment variable.
 
Latest version available here: http://svardos.org/svarcom
 
 
=== INTERNAL COMMANDS ========================================================
 
SvarCOM implements the following internal commands. For help on each command,
run it with a "/?" argument.
 
BREAK - sets or clears extended CTRL+C checking
CALL - calls a batch file from within another batch file
CD/CHDIR - displays the name of or changes the current directory
CHCP - displays or sets the active code page number
CLS - clears the screen
COPY - copies one or more files to another location
DATE - displays or sets the system date
DEL/ERASE - deletes one or more files
DIR - displays a list of files and subdirectories in a directory
ECHO - displays messages, or turns command-echoing on or off
EXIT - quits the command.com program (command interpreter)
FOR - runs a specified command for each element in a list
GOTO - directs batch processing to a labelled line in the batch program
IF - performs conditional processing in batch programs
LN - adds, deletes and displays global executable links
MD/MKDIR - creates a directory
PATH - displays or sets a search path for executable files
PAUSE - suspends processing of a batch program
PROMPT - changes the DOS command prompt
RD/RMDIR - removes (deletes) a directory
REM - records comments (remarks) in a batch file
REN/RENAME - renames one or more files or directories
SET - displays, sets or removes DOS environment variables
SHIFT - changes the position of arguments in a batch file
TIME - displays or sets the system time
TRUENAME - returns a fully qualified path or filename
TYPE - displays the contents of a text file
VER - displays the DOS kernel and SvarCOM shell versions
VERIFY - tells DOS whether to verify that files are written correctly
VOL - displays the disk volume label and serial number
 
 
=== INSTALLATION =============================================================
 
Installing SvarCOM requires to either copy it to the root of your boot drive
replacing your current COMMAND.COM, or adding a SHELL directive to your
CONFIG.SYS file to instruct DOS that it should load SvarCOM as its shell, eg.:
 
SHELL=C:\SVARCOM\COMMAND.COM /P
 
Some DOSes support a SHELLHIGH directive that loads the shell in high memory.
It is pointless to use it to load SvarCOM. SvarCOM will load its resident part
as high as possible on its own, enforcing this through SHELLHIGH could even
be harmful since SvarCOM wouldn't be able to relocate to the highest address
as it would be allocated by SHELLHIGH already.
 
SvarCOM supports multiple languages. To enable SvarCOM using them it is
necessary to define an NLSPATH environment variable that would point to a
directory and copy the SVARCOM.LNG file there. Once done, SvarCOM will try
loading whatever language is being set up in the LANG environment variable.
 
 
=== LICENSE ==================================================================
 
SvarCOM 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.
 
 
====================================================================== EOF ===
/svarcom/tags/svarcom-2023.1/svarlang.lib
0,0 → 1,0
link ../../svarlang.lib/tags/20220314
Property changes:
Added: svn:special
+*
\ No newline at end of property
/svarcom/tags/svarcom-2023.1/toys/erlev.c
0,0 → 1,7
#include <stdio.h>
#include <stdlib.h>
 
int main(int argc, char **argv) {
int d = atoi(argv[1]);
return(d);
}
/svarcom/tags/svarcom-2023.1/toys/fcbdir.asm
0,0 → 1,77
;
; lists files using first or second FCB provided by COMMAND.COM in PSP
; Copyright (C) 2022 Mateusz Viste
;
; to be assembled with NASM.
;
; lists file entries matching first argument of the program using the default
; unopened FCB entry in PSP as preset by COMMAND.COM.
;
; usage: fcbdir file-pattern
;
; example: fcbdir c:*.txt
;
 
CPU 8086
org 0x100
 
; print whatever drive/filename is set at 0x5C (1st unopened FCB in the PSP)
mov dx, PARAM
mov ah, 0x09
int 0x21
 
mov bx, 0x5C
call PRINTDTA
 
; FindFirst_FCB applied to PSP:5C (1st unopened FCB)
mov dx, 0x5C
mov ah, 0x11
int 0x21
 
cmp al, 0
jne GAMEOVER
 
NEXT:
 
; print filename in DTA
mov bx, 0x80
call PRINTDTA
 
; FindNext_FCB on PSP until nothing left
mov ah, 0x12
mov dx, 0x5C
int 0x21
cmp al, 0
je NEXT
 
GAMEOVER:
 
int 0x20
 
PARAM:
db "PARAMETER = $";
 
 
; ****** print the filename present in the DTA (DTA is at [BX]) ******
PRINTDTA:
; print drive in the DTA
mov ah, 0x02
mov dl, [bx]
add dl, '@'
int 0x21
mov dl, ':'
int 0x21
; print filename/extension (in FCB format)
mov ah, 0x40 ; write to file
mov cx, 11 ; 11 bytes (8+3)
mov dx, bx ; filename field at the default DTA location
inc dx
mov bx, 1 ; output to stdout
int 0x21
; print a trailing CR/LF
mov ah, 0x02 ; display character in DL
mov dl, 0x0D ; CR
int 0x21
mov dl, 0x0A ; LF
int 0x21
ret
/svarcom/tags/svarcom-2023.1/toys/hackz.c
0,0 → 1,41
/*
* reads stdin and writes to stdout after hacker-like conversion
*/
 
#include <stdio.h>
 
int main(void) {
int c;
 
while ((c = getchar()) != EOF) {
switch (c) {
case 'o':
case 'O':
c = '0';
break;
case 'i':
case 'I':
c = '1';
break;
case 'A':
c = '4';
break;
case 'a':
c = '@';
break;
case 'S':
c = '$';
break;
case 'e':
case 'E':
c = '3';
break;
case '0':
c = 'o';
break;
}
putchar(c);
}
 
return(0);
}
/svarcom/tags/svarcom-2023.1/toys/makefile
0,0 → 1,16
 
CFLAGS = -0 -mt -wx -lr -we -ox
 
all: erlev.com upcase.com hackz.com fcbdir.com
 
erlev.com: erlev.c
*wcl $(CFLAGS) $<
 
upcase.com: upcase.c
*wcl $(CFLAGS) $<
 
hackz.com: hackz.c
*wcl $(CFLAGS) $<
 
fcbdir.com: fcbdir.asm
nasm fcbdir.asm -o fcbdir.com
/svarcom/tags/svarcom-2023.1/toys/readme.txt
0,0 → 1,2
This directory contains tiny applications that are overall not very useful.
Their job is only to help me test SvarCOM.
/svarcom/tags/svarcom-2023.1/toys/upcase.c
0,0 → 1,16
/*
* reads stdin and writes to stdout after upcasing
*/
 
#include <stdio.h>
 
int main(void) {
int c;
 
while ((c = getchar()) != EOF) {
if ((c >= 'a') && (c <= 'z')) c -= ('a' - 'A');
putchar(c);
}
 
return(0);
}