//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); |
} |