/svarcom/trunk/cmd.c |
---|
36,6 → 36,7 |
#include "doserr.h" |
#include "env.h" |
#include "helpers.h" |
#include "redir.h" |
#include "rmodinit.h" |
#include "sayonara.h" |
198,9 → 199,10 |
} |
int cmd_process(struct rmod_props far *rmod, unsigned short env_seg, const char *cmdline, void *BUFFER, unsigned short BUFFERSZ) { |
int cmd_process(struct rmod_props far *rmod, unsigned short env_seg, const char *cmdline, void *BUFFER, unsigned short BUFFERSZ, const struct redir_data *redir) { |
const struct CMD_ID *cmdptr; |
unsigned short argoffset; |
int cmdres; |
struct cmd_funcparam *p = (void *)BUFFER; |
p->BUFFERSZ = BUFFERSZ - sizeof(*p); |
237,6 → 239,9 |
/* 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(-1); |
/* 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; |
244,5 → 249,10 |
p->argoffset = argoffset; |
p->cmdline = cmdline; |
return((cmdptr->func_ptr)(p)); |
cmdres = (cmdptr->func_ptr)(p); |
/* cancel redirections */ |
redir_revert(); |
return(cmdres); |
} |
/svarcom/trunk/cmd.h |
---|
28,7 → 28,7 |
#include "rmodinit.h" |
/* process internal commands */ |
int cmd_process(struct rmod_props far *rmod, unsigned short env_seg, const char *cmdline, void *BUFFER, unsigned short BUFFERSZ); |
int cmd_process(struct rmod_props far *rmod, unsigned short env_seg, const char *cmdline, void *BUFFER, unsigned short BUFFERSZ, const struct redir_data *r); |
/* 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 |
/svarcom/trunk/command.c |
---|
350,7 → 350,7 |
} |
static void run_as_external(char *buff, const char *cmdline, unsigned short envseg, struct rmod_props far *rmod) { |
static void run_as_external(char *buff, const char *cmdline, unsigned short envseg, struct rmod_props far *rmod, struct redir_data *redir) { |
char *cmdfile = buff + 512; |
const char far *pathptr; |
int lookup; |
429,9 → 429,30 |
return; |
} |
/* copy full filename to execute */ |
/* copy full filename to execute, along with redirected files (if any) */ |
for (i = 0; cmdfile[i] != 0; i++) rmod_execprog[i] = cmdfile[i]; |
rmod_execprog[i] = 0; |
rmod_execprog[i++] = 0; |
if (redir->stdinfile) { |
unsigned short far *farptr = MK_FP(rmod->rmodseg, RMOD_OFFSET_STDINFILE); |
unsigned short t; |
*farptr = i; |
for (t = 0;; t++) { |
rmod_execprog[i++] = redir->stdinfile[t]; |
if (redir->stdinfile[t] == 0) break; |
} |
} |
if (redir->stdoutfile) { |
unsigned short far *farptr = MK_FP(rmod->rmodseg, RMOD_OFFSET_STDOUTFILE); |
unsigned short t; |
*farptr = i; |
for (t = 0;; t++) { |
rmod_execprog[i++] = redir->stdoutfile[t]; |
if (redir->stdoutfile[t] == 0) break; |
} |
/* openflag */ |
farptr = MK_FP(rmod->rmodseg, RMOD_OFFSET_STDOUTAPP); |
*farptr = 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]; |
701,6 → 722,7 |
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; |
rmod = rmod_find(BUFFER_len); |
if (rmod == NULL) { |
814,26 → 836,19 |
rmod_updatecomspecptr(rmod->rmodseg, *rmod_envseg); |
/* handle redirections (if any) */ |
if (redir_parsecmd(cmdline, BUFFER) != 0) { |
outputnl(""); |
continue; |
} |
redir_parsecmd(&redirprops, cmdline); |
/* try matching (and executing) an internal command */ |
if (cmd_process(rmod, *rmod_envseg, cmdline, BUFFER, sizeof(BUFFER)) >= -1) { |
if (cmd_process(rmod, *rmod_envseg, cmdline, BUFFER, sizeof(BUFFER), &redirprops) >= -1) { |
/* internal command executed */ |
redir_revert(); /* revert stdout (in case it was redirected) */ |
continue; |
} |
/* if here, then this was not an internal command */ |
run_as_external(BUFFER, cmdline, *rmod_envseg, rmod); |
run_as_external(BUFFER, cmdline, *rmod_envseg, rmod, &redirprops); |
/* perhaps this is a newly launched BAT file */ |
if ((rmod->batfile[0] != 0) && (rmod->batnextline == 0)) goto SKIP_NEWLINE; |
/* revert stdout (so the err msg is not redirected) */ |
redir_revert(); |
/* run_as_external() does not return on success, if I am still alive then |
* external command failed to execute */ |
outputnl("Bad command or file name"); |
/svarcom/trunk/redir.c |
---|
22,21 → 22,21 |
* DEALINGS IN THE SOFTWARE. |
*/ |
#include <string.h> /* memset() */ |
#include "doserr.h" |
#include "helpers.h" |
#include "rmodinit.h" |
#include "redir.h" |
static unsigned short oldstdout = 0xffff; |
/* parse commandline and performs necessary redirections. cmdline is |
* modified so all redirections are cut out. |
* returns 0 on success, non-zero otherwise */ |
int redir_parsecmd(char *cmdline, char *BUFFER) { |
* modified so all redirections are cut out. */ |
void redir_parsecmd(struct redir_data *d, char *cmdline) { |
unsigned short i; |
unsigned short rediroffset_stdin = 0; |
unsigned short rediroffset_stdout = 0; |
unsigned short pipesoffsets[16]; |
unsigned short pipescount = 0; |
/* NOTE: |
53,51 → 53,51 |
/* preset oldstdout to 0xffff in case no redirection is required */ |
oldstdout = 0xffff; |
/* clear out the redir_data struct */ |
memset(d, 0, sizeof(*d)); |
/* parse the command line and fill struct with pointers */ |
for (i = 0;; i++) { |
if (cmdline[i] == '>') { |
cmdline[i] = 0; |
rediroffset_stdout = i + 1; |
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; |
rediroffset_stdin = i + 1; |
d->stdinfile = cmdline + i + 1; |
while (d->stdinfile[0] == ' ') d->stdinfile++; |
} else if (cmdline[i] == '|') { |
cmdline[i] = 0; |
pipesoffsets[pipescount++] = i + 1; |
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 (rediroffset_stdin != 0) { |
/* apply stdin/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 (pipescount != 0) { |
outputnl("ERROR: pipe redirections are not supported yet"); |
return(-1); |
} |
if (rediroffset_stdout != 0) { |
unsigned short openflag = 0x12; /* used during the int 21h,ah=6c call */ |
if (d->stdoutfile != NULL) { |
unsigned short openflag = d->stdout_openflag; |
unsigned short errcode = 0; |
unsigned short handle = 0; |
char *ptr; |
/* append? */ |
if (cmdline[rediroffset_stdout] == '>') { |
openflag = 0x11; |
rediroffset_stdout++; |
} |
const char *myptr = d->stdoutfile; |
/* copy dst file to BUFFER */ |
ptr = cmdline + rediroffset_stdout; |
while (*ptr == ' ') ptr++; /* skip leading white spaces */ |
for (i = 0;; i++) { |
BUFFER[i] = ptr[i]; |
if ((BUFFER[i] == ' ') || (BUFFER[i] == 0)) break; |
} |
BUFFER[i] = 0; |
/* */ |
_asm { |
push ax |
109,7 → 109,7 |
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, BUFFER /* ASCIIZ filename */ |
mov si, myptr /* ASCIIZ filename */ |
int 0x21 /* AX=handle on success (CF clear), otherwise dos err */ |
mov [handle], ax /* save the file handler */ |
jnc DUPSTDOUT |
/svarcom/trunk/redir.h |
---|
25,11 → 25,22 |
#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. |
* returns 0 on success, non-zero otherwise */ |
int redir_parsecmd(char *cmdline, char *BUFFER); |
* modified so all redirections are cut out. */ |
void redir_parsecmd(struct redir_data *r, char *cmdline); |
/* 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); |
/svarcom/trunk/rmod.asm |
---|
48,8 → 48,14 |
; Program to execute, preset by SvarCOM (128 bytes, ASCIIZ) ; +6Bh |
EXECPROG dd 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 |
skipsig: ; +EBh |
; offset within EXECPROG for out and in filenames in case stdin or stdout |
; needs to be redirected (0xffff=no redirection) |
REDIR_OUTFIL dw 0xffff ; +EBh |
REDIR_INFIL dw 0xffff ; +EDh |
REDIR_OUTAPPEND dw 0 ; +EFh |
skipsig: ; +F1h |
; set up CS=DS=SS and point SP to my private stack buffer |
mov ax, cs |
mov ds, ax |
57,6 → 63,12 |
mov ss, ax |
mov sp, STACKPTR |
; revert stdin/stdout redirections (if any) to their initial state |
call REVERT_REDIR_IF_ANY |
; redirect stdout if required |
call REDIR_OUTFILE_IF_REQUIRED |
; should I executed command.com or a pre-set application? |
or [EXECPROG], byte 0 |
jz EXEC_COMMAND_COM |
148,3 → 160,57 |
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 |
; all memory accesses are CS-prefixes because this code may be called at |
; times when DS is out of whack. |
REVERT_REDIR_IF_ANY: |
; is stdout redirected? |
mov bx, [OLD_STDOUT] |
cmp bx, 0xffff |
je STDOUT_DONE |
; revert the stdout handle (dst in BX alread) |
mov cx, 1 ; src handle (1=stdout) |
mov ah, 0x46 ; redirect a handle |
int 0x21 |
mov [OLD_STDOUT], word 0xffff ; mark stdout as "not redirected" |
STDOUT_DONE: |
ret |
; redirect stdout if REDIR_OUTFIL points to something |
REDIR_OUTFILE_IF_REQUIRED: |
mov si, [REDIR_OUTFIL] |
cmp si, 0xffff |
je NO_STDOUT_REDIR |
add si, EXECPROG ; 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], word 0xffff |
jc NO_STDOUT_REDIR ; TODO: abort with an error message instead |
; 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) |
NO_STDOUT_REDIR: |
ret |
/svarcom/trunk/rmodinit.h |
---|
49,7 → 49,10 |
#define RMOD_OFFSET_BOOTDRIVE (0x100 + 0x4E) |
#define RMOD_OFFSET_EXECPARAM (0x100 + 0x5D) |
#define RMOD_OFFSET_EXECPROG (0x100 + 0x6B) |
#define RMOD_OFFSET_ROUTINE (0x100 + 0xEB) |
#define RMOD_OFFSET_STDOUTFILE (0x100 + 0xEB) |
#define RMOD_OFFSET_STDINFILE (0x100 + 0xED) |
#define RMOD_OFFSET_STDOUTAPP (0x100 + 0xEF) |
#define RMOD_OFFSET_ROUTINE (0x100 + 0xF1) |
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); |
/svarcom/trunk/todo.txt |
---|
7,12 → 7,16 |
=== HIGH PRIORITY ============================================================ |
redirections to be handled (applied) by RMOD |
pipes redirections |
DIR /A |
ctrl+break handler |
int 24h handler (abort, retry, fail, ignore) |
advanced batch constructs: CALL, :labels, FOR, GOTO, IF EXIST/ERRORLEVEL |
del review: sometimes says "file not found" while file xxx exists, or does |
not complain when even though file does not exists... also it |
probably does not work with deleting anything in non-current |
directory |
when reverting redirections I should probably close the old handle |
=== MEDIUM PRIORITY ========================================================== |