//svarcom/trunk/command.c |
---|
731,6 → 731,7 |
static char *cmdline; |
static struct redir_data redirprops; |
static enum cmd_result cmdres; |
static unsigned short i; /* general-purpose variable for short-lived things */ |
rmod = rmod_find(BUFFER_len); |
if (rmod == NULL) { |
793,6 → 794,13 |
/* (re)load translation strings if needed */ |
nls_langreload(BUFFER, *rmod_envseg); |
/* load awaiting command, if any (used to run piped commands) */ |
if (rmod->awaitingcmd[0] != 0) { |
_fstrcpy(cmdline, rmod->awaitingcmd); |
rmod->awaitingcmd[0] = 0; |
goto EXEC_CMDLINE; |
} |
/* skip user input if I have a command to exec (/C or /K) */ |
if (cfg.execcmd != NULL) { |
cmdline = cfg.execcmd; |
844,7 → 852,12 |
rmod_updatecomspecptr(rmod->rmodseg, *rmod_envseg); |
/* handle redirections (if any) */ |
redir_parsecmd(&redirprops, cmdline); |
i = redir_parsecmd(&redirprops, cmdline, rmod->awaitingcmd); |
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); |
//svarcom/trunk/history.txt |
---|
6,6 → 6,7 |
=== ver 2021.1 (xx.xx.2021) ================================================== |
- 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) |
//svarcom/trunk/redir.c |
---|
24,6 → 24,7 |
#include <string.h> /* memset() */ |
#include "env.h" |
#include "helpers.h" |
#include "rmodinit.h" |
32,13 → 33,44 |
static unsigned short oldstdout = 0xffff; |
/* compute a filename to be used for pipes */ |
static unsigned short gentmpfile(char *s) { |
unsigned short err = 0; |
/* do I have a %temp% path? */ |
/* TODO */ |
/* 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 */ |
CLOSEFILE: |
mov ah, 0x3e |
mov bx, ax |
int 0x21 |
DONE: |
} |
return(err); |
} |
#include <stdio.h> |
/* parse commandline and performs necessary redirections. cmdline is |
* modified so all redirections are cut out. */ |
void redir_parsecmd(struct redir_data *d, char *cmdline) { |
* modified so all redirections are cut out. |
* piped commands are move 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 i; |
unsigned short pipescount = 0; |
/* NOTE: |
/* NOTES: |
* |
* 1. while it is possible to type a command with multiple |
* redirections, MSDOS executes only the last redirection. |
47,6 → 79,7 |
* 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 */ |
55,6 → 88,8 |
/* 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] == '>') { |
81,15 → 116,42 |
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); |
if (i != 0) return(i); |
_fstrcat(awaitingcmd, tmpfile); |
/* same file is used as my stdout */ |
d->stdoutfile = tmpfile; |
d->stdout_openflag = 0x12; |
/* TODO I need to remember that the tmp file must be removed... */ |
/* outputnl("awaitingcmd:"); |
for (i = 0; awaitingcmd[i] != 0; i++) printf("%c", awaitingcmd[i]); |
printf("\r\n");*/ |
} |
return(0); |
} |
/* apply stdin/stdout redirections defined in redir_data, returns 0 on success */ |
/* apply stdout redirections defined in redir_data, returns 0 on success */ |
int redir_apply(const struct redir_data *d) { |
if (d->stdinfile != NULL) { |
outputnl("ERROR: stdin redirection is not supported yet"); |
return(-1); |
} |
if (d->stdoutfile != NULL) { |
unsigned short openflag = d->stdout_openflag; |
156,7 → 218,7 |
} |
/* restores previous stdout/stdin handlers if they have been redirected */ |
/* restores previous stdout handle if is has been redirected */ |
void redir_revert(void) { |
_asm { |
/* if oldstdout is 0xffff then not redirected */ |
//svarcom/trunk/redir.h |
---|
35,8 → 35,10 |
}; |
/* parse commandline and performs necessary redirections. cmdline is |
* modified so all redirections are cut out. */ |
void redir_parsecmd(struct redir_data *r, char *cmdline); |
* modified so all redirections are cut out. |
* piped commands are move 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); |
/* apply stdin/stdout redirections defined in redir_data, returns 0 on success */ |
int redir_apply(const struct redir_data *d); |
//svarcom/trunk/rmod.asm |
---|
81,7 → 81,7 |
call REVERT_REDIR_IF_ANY |
; redirect stdout if required |
call REDIR_OUTFILE_IF_REQUIRED |
call REDIR_INOUTFILE_IF_REQUIRED |
; should I executed command.com or a pre-set application? |
or [EXECPROG], byte 0 |
201,6 → 201,21 |
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 stdout 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" |
STDIN_DONE: |
ret |
; ---------------------------------------------------------------------------- |
207,7 → 222,7 |
; ---------------------------------------------------------------------------- |
; redirect stdout if REDIR_OUTFIL points to something |
REDIR_OUTFILE_IF_REQUIRED: |
REDIR_INOUTFILE_IF_REQUIRED: |
mov si, [REDIR_OUTFIL] |
cmp si, 0xffff |
je NO_STDOUT_REDIR |
248,5 → 263,33 |
mov ah, 0x3e ; close a file handle (handle in BX) |
int 0x21 |
NO_STDOUT_REDIR: |
; *** redirect stdin if REDIR_INFIL points to something *** |
mov dx, [REDIR_INFIL] |
cmp dx, 0xffff |
je NO_STDIN_REDIR |
add dx, EXECPROG ; ds:dx=file |
mov ax, 0x3d00 ; open file for read |
int 0x21 ; ax=handle on success (CF clear) |
mov [REDIR_INFIL], word 0xffff |
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/trunk/rmodinit.h |
---|
41,6 → 41,7 |
char batfile[130]; /* truename of batch file being processed */ |
char batargv[130]; /* args of the batch call (0-separated) */ |
unsigned long batnextline; /* offset in file of next bat line to process */ |
char awaitingcmd[130]; /* command to exec next time (if any) */ |
}; |
#define RMOD_OFFSET_ENVSEG 0x2C /* stored in rmod's PSP */ |
//svarcom/trunk/svarcom.txt |
---|
11,16 → 11,13 |
Why replacing FreeCOM, you ask? See FREECOM.TXT for details. |
SvarCOM is a work-in-progress effort. As such, it still lacks a few things: |
- pipes (cmd.exe | more) and stdin redirections (cmd.exe < file) |
- advanced batch constructs (conditionals, errorlevels...) |
- a few internal commands missing: CALL, CTTY, GOTO, IF, LH |
- DIR misses a few switches (/S, /O, /A) |
- ... (see TODO.TXT for more details) |
- a few internal commands missing: CALL, CTTY, GOTO, LH |
- DIR misses two switches: /S, /O |
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. |
As of version 2021.0, SvarCOM's resident footprint is under 2 KiB. |
As of version 2021.1, 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 |
46,6 → 43,7 |
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) |
IF - performs conditional processing in batch programs |
MD/MKDIR - creates a directory |
PATH - displays or sets a search path for executable files |
PAUSE - suspends processing of a batch program |
//svarcom/trunk/todo.txt |
---|
7,7 → 7,9 |
=== HIGH PRIORITY ============================================================ |
pipes redirections |
delete temporary files after pipe redirections |
write temporary pipe files to %TEMP% if defined |
test pipe redirections (multiple redirections, failure to create file, ...) |
int 24h handler (abort, retry, fail, ignore) |
advanced batch constructs: CALL, FOR, GOTO |
IF EXIST on an empty drive should not lead to the 'Abort, Retry, Fail' prompt |