Subversion Repositories SvarDOS

Compare Revisions

Ignore whitespace Rev 473 → Rev 474

/svarcom/trunk/command.c
163,7 → 163,9
}
 
 
static void buildprompt(char *s, unsigned short envseg) {
/* 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 */
264,7 → 266,8
break;
}
}
*s = '$';
*s = 0;
output(buff);
}
 
 
416,6 → 419,9
for (i = 0; cmdtail[i] != 0; i++) rmod->batargs[i] = cmdtail[i];
/* reset the 'next line to execute' counter */
rmod->batnextline = 0;
/* remember the echo flag (in case bat file disables echo) */
rmod->flags &= ~FLAG_ECHO_BEFORE_BAT;
if (rmod->echoflag) rmod->flags |= FLAG_ECHO_BEFORE_BAT;
return;
}
 
519,34 → 525,87
 
 
/* fetches a line from batch file and write it to buff, increments
* rmod counter on success. returns NULL on failure.
* buff must start with a length byte but the returned pointer must
* skip it. */
static char far *getbatcmd(char *buff, struct rmod_props far *rmod) {
* rmod counter on success. returns 0 on success.
* buff starts with a length byte and is NULL-terminated */
static int getbatcmd(char *buff, struct rmod_props far *rmod) {
unsigned short i;
buff++; /* make room for the len byte */
/* TODO temporary hack to display a dummy message */
if (rmod->batnextline == 0) {
char *msg = "ECHO batch files not supported yet";
for (i = 0; msg[i] != 0; i++) buff[i] = msg[i];
buff[i] = 0;
buff[-1] = i;
} else {
rmod->batfile[0] = 0;
return(NULL);
unsigned short batname_seg = FP_SEG(rmod->batfile);
unsigned short batname_off = FP_OFF(rmod->batfile);
unsigned short filepos_cx = rmod->batnextline >> 16;
unsigned short filepos_dx = rmod->batnextline & 0xffff;
unsigned char blen = 0;
 
buff++; /* make room for the len byte prefix */
 
/* 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 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 DONE
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 CLOSEANDQUIT
 
/* read the line into buff */
mov ah, 0x3f
mov cx, 255
mov dx, buff
int 0x21 /* CF clear on success, AX=number of bytes read */
jc CLOSEANDQUIT
mov blen, al
 
CLOSEANDQUIT:
/* close file (handle in bx) */
mov ah, 0x3e
int 0x21
 
DONE:
pop dx
pop cx
pop bx
pop ax
}
/* open file */
/* read until awaiting line */
/* copy line to buff */
/* close file */
/* */
rmod->batnextline++;
if (rmod->batnextline == 0) rmod->batfile[0] = 0; /* max line count reached */
 
/* output command on screen if echo on */
if (rmod->echoflag != 0) outputnl(buff);
/* printf("blen=%u filepos_cx=%u filepos_dx=%u\r\n", blen, filepos_cx, filepos_dx); */
 
return(buff);
/* 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->batnextline += 1;
break;
}
}
buff[i] = 0;
buff[-1] = i;
rmod->batnextline += i + 1;
 
return(0);
 
OOPS:
rmod->batfile[0] = 0;
rmod->batnextline = 0;
return(-1);
}
 
 
592,8 → 651,17
}*/
 
do {
char far *cmdline = rmod->inputbuf + 2;
char far *cmdline;
 
if (rmod->echoflag != 0) outputnl(""); /* terminate the previous command with a CR/LF */
 
SKIP_NEWLINE:
 
/* cancel any redirections that may have been set up before */
redir_revert();
 
cmdline = rmod->inputbuf + 2;
 
/* (re)load translation strings if needed */
nls_langreload(BUFFER, *rmod_envseg);
 
604,45 → 672,43
goto EXEC_CMDLINE;
}
 
if (rmod->echoflag != 0) outputnl(""); /* terminate the previous command with a CR/LF */
 
SKIP_NEWLINE:
 
/* print shell prompt (only if ECHO is enabled) */
if (rmod->echoflag != 0) {
char *promptptr = BUFFER;
buildprompt(promptptr, *rmod_envseg);
_asm {
push ax
push dx
mov ah, 0x09
mov dx, promptptr
int 0x21
pop dx
pop ax
}
}
 
/* revert input history terminator to \r */
if (cmdline[-1] != 0) {
cmdline[(unsigned short)(cmdline[-1])] = '\r';
}
 
/* if batch file is being executed -> fetch next line */
if (rmod->batfile[0] != 0) {
cmdline = getbatcmd(BUFFER + sizeof(BUFFER) - 130, rmod);
if (cmdline == NULL) continue;
char *tmpbuff = BUFFER + sizeof(BUFFER) - 256;
if (getbatcmd(tmpbuff, rmod) != 0) { /* end of batch */
redir_revert(); /* cancel redirections (if there were any) */
/* restore echo flag as it was before running the bat file */
rmod->echoflag = 0;
if (rmod->flags & FLAG_ECHO_BEFORE_BAT) rmod->echoflag = 1;
continue;
}
/* output prompt and command on screen if echo on and command is not
* inhibiting it with the @ prefix */
if ((rmod->echoflag != 0) && (tmpbuff[1] != '@')) {
build_and_display_prompt(BUFFER, *rmod_envseg);
outputnl(tmpbuff + 1);
}
/* strip the @ prefix if present, it is no longer useful */
if (tmpbuff[1] == '@') {
memmove(tmpbuff + 1, tmpbuff + 2, tmpbuff[0] + 1);
tmpbuff[0] -= 1; /* update the length byte */
}
cmdline = tmpbuff + 1;
} else {
/* interactive mode: wait for user command line */
/* interactive mode: display prompt (if echo enabled) and wait for user
* command line */
if (rmod->echoflag != 0) build_and_display_prompt(BUFFER, *rmod_envseg);
/* revert input history terminator to \r so DOS or DOSKEY are not confused */
cmdline[(unsigned short)(cmdline[-1])] = '\r';
/* collect user input */
cmdline_getinput(FP_SEG(rmod->inputbuf), FP_OFF(rmod->inputbuf));
/* replace \r by a zero terminator */
cmdline[(unsigned char)(cmdline[-1])] = 0;
}
 
/* if nothing entered, loop again (but without appending an extra CR/LF) */
if (cmdline[-1] == 0) goto SKIP_NEWLINE;
 
/* replace \r by a zero terminator */
cmdline[(unsigned char)(cmdline[-1])] = 0;
 
/* I jump here when I need to exec an initial command (/C or /K) */
EXEC_CMDLINE:
 
670,7 → 736,7
/* perhaps this is a newly launched BAT file */
if ((rmod->batfile[0] != 0) && (rmod->batnextline == 0)) goto SKIP_NEWLINE;
 
/* revert stdout (in case it was redirected) */
/* 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
/svarcom/trunk/internal.txt
12,7 → 12,7
application, waits for it to finish and then calls back SvarCOM.
 
 
=== NLS strings ==============================================================
=== 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
26,13 → 26,13
SVARCOM.LNG is unavailable.
 
 
=== Batch files support ======================================================
=== 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:
 
- Writes the batch filename into its persistent (rmod-owned) buffer, along
with a line counter that holds the number of "next line to be executed".
with a counter that holds the offset of the next line to be executed.
- When a batch file CALLs another batch file, then a new SvarCOM instance is
started. This ensures that once the CALLed batch ends, processing will
return to the original batch file at the correct position.
40,8 → 40,7
When the batch buffer is non-zero, 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 this counter in the
process. The maximum length of a batch file is of 65535 lines (any lines after
this limit will be ignored).
process.
 
 
====================================================================== EOF ===
/svarcom/trunk/rmodinit.h
27,6 → 27,7
 
#define FLAG_EXEC_AND_QUIT 1
#define FLAG_PERMANENT 2
#define FLAG_ECHO_BEFORE_BAT 8
 
struct rmod_props {
char inputbuf[130]; /* input buffer for INT 21, AH=0x0A */
37,7 → 38,7
unsigned char echoflag; /* ECHO ON / ECHO OFF */
char batfile[130]; /* truename of batch file being processed */
char batargs[130]; /* arguments of the processed batch files */
unsigned short batnextline; /* next line of bat file to be executed */
unsigned long batnextline; /* offset in file of next bat line to process */
};
 
#define RMOD_OFFSET_ENVSEG 0x2C /* stored in rmod's PSP */
/svarcom/trunk/svarcom.txt
14,11 → 14,11
 
Since SvarCOM is a work-in-progress effort, it is missing a few things yet:
- no support for pipes (eg. file.exe | more)
- no support for batch (*.BAT) files (hence no AUTOEXEC.BAT execution)
- no support for advanced batch constructs (conditionals, errorlevels...)
- a few internal commands missing: CALL, CTTY, GOTO, IF, LH, SHIFT
 
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.
functionaly equivalent to COMMAND.COM from MS-DOS 5.x/6.x. No LFN support.
 
Latest version available here: http://svardos.osdn.io/svarcom
 
/svarcom/trunk/todo.txt
8,7 → 8,9
=== BEFORE NEXT RELEASE ======================================================
 
pipes redirections
basic BAT support (without workflow controls, FOR loops etc)
autoexec.bat processing (with F5 skipping)
make cmdline a near pointer for better performance (maybe a separate buffer)
put the rmod->echoflag inside rmod->flags
 
 
=== AT SOME LATER TIME =======================================================
38,7 → 40,6
 
dynamic resizing of environment space
single-stepping AUTOEXEC with F8 at boot time (/Y)
skipping AUTOEXEC with F5 at boot time (/D)
CTTY
LOADHIGH/LH