/svarcom/trunk/cmd/call.c |
---|
0,0 → 1,49 |
/* This file is part of the SvarCOM project and is published under the terms |
* of the MIT license. |
* |
* 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"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
* DEALINGS IN THE SOFTWARE. |
*/ |
/* |
* calls one batch program from another. |
* |
* CALL [drive:][path]filename [batch-parameters] |
* |
* batch-parameters Specifies any command-line information required by the |
* batch program. |
*/ |
static enum cmd_result cmd_call(struct cmd_funcparam *p) { |
if (cmd_ishlp(p)) { |
outputnl("Calls one batch program from another"); |
outputnl(""); |
outputnl("CALL [drive:][path]filename [batch-parameters]"); |
return(CMD_OK); |
} |
/* no argument? do nothing */ |
if (p->argc == 0) return(CMD_OK); |
/* change the command by moving batch filename and arguments to the start of the string */ |
memmove((void *)(p->cmdline), p->cmdline + p->argoffset, strlen(p->cmdline + p->argoffset) + 1); |
return(CMD_CHANGED_BY_CALL); /* notify callee that command needs to be reevaluated */ |
} |
/svarcom/trunk/cmd.c |
---|
22,10 → 22,15 |
* DEALINGS IN THE SOFTWARE. |
*/ |
/* entry point for internal commands |
* matches internal commands and executes them |
* returns -1 or exit code if processed |
* returns -2 if command unrecognized |
/* entry point for internal commands, it matches internal commands and |
* executes them. |
* |
* returns one of the following values: |
* CMD_OK command executed successfully |
* CMD_FAIL command ended in error |
* CMD_CHANGED command-line has been modified (used by IF) |
* CMD_CHANGED_BY_CALL command-line has been modified by CALL |
* CMD_NOTFOUND command unrecognized |
*/ |
#include <i86.h> |
65,6 → 70,7 |
#include "cmd/_notimpl.c" |
#include "cmd/break.c" |
#include "cmd/call.c" |
#include "cmd/cd.c" |
#include "cmd/chcp.c" |
#include "cmd/cls.c" |
99,6 → 105,7 |
const struct CMD_ID INTERNAL_CMDS[] = { |
{"BREAK", cmd_break}, |
{"CALL", cmd_call}, |
{"CD", cmd_cd}, |
{"CHCP", cmd_chcp}, |
{"CHDIR", cmd_cd}, |
/svarcom/trunk/cmd.h |
---|
32,7 → 32,8 |
CMD_OK, /* command executed and succeeded */ |
CMD_FAIL, /* command executed and failed */ |
CMD_NOTFOUND, /* no such command (not an internal command) */ |
CMD_CHANGED /* command-line transformed, please reparse it */ |
CMD_CHANGED, /* command-line transformed, please reparse it */ |
CMD_CHANGED_BY_CALL /* command-line transformed by CALL */ |
}; |
/* process internal commands */ |
/svarcom/trunk/command.c |
---|
315,7 → 315,11 |
} |
static void run_as_external(char *buff, const char *cmdline, unsigned short envseg, struct rmod_props far *rmod, struct redir_data *redir, unsigned char delete_stdin_file) { |
/* a few internal flags */ |
#define DELETE_STDIN_FILE 1 |
#define CALL_FLAG 2 |
static void run_as_external(char *buff, const char *cmdline, unsigned short envseg, struct rmod_props far *rmod, struct redir_data *redir, unsigned char flags) { |
char *cmdfile = buff + 512; |
const char far *pathptr; |
int lookup; |
430,31 → 434,39 |
/* 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 */ |
struct batctx far *newbat; |
/* remember the echo flag (in case bat file disables echo, only when starting first bat) */ |
if (rmod->bat == NULL) { |
rmod->flags &= ~FLAG_ECHO_BEFORE_BAT; |
if (rmod->flags & FLAG_ECHOFLAG) rmod->flags |= FLAG_ECHO_BEFORE_BAT; |
} |
/* if bat is not called via a CALL, then free the bat-context linked list */ |
if ((flags & CALL_FLAG) == 0) { |
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"); |
} |
/* allocate a new bat context */ |
newbat = rmod_fcalloc(sizeof(struct batctx), rmod->rmodseg, "SVBATCTX"); |
if (newbat == NULL) { |
nls_outputnl_doserr(8); /* insufficient memory */ |
return; |
} |
_fmemset(rmod->bat, 0, sizeof(struct batctx)); |
/* copy truename of the bat file to rmod buff */ |
_fstrcpy(rmod->bat->fname, cmdfile); |
/* fill the newly allocated batctx structure */ |
_fstrcpy(newbat->fname, cmdfile); /* truename of the BAT file */ |
/* 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(newbat->argv, buff, sizeof(newbat->argv)); |
/* reset the 'next line to execute' counter */ |
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; |
/* push the new bat to the top of rmod's linked list */ |
newbat->parent = rmod->bat; |
rmod->bat = newbat; |
return; |
} |
466,7 → 478,7 |
char far *farptr = MK_FP(rmod->rmodseg, RMOD_OFFSET_STDINFILE); |
char far *delstdin = MK_FP(rmod->rmodseg, RMOD_OFFSET_STDIN_DEL); |
_fstrcpy(farptr, redir->stdinfile); |
if (delete_stdin_file) { |
if (flags & DELETE_STDIN_FILE) { |
*delstdin = redir->stdinfile[0]; |
} else { |
*delstdin = 0; |
744,6 → 756,7 |
} |
int main(void) { |
static struct config cfg; |
static unsigned short far *rmod_envseg; |
754,7 → 767,7 |
static struct redir_data redirprops; |
static enum cmd_result cmdres; |
static unsigned short i; /* general-purpose variable for short-lived things */ |
static unsigned char delete_stdin_file; |
static unsigned char flags; |
rmod = rmod_find(BUFFER_len); |
if (rmod == NULL) { |
828,10 → 841,10 |
if (rmod->awaitingcmd[0] != 0) { |
_fstrcpy(cmdline, rmod->awaitingcmd); |
rmod->awaitingcmd[0] = 0; |
delete_stdin_file = 1; |
flags |= DELETE_STDIN_FILE; |
goto EXEC_CMDLINE; |
} else { |
delete_stdin_file = 0; |
flags &= ~DELETE_STDIN_FILE; |
} |
/* skip user input if I have a command to exec (/C or /K) */ |
847,7 → 860,7 |
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 */ |
/* end of batch? then restore echo flag as it was before running the (first) bat file */ |
if (rmod->bat == NULL) { |
rmod->flags &= ~FLAG_ECHOFLAG; |
if (rmod->flags & FLAG_ECHO_BEFORE_BAT) rmod->flags |= FLAG_ECHOFLAG; |
898,16 → 911,22 |
} |
/* try matching (and executing) an internal command */ |
cmdres = cmd_process(rmod, *rmod_envseg, cmdline, BUFFER, sizeof(BUFFER), &redirprops, delete_stdin_file); |
cmdres = cmd_process(rmod, *rmod_envseg, cmdline, BUFFER, sizeof(BUFFER), &redirprops, flags & DELETE_STDIN_FILE); |
if ((cmdres == CMD_OK) || (cmdres == CMD_FAIL)) { |
/* internal command executed */ |
continue; |
} else if (cmdres == CMD_CHANGED) { /* cmdline changed, needs to be reprocessed */ |
goto EXEC_CMDLINE; |
} else if (cmdres == CMD_CHANGED_BY_CALL) { /* cmdline changed *specifically* by CALL */ |
/* the distinction is important since it changes the way batch files are processed */ |
flags |= CALL_FLAG; |
goto EXEC_CMDLINE; |
} else if (cmdres == CMD_NOTFOUND) { |
/* 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 */ |
run_as_external(BUFFER, cmdline, *rmod_envseg, rmod, &redirprops, flags); |
flags &= ~CALL_FLAG; /* reset callflag to make sure it is processed only once */ |
/* is it a newly launched BAT file? */ |
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 */ |
/svarcom/trunk/history.txt |
---|
3,6 → 3,11 |
=== SvarCOM's history / changelog === |
=== ver 2022.1 (xx.xx.xxxx) ================================================== |
- added CALL support for calling batch files from within batch files |
=== ver 2022.0 (01.02.2022) ================================================== |
- added "global executable links" support (new command: LN) |
/svarcom/trunk/rmodinit.c |
---|
228,9 → 228,10 |
/* allocates bytes of far memory, flags it as belonging to rmod |
* the new block can be optionally flagged as 'ident' (if not null) |
* the new block can be optionally flagged as 'ident' (if not null) and zero |
* out the newly allocated memory. |
* 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) { |
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident) { |
unsigned short far *owner; |
unsigned short newseg = 0; |
289,11 → 290,14 |
} |
} |
/* zero out the memory before handing it out */ |
_fmemset(MK_FP(newseg, 0), 0, bytes); |
return(MK_FP(newseg, 0)); |
} |
/* free memory previously allocated by rmod_ffmalloc() */ |
/* free memory previously allocated by rmod_fcalloc() */ |
void rmod_ffree(void far *ptr) { |
unsigned short ptrseg; |
unsigned short myseg = 0; |
/svarcom/trunk/rmodinit.h |
---|
68,8 → 68,13 |
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); |
/* allocates bytes of far memory, flags it as belonging to rmod |
* the new block can be optionally flagged as 'ident' (if not null) and zero |
* out the newly allocated memory. |
* returns a far ptr to the allocated block, or NULL on error */ |
void far *rmod_fcalloc(unsigned short bytes, unsigned short rmod_seg, char *ident); |
/* free memory previously allocated by rmod_fcalloc() */ |
void rmod_ffree(void far *ptr); |
#endif |
/svarcom/trunk/todo.txt |
---|
8,7 → 8,7 |
=== HIGH PRIORITY ============================================================ |
int 24h handler (abort, retry, fail, ignore) |
advanced batch constructs: CALL, FOR, GOTO |
advanced batch constructs: FOR, GOTO |
IF EXIST on an empty drive should not lead to the 'Abort, Retry, Fail' prompt |