Subversion Repositories SvarDOS

Compare Revisions

Ignore whitespace Rev 349 → Rev 350

/svarcom/command.c
48,6 → 48,7
#include <i86.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <process.h>
57,16 → 58,41
struct config {
int locate;
int install;
int envsiz;
} cfg;
 
 
#define RMOD_OFFSET_ENVSEG 0x08
#define RMOD_OFFSET_INPBUFF 0x0A
#define RMOD_OFFSET_ROUTINE 0x8C
 
/* returns segment where rmod is installed */
unsigned short install_routine(void) {
char far *ptr, far *mcb;
unsigned short rmod_install(unsigned short envsize) {
char far *myptr, far *mcb;
unsigned short far *owner;
unsigned int memseg = 0xffff;
unsigned int rmodseg = 0xffff;
unsigned int envseg = 0;
 
/* read my current env segment from PSP */
_asm {
push ax
push bx
mov bx, 0x2c
mov ax, [bx]
mov envseg, ax
pop bx
pop ax
}
 
printf("original (PSP) env buffer at %04X\r\n", envseg);
/* if custom envsize requested, convert it to number of paragraphs */
if (envsize != 0) {
envsize += 15;
envsize /= 16;
}
 
 
_asm {
/* link in the UMB memory chain for enabling high-memory allocation (and save initial status on stack) */
mov ax, 0x5802 /* GET UMB LINK STATE */
int 0x21
84,12 → 110,21
mov ax, 0x5801
mov bx, 0x0082
int 0x21
/* ask for a memory block and save the given segment to memseg */
/* ask for a memory block and save the given segment to rmodseg */
mov ah, 0x48
mov bx, (rmod_len + 15) / 16
int 0x21
jc ALLOC_FAIL
mov memseg, ax
mov rmodseg, ax
/* ask for a memory block for the environment and save it to envseg (only if custom size requested) */
mov bx, envsize
test bx, bx
jz ALLOC_FAIL
mov ah, 0x48
int 0x21
jc ALLOC_FAIL
mov envseg, ax
 
ALLOC_FAIL:
/* restore initial allocation strategy */
mov ax, 0x5801
101,15 → 136,35
int 0x21
}
 
if (memseg == 0xffff) {
if (rmodseg == 0xffff) {
puts("malloc error");
return(0xffff);
}
ptr = MK_FP(memseg, 0);
mcb = MK_FP(memseg - 1, 0);
 
/* copy rmod to its destination */
myptr = MK_FP(rmodseg, 0);
_fmemcpy(myptr, rmod, rmod_len);
 
/* mark rmod memory as "self owned" */
mcb = MK_FP(rmodseg - 1, 0);
owner = (void far *)(mcb + 1);
_fmemcpy(ptr, rmod, rmod_len);
*owner = rmodseg;
_fmemcpy(mcb + 8, "SVARCOM", 8);
 
/* mark env memory as "self owned" (only if allocated by me) */
if (envsize != 0) {
printf("envseg allocated at %04X:0000 with %u paragraphs\r\n", envseg, envsize);
mcb = MK_FP(envseg - 1, 0);
owner = (void far *)(mcb + 1);
*owner = rmodseg;
_fmemcpy(mcb + 8, "SVARENV", 8);
}
 
/* write env segment to rmod buffer */
owner = MK_FP(rmodseg, RMOD_OFFSET_ENVSEG);
*owner = envseg;
 
/*
printf("MCB sig: %c\r\nMCB owner: 0x%04X\r\n", mcb[0], *owner);
{
int i;
125,28 → 180,41
}
}
printf("\r\n");
}
}*/
 
/* mark memory as "self owned" */
*owner = memseg;
_fmemcpy(mcb + 8, "COMMAND", 8);
return(memseg);
return(rmodseg);
}
 
 
/* returns zero if s1 starts with s2 */
static int strstartswith(const char *s1, const char *s2) {
while (*s2 != 0) {
if (*s1 != *s2) return(-1);
s1++;
s2++;
}
return(0);
}
 
 
static void parse_argv(struct config *cfg, int argc, char **argv) {
int i;
memset(cfg, 0, sizeof(*cfg));
 
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "/locate") == 0) {
cfg->locate = 1;
}
if (strstartswith(argv[i], "/e:") == 0) {
cfg->envsiz = atoi(argv[i]+3);
if (cfg->envsiz < 64) cfg->envsiz = 0;
}
}
}
 
 
/* scan memory for my shared buffer, return segment of buffer */
static unsigned short find_shm(void) {
static unsigned short rmod_find(void) {
unsigned short i;
unsigned short far *pattern;
 
153,10 → 221,10
/* iterate over all paragraphs, looking for my signature */
for (i = 0; i != 65535; i++) {
pattern = MK_FP(i, 0);
if (pattern[1] != 0x1983) continue;
if (pattern[2] != 0x1985) continue;
if (pattern[3] != 0x2017) continue;
if (pattern[4] != 0x2019) continue;
if (pattern[0] != 0x1983) continue;
if (pattern[1] != 0x1985) continue;
if (pattern[2] != 0x2017) continue;
if (pattern[3] != 0x2019) continue;
return(i);
}
return(0xffff);
206,16 → 274,16
 
int main(int argc, char **argv) {
struct config cfg;
unsigned short env_seg = 0, rmod_seg, rmod_buff = 0;
void far *rmod_func;
unsigned short rmod_seg;
unsigned short far *rmod_envseg;
 
parse_argv(&cfg, argc, argv);
 
rmod_seg = find_shm();
rmod_seg = rmod_find();
if (rmod_seg == 0xffff) {
rmod_seg = install_routine();
rmod_seg = rmod_install(cfg.envsiz);
if (rmod_seg == 0xffff) {
puts("ERROR: install_rmod() failed");
puts("ERROR: rmod_install() failed");
return(1);
} else {
printf("rmod installed at seg 0x%04X\r\n", rmod_seg);
224,15 → 292,16
printf("rmod found at seg 0x%04x\r\n", rmod_seg);
}
 
rmod_func = MK_FP(rmod_seg, 0x0A);
/* fetch offset of buffer (result in AX) */
_asm {
call dword ptr [rmod_func]
mov rmod_buff, ax
rmod_envseg = MK_FP(rmod_seg, RMOD_OFFSET_ENVSEG);
 
{
unsigned short envsiz;
unsigned short far *sizptr = MK_FP(*rmod_envseg - 1, 3);
envsiz = *sizptr;
envsiz *= 16;
printf("rmod_inpbuff at %04X:%04X, env_seg at %04X:0000 (env_size = %u bytes)\r\n", rmod_seg, RMOD_OFFSET_INPBUFF, *rmod_envseg, envsiz);
}
 
printf("rmod_buff at %04X:%04X\r\n", rmod_seg, rmod_buff);
 
_asm {
/* set the int22 handler in my PSP to rmod so DOS jumps to rmod after I terminate */
mov bx, 0x0a
240,17 → 309,11
mov [bx], ax
mov ax, rmod_seg
mov [bx+2], ax
/* get the segment of my environment */
mov bx, 0x2c
mov ax, [bx]
mov env_seg, ax
}
 
printf("env_seg at %04X\r\n", env_seg);
 
for (;;) {
int i, argcount;
char far *cmdline = MK_FP(rmod_seg, rmod_buff + 2);
char far *cmdline = MK_FP(rmod_seg, RMOD_OFFSET_INPBUFF + 2);
char path[256] = "C:\\>$";
char const *argvlist[256];
union REGS r;
273,7 → 336,7
mov ax, rmod_seg
push ax
pop ds
mov dx, rmod_buff
mov dx, RMOD_OFFSET_INPBUFF
 
/* execute either DOS input or DOSKEY */
test bl, bl /* zf set if no DOSKEY present */
310,7 → 373,7
 
/* TODO is it an internal command? */
if (strcmp(argvlist[0], "set") == 0) {
cmd_set(argcount, argvlist, env_seg);
cmd_set(argcount, argvlist, *rmod_envseg);
continue;
}