Subversion Repositories SvarDOS

Compare Revisions

Ignore whitespace Rev 363 → Rev 364

/svarcom/cmd/cd.c
10,14 → 10,14
* Type CD without parameters to display the current drive and directory.
*/
 
static int cmd_cd(int argc, char const **argv) {
static int cmd_cd(const struct cmd_funcparam *p) {
/* two arguments max */
if (argc > 2) {
if (p->argc > 1) {
puts("Too many parameters");
}
 
/* no argument? display current drive and dir ("CWD") */
if (argc == 1) {
if (p->argc == 0) {
char buff[64];
char *buffptr = buff;
_asm {
40,21 → 40,22
xor dl, dl /* select drive (0 = current drive) */
mov si, buffptr /* 64-byte buffer for ASCIZ pathname */
int 0x21
pop si
pop dx
pop ax
pop dx
pop si
}
puts(buff);
}
 
/* argument can be either a drive (D:) or a path */
if (argc == 2) {
if (p->argc == 1) {
const char *arg = p->argv[0];
unsigned short err = 0;
/* drive (CD B:) */
if ((argv[1][0] != '\\') && (argv[1][1] == ':') && (argv[1][2] == 0)) {
if ((arg[0] != '\\') && (arg[1] == ':') && (arg[2] == 0)) {
char buff[64];
char *buffptr = buff;
unsigned char drive = argv[1][0];
unsigned short err = 0;
unsigned char drive = arg[0];
if (drive >= 'a') {
drive -= 'a';
} else {
76,19 → 77,13
pop ax
pop si
}
if (err != 0) {
if (err != 0) puts(doserr(err));
} else {
printf("%c:\\%s\r\n", drive + 'A' - 1, buff);
}
if (err == 0) 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, dir
mov dx, arg
int 0x21
jnc DONE
mov [err], ax
96,8 → 91,8
pop ax
pop dx
}
if (err != 0) puts(doserr(err));
}
if (err != 0) puts(doserr(err));
}
 
return(-1);
/svarcom/cmd/exit.c
0,0 → 1,18
/*
* exit
*
* Quits the COMMAND.COM program (command interpreter)
*
*/
 
static int cmd_exit(const struct cmd_funcparam *p) {
if ((p->argc == 1) && (imatch(p->argv[0], "/?"))) {
puts("EXIT");
puts("");
puts("Quits the COMMAND.COM program (command interpreter)");
puts("");
} else {
exit(0);
}
return(-1);
}
/svarcom/cmd/set.c
7,13 → 7,12
 
#include "env.h"
 
 
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);
static int cmd_set(const struct cmd_funcparam *p) {
char far *env = MK_FP(p->env_seg, 0);
char buff[256];
int i;
/* no arguments - display content */
if (argc == 1) {
if (p->argc == 0) {
while (*env != 0) {
/* copy string to local buff for display */
for (i = 0;; i++) {
23,7 → 22,7
}
puts(buff);
}
} else if ((argc == 2) && (imatch(argv[1], "/?"))) {
} else if ((p->argc == 1) && (imatch(p->argv[0], "/?"))) {
puts("TODO: help screen"); /* TODO */
} else { /* set variable (do not rely on argv, SET has its own rules...) */
const char far *ptr;
30,7 → 29,7
char buff[256];
unsigned short i;
/* locate the first space */
for (ptr = cmdline; *ptr != ' '; ptr++);
for (ptr = p->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 */
52,7 → 51,7
buff[i] = 0;
 
/* commit variable to environment */
i = env_setvar(env_seg, buff);
i = env_setvar(p->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,19 → 5,114
 
#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) {
 
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));
struct CMD_ID {
const char *cmd;
int (*func_ptr)(const struct cmd_funcparam *); /* pointer to handling function */
};
 
return(-2); /* command is not recognized as internal */
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];
}
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,6 → 1,11
#ifndef CMD_H
#define CMD_H
 
int cmd_process(int argc, const char **argv, unsigned short env_seg, const char far *cmdline);
/* process internal commands */
int cmd_process(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,31 → 80,6
}
 
 
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 != '$') {
206,6 → 181,30
}
 
 
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;
239,26 → 238,35
}
 
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) */
286,6 → 294,10
 
DONE:
pop ds
pop dx
pop cx
pop bx
pop ax
}
printf("\r\n");
 
292,34 → 304,21
/* if nothing entered, loop again */
if (cmdline[-1] == 0) continue;
 
/* 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;
/* replace \r by a zero terminator */
cmdline[(unsigned char)(cmdline[-1])] = 0;
 
argcount = explode_progparams(buff, argvlist);
/* move pointer forward to skip over any leading spaces */
while (*cmdline == ' ') cmdline++;
 
/* 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 */
/* try matching (and executing) an internal command */
{
int ecode = cmd_process(argcount, argvlist, *rmod_envseg, cmdline);
int ecode = cmd_process(*rmod_envseg, cmdline);
if (ecode >= 0) *lastexitcode = ecode;
if (ecode >= -1) continue; /* command is internal but did not set an exit code */
if (ecode >= -1) continue; /* internal command executed */
}
 
/* must be an external command then */
execvp(argvlist[0], argvlist);
/* if here, then this was not an internal command */
run_as_external(cmdline);
 
/* execvp() replaces the current process by the new one
if I am still alive then external command failed to execute */
/svarcom/doserr.c
0,0 → 1,56
/*
* translates a DOS extended error into a human string
* (as defined by INT 21/AH=59h/BX=0000h)
*/
 
#include <stdio.h>
 
#include "doserr.h"
 
const char *doserr(unsigned short err) {
static char buf[24];
switch (err) {
case 0x00: return("Success");
case 0x01: return("Function number invalid");
case 0x02: return("File not found");
case 0x03: return("Path not found");
case 0x04: return("Too many open files (no handles available)");
case 0x05: return("Access denied");
case 0x06: return("Invalid handle");
case 0x07: return("Memory control block destroyed");
case 0x08: return("Insufficient memory");
case 0x09: return("Memory block address invalid");
case 0x0A: return("Environment invalid");
case 0x0B: return("Format invalid");
case 0x0C: return("Access code invalid");
case 0x0D: return("Data invalid");
case 0x0F: return("Invalid drive");
case 0x10: return("Attemted to remove current directory");
case 0x11: return("Not same device");
case 0x12: return("No more files");
case 0x13: return("Disk write-protected");
case 0x14: return("Unknown unit");
case 0x15: return("Drive not ready");
case 0x16: return("Unknown command");
case 0x17: return("Data error (CRC)");
case 0x18: return("Bad request structure length");
case 0x19: return("Seek error");
case 0x1A: return("Unknown media type (non-DOS disk)");
case 0x1B: return("Sector not found");
case 0x1C: return("Printer out of paper");
case 0x1D: return("Write fault");
case 0x1E: return("Read fault");
case 0x1F: return("General failure");
case 0x20: return("Sharing violation");
case 0x21: return("Lock violation");
case 0x22: return("Disk change invalid");
case 0x23: return("FCB unavailable");
case 0x24: return("Sharing buffer overflow");
case 0x25: return("Code page mismatch");
case 0x26: return("Cannot complete file operations (EOF / out of input)");
case 0x27: return("Insufficient disk space");
default:
snprintf(buf, sizeof(buf), "DOS ERROR 0x%02X", err);
return(buf);
}
}
/svarcom/doserr.h
0,0 → 1,11
/*
* translates a DOS extended error into a human string
* (as defined by INT 21/AH=59h/BX=0000h)
*/
 
#ifndef DOSERR_H
#define DOSERR_H
 
const char *doserr(unsigned short err);
 
#endif