/svarcom/trunk/cmd/shift.c |
---|
27,7 → 27,7 |
*/ |
static enum cmd_result cmd_shift(struct cmd_funcparam *p) { |
char far *batargv; |
char far *batargv = p->rmod->batargv; |
char far *nextarg; |
if (cmd_ishlp(p)) { |
39,8 → 39,7 |
} |
/* abort if batargv is empty */ |
if ((p->rmod->bat == NULL) || (p->rmod->bat->argv[0] == 0)) return(CMD_OK); |
batargv = p->rmod->bat->argv; |
if (*batargv == 0) return(CMD_OK); |
/* find the next argument in batargv */ |
for (nextarg = batargv + 1; *nextarg != 0; nextarg++); |
47,7 → 46,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->bat->argv) - (nextarg - batargv)); |
_fmemmove(batargv, nextarg, sizeof(p->rmod->batargv) - (nextarg - batargv)); |
return(CMD_OK); |
} |
/svarcom/trunk/command.c |
---|
430,28 → 430,15 |
/* 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->bat->fname, cmdfile); |
_fstrcpy(rmod->batfile, cmdfile); |
/* explode args of the bat file and store them in rmod buff */ |
cmd_explode(buff, cmdline, NULL); |
_fmemcpy(rmod->bat->argv, buff, sizeof(rmod->bat->argv)); |
_fmemcpy(rmod->batargv, buff, sizeof(rmod->batargv)); |
/* reset the 'next line to execute' counter */ |
rmod->bat->nextline = 0; |
rmod->batnextline = 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; |
581,10 → 568,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->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 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; |
unsigned short errv = 0; |
653,18 → 640,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->bat->nextline += 1; |
if ((buff[i] == '\r') && ((i+1) < blen) && (buff[i+1] == '\n')) rmod->batnextline += 1; |
break; |
} |
} |
buff[i] = 0; |
rmod->bat->nextline += i + 1; |
rmod->batnextline += i + 1; |
return(0); |
OOPS: |
rmod->bat->fname[0] = 0; |
rmod->bat->nextline = 0; |
rmod->batfile[0] = 0; |
rmod->batnextline = 0; |
return(-1); |
} |
715,8 → 702,7 |
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; |
const char far *argv = rmod->batargv; |
/* locate the proper arg */ |
for (i = 0; i != argid; i++) { |
811,7 → 797,7 |
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(""); |
if ((rmod->flags & FLAG_ECHOFLAG) && (rmod->batfile[0] == 0)) outputnl(""); |
SKIP_NEWLINE: |
842,16 → 828,11 |
} |
/* if batch file is being executed -> fetch next line */ |
if (rmod->bat != NULL) { |
if (rmod->batfile[0] != 0) { |
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 bat file */ |
if (rmod->bat == NULL) { |
rmod->flags &= ~FLAG_ECHOFLAG; |
if (rmod->flags & FLAG_ECHO_BEFORE_BAT) rmod->flags |= FLAG_ECHOFLAG; |
} |
/* 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; |
continue; |
} |
/* %-decoding of variables (%PATH%, %1, %%...), result in cmdline */ |
908,7 → 889,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->bat != NULL) && (rmod->bat->nextline == 0)) goto SKIP_NEWLINE; |
if ((rmod->batfile[0] != 0) && (rmod->batnextline == 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,16 → 32,10 |
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 |
- Writes the batch filename into its persistent (rmod-owned) buffer, 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 |
When the batch filename buffer is non-empty, 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-2022 Mateusz Viste |
* 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"), |
225,97 → 225,3 |
*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,15 → 31,6 |
#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 */ |
47,8 → 38,10 |
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 */ |
68,8 → 61,4 |
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 |