home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet MPEG Audio Archive
/
IMAA.mdf
/
util
/
dos
/
l3v100n
/
rsx
/
source
/
sysdj.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-19
|
16KB
|
653 lines
/* This file is SYSDJ.c
** contains :
**
** - int21,ah=0xff djgpp syscall handler
**
** Copyright (c) Rainer Schnitker 92 93
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <fcntl.h>
#include <direct.h>
#include <io.h>
#include <time.h>
#include <ctype.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "DPMI.H"
#include "PROCESS.H"
#include "SIGNALS.H"
#include "CDOSX32.H"
#include "START32.H"
#include "COPY32.H"
#include "RSX.H"
#include "DOSERRNO.H"
#ifndef __TURBOC__
#define MAXPATH _MAX_PATH
#include <dos.h>
static int stime(time_t *gmt_seconds)
{
struct tm *pTM;
struct dostime_t dost;
pTM = gmtime(gmt_seconds);
dost.hour = (char) pTM->tm_hour;
dost.minute = (char) pTM->tm_min;
dost.second = (char) pTM->tm_sec;
dost.hsecond = 0;
_dos_settime(&dost);
return 0;
}
int convert_open_attrib(int att)
{
int o_rdwr = (att & 0x0F) >> 1; /* bcc O_R/W flags */
if (att & 0x800)
o_rdwr &= O_APPEND;
return (att & 0xFFF0) | o_rdwr;
}
#endif
static int fscan_q(FILE *, char *);
int unixlike_stat(char *, struct stat *);
/*
** move stack,data,bss,heap
** |-CCCCC---------------------------------SSSS-DDDD-HHH-|
** 0 ^0x400000
**
** to the end of text
** |-CCCCC-SSSS-DDDD-HHH-|
*/
void compress_memory(void)
{
DWORD movedmem, newhandle, newaddress;
DWORD r_esp = ESP & ~4095L;
/* check djgpp segment, and stack */
if (npz->data_start != 0x400000L || r_esp > npz->data_start)
return;
movedmem = npz->membytes - r_esp; /* memory to move */
if (r_esp - npz->stack_down < movedmem) /* enough space? */
return;
cpy32_32(DS, r_esp, DS, npz->stack_down, movedmem);
if (ResizeMem(npz->stack_down + movedmem, npz->memhandle, &newhandle,
&newaddress)) {
printf("error:resize memory block\n");
return;
}
if (npz->memaddress != newaddress) {
npz->memaddress = newaddress;
SetBaseAddress(npz->code32sel, npz->memaddress);
SetBaseAddress(npz->data32sel, npz->memaddress);
SetBaseAddress(npz->data32sel + sel_incr, npz->memaddress);
}
npz->p_flags |= PF_COMPRESS;
}
void uncompress_memory(void)
{
DWORD movedmem, newhandle, newaddress;
DWORD r_esp = ESP & ~4095L;
/* check djgpp segment, and stack */
if (npz->data_start != 0x400000L || !(npz->p_flags & PF_COMPRESS))
return;
if (ResizeMem(npz->membytes, npz->memhandle, &newhandle, &newaddress)) {
printf("Can't switch to parant process: ENOMEM\n");
shut_down(1);
}
if (npz->memaddress != newaddress) {
npz->memaddress = newaddress;
SetBaseAddress(npz->code32sel, npz->memaddress);
SetBaseAddress(npz->data32sel, npz->memaddress);
SetBaseAddress(npz->data32sel + sel_incr, npz->memaddress);
}
movedmem = npz->membytes - r_esp; /* memory to move */
cpy32_32(DS, npz->stack_down, DS, r_esp, movedmem);
npz->p_flags &= ~PF_COMPRESS;
}
void def_extention(char *dst, const char *ext)
{
int dot, sep;
dot = 0; sep = 1;
while (*dst != 0)
switch (*dst++)
{
case '.':
dot = 1;
sep = 0;
break;
case ':':
case '/':
case '\\':
dot = 0;
sep = 1;
break;
default:
sep = 0;
break;
}
if (!dot && !sep)
{
*dst++ = '.';
strcpy (dst, ext);
}
}
char * search_path(char *file, char *path)
{
char *list, *end;
int i;
strcpy(path, file);
if (access(path, 4) == 0)
return path;
list = getenv("PATH");
if (list != NULL)
for (;;) {
while (*list == ' ' || *list == '\t')
++list;
if (*list == 0)
break;
end = list;
while (*end != 0 && *end != ';')
++end;
i = end - list;
while (i > 0 && (list[i - 1] == ' ' || list[i - 1] == '\t'))
--i;
if (i != 0) {
memcpy(path, list, i);
if (list[i - 1] != '/' && list[i - 1] != '\\' && list[i - 1] != ':')
path[i++] = '\\';
strcpy(path + i, file);
if (access(path, 4) == 0)
return path;
}
if (*end == 0)
break;
list = end + 1;
}
path[0] = 0;
return (char *)0;
}
struct time32 {
DWORD secs, usecs;
};
struct tz32 {
DWORD offset, dst;
};
struct stat32 {
short st_dev, st_ino, st_mode, st_nlink,
st_uid, st_gid, st_rdev, st_align_for_DWORD;
long st_size, st_atime, st_mtime, st_ctime, st_blksize;
};
int i_21_ff(void)
{
static int dev_count = 1;
int r,i;
DWORD p1 = EBX, p2 = ECX;
switch (AX & 0xff) { /* al=? */
case 1:
strcpy32_16(DS, p1, iobuf); /* p1 -> iobuf */
r = creat(iobuf, S_IREAD | S_IWRITE);
break;
case 2:
strcpy32_16(DS, p1, iobuf); /* p1 -> iobuf */
i = (int) (WORD) p2;
#ifndef __TURBOC__
i = convert_open_attrib(i);
#endif
r = open(iobuf, i, S_IREAD | S_IWRITE);
break;
case 3: /* fstat */
{
struct stat32 statbuf32;
struct stat statbuf;
memset(&statbuf, 0, sizeof(statbuf));
if ((r = fstat((int) p1, &statbuf)) == -1)
break;
statbuf32.st_dev = dev_count++;
statbuf32.st_ino = statbuf.st_ino;
statbuf32.st_mode = statbuf.st_mode;
statbuf32.st_nlink = statbuf.st_nlink;
statbuf32.st_uid = statbuf.st_uid;
statbuf32.st_gid = statbuf.st_gid;
statbuf32.st_rdev = statbuf.st_rdev;
statbuf32.st_size = statbuf.st_size;
statbuf32.st_atime = statbuf.st_atime;
statbuf32.st_mtime = statbuf.st_mtime;
statbuf32.st_ctime = statbuf.st_ctime;
statbuf32.st_blksize = 512;
/* stat -> p2 */
cpy16_32(DS, p2, &statbuf32, (DWORD) sizeof(statbuf32));
}
break;
case 4: /* get time & day */
{
struct time32 time32;
struct tz32 tz32;
if (p2) {
tz32.offset = timezone;
tz32.dst = (long) daylight;
/* tz -> p2 */
cpy16_32(DS, p2, &tz32, (DWORD) sizeof(tz32));
}
if (p1) {
time32.secs = 0;
time((time_t *) & (time32.secs));
time32.usecs = 0;
/* time -> p1 */
cpy16_32(DS, p1, &time32, (DWORD) sizeof(time32));
}
r = 0;
}
break;
case 5: /* set time & day */
{
struct time32 time32;
struct tz32 tz32;
if (p2) {
/* p2 -> tz */
cpy32_16(DS, p2, &tz32, (DWORD) sizeof(tz32));
timezone = tz32.offset;
daylight = (WORD) tz32.dst;
}
if (p1) {
/* p1 -> time */
cpy32_16(DS, p1, &time32, (DWORD) sizeof(time32));
stime((time_t *) & (time32.secs));
}
r = 0;
}
break;
case 6: /* stat */
{
struct stat32 statbuf32;
struct stat statbuf;
char fname[128];
memset(&statbuf, 0, sizeof(statbuf));
strcpy32_16(DS, p1, fname);
r = unixlike_stat(fname, &statbuf);
statbuf32.st_dev = dev_count++;
statbuf32.st_ino = statbuf.st_ino;
statbuf32.st_mode = statbuf.st_mode;
statbuf32.st_nlink = statbuf.st_nlink;
statbuf32.st_uid = statbuf.st_uid;
statbuf32.st_gid = statbuf.st_gid;
statbuf32.st_rdev = statbuf.st_rdev;
statbuf32.st_size = statbuf.st_size;
statbuf32.st_atime = statbuf.st_atime;
statbuf32.st_mtime = statbuf.st_mtime;
statbuf32.st_ctime = statbuf.st_ctime;
statbuf32.st_blksize = 512;
/* stat -> p2 */
cpy16_32(DS, p2, &statbuf32, (DWORD) sizeof(statbuf32));
}
break;
case 7:
{
char *argmem;
char **argp;
char exe[260];
int args;
argmem = (char *) malloc(1000);
argp = (char **) malloc(100);
if (argmem == NULL || argp == NULL) {
if (argmem != NULL)
free(argmem);
EAX = EMX_ENOMEM;
return CARRY_ON;
}
strcpy32_16(DS, p1, argmem);
/* make strings from cmdline ; build argv */
argp[0] = argmem;
args = 1;
for (i = 0; *(argmem + i) != 0; i++)
if (*(argmem + i) == ' ') {
*(argmem + i) = 0;
if (*(argmem + i + 1) == ' ')
continue;
if (*(argmem + i + 1) == 0)
break;
argp[args++] = (argmem + i + 1);
}
argp[args] = 0;
/* check last argument, response file? */
if (argp[args - 1][0] == '@') {
FILE *f;
char buf[80];
char *s = &argmem[i + 2];
args--;
f = fopen(argp[args] + 1, "rt");
while (fscan_q(f, buf) == 1) {
if (!strcmp(buf, "\032"))
continue;
strcpy(s, buf);
argp[args++] = s;
s += strlen(buf) + 1;
}
fclose(f);
argp[args] = 0;
}
if (access(argmem, 0))
if (!search_path(argmem, exe)) {
EAX = EMX_ENOENT;
free(argmem);
free(argp);
return CARRY_ON;
}
else {
argp[0] = exe;
}
/* resize memory to the real used page */
if (npz->entry == 0x1020L)
compress_memory();
r = exec32(P_WAIT, argp[0], args, argp, org_envc, org_env);
/* if error, try a real-mode prg */
if (r == EMX_ENOEXEC) {
r = realmode_prg(argmem, &(argp[0]), org_env);
uncompress_memory(); /* we switch back to father process */
}
if (r) {
errno = r;
r = -1;
}
free(argmem);
free(argp);
}
break;
case 8:
/* ioctl: get mode */
tr.eax = 0x4400;
tr.ebx = p1;
realdos();
i = (WORD) tr.edx;
if (p2 & 0x8000) /* O_BINARY */
i |= 0x20;
else
i &= ~0x20;
/* ioctl: set mode */
tr.eax = 0x4401;
tr.ebx = p1;
tr.edx = (DWORD) i;
realdos();
r = setmode((int) p1, (int) p2);
break;
case 9:
strcpy32_16(DS, p1, iobuf); /* p1 -> iobuf */
r = chmod(iobuf, (int) p2);
break;
default:
r = -1;
break;
} /* switch */
if (r == -1) {
#ifdef __TURBOC__
EAX = (DWORD) doserror_to_errno(_doserrno);
#else
EAX = errno;
#endif
return CARRY_ON;
} else {
EAX = (DWORD) r;
return CARRY_OFF;
}
}
static int fscan_q(FILE * f, char *buf)
{
char *ibuf = buf;
int c, quote = -1, gotsome = 0, addquote = 0;
while ((c = fgetc(f)) != EOF) {
if (c == '\\') {
char c2 = (char) fgetc(f);
if (!strchr("\"'`\\ \t\n\r", c2))
*buf++ = (char) c;
*buf++ = c2;
addquote = 0;
} else if (c == quote) {
quote = -1;
if (c == '\'')
addquote = 1;
} else if (isspace(c) && (quote == -1)) {
if (gotsome) {
if (addquote)
*buf++ = '\'';
*buf = 0;
return 1;
}
addquote = 0;
} else {
if ((quote == -1) && ((c == '"') || (c == '\''))) {
quote = c;
gotsome = 1;
if ((c == '\'') && (buf == ibuf))
*buf++ = (char) c;
} else {
*buf++ = (char) c;
gotsome = 1;
}
addquote = 0;
}
}
return 0;
}
/*
* An improved version of stat(). This version ensures that "." and ".."
* appear to exist in all directories, including Novell network drives, and
* that the root directory also returns the correct result.
*
* This function replaces any \'s with /'s in the input string, it should
* really take a copy of the string first, but this isn't necessary for go32
* which uses a transfer buffer between the program and the DOS extender
* anyway.
*
* Chris Boucher ccb@southampton.ac.uk
*/
/*
* I found the following function on SIMTEL20, it dates back to 1987 but
* there's no mention of who the author was. I've modified/fixed it quite
* a bit. It neatly avoids any problems with "." and ".." on Novell networks.
*/
static int rootpath(const char *relpath, char *fullpath);
int unixlike_stat(char *name, struct stat * buf)
{
static char path[2 * MAXPATH];
char *s = name;
int len;
/* First off, try the standard stat(), if that works then all is well. */
if (stat(name, buf) == 0) {
return 0;
}
/* Swap all \'s for /'s. */
while (*s) {
if (*s == '\\')
*s = '/';
s++;
}
/* Convert path name into root based cannonical form. */
if (rootpath(name, path) != 0) {
return -1;
}
/* DOS doesn't stat "/" correctly, so fake it here. */
if (strcmp(path + 1, ":/") == 0
|| strcmp(path + 1, ":") == 0) {
buf->st_dev = 0;
buf->st_ino = 0;
buf->st_mode = S_IREAD | S_IWRITE | S_IFDIR;
buf->st_uid = buf->st_gid = 0;
buf->st_nlink = 1;
buf->st_rdev = 0;
buf->st_size = 0;
buf->st_atime = buf->st_mtime = buf->st_ctime = 0;
return 0;
}
/* Now modify the string so that "dir/" works. */
len = strlen(path);
if (path[len - 1] == '/')
path[len - 1] = '\0';
return stat(path, buf);
}
/*
* rootpath -- convert a pathname argument to root based cannonical form.
*
* rootpath determines the current directory, appends the path argument (which
* may affect which disk the current directory is relative to), and qualifies
* "." and ".." references. The result is a complete, simple, path name with
* drive specifier.
*
* If the relative path the user specifies does not include a drive spec., the
* default drive will be used as the base. (The default drive will never be
* changed.)
*
* entry: relpath -- pointer to the pathname to be expanded
* fullpath -- must point to a working buffer, see warning
* exit: fullpath -- the full path which results
* return: -1 if an error occurs, 0 otherwise
*
* warning: fullpath must point to a working buffer large enough to hold the
* longest possible relative path argument plus the longest possible
* current directory path.
*/
static int rootpath(const char *relpath, char *fullpath)
{
register char *lead, *follow, *s;
char tempchar;
int drivenum;
/* Extract drive spec. */
if ((*relpath != '\0') && (relpath[1] == ':')) {
drivenum = toupper(*relpath) - 'A';
relpath += 2;
} else {
drivenum = _getdrive();
}
/* Fill in the drive path. */
strcpy(fullpath, " :/");
fullpath[0] = (char) (drivenum + 'A');
#ifdef __TURBOC__
/* Get cwd for drive - also checks that drive exists. */
if (getcurdir(drivenum + 1, fullpath + 3) == -1) {
return -1; /* No such drive - give up. */
}
#else
if (!_getdcwd(drivenum +1 , fullpath + 3, _MAX_PATH))
return -1;
#endif
/* Swap all \'s for /'s. */
s = fullpath;
while (*s) {
if (*s == '\\')
*s = '/';
s++;
}
/* Append relpath to fullpath/base. */
if (*relpath == '/') { /* relpath starts at base... */
strcpy(fullpath + 2, relpath); /* ...so ignore cwd. */
} else { /* relpath is relative to cwd. */
if (*relpath != '\0') {
if (strlen(fullpath) > 3) {
strcat(fullpath, "/"); /* Add a '/' to end of cwd. */
}
strcat(fullpath, relpath); /* Add relpath to end of cwd. */
}
}
/* Convert path to cannonical form. */
lead = fullpath;
while (*lead != '\0') {
/* Mark next path segment. */
follow = lead;
lead = (char *) strchr(follow + 1, '/');
if (lead == 0) {
lead = fullpath + strlen(fullpath);
}
tempchar = *lead;
*lead = '\0';
/* "." segment? */
if (strcmp(follow + 1, ".") == 0) {
*lead = tempchar;
strcpy(follow, lead); /* Remove "." segment. */
lead = follow;
}
/* ".." segment? */
else if (strcmp(follow + 1, "..") == 0) {
*lead = tempchar;
do {
if (--follow < fullpath) {
follow = fullpath + 2;
break;
}
} while (*follow != '/');
strcpy(follow, lead); /* Remove ".." segment. */
lead = follow;
}
/* Normal segment. */
else {
*lead = tempchar;
}
}
if (strlen(fullpath) == 2) {/* 'D:' or some such. */
strcat(fullpath, "/");
}
/* All done. */
return 0;
}