Subversion Repositories SvarDOS

Compare Revisions

Ignore whitespace Rev 948 → Rev 949

/svarcom/trunk/cmd/shift.c
27,7 → 27,7
*/
 
static enum cmd_result cmd_shift(struct cmd_funcparam *p) {
char far *batargv = p->rmod->batargv;
char far *batargv;
char far *nextarg;
 
if (cmd_ishlp(p)) {
39,7 → 39,8
}
 
/* abort if batargv is empty */
if (*batargv == 0) return(CMD_OK);
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++);
46,7 → 47,7
nextarg++; /* move ptr past the zero terminator */
 
/* move down batargv so 2nd argument is at the head now */
_fmemmove(batargv, nextarg, sizeof(p->rmod->batargv) - (nextarg - batargv));
_fmemmove(batargv, nextarg, sizeof(p->rmod->bat->argv) - (nextarg - batargv));
 
return(CMD_OK);
}
/svarcom/trunk/command.c
430,15 → 430,28
 
/* special handling of batch files */
if ((ext != NULL) && (imatch(ext, "bat"))) {
/* free the bat-context linked list, if present, and replace it with a new entry */
while (rmod->bat != NULL) {
struct batctx far *victim = rmod->bat;
rmod->bat = rmod->bat->parent;
rmod_ffree(victim);
}
rmod->bat = rmod_fmalloc(sizeof(struct batctx), rmod->rmodseg, "SVBATCTX");
if (rmod->bat == NULL) {
outputnl("INTERNAL ERR: OUT OF MEMORY");
return;
}
_fmemset(rmod->bat, 0, sizeof(struct batctx));
 
/* copy truename of the bat file to rmod buff */
_fstrcpy(rmod->batfile, cmdfile);
_fstrcpy(rmod->bat->fname, cmdfile);
 
/* explode args of the bat file and store them in rmod buff */
cmd_explode(buff, cmdline, NULL);
_fmemcpy(rmod->batargv, buff, sizeof(rmod->batargv));
_fmemcpy(rmod->bat->argv, buff, sizeof(rmod->bat->argv));
 
/* reset the 'next line to execute' counter */
rmod->batnextline = 0;
rmod->bat->nextline = 0;
/* remember the echo flag (in case bat file disables echo) */
rmod->flags &= ~FLAG_ECHO_BEFORE_BAT;
if (rmod->flags & FLAG_ECHOFLAG) rmod->flags |= FLAG_ECHO_BEFORE_BAT;
568,10 → 581,10
* 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->batfile);
unsigned short batname_off = FP_OFF(rmod->batfile);
unsigned short filepos_cx = rmod->batnextline >> 16;
unsigned short filepos_dx = rmod->batnextline & 0xffff;
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;
 
640,18 → 653,18
* 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;
if ((buff[i] == '\r') && ((i+1) < blen) && (buff[i+1] == '\n')) rmod->bat->nextline += 1;
break;
}
}
buff[i] = 0;
rmod->batnextline += i + 1;
rmod->bat->nextline += i + 1;
 
return(0);
 
OOPS:
rmod->batfile[0] = 0;
rmod->batnextline = 0;
rmod->bat->fname[0] = 0;
rmod->bat->nextline = 0;
return(-1);
}
 
702,7 → 715,8
if ((line[1] >= '0') && (line[1] <= '9')) {
unsigned short argid = line[1] - '0';
unsigned short i;
const char far *argv = rmod->batargv;
const char far *argv = "";
if ((rmod != NULL) && (rmod->bat != NULL)) argv = rmod->bat->argv;
 
/* locate the proper arg */
for (i = 0; i != argid; i++) {
797,7 → 811,7
 
do {
/* terminate previous command with a CR/LF if ECHO ON (but not during BAT processing) */
if ((rmod->flags & FLAG_ECHOFLAG) && (rmod->batfile[0] == 0)) outputnl("");
if ((rmod->flags & FLAG_ECHOFLAG) && (rmod->bat == NULL)) outputnl("");
 
SKIP_NEWLINE:
 
828,11 → 842,16
}
 
/* if batch file is being executed -> fetch next line */
if (rmod->batfile[0] != 0) {
if (rmod->bat != NULL) {
if (getbatcmd(BUFFER, CMDLINE_MAXLEN, rmod) != 0) { /* end of batch */
/* restore echo flag as it was before running the bat file */
rmod->flags &= ~FLAG_ECHOFLAG;
if (rmod->flags & FLAG_ECHO_BEFORE_BAT) rmod->flags |= FLAG_ECHOFLAG;
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 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 */
889,7 → 908,7
/* this was not an internal command, try matching an external command */
run_as_external(BUFFER, cmdline, *rmod_envseg, rmod, &redirprops, delete_stdin_file);
/* perhaps this is a newly launched BAT file */
if ((rmod->batfile[0] != 0) && (rmod->batnextline == 0)) goto SKIP_NEWLINE;
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 */
outputnl("Bad command or file name");
/svarcom/trunk/internal.txt
32,10 → 32,16
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
- 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 batch filename buffer is non-empty, SvarCOM does not ask the user for
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.
/svarcom/trunk/rmodinit.c
1,7 → 1,7
/* This file is part of the SvarCOM project and is published under the terms
* of the MIT license.
*
* Copyright (C) 2021 Mateusz Viste
* 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"),
225,3 → 225,97
*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)
* returns a far ptr to the allocated block, or NULL on error */
void far *rmod_fmalloc(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];
}
}
 
return(MK_FP(newseg, 0));
}
 
 
/* free memory previously allocated by rmod_ffmalloc() */
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
}
}
/svarcom/trunk/rmodinit.h
31,6 → 31,15
#define FLAG_ECHO_BEFORE_BAT 8
#define FLAG_SKIP_AUTOEXEC 16
 
/* 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 long nextline; /* offset in file of next bat line to process */
struct batctx far *parent; /* parent context if this batch was CALLed */
};
 
struct rmod_props {
char inputbuf[130]; /* input buffer for INT 21, AH=0x0A */
unsigned short rmodseg; /* segment where rmod is loaded */
38,10 → 47,8
unsigned short origenvseg; /* original environment segment */
unsigned char flags; /* command line parameters */
unsigned char version; /* used to detect mismatch between rmod and SvarCOM */
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) */
struct batctx far *bat;
};
 
#define RMOD_OFFSET_ENVSEG 0x2C /* stored in rmod's PSP */
61,4 → 68,8
struct rmod_props far *rmod_find(unsigned short rmodcore_len);
void rmod_updatecomspecptr(unsigned short rmod_seg, unsigned short env_seg);
 
/* allocate */
void far *rmod_fmalloc(unsigned short bytes, unsigned short rmod_seg, char *ident);
void rmod_ffree(void far *ptr);
 
#endif