/svarcom/doserr.h |
---|
File deleted |
/svarcom/doserr.c |
---|
File deleted |
/svarcom/cmd/exit.c |
---|
File deleted |
/svarcom/cmd/cd.c |
---|
10,14 → 10,14 |
* Type CD without parameters to display the current drive and directory. |
*/ |
static int cmd_cd(const struct cmd_funcparam *p) { |
static int cmd_cd(int argc, char const **argv) { |
/* two arguments max */ |
if (p->argc > 1) { |
if (argc > 2) { |
puts("Too many parameters"); |
} |
/* no argument? display current drive and dir ("CWD") */ |
if (p->argc == 0) { |
if (argc == 1) { |
char buff[64]; |
char *buffptr = buff; |
_asm { |
40,22 → 40,21 |
xor dl, dl /* select drive (0 = current drive) */ |
mov si, buffptr /* 64-byte buffer for ASCIZ pathname */ |
int 0x21 |
pop ax |
pop dx |
pop si |
pop dx |
pop ax |
} |
puts(buff); |
} |
/* argument can be either a drive (D:) or a path */ |
if (p->argc == 1) { |
const char *arg = p->argv[0]; |
unsigned short err = 0; |
if (argc == 2) { |
/* drive (CD B:) */ |
if ((arg[0] != '\\') && (arg[1] == ':') && (arg[2] == 0)) { |
if ((argv[1][0] != '\\') && (argv[1][1] == ':') && (argv[1][2] == 0)) { |
char buff[64]; |
char *buffptr = buff; |
unsigned char drive = arg[0]; |
unsigned char drive = argv[1][0]; |
unsigned short err = 0; |
if (drive >= 'a') { |
drive -= 'a'; |
} else { |
77,13 → 76,19 |
pop ax |
pop si |
} |
if (err == 0) printf("%c:\\%s\r\n", drive + 'A' - 1, buff); |
if (err != 0) { |
if (err != 0) puts(doserr(err)); |
} else { |
printf("%c:\\%s\r\n", drive + 'A' - 1, buff); |
} |
} else { /* path */ |
char const *dir = argv[1]; |
unsigned short err = 0; |
_asm { |
push dx |
push ax |
mov ah, 0x3B /* CHDIR (set current directory) */ |
mov dx, arg |
mov dx, dir |
int 0x21 |
jnc DONE |
mov [err], ax |
91,9 → 96,9 |
pop ax |
pop dx |
} |
} |
if (err != 0) puts(doserr(err)); |
} |
} |
return(-1); |
} |
/svarcom/cmd/set.c |
---|
7,12 → 7,13 |
#include "env.h" |
static int cmd_set(const struct cmd_funcparam *p) { |
char far *env = MK_FP(p->env_seg, 0); |
static int cmd_set(int argc, char const **argv, unsigned short env_seg, const char far *cmdline) { |
char far *env = MK_FP(env_seg, 0); |
char buff[256]; |
int i; |
/* no arguments - display content */ |
if (p->argc == 0) { |
if (argc == 1) { |
while (*env != 0) { |
/* copy string to local buff for display */ |
for (i = 0;; i++) { |
22,7 → 23,7 |
} |
puts(buff); |
} |
} else if ((p->argc == 1) && (imatch(p->argv[0], "/?"))) { |
} else if ((argc == 2) && (imatch(argv[1], "/?"))) { |
puts("TODO: help screen"); /* TODO */ |
} else { /* set variable (do not rely on argv, SET has its own rules...) */ |
const char far *ptr; |
29,7 → 30,7 |
char buff[256]; |
unsigned short i; |
/* locate the first space */ |
for (ptr = p->cmdline; *ptr != ' '; ptr++); |
for (ptr = cmdline; *ptr != ' '; ptr++); |
/* now locate the first non-space: that's where the variable name begins */ |
for (; *ptr == ' '; ptr++); |
/* copy variable to buff and switch it upercase */ |
51,7 → 52,7 |
buff[i] = 0; |
/* commit variable to environment */ |
i = env_setvar(p->env_seg, buff); |
i = env_setvar(env_seg, buff); |
if (i == ENV_INVSYNT) goto syntax_err; |
if (i == ENV_NOTENOM) puts("Not enough available space within the environment block"); |
} |
/svarcom/cmd.c |
---|
5,114 → 5,19 |
#include <i86.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include "doserr.h" |
#include "helpers.h" |
struct cmd_funcparam { |
int argc; |
const char *argv[256]; |
unsigned short env_seg; |
const char far *cmdline; |
}; |
#include "cmd/cd.c" |
#include "cmd/exit.c" |
#include "cmd/set.c" |
#include "cmd.h" |
int cmd_process(int argc, const char **argv, unsigned short env_seg, const char far *cmdline) { |
struct CMD_ID { |
const char *cmd; |
int (*func_ptr)(const struct cmd_funcparam *); /* pointer to handling function */ |
}; |
if ((imatch(argv[0], "cd")) || (imatch(argv[0], "chdir"))) return(cmd_cd(argc, argv)); |
if (imatch(argv[0], "set")) return(cmd_set(argc, argv, env_seg, cmdline)); |
const struct CMD_ID INTERNAL_CMDS[] = { |
{"CD", cmd_cd}, |
{"CHDIR", cmd_cd}, |
{"EXIT", cmd_exit}, |
{"SET", cmd_set}, |
{NULL, NULL} |
}; |
/* NULL if cmdline is not matching an internal command, otherwise returns a |
* pointer to a CMD_ID struct */ |
static const struct CMD_ID *cmd_match(const char far *cmdline, unsigned short *argoffset) { |
unsigned short i; |
char buff[10]; |
/* copy command to buffer, until space, NULL, tab, return, dot, slash or backslash */ |
for (i = 0; i < 9; i++) { |
if (cmdline[i] == ' ') break; |
if (cmdline[i] == 0) break; |
if (cmdline[i] == '\t') break; |
if (cmdline[i] == '\r') break; |
if (cmdline[i] == '.') break; |
if (cmdline[i] == '/') break; |
if (cmdline[i] == '\\') break; |
buff[i] = cmdline[i]; |
return(-2); /* command is not recognized as internal */ |
} |
buff[i] = 0; |
/* advance to nearest non-space to find where arguments start */ |
while (cmdline[i] == ' ') i++; |
*argoffset = i; |
/* try matching an internal command */ |
for (i = 0; INTERNAL_CMDS[i].cmd != NULL; i++) { |
/*printf("imatch(%s,%s)\r\n", buff, INTERNAL_CMDS[i].cmd); */ |
if (imatch(buff, INTERNAL_CMDS[i].cmd)) { |
/*printf("match cmd i=%u (buff=%s)\r\n", i, buff);*/ |
return(&(INTERNAL_CMDS[i])); |
} |
} |
return(NULL); /* command is not recognized as internal */ |
} |
/* explodes a command into an array of arguments where last arg is NULL |
* returns number of args */ |
unsigned short cmd_explode(char *buff, const char far *s, char const **argvlist) { |
int si = 0, argc = 0, i = 0; |
for (;;) { |
/* skip to next non-space character */ |
while (s[si] == ' ') si++; |
/* end of string? */ |
if (s[si] == 0) break; |
/* set argv ptr */ |
argvlist[argc++] = buff + i; |
/* find next space while copying arg to local buffer */ |
do { |
buff[i++] = s[si++]; |
} while (s[si] != ' ' && s[si] != 0 && s[si] != '/'); |
buff[i++] = 0; |
/* is this end of string? */ |
if (s[si] == 0) break; |
} |
argvlist[argc] = NULL; |
return(argc); |
} |
int cmd_process(unsigned short env_seg, const char far *cmdline) { |
const struct CMD_ID *cmdptr; |
struct cmd_funcparam p; |
unsigned short argoffset; |
char cmdbuff[256]; |
cmdptr = cmd_match(cmdline, &argoffset); |
if (cmdptr == NULL) return(-2); /* command is not recognized as internal */ |
/* printf("recognized internal command: '%s', tail of command at offset %u\r\n", cmdptr->cmd, argoffset); */ |
/* prepare function parameters and feed it to the cmd handling function */ |
p.argc = cmd_explode(cmdbuff, cmdline + argoffset, p.argv); |
p.env_seg = env_seg; |
p.cmdline = cmdline; |
return((cmdptr->func_ptr)(&p)); |
} |
/svarcom/cmd.h |
---|
1,11 → 1,6 |
#ifndef CMD_H |
#define CMD_H |
/* process internal commands */ |
int cmd_process(unsigned short env_seg, const char far *cmdline); |
int cmd_process(int argc, const char **argv, unsigned short env_seg, const char far *cmdline); |
/* explodes a command into an array of arguments where last arg is NULL |
* returns number of args */ |
unsigned short cmd_explode(char *buff, const char far *s, char const **argvlist); |
#endif |
/svarcom/command.c |
---|
80,6 → 80,31 |
} |
static int explode_progparams(char *s, char const **argvlist) { |
int si = 0, argc = 0; |
for (;;) { |
/* skip to next non-space character */ |
while (s[si] == ' ') si++; |
/* end of string? */ |
if (s[si] == '\r') break; |
/* set argv ptr */ |
argvlist[argc++] = s + si; |
/* find next space */ |
while (s[si] != ' ' && s[si] != '\r') si++; |
/* is this end of string? */ |
if (s[si] == '\r') { |
s[si] = 0; |
break; |
} |
/* not end: terminate arg and look for next one */ |
s[si++] = 0; |
} |
/* terminate argvlist with a NULL value */ |
argvlist[argc] = NULL; |
return(argc); |
} |
static void buildprompt(char *s, const char *fmt) { |
for (; *fmt != 0; fmt++) { |
if (*fmt != '$') { |
181,30 → 206,6 |
} |
static void run_as_external(const char far *cmdline) { |
char buff[256]; |
char const *argvlist[256]; |
int i, n; |
/* copy buffer to a near var (incl. trailing CR), insert a space before |
every slash to make sure arguments are well separated */ |
n = 0; |
i = 0; |
for (;;) { |
if (cmdline[i] == '/') buff[n++] = ' '; |
buff[n++] = cmdline[i++]; |
if (buff[n] == 0) break; |
} |
cmd_explode(buff, cmdline, argvlist); |
/* for (i = 0; argvlist[i] != NULL; i++) printf("arg #%d = '%s'\r\n", i, argvlist[i]); */ |
/* must be an external command then. this call should never return, unless |
* the other program failed to be executed. */ |
execvp(argvlist[0], argvlist); |
} |
int main(int argc, char **argv) { |
struct config cfg; |
unsigned short rmod_seg; |
238,35 → 239,26 |
} |
for (;;) { |
int i, n, argcount; |
char far *cmdline = MK_FP(rmod_seg, RMOD_OFFSET_INPBUFF + 2); |
char buff[256]; |
char const *argvlist[256]; |
/* revert input history terminator to \r */ |
if (cmdline[-1] != 0) { |
cmdline[(unsigned short)(cmdline[-1])] = '\r'; |
} |
{ |
/* print shell prompt */ |
char buff[256]; |
char *promptptr = buff; |
buildprompt(promptptr, "$p$g"); /* TODO: prompt should be configurable via environment */ |
_asm { |
push ax |
push dx |
mov ah, 0x09 |
mov dx, promptptr |
int 0x21 |
pop dx |
pop ax |
} |
} |
/* wait for user input */ |
_asm { |
push ax |
push bx |
push cx |
push dx |
push ds |
/* is DOSKEY support present? (INT 2Fh, AX=4800h, returns non-zero in AL if present) */ |
294,10 → 286,6 |
DONE: |
pop ds |
pop dx |
pop cx |
pop bx |
pop ax |
} |
printf("\r\n"); |
304,21 → 292,34 |
/* if nothing entered, loop again */ |
if (cmdline[-1] == 0) continue; |
/* replace \r by a zero terminator */ |
cmdline[(unsigned char)(cmdline[-1])] = 0; |
/* copy buffer to a near var (incl. trailing CR), insert a space before |
every slash to make sure arguments are well separated */ |
n = 0; |
for (i = 0; i < cmdline[-1] + 1; i++) { |
if (cmdline[i] == '/') buff[n++] = ' '; |
buff[n++] = cmdline[i]; |
} |
buff[n] = 0; |
/* move pointer forward to skip over any leading spaces */ |
while (*cmdline == ' ') cmdline++; |
argcount = explode_progparams(buff, argvlist); |
/* try matching (and executing) an internal command */ |
/* if no args found (eg. all-spaces), loop again */ |
if (argcount == 0) continue; |
/* for (i = 0; i < argcount; i++) printf("arg #%d = '%s'\r\n", i, argvlist[i]); */ |
/* is it about quitting? */ |
if (imatch(argvlist[0], "exit")) break; |
/* try running it as an internal command */ |
{ |
int ecode = cmd_process(*rmod_envseg, cmdline); |
int ecode = cmd_process(argcount, argvlist, *rmod_envseg, cmdline); |
if (ecode >= 0) *lastexitcode = ecode; |
if (ecode >= -1) continue; /* internal command executed */ |
if (ecode >= -1) continue; /* command is internal but did not set an exit code */ |
} |
/* if here, then this was not an internal command */ |
run_as_external(cmdline); |
/* must be an external command then */ |
execvp(argvlist[0], argvlist); |
/* execvp() replaces the current process by the new one |
if I am still alive then external command failed to execute */ |