Subversion Repositories SvarDOS

Compare Revisions

Ignore whitespace Rev 396 → Rev 397

/svarcom/trunk/cmd/_notimpl.c
0,0 → 1,8
/*
* handler for all "not implemented yet" commands
*/
 
static int cmd_notimpl(struct cmd_funcparam *p) {
outputnl("This command is not implemented yet. Sorry!");
return(-1);
}
/svarcom/trunk/cmd/cd.c
0,0 → 1,124
/*
* chdir
*
* displays the name of or changes the current directory.
*
* CHDIR [drive:][path]
* CD..
*
* Type CD drive: to display the current directory in the specified drive.
* Type CD without parameters to display the current drive and directory.
*/
 
 
/* display current path drive d (A=1, B=2, etc)
* returns 0 on success, doserr otherwise */
static unsigned short cmd_cd_curpathfordrv(char *buff, unsigned char d) {
unsigned short r = 0;
 
buff[0] = d + 'A' - 1;
buff[1] = ':';
buff[2] = '\\';
 
_asm {
push si
push ax
push dx
mov ah, 0x47 /* get current directory */
mov dl, [d] /* A: = 1, B: = 2, etc */
mov si, buff /* append cur dir to buffer */
add si, 3 /* skip the present drive:\ prefix */
int 0x21
jnc DONE
mov [r], ax /* copy result from ax */
DONE:
pop dx
pop ax
pop si
}
 
return(r);
}
 
 
static int cmd_cd(struct cmd_funcparam *p) {
char *buffptr = p->BUFFER;
 
/* CD /? */
if (cmd_ishlp(p)) {
outputnl("Displays the name of or changes the current directory.");
outputnl("");
outputnl("CHDIR [drive:][path]");
outputnl("CHDIR[..]");
outputnl("CD [drive:][path]");
outputnl("CD[..]");
outputnl("");
outputnl(".. Specifies that you want to change to the parent directory.");
outputnl("");
outputnl("Type CD drive: to display the current directory in the specified drive.");
outputnl("Type CD without parameters to display the current drive and directory.");
return(-1);
}
 
/* one argument max */
if (p->argc > 1) {
outputnl("Too many parameters");
return(-1);
}
 
/* no argument? display current drive and dir ("CWD") */
if (p->argc == 0) {
unsigned char drv = 0;
 
_asm {
push ax
push dx
push si
mov ah, 0x19 /* get current default drive */
int 0x21 /* al = drive (00h = A:, 01h = B:, etc) */
inc al /* convert to 1=A, 2=B, etc */
mov [drv], al
}
 
cmd_cd_curpathfordrv(buffptr, drv);
outputnl(buffptr);
 
return(-1);
}
 
/* argument can be either a drive (D:) or a path */
if (p->argc == 1) {
const char *arg = p->argv[0];
unsigned short err = 0;
/* drive (CD B:) */
if ((arg[0] != '\\') && (arg[1] == ':') && (arg[2] == 0)) {
unsigned char drive = arg[0];
if (drive >= 'a') {
drive -= ('a' - 1);
} else {
drive -= ('A' - 1);
}
 
err = cmd_cd_curpathfordrv(buffptr, drive);
if (err == 0) outputnl(buffptr);
} else { /* path */
_asm {
push dx
push ax
mov ah, 0x3B /* CHDIR (set current directory) */
mov dx, arg
int 0x21
jnc DONE
mov [err], ax
DONE:
pop ax
pop dx
}
}
if (err != 0) {
outputnl(doserr(err));
}
}
 
return(-1);
}
/svarcom/trunk/cmd/del.c
0,0 → 1,107
/*
* del/erase
*/
 
static int cmd_del(struct cmd_funcparam *p) {
const char *delspec = NULL;
unsigned short err = 0;
unsigned short confirmflag = 0;
unsigned short i;
unsigned short pathlimit = 0;
char *buff = p->BUFFER;
 
struct DTA *dta = (void *)0x80; /* use the default DTA at location 80h in PSP */
char *fname = dta->fname;
 
if (cmd_ishlp(p)) {
outputnl("Deletes one or more files.");
outputnl("");
outputnl("DEL [drive:][path]filename [/P]");
outputnl("ERASE [drive:][path]filename [/P]");
outputnl("");
outputnl("[drive:][path]filename Specifies the file(s) to delete.");
outputnl("/P Prompts for confirmation before deleting each file.");
return(-1);
}
 
if (p->argc == 0) {
outputnl("Required parameter missing");
return(-1);
}
 
/* scan argv for delspec and possible /p or /v */
for (i = 0; i < p->argc; i++) {
/* delspec? */
if (p->argv[i][0] == '/') {
if (imatch(p->argv[i], "/p")) {
confirmflag = 1;
} else {
output("Invalid switch:");
output(" ");
outputnl(p->argv[i]);
return(-1);
}
} else if (delspec != NULL) { /* otherwise its a delspec */
outputnl("Too many parameters");
return(-1);
} else {
delspec = p->argv[i];
}
}
 
/* convert path to canonical form */
file_truename(delspec, buff);
 
/* is delspec pointing at a directory? if so, add a \*.* */
{ int attr = file_getattr(delspec);
if ((attr > 0) && (attr & DOS_ATTR_DIR)) strcat(buff, "\\????????.???");
}
 
/* parse delspec in buff and remember where last backslash or slash is */
for (i = 0; buff[i] != 0; i++) if (buff[i] == '\\') pathlimit = i + 1;
 
/* is this about deleting all content inside a directory? if no per-file
* confirmation set, ask for a global confirmation */
if ((confirmflag == 0) && (imatch(buff + pathlimit, "????????.???"))) {
outputnl("All files in directory will be deleted!");
if (askchoice("Are you sure (Y/N)?", "YN") != 0) return(-1);
}
 
for (i = 0;; i = 1) {
 
/* exec FindFirst or FindNext */
if (i == 0) {
err = findfirst(dta, buff, DOS_ATTR_RO | DOS_ATTR_SYS | DOS_ATTR_HID);
} else {
err = findnext(dta);
}
 
if (err != 0) break;
 
/* ask if confirmation required: PLIK.TXT Delete (Y/N)? */
if (confirmflag) {
strcpy(buff + pathlimit, fname); /* note: buff contained the search pattern but it no longer needed so I can reuse it now */
output(buff);
output(" \t");
if (askchoice("Delete (Y/N)?", "YN") != 0) continue;
}
 
/* del found file */
_asm {
mov ah, 0x41 /* delete a file, DS:DX points to an ASCIIZ filespec (no wildcards allowed) */
mov dx, fname
int 0x21
jnc DONE
mov [err], ax
DONE:
}
 
if (err != 0) {
output(fname);
output(": ");
outputnl(doserr(err));
break;
}
}
return(-1);
}
/svarcom/trunk/cmd/dir.c
0,0 → 1,133
/*
* dir
*
* Displays a list of files and subdirectories in a directory.
*
* DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]
*
* /P Pauses after each screenful of information.
* /W Uses wide list format.
*
* /A Displays file with specified attributes:
* D Directories R Read-only files H Hidden files
* A Ready for archiving S System files - prefix meaning "not"
*
* /O List files in sorted order:
* N by name S by size E by extension
* D by date G group dirs first - prefix to reverse order
*
* /S Displays files in specified directory and all subdirectories.
* /B Uses bare format (no heading information or summary)
* /L Uses lowercases
*/
 
/* NOTE: /A attributes are matched in an exclusive way, ie. only files with
* the specified attributes are matched. This is different from how DOS
* itself matches attributes hence DIR cannot rely on the attributes
* filter within FindFirst.
*
* NOTE: Multiple /A are not supported - only the last one is significant.
*/
 
static int cmd_dir(struct cmd_funcparam *p) {
const char *filespecptr = NULL;
struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */
int i;
unsigned short availrows; /* counter of available rows on display (used for /P) */
#define DIR_FLAG_PAUSE 1
#define DIR_FLAG_WIDE 2
#define DIR_FLAG_RECUR 4
#define DIR_FLAG_BARE 8
#define DIR_FLAG_LCASE 16
unsigned char flags = 0;
// unsigned char attribs_show = 0; /* show only files with ALL these attribs */
// unsigned char attribs_hide = 0; /* hide files with ANY of these attribs */
 
if (cmd_ishlp(p)) {
outputnl("Displays a list of files and subdirectories in a directory");
outputnl("");
outputnl("DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]");
outputnl("");
outputnl("/P Pauses after each screenful of information");
outputnl("/W Uses wide list format");
outputnl("");
outputnl("/A Displays files with specified attributes:");
outputnl(" D Directories R Read-only files H Hidden files");
outputnl(" A Ready for archiving S System files - prefix meaning \"not\"");
outputnl("");
outputnl("/O List files in sorted order:");
outputnl(" N by name S by size E by extension");
outputnl(" D by date G group dirs first - prefix to reverse order");
outputnl("");
outputnl("/S Displays files in specified directory and all subdirectories");
outputnl("/B Uses bare format (no heading information or summary)");
outputnl("/L Uses lowercases");
 
/* TODO FIXME REMOVE THIS ONCE ALL IMPLEMENTED */
outputnl("\r\n*** THIS COMMAND IS NOT FULLY IMPLEMENTED YET ***");
 
return(-1);
}
 
/* parse command line */
for (i = 0; i < p->argc; i++) {
if (p->argv[i][0] == '/') {
char arg;
char neg = 0;
/* detect negations and get actual argument */
if (p->argv[i][1] == '-') neg = 1;
arg = p->argv[i][1 + neg];
/* */
switch (arg) {
case 'a':
case 'A':
/* TODO */
outputnl("/A NOT IMPLEMENTED YET");
return(-1);
break;
case 'p':
case 'P':
flags |= DIR_FLAG_PAUSE;
if (neg) flags &= (0xff ^ DIR_FLAG_PAUSE);
break;
default:
outputnl("Invalid switch");
return(-1);
}
} else { /* filespec */
if (filespecptr != NULL) {
outputnl("Too many parameters");
return(-1);
}
filespecptr = p->argv[i];
}
}
 
if (filespecptr == NULL) filespecptr = ".";
 
file_truename(filespecptr, p->BUFFER);
 
/* if dir then append \????????.??? */
i = file_getattr(p->BUFFER);
if ((i > 0) && (i & DOS_ATTR_DIR)) strcat(p->BUFFER, "\\????????.???");
 
if (findfirst(dta, p->BUFFER, DOS_ATTR_RO | DOS_ATTR_HID | DOS_ATTR_SYS | DOS_ATTR_DIR | DOS_ATTR_ARC) != 0) return(-1);
 
availrows = screen_getheight();
 
outputnl(dta->fname);
availrows--;
 
while (findnext(dta) == 0) {
outputnl(dta->fname);
if (flags & DIR_FLAG_PAUSE) {
availrows--;
if (availrows < 2) {
press_any_key();
availrows = screen_getheight();
}
}
}
 
return(-1);
}
/svarcom/trunk/cmd/exit.c
0,0 → 1,16
/*
* exit
*
* Quits the COMMAND.COM program (command interpreter)
*
*/
 
static int cmd_exit(struct cmd_funcparam *p) {
if (cmd_ishlp(p)) {
outputnl("EXIT\r\n");
outputnl("Quits the COMMAND.COM program (command interpreter)");
} else {
exit(0);
}
return(-1);
}
/svarcom/trunk/cmd/mkdir.c
0,0 → 1,50
/*
* mkdir
*/
 
static int cmd_mkdir(struct cmd_funcparam *p) {
const char *dname = p->argv[0];
unsigned short err = 0;
 
if (cmd_ishlp(p)) {
outputnl("Creates a directory");
outputnl("");
outputnl("MKDIR [drive:]path");
outputnl("MD [drive:]path");
return(-1);
}
 
if (p->argc == 0) {
outputnl("Required parameter missing");
return(-1);
}
 
if (p->argc > 1) {
outputnl("Too many parameters");
return(-1);
}
 
if (p->argv[0][0] == '/') {
outputnl("Invalid parameter");
return(-1);
}
 
_asm {
push ax
push dx
 
mov ah, 0x39 /* create new directory, DS:DX points to ASCIIZ dir name */
mov dx, [dname]
int 0x21
jnc DONE
mov [err], ax
DONE:
 
pop dx
pop ax
}
 
if (err != 0) outputnl(doserr(err));
 
return(-1);
}
/svarcom/trunk/cmd/path.c
0,0 → 1,67
/*
* path
*
* Displays or sets a search path for executable files.
*/
 
static int cmd_path(struct cmd_funcparam *p) {
char *buff = p->BUFFER;
 
/* help screen (/?) */
if (cmd_ishlp(p)) {
output("Displays or sets a search path for executable files.\r\n"
"\r\n"
"PATH [[drive:]path[;...]]\r\n"
"PATH ;\r\n"
"\r\n"
"Type PATH ; to clear all search-path settings and direct DOS to search\r\n"
"only in the current directory.\r\n"
"\r\n"
"Type PATH without parameters to display the current path.\r\n");
return(-1);
}
 
/* no parameter - display current path */
if (p->argc == 0) {
char far *curpath = env_lookup(p->env_seg, "PATH");
if (curpath == NULL) {
outputnl("No Path");
} else {
unsigned short i;
for (i = 0;; i++) {
buff[i] = curpath[i];
if (buff[i] == 0) break;
}
outputnl(buff);
}
return(-1);
}
 
/* more than 1 parameter */
if (p->argc > 1) {
outputnl("Too many parameters");
return(-1);
}
 
/* IF HERE: THERE IS EXACTLY 1 ARGUMENT (argc == 1) */
 
/* reset the PATH string (PATH ;) */
if (imatch(p->argv[0], ";")) {
env_dropvar(p->env_seg, "PATH");
return(-1);
}
 
/* otherwise set PATH to whatever is passed on command-line */
{
unsigned short i;
strcpy(buff, "PATH=");
for (i = 0;; i++) {
buff[i + 5] = p->argv[0][i];
if (buff[i + 5] == '\r') break;
}
buff[i + 5] = 0;
env_setvar(p->env_seg, buff);
}
 
return(-1);
}
/svarcom/trunk/cmd/prompt.c
0,0 → 1,37
/*
* prompt
*
* Changes the DOS command prompt.
*
*/
 
static int cmd_prompt(struct cmd_funcparam *p) {
 
if (cmd_ishlp(p)) {
outputnl("Changes the DOS command prompt.");
outputnl("");
outputnl("PROMPT [new command prompt specification]");
return(-1);
}
 
/* no parameter - restore default prompt path */
if (p->argc == 0) {
env_dropvar(p->env_seg, "PROMPT");
return(-1);
}
 
/* otherwise set PROMPT to whatever is passed on command-line */
{
unsigned short i;
char *buff = p->BUFFER;
strcpy(buff, "PROMPT=");
for (i = 0;; i++) {
buff[i + 7] = p->cmdline[p->argoffset + i];
if (buff[i + 7] == '\r') break;
}
buff[i + 7] = 0;
env_setvar(p->env_seg, buff);
}
 
return(-1);
}
/svarcom/trunk/cmd/rmdir.c
0,0 → 1,50
/*
* rmdir
*/
 
static int cmd_rmdir(struct cmd_funcparam *p) {
const char *dname = p->argv[0];
unsigned short err = 0;
 
if (cmd_ishlp(p)) {
outputnl("Removes (deletes) a directory");
outputnl("");
outputnl("RMDIR [drive:]path");
outputnl("RD [drive:]path");
return(-1);
}
 
if (p->argc == 0) {
outputnl("Required parameter missing");
return(-1);
}
 
if (p->argc > 1) {
outputnl("Too many parameters");
return(-1);
}
 
if (p->argv[0][0] == '/') {
outputnl("Invalid parameter");
return(-1);
}
 
_asm {
push ax
push dx
 
mov ah, 0x3a /* delete a directory, DS:DX points to ASCIIZ dir name */
mov dx, [dname]
int 0x21
jnc DONE
mov [err], ax
DONE:
 
pop dx
pop ax
}
 
if (err != 0) outputnl(doserr(err));
 
return(-1);
}
/svarcom/trunk/cmd/set.c
0,0 → 1,72
/*
* set [varname[=value]]
*
* value cannot contain any '=' character, but it can contain spaces
* varname can also contain spaces
*/
 
 
static int cmd_set(struct cmd_funcparam *p) {
char far *env = MK_FP(p->env_seg, 0);
char *buff = p->BUFFER;
 
if (cmd_ishlp(p)) {
outputnl("Displays, sets, or removes DOS environment variables");
outputnl("");
outputnl("SET [variable=[string]]");
outputnl("");
outputnl("variable Specifies the environment-variable name");
outputnl("string Specifies a series of characters to assign to the variable");
outputnl("");
outputnl("Type SET without parameters to display the current environment variables.");
}
 
/* no arguments - display content */
if (p->argc == 0) {
while (*env != 0) {
unsigned short i;
/* copy string to local buff for display */
for (i = 0;; i++) {
buff[i] = *env;
env++;
if (buff[i] == 0) break;
}
outputnl(buff);
}
} else { /* set variable (do not rely on argv, SET has its own rules...) */
const char far *ptr;
unsigned short i;
/* locate the first space */
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 */
i = 0;
for (; *ptr != '='; ptr++) {
if (*ptr == '\r') goto syntax_err;
buff[i] = *ptr;
if ((buff[i] >= 'a') && (buff[i] <= 'z')) buff[i] -= ('a' - 'A');
i++;
}
 
/* copy value now */
while (*ptr != '\r') {
buff[i++] = *ptr;
ptr++;
}
 
/* terminate buff */
buff[i] = 0;
 
/* commit variable to environment */
i = env_setvar(p->env_seg, buff);
if (i == ENV_INVSYNT) goto syntax_err;
if (i == ENV_NOTENOM) outputnl("Not enough available space within the environment block");
}
return(-1);
 
syntax_err:
 
outputnl("Syntax error");
return(-1);
}
/svarcom/trunk/cmd/type.c
0,0 → 1,86
/*
* type
*/
 
static int cmd_type(struct cmd_funcparam *p) {
char *buff = p->BUFFER;
const char *fname = p->argv[0];
unsigned short err = 0;
 
if (cmd_ishlp(p)) {
outputnl("Displays the contents of a text file.");
outputnl("");
outputnl("TYPE [drive:][path]filename");
return(-1);
}
 
if (p->argc == 0) {
outputnl("Required parameter missing");
return(-1);
}
 
if (p->argc > 1) {
outputnl("Too many parameters");
return(-1);
}
 
/* if here then display the file */
_asm {
push ax
push bx
push cx
push dx
push si
 
mov ax, 0x3d00 /* open file via handle, access mode in AL (0 = read) */
mov dx, fname
int 0x21 /* file handle in ax on success (CF clear) */
jnc FILE_OPEN_OK
mov [err], ax /* on error AX contains the DOS err code */
jmp FOPENFAIL
FILE_OPEN_OK:
/* copy obtained file handle to BX */
mov bx, ax
 
READNEXTBLOCK:
/* read file block by block */
mov cx, 1024 /* read 1K at a time */
mov dx, buff
mov ah, 0x3f /* read CX bytes from file handle in BX and write to DS:DX */
int 0x21 /* CF set on error, AX=errno or AX=number of bytes read */
jc GOTERROR /* abort on error */
test ax, ax /* EOF? */
jz ENDFILE
/* display read block (AX=len) */
mov si, dx /* preset DS:SI to DS:DX (DL will be reused soon) */
mov cx, ax /* set loop count to CX */
mov ah, 0x02 /* write character in DL to stdout */
NEXTCHAR:
mov dl, [si]
inc si
int 0x21
loopnz NEXTCHAR /* CX-- ; jnz NEXTCHAR (display CX characters) */
/* read (and display) next block */
jmp READNEXTBLOCK
 
GOTERROR:
mov [err], ax
 
ENDFILE:
/* close file */
mov ah, 0x3e /* close file handle (file handle already in BX) */
int 0x21
 
FOPENFAIL:
 
pop si
pop dx
pop cx
pop bx
pop ax
}
 
if (err != 0) outputnl(doserr(err));
 
return(-1);
}
/svarcom/trunk/cmd/ver.c
0,0 → 1,40
/*
* ver
*/
 
#define PVER "20211027"
 
static int cmd_ver(struct cmd_funcparam *p) {
char *buff = p->BUFFER;
unsigned char maj = 0, min = 0;
 
/* help screen */
if (cmd_ishlp(p)) {
outputnl("Displays the DOS version.");
return(-1);
}
 
if (p->argc != 0) {
outputnl("Invalid parameter");
return(-1);
}
 
_asm {
push ax
push bx
push cx
mov ah, 0x30 /* Get DOS version number */
int 0x21 /* AL=maj_ver_num AH=min_ver_num BX,CX=OEM */
mov [maj], al
mov [min], ah
pop cx
pop bx
pop ax
}
 
sprintf(buff, "DOS kernel version %u.%u", maj, min);
 
outputnl(buff);
outputnl("SvarCOM shell ver " PVER);
return(-1);
}
/svarcom/trunk/cmd/verify.c
0,0 → 1,62
/*
* verify
*/
 
static int cmd_verify(struct cmd_funcparam *p) {
 
if (cmd_ishlp(p)) {
outputnl("Tells DOS whether to verify that files are written correctly to disk.");
outputnl("\r\nVERIFY [ON | OFF]\r\n");
outputnl("Type VERIFY without a parameter to display its current setting.");
return(-1);
}
 
if (p->argc > 1) {
outputnl("Too many parameters");
return(-1);
}
 
if (p->argc == 0) {
unsigned char verstate = 0;
_asm {
push ax
mov ah, 0x54 /* Get VERIFY status */
int 0x21 /* AL == 0 (off) or AL == 1 (on) */
mov [verstate], al
pop ax
}
if (verstate == 0) {
outputnl("VERIFY is off");
} else {
outputnl("VERIFY is on");
}
return(-1);
}
 
/* argc == 1*/
if (imatch(p->argv[0], "on")) {
_asm {
push ax
push dx
mov ax, 0x2e01 /* set verify ON */
xor dl, dl /* apparently required by MS-DOS 2.x */
int 0x21
pop dx
pop ax
}
} else if (imatch(p->argv[0], "off")) {
_asm {
push ax
push dx
mov ax, 0x2e00 /* set verify OFF */
xor dl, dl /* apparently required by MS-DOS 2.x */
int 0x21
pop dx
pop ax
}
} else {
outputnl("Must specify ON or OFF");
}
 
return(-1);
}