Merge pull request #229 from tkchia/tkchia/msdos86
Add support for compiling MS-DOS .com programs (msdos86).
This commit is contained in:
commit
a740f476c2
1
README
1
README
|
@ -37,6 +37,7 @@ linuxmips produces ELF executables for little-endian MIPS32r2 Linux systems
|
|||
cpm produces i80 CP/M .COM files
|
||||
rpi produces Raspberry Pi GPU binaries
|
||||
pdpv7 produces PDP/11 V7 Unix binaries
|
||||
msdos86 produces i86 MS-DOS .COM files
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ vars.plats = {
|
|||
"linux68k",
|
||||
"linuxppc",
|
||||
"linuxmips",
|
||||
"msdos86",
|
||||
"osx386",
|
||||
"osxppc",
|
||||
"pc86",
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
#define ACKCONF_WANT_STANDARD_O 1
|
||||
#endif
|
||||
|
||||
#ifndef ACKCONF_WANT_O_TEXT_O_BINARY
|
||||
#define ACKCONF_WANT_O_TEXT_O_BINARY 0
|
||||
#endif
|
||||
|
||||
#ifndef ACKCONF_WANT_STANDARD_SIGNALS
|
||||
#define ACKCONF_WANT_STANDARD_SIGNALS 1
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,7 @@ struct FILE {
|
|||
#define _IOREADING 0x080
|
||||
#define _IOWRITING 0x100
|
||||
#define _IOAPPEND 0x200
|
||||
#define _IOBINARY 0x400
|
||||
|
||||
#if !defined BUFSIZ
|
||||
#define BUFSIZ 1024
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
O_WRONLY = 1,
|
||||
O_RDWR = 2,
|
||||
|
||||
#if ACKCONF_WANT_O_TEXT_O_BINARY
|
||||
O_TEXT = 010000,
|
||||
O_BINARY = 020000,
|
||||
#endif
|
||||
O_CREAT = 0100,
|
||||
O_TRUNC = 01000,
|
||||
O_APPEND = 02000,
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if ACKCONF_WANT_O_TEXT_O_BINARY
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#if ACKCONF_WANT_STDIO && ACKCONF_WANT_EMULATED_FILE
|
||||
|
||||
|
@ -38,6 +42,9 @@ FILE* fdopen(int fd, const char* mode)
|
|||
switch (*mode++)
|
||||
{
|
||||
case 'b':
|
||||
#if ACKCONF_WANT_O_TEXT_O_BINARY
|
||||
flags |= _IOBINARY;
|
||||
#endif
|
||||
continue;
|
||||
case '+':
|
||||
flags |= _IOREAD | _IOWRITE;
|
||||
|
@ -57,6 +64,17 @@ FILE* fdopen(int fd, const char* mode)
|
|||
if ((flags & _IOREAD) && (flags & _IOWRITE))
|
||||
flags &= ~(_IOREADING | _IOWRITING);
|
||||
|
||||
#if ACKCONF_WANT_O_TEXT_O_BINARY
|
||||
{
|
||||
/*
|
||||
* FIXME: this assumes that any platform that has O_TEXT and
|
||||
* O_BINARY will also have a _setmode() function.
|
||||
*/
|
||||
extern int _setmode(int, int);
|
||||
_setmode(fd, (flags & _IOBINARY) ? O_BINARY : O_TEXT);
|
||||
}
|
||||
#endif
|
||||
|
||||
stream->_count = 0;
|
||||
stream->_fd = fd;
|
||||
stream->_flags = flags;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if ACKCONF_WANT_STDIO && ACKCONF_WANT_EMULATED_FILE
|
||||
|
||||
|
@ -68,6 +67,9 @@ FILE* fopen(const char* name, const char* mode)
|
|||
switch (*mode++)
|
||||
{
|
||||
case 'b':
|
||||
#if ACKCONF_WANT_O_TEXT_O_BINARY
|
||||
flags |= _IOBINARY;
|
||||
#endif
|
||||
continue;
|
||||
case '+':
|
||||
rwmode = O_RDWR;
|
||||
|
@ -80,6 +82,7 @@ FILE* fopen(const char* name, const char* mode)
|
|||
break;
|
||||
}
|
||||
|
||||
#if !ACKCONF_WANT_O_TEXT_O_BINARY
|
||||
/* Perform a creat() when the file should be truncated or when
|
||||
* the file is opened for writing and the open() failed.
|
||||
*/
|
||||
|
@ -87,12 +90,16 @@ FILE* fopen(const char* name, const char* mode)
|
|||
|| (((fd = open(name, rwmode)) < 0)
|
||||
&& (rwflags & O_CREAT)))
|
||||
{
|
||||
if (((fd = creat(name, PMODE)) > 0) && flags | _IOREAD)
|
||||
if (((fd = creat(name, PMODE)) >= 0) && (flags & _IOREAD))
|
||||
{
|
||||
(void)close(fd);
|
||||
fd = open(name, rwmode);
|
||||
}
|
||||
}
|
||||
#else
|
||||
rwflags |= (flags & _IOBINARY) ? O_BINARY : O_TEXT;
|
||||
fd = open(name, rwmode | rwflags, PMODE);
|
||||
#endif
|
||||
|
||||
if (fd < 0)
|
||||
return (FILE*)NULL;
|
||||
|
|
|
@ -50,6 +50,9 @@ FILE* freopen(const char* name, const char* mode, FILE* stream)
|
|||
switch (*mode++)
|
||||
{
|
||||
case 'b':
|
||||
#if ACKCONF_WANT_O_TEXT_O_BINARY
|
||||
flags |= _IOBINARY;
|
||||
#endif
|
||||
continue;
|
||||
case '+':
|
||||
rwmode = O_RDWR;
|
||||
|
@ -62,16 +65,21 @@ FILE* freopen(const char* name, const char* mode, FILE* stream)
|
|||
break;
|
||||
}
|
||||
|
||||
#if !ACKCONF_WANT_O_TEXT_O_BINARY
|
||||
if ((rwflags & O_TRUNC)
|
||||
|| (((fd = open(name, rwmode)) < 0)
|
||||
&& (rwflags & O_CREAT)))
|
||||
{
|
||||
if (((fd = creat(name, PMODE)) < 0) && flags | _IOREAD)
|
||||
if (((fd = creat(name, PMODE)) >= 0) && (flags & _IOREAD))
|
||||
{
|
||||
(void)close(fd);
|
||||
fd = open(name, rwmode);
|
||||
}
|
||||
}
|
||||
#else
|
||||
rwflags |= (flags & _IOBINARY) ? O_BINARY : O_TEXT;
|
||||
fd = open(name, rwmode | rwflags, PMODE);
|
||||
#endif
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
|
|
145
plat/msdos86/boot.s
Normal file
145
plat/msdos86/boot.s
Normal file
|
@ -0,0 +1,145 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
begtext:
|
||||
! Make sure we are running under MS-DOS 2 or above.
|
||||
!
|
||||
! While at it, also remember the actual DOS version, so that we know
|
||||
! whether DOS gives us the program's name in the environment
|
||||
! segment. (DOS 3+ does; DOS 2.x does not.)
|
||||
movb ah, 0x30
|
||||
int 0x21
|
||||
cmpb al, 2
|
||||
xchg bx, ax
|
||||
jc bad_sys
|
||||
|
||||
! Clear BSS.
|
||||
mov di, begbss
|
||||
mov cx, endbss+1
|
||||
sub cx, di
|
||||
shr cx, 1
|
||||
xor ax, ax
|
||||
cld
|
||||
rep stosw
|
||||
|
||||
! Get the size of the environment variables plus (if present) the
|
||||
! program name. Also count the number of environment variables.
|
||||
mov es, (0x002C)
|
||||
xor di, di
|
||||
! ax = 0 from above
|
||||
cwd ! dx = count of env. vars.
|
||||
mov cx, -1
|
||||
scasb ! handle special case of empty env.
|
||||
jz is_empty_env
|
||||
size_env:
|
||||
inc dx
|
||||
repnz scasb
|
||||
scasb
|
||||
jnz size_env
|
||||
is_empty_env:
|
||||
cmpb bl, 2
|
||||
jz no_argv0
|
||||
scasw
|
||||
repnz scasb
|
||||
no_argv0:
|
||||
|
||||
! Copy out the environment variables and (possibly) program name
|
||||
! onto the stack.
|
||||
mov si, di
|
||||
dec si
|
||||
and si, -2
|
||||
std
|
||||
copy_env:
|
||||
test si, si
|
||||
eseg lodsw
|
||||
push ax
|
||||
jnz copy_env
|
||||
mov cx, sp
|
||||
|
||||
! Reset DF and es properly.
|
||||
cld
|
||||
push ss
|
||||
pop es
|
||||
|
||||
! Reserve space for argc and the argv and envp pointers on the
|
||||
! stack. These will be passed to __m_a_i_n later.
|
||||
sub sp, 6
|
||||
mov ax, sp
|
||||
|
||||
! Build up argc, argv[], and envp[].
|
||||
push ax ! output buffer for argc, argv, envp
|
||||
push bx ! MS-DOS version
|
||||
push cx ! env. string data
|
||||
push dx ! count of env. vars.
|
||||
mov ax, 0x0080
|
||||
push ax ! raw command line
|
||||
call __sys_initmain
|
||||
add sp, 10
|
||||
|
||||
! Bail out if something went wrong.
|
||||
test ax, ax
|
||||
jnz no_room
|
||||
|
||||
! argc, argv, and envp are now at the stack top. Now go.
|
||||
call __m_a_i_n
|
||||
add sp, 6
|
||||
push ax
|
||||
call _exit
|
||||
|
||||
bad_sys:
|
||||
mov dx, bad_sys_msg
|
||||
dos_msg:
|
||||
movb ah, 9
|
||||
int 0x21
|
||||
ret
|
||||
|
||||
no_room:
|
||||
mov dx, no_room_msg
|
||||
call dos_msg
|
||||
movb al, -1
|
||||
jmp al_exit
|
||||
|
||||
! Exit.
|
||||
.define __exit
|
||||
.extern __exit
|
||||
.define EXIT
|
||||
.extern EXIT
|
||||
__exit:
|
||||
EXIT:
|
||||
pop bx
|
||||
pop ax
|
||||
al_exit:
|
||||
movb ah, 0x4c
|
||||
int 0x21
|
||||
|
||||
! Define symbols at the beginning of our various segments, so that we can find
|
||||
! them. (Except .text, which has already been done.)
|
||||
|
||||
.define begtext, begdata, begbss
|
||||
.sect .data; begdata:
|
||||
.sect .rom; begrom:
|
||||
.sect .bss; begbss:
|
||||
|
||||
.sect .rom
|
||||
|
||||
! Some text messages.
|
||||
bad_sys_msg: .ascii 'Bad DOS$'
|
||||
no_room_msg: .ascii 'No room$'
|
||||
|
||||
! Some magic data. All EM systems need these.
|
||||
|
||||
.define .trppc, .ignmask, _errno
|
||||
.comm .trppc, 4
|
||||
.comm .ignmask, 4
|
||||
.comm _errno, 4
|
25
plat/msdos86/build-pkg.lua
Normal file
25
plat/msdos86/build-pkg.lua
Normal file
|
@ -0,0 +1,25 @@
|
|||
include("plat/build.lua")
|
||||
|
||||
ackfile {
|
||||
name = "boot",
|
||||
srcs = { "./boot.s" },
|
||||
vars = { plat = "msdos86" }
|
||||
}
|
||||
|
||||
build_plat_libs {
|
||||
name = "libs",
|
||||
arch = "i86",
|
||||
plat = "msdos86",
|
||||
}
|
||||
|
||||
installable {
|
||||
name = "pkg",
|
||||
map = {
|
||||
"+tools",
|
||||
"+libs",
|
||||
"./include+pkg",
|
||||
["$(PLATIND)/msdos86/boot.o"] = "+boot",
|
||||
["$(PLATIND)/msdos86/libsys.a"] = "./libsys+lib",
|
||||
}
|
||||
}
|
||||
|
21
plat/msdos86/build-tools.lua
Normal file
21
plat/msdos86/build-tools.lua
Normal file
|
@ -0,0 +1,21 @@
|
|||
include("plat/build.lua")
|
||||
|
||||
build_as {
|
||||
name = "as",
|
||||
arch = "i86",
|
||||
}
|
||||
|
||||
build_ncg {
|
||||
name = "ncg",
|
||||
arch = "i86",
|
||||
}
|
||||
|
||||
return installable {
|
||||
name = "tools",
|
||||
map = {
|
||||
["$(PLATDEP)/msdos86/as"] = "+as",
|
||||
["$(PLATDEP)/msdos86/ncg"] = "+ncg",
|
||||
["$(PLATIND)/descr/msdos86"] = "./descr",
|
||||
"util/opt+pkg",
|
||||
}
|
||||
}
|
88
plat/msdos86/descr
Normal file
88
plat/msdos86/descr
Normal file
|
@ -0,0 +1,88 @@
|
|||
# $Source$
|
||||
# $State$
|
||||
# $Revision$
|
||||
|
||||
var w=2
|
||||
var wa=2
|
||||
var p=2
|
||||
var pa=2
|
||||
var s=2
|
||||
var sa=2
|
||||
var l=4
|
||||
var la=2
|
||||
var f=4
|
||||
var fa=2
|
||||
var d=8
|
||||
var da=2
|
||||
var x=8
|
||||
var xa=2
|
||||
var ARCH=i86
|
||||
var PLATFORM=msdos86
|
||||
var PLATFORMDIR={EM}/share/ack/{PLATFORM}
|
||||
var CPP_F=-D__MSDOS__ -D__DOS__ -D_DOS
|
||||
var ALIGN=-a0:2 -a1:2 -a2:2 -a3:2
|
||||
var MACHOPT_F=-m8
|
||||
var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr
|
||||
|
||||
# Override the setting in fe so that files compiled for this platform can see
|
||||
# the platform-specific headers.
|
||||
|
||||
var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi
|
||||
|
||||
# These will be overridden under the small (separate I/D) memory model.
|
||||
|
||||
var SEPID=-b0:0x100
|
||||
var LOD=aslod
|
||||
|
||||
name be
|
||||
from .m.g
|
||||
to .s
|
||||
program {EM}/lib/ack/{PLATFORM}/ncg
|
||||
args <
|
||||
stdout
|
||||
need .e
|
||||
end
|
||||
name as
|
||||
from .s.so
|
||||
to .o
|
||||
program {EM}/lib/ack/{PLATFORM}/as
|
||||
args - -o > <
|
||||
prep cond
|
||||
end
|
||||
name led
|
||||
from .o.a
|
||||
to .out
|
||||
program {EM}/lib/ack/em_led
|
||||
mapflag -l* LNAME={PLATFORMDIR}/lib*
|
||||
mapflag -i SEPID=-b1:0
|
||||
mapflag -fp FLOATS={EM}/{ILIB}fp
|
||||
args {ALIGN} {SEPID} \
|
||||
({RTS}:.b=-u _i_main) \
|
||||
(.e:{HEAD}={PLATFORMDIR}/boot.o) \
|
||||
({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
|
||||
({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
|
||||
({RTS}:.mod={PLATFORMDIR}/modula2.o) \
|
||||
({RTS}:.p={PLATFORMDIR}/pascal.o) \
|
||||
-o > < \
|
||||
(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
|
||||
(.b:{TAIL}={PLATFORMDIR}/libb.a) \
|
||||
(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
|
||||
(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
|
||||
(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
|
||||
(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
|
||||
{FLOATS?} \
|
||||
(.e:{TAIL}={PLATFORMDIR}/libem.a \
|
||||
{PLATFORMDIR}/libsys.a \
|
||||
{PLATFORMDIR}/libc.a \
|
||||
{PLATFORMDIR}/libem.a \
|
||||
{PLATFORMDIR}/libend.a)
|
||||
linker
|
||||
end
|
||||
name cv
|
||||
from .out
|
||||
to .exe
|
||||
mapflag -i LOD=amzlod
|
||||
program {EM}/bin/{LOD}
|
||||
args < >
|
||||
outfile msdos86.exe
|
||||
end
|
11
plat/msdos86/include/ack/plat.h
Normal file
11
plat/msdos86/include/ack/plat.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#ifndef _ACK_PLAT_H
|
||||
#define _ACK_PLAT_H
|
||||
|
||||
#define ACKCONF_WANT_O_TEXT_O_BINARY 1
|
||||
|
||||
#endif
|
24
plat/msdos86/include/build.lua
Normal file
24
plat/msdos86/include/build.lua
Normal file
|
@ -0,0 +1,24 @@
|
|||
include("plat/build.lua")
|
||||
|
||||
headermap = {}
|
||||
packagemap = {}
|
||||
|
||||
local function addheader(h)
|
||||
headermap[h] = "./"..h
|
||||
packagemap["$(PLATIND)/msdos86/include/"..h] = "./"..h
|
||||
end
|
||||
|
||||
addheader("ack/plat.h")
|
||||
addheader("sys/types.h")
|
||||
|
||||
acklibrary {
|
||||
name = "headers",
|
||||
hdrs = headermap
|
||||
}
|
||||
|
||||
installable {
|
||||
name = "pkg",
|
||||
map = packagemap
|
||||
}
|
||||
|
||||
|
9
plat/msdos86/include/sys/types.h
Normal file
9
plat/msdos86/include/sys/types.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef _SYS_TYPES_H
|
||||
#define _SYS_TYPES_H
|
||||
|
||||
typedef long pid_t;
|
||||
typedef int mode_t;
|
||||
typedef long time_t;
|
||||
typedef long suseconds_t;
|
||||
|
||||
#endif
|
19
plat/msdos86/libsys/_hol0.s
Normal file
19
plat/msdos86/libsys/_hol0.s
Normal file
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .bss
|
||||
|
||||
! This data block is used to store information about the current line number
|
||||
! and file.
|
||||
|
||||
.define hol0
|
||||
.comm hol0, 8
|
59
plat/msdos86/libsys/brk.c
Normal file
59
plat/msdos86/libsys/brk.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "libsys.h"
|
||||
|
||||
#define STACK_BUFFER 128 /* number of bytes to leave for stack */
|
||||
|
||||
extern char _end[1];
|
||||
static char* current = _end;
|
||||
|
||||
int brk(void* newend)
|
||||
{
|
||||
/* This variable is used to figure out the current stack pointer,
|
||||
* by taking its address. */
|
||||
char dummy;
|
||||
char* p = newend;
|
||||
|
||||
if ((p > (&dummy - STACK_BUFFER)) ||
|
||||
(p < _end))
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
current = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* sbrk(int increment)
|
||||
{
|
||||
char* old;
|
||||
char* new;
|
||||
|
||||
if (increment == 0)
|
||||
return current;
|
||||
|
||||
old = current;
|
||||
|
||||
new = old + increment;
|
||||
|
||||
if ((increment > 0) && (new <= old))
|
||||
goto out_of_memory;
|
||||
else if ((increment < 0) && (new >= old))
|
||||
goto out_of_memory;
|
||||
|
||||
if (brk(new) < 0)
|
||||
goto out_of_memory;
|
||||
|
||||
return old;
|
||||
|
||||
out_of_memory:
|
||||
errno = ENOMEM;
|
||||
return OUT_OF_MEMORY;
|
||||
}
|
15
plat/msdos86/libsys/build.lua
Normal file
15
plat/msdos86/libsys/build.lua
Normal file
|
@ -0,0 +1,15 @@
|
|||
acklibrary {
|
||||
name = "lib",
|
||||
srcs = {
|
||||
"./*.c",
|
||||
"./*.s",
|
||||
},
|
||||
deps = {
|
||||
"lang/cem/libcc.ansi/headers+headers",
|
||||
"plat/msdos86/include+headers",
|
||||
},
|
||||
vars = {
|
||||
plat = "msdos86"
|
||||
}
|
||||
}
|
||||
|
23
plat/msdos86/libsys/close.s
Normal file
23
plat/msdos86/libsys/close.s
Normal file
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Close a file.
|
||||
|
||||
.define _close
|
||||
_close:
|
||||
mov bx, sp
|
||||
mov bx, 2(bx)
|
||||
movb ah, 0x3E
|
||||
int 0x21
|
||||
jmp .sys_zret
|
14
plat/msdos86/libsys/creat.c
Normal file
14
plat/msdos86/libsys/creat.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "libsys.h"
|
||||
|
||||
int creat(const char* path, int mode)
|
||||
{
|
||||
return open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
|
||||
}
|
28
plat/msdos86/libsys/errno.s
Normal file
28
plat/msdos86/libsys/errno.s
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
#define D(e) .define e; e
|
||||
|
||||
.sect .data
|
||||
|
||||
! Define various ACK error numbers. Note that these are *not* ANSI C
|
||||
! errnos, and are used for different purposes.
|
||||
|
||||
D(ERANGE) = 1
|
||||
D(ESET) = 2
|
||||
D(EIDIVZ) = 6
|
||||
D(EHEAP) = 17
|
||||
D(EILLINS) = 18
|
||||
D(EODDZ) = 19
|
||||
D(ECASE) = 20
|
||||
D(EBADMON) = 25
|
||||
|
27
plat/msdos86/libsys/getpid.s
Normal file
27
plat/msdos86/libsys/getpid.s
Normal file
|
@ -0,0 +1,27 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Get the current process identifier. For MS-DOS, use the Program Segment
|
||||
! Prefix (PSP) segment as the PID.
|
||||
!
|
||||
! (Note that pid_t is a 32-bit type. This is to allow for PSP addresses
|
||||
! above 0x7FFF:0.)
|
||||
|
||||
.define _getpid
|
||||
_getpid:
|
||||
movb ah, 0x51
|
||||
int 0x21
|
||||
xchg bx, ax
|
||||
xor dx, dx
|
||||
ret
|
92
plat/msdos86/libsys/gettimeofday.c
Normal file
92
plat/msdos86/libsys/gettimeofday.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Derived from dos-gettimeofday.c for newlib-ia16 which was written for the
|
||||
* gcc-ia16 toolchain.
|
||||
*
|
||||
* Copyright (c) 2017--2021 TK Chia
|
||||
*
|
||||
* The authors hereby grant permission to use, copy, modify, distribute,
|
||||
* and license this software and its documentation for any purpose, provided
|
||||
* that existing copyright notices are retained in all copies and that this
|
||||
* notice is included verbatim in any distributions. No written agreement,
|
||||
* license, or royalty fee is required for any of the authorized uses.
|
||||
* Modifications to this software may be copyrighted by their authors
|
||||
* and need not follow the licensing terms described here, provided that
|
||||
* the new terms are clearly indicated on the first page of each file where
|
||||
* they apply.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include "libsys.h"
|
||||
|
||||
extern long _timezone;
|
||||
extern int _daylight;
|
||||
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
static volatile bool tzinited = false;
|
||||
struct _dosdate dosdt, olddt;
|
||||
struct _dostime dostm;
|
||||
suseconds_t usec;
|
||||
struct tm tm;
|
||||
time_t tim;
|
||||
|
||||
if (!tzinited)
|
||||
{
|
||||
tzset();
|
||||
tzinited = true;
|
||||
}
|
||||
|
||||
memset(&tm, 0, sizeof tm);
|
||||
|
||||
_sys_getdate(&dosdt);
|
||||
do
|
||||
{
|
||||
uint8_t hour;
|
||||
|
||||
_sys_gettime(&dostm);
|
||||
tm.tm_hour = hour = dostm.hour;
|
||||
tm.tm_min = dostm.minute;
|
||||
tm.tm_sec = dostm.second;
|
||||
usec = dostm.hsecond * 10000UL;
|
||||
|
||||
/* If the time is close to midnight, read the date again to
|
||||
* check for midnight crossover. If crossover happens,
|
||||
* repeat until it stops. */
|
||||
if (hour)
|
||||
break;
|
||||
|
||||
olddt = dosdt;
|
||||
_sys_getdate(&dosdt);
|
||||
} while (dosdt.day != olddt.day);
|
||||
|
||||
tm.tm_year = dosdt.year - 1900;
|
||||
tm.tm_mon = dosdt.month - 1;
|
||||
tm.tm_mday = dosdt.day;
|
||||
tm.tm_isdst = -1;
|
||||
|
||||
tim = mktime(&tm);
|
||||
if (tim == -1)
|
||||
return -1;
|
||||
|
||||
if (tv)
|
||||
{
|
||||
tv->tv_sec = tim;
|
||||
tv->tv_usec = usec;
|
||||
}
|
||||
|
||||
if (tz)
|
||||
{
|
||||
tz->tz_minuteswest = _timezone / 60;
|
||||
tz->tz_dsttime = _daylight;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
37
plat/msdos86/libsys/isatty.s
Normal file
37
plat/msdos86/libsys/isatty.s
Normal file
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Say whether a given file descriptor number refers to a terminal.
|
||||
|
||||
.define _isatty
|
||||
_isatty:
|
||||
mov bx, sp
|
||||
mov bx, 2(bx)
|
||||
mov ax, 0x4400
|
||||
int 0x21
|
||||
jc error
|
||||
testb dl, dl
|
||||
jz not_tty
|
||||
mov ax, 1
|
||||
ret
|
||||
not_tty:
|
||||
mov (_errno), 25 ! ENOTTY
|
||||
not_tty_2:
|
||||
xor ax, ax
|
||||
ret
|
||||
error:
|
||||
push ax
|
||||
call __sys_seterrno
|
||||
pop cx
|
||||
jmp not_tty_2
|
14
plat/msdos86/libsys/kill.c
Normal file
14
plat/msdos86/libsys/kill.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int kill(pid_t pid, int sig)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
74
plat/msdos86/libsys/libsys.h
Normal file
74
plat/msdos86/libsys/libsys.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#ifndef LIBSYS_H
|
||||
#define LIBSYS_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define OUT_OF_MEMORY ((void *)-1) /* sbrk returns this on failure */
|
||||
|
||||
/*
|
||||
* Data structure for remembering whether each file descriptor is open in
|
||||
* text mode (O_TEXT) or binary mode (O_BINARY).
|
||||
*
|
||||
* Currently this is just a simple linked list, where each linked list node
|
||||
* records the modes for 16 file descriptors, in bit vector form (0: text,
|
||||
* 1: binary). In addition, each node also remembers, for each of its file
|
||||
* descriptors, whether an end-of-file (^Z) character was encountered when
|
||||
* reading from it in text mode.
|
||||
*
|
||||
* List nodes are allocated using sbrk() and never freed.
|
||||
*
|
||||
* This scheme should be fast and light enough, as the number of open file
|
||||
* descriptors is expected to be small.
|
||||
*
|
||||
* FIXME: the code for updating this structure is not exactly thread-safe.
|
||||
*/
|
||||
typedef uint16_t _fdvec_t;
|
||||
|
||||
struct _fdmodes {
|
||||
struct _fdmodes *next;
|
||||
int begfd;
|
||||
_fdvec_t modevec, eofvec;
|
||||
};
|
||||
|
||||
extern struct _fdmodes _sys_fdmodes;
|
||||
|
||||
#define _FDVECMASK (sizeof(_fdvec_t) * CHAR_BIT - 1)
|
||||
|
||||
/* Structures for getting MS-DOS's idea of the current date and time. */
|
||||
|
||||
struct _dosdate {
|
||||
uint8_t day;
|
||||
uint8_t month;
|
||||
uint16_t year;
|
||||
};
|
||||
|
||||
struct _dostime {
|
||||
uint8_t minute;
|
||||
uint8_t hour;
|
||||
uint8_t hsecond;
|
||||
uint8_t second;
|
||||
};
|
||||
|
||||
extern int _sys_getmode(int);
|
||||
extern int _sys_setmode(int, int);
|
||||
extern int _sys_iseof(int);
|
||||
extern int _sys_seteof(int, int);
|
||||
extern ssize_t _sys_rawread(int, char *, size_t);
|
||||
extern ssize_t _sys_rawwrite(int, const char *, size_t);
|
||||
extern int _sys_isopen(int);
|
||||
extern int _sys_isreadyr(int);
|
||||
extern int _sys_exists(const char *);
|
||||
extern int _sys_rawcreat(const char *, unsigned);
|
||||
extern int _sys_rawopen(const char *, int);
|
||||
extern off_t _sys_rawlseek(int, off_t, int);
|
||||
extern void _sys_getdate(struct _dosdate *);
|
||||
extern void _sys_gettime(struct _dostime *);
|
||||
|
||||
#endif
|
26
plat/msdos86/libsys/lseek.c
Normal file
26
plat/msdos86/libsys/lseek.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "libsys.h"
|
||||
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
off_t newoff;
|
||||
|
||||
if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1L;
|
||||
}
|
||||
|
||||
newoff = _sys_rawlseek(fd, offset, whence);
|
||||
if (newoff != -1L)
|
||||
_sys_seteof(fd, 0);
|
||||
|
||||
return newoff;
|
||||
}
|
101
plat/msdos86/libsys/open.c
Normal file
101
plat/msdos86/libsys/open.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Derived from dos-open.c for newlib-ia16 which was written for the
|
||||
* gcc-ia16 toolchain.
|
||||
*
|
||||
* Copyright (c) 2018 Bart Oldeman
|
||||
* Copyright (c) 2019--2021 TK Chia
|
||||
*
|
||||
* The authors hereby grant permission to use, copy, modify, distribute,
|
||||
* and license this software and its documentation for any purpose, provided
|
||||
* that existing copyright notices are retained in all copies and that this
|
||||
* notice is included verbatim in any distributions. No written agreement,
|
||||
* license, or royalty fee is required for any of the authorized uses.
|
||||
* Modifications to this software may be copyrighted by their authors
|
||||
* and need not follow the licensing terms described here, provided that
|
||||
* the new terms are clearly indicated on the first page of each file where
|
||||
* they apply.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "libsys.h"
|
||||
|
||||
int open(const char* pathname, int flags, ...)
|
||||
{
|
||||
int fd = -1, binmode;
|
||||
off_t ret;
|
||||
|
||||
if ((flags & ~(O_ACCMODE | O_CREAT | O_TRUNC | O_APPEND
|
||||
| O_TEXT | O_BINARY)))
|
||||
{
|
||||
/* bail out if there are unknown flags */
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
binmode = flags & (O_TEXT | O_BINARY);
|
||||
if (binmode != O_TEXT && binmode != O_BINARY && binmode != 0)
|
||||
{
|
||||
/* bail out if both O_TEXT and O_BINARY are specified (!) */
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((flags & O_CREAT))
|
||||
{
|
||||
/* special but common case O_WRONLY | O_CREAT | O_TRUNC
|
||||
* should be handled by only calling _sys_rawcreat */
|
||||
int fileexists = 0;
|
||||
if (!(flags & O_TRUNC))
|
||||
fileexists = _sys_exists(pathname);
|
||||
if (!fileexists)
|
||||
{
|
||||
va_list ap;
|
||||
mode_t mode;
|
||||
|
||||
va_start(ap, flags);
|
||||
mode = va_arg(ap, mode_t);
|
||||
va_end(ap);
|
||||
|
||||
fd = _sys_rawcreat(pathname, mode & 0200 ? 0 : 1);
|
||||
if (fd != -1)
|
||||
{
|
||||
if ((flags & O_ACCMODE) == O_WRONLY)
|
||||
return fd;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* try to open file with mode */
|
||||
if (fd == -1)
|
||||
fd = _sys_rawopen(pathname, flags & O_ACCMODE);
|
||||
if (fd == -1)
|
||||
return fd;
|
||||
ret = 0;
|
||||
|
||||
/* handle O_TRUNC and O_APPEND */
|
||||
if ((flags & O_TRUNC))
|
||||
ret = _sys_rawwrite(fd, NULL, 0);
|
||||
else if ((flags & O_APPEND))
|
||||
ret = _sys_rawlseek(fd, 0L, SEEK_END);
|
||||
if (ret == -1)
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* handle O_TEXT and O_BINARY, and reset "end of file encountered" */
|
||||
_sys_setmode(fd, binmode == O_BINARY ? O_BINARY : O_TEXT);
|
||||
_sys_seteof(fd, 0);
|
||||
|
||||
return fd;
|
||||
}
|
77
plat/msdos86/libsys/read.c
Normal file
77
plat/msdos86/libsys/read.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "libsys.h"
|
||||
|
||||
ssize_t read(int fd, void* buffer, size_t count)
|
||||
{
|
||||
char *p, *q;
|
||||
ssize_t r, tot;
|
||||
size_t left;
|
||||
int eof = 0;
|
||||
|
||||
if (!count || _sys_getmode(fd) == O_BINARY)
|
||||
return _sys_rawread(fd, buffer, count);
|
||||
|
||||
if (_sys_iseof(fd))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the file descriptor is an O_TEXT fd, read from it, and then
|
||||
* remove CRs from the input. After removing CRs, if the buffer is
|
||||
* not filled and the fd still has bytes left to read, then keep
|
||||
* reading, and keep removing CRs.
|
||||
*
|
||||
* Also handle end-of-file indicators (^Z). If we see one, move the
|
||||
* file pointer to just before the ^Z. Also set an internal flag
|
||||
* for the fd so that we do not try to read any further (until e.g.
|
||||
* a seek happens).
|
||||
*/
|
||||
p = buffer;
|
||||
tot = 0;
|
||||
|
||||
do
|
||||
{
|
||||
r = _sys_rawread(fd, p, count - (p - (char *)buffer));
|
||||
if (r <= 0)
|
||||
return tot;
|
||||
|
||||
q = memchr(p, 0x1a, (size_t)r);
|
||||
if (q)
|
||||
{
|
||||
_sys_rawlseek(fd, (off_t)(q - p) - r, SEEK_CUR);
|
||||
r = q - p;
|
||||
eof = 1;
|
||||
_sys_seteof(fd, 1);
|
||||
}
|
||||
|
||||
q = memchr(p, '\r', (size_t)r);
|
||||
if (!q)
|
||||
return tot + r;
|
||||
|
||||
tot += q - p;
|
||||
left = r - (q + 1 - p);
|
||||
p = q;
|
||||
++q;
|
||||
|
||||
while (left)
|
||||
{
|
||||
char c = *q++;
|
||||
if (c != '\r')
|
||||
{
|
||||
*p++ = c;
|
||||
++tot;
|
||||
}
|
||||
--left;
|
||||
}
|
||||
} while (tot < count && !eof && _sys_isreadyr(fd));
|
||||
|
||||
return tot;
|
||||
}
|
23
plat/msdos86/libsys/setmode.c
Normal file
23
plat/msdos86/libsys/setmode.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include "libsys.h"
|
||||
|
||||
int _setmode(int fd, int mode)
|
||||
{
|
||||
if (mode != O_TEXT && mode != O_BINARY)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!_sys_isopen(fd))
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
return _sys_setmode(fd, mode);
|
||||
}
|
15
plat/msdos86/libsys/signal.c
Normal file
15
plat/msdos86/libsys/signal.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include "libsys.h"
|
||||
|
||||
sighandler_t signal(int signum, sighandler_t handler)
|
||||
{
|
||||
return SIG_DFL;
|
||||
}
|
25
plat/msdos86/libsys/sys_exists.s
Normal file
25
plat/msdos86/libsys/sys_exists.s
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Say whether a file exists with the given name.
|
||||
|
||||
.define __sys_exists
|
||||
__sys_exists:
|
||||
mov bx, sp
|
||||
mov dx, 2(bx)
|
||||
mov ax, 0x4300
|
||||
int 0x21
|
||||
sbb ax, ax
|
||||
inc ax
|
||||
ret
|
13
plat/msdos86/libsys/sys_fdmodes.c
Normal file
13
plat/msdos86/libsys/sys_fdmodes.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "libsys.h"
|
||||
|
||||
/*
|
||||
* By default, consider all file descriptors, including those for stdin (0),
|
||||
* stdout (1), and stderr (2), as being open in text mode.
|
||||
*/
|
||||
struct _fdmodes _sys_fdmodes = { NULL, 0, 0 };
|
25
plat/msdos86/libsys/sys_getdate.s
Normal file
25
plat/msdos86/libsys/sys_getdate.s
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Get the current system date from MS-DOS.
|
||||
|
||||
.define __sys_getdate
|
||||
__sys_getdate:
|
||||
movb ah, 0x2a
|
||||
int 0x21
|
||||
mov bx, sp
|
||||
mov bx, 2(bx)
|
||||
mov (bx), dx
|
||||
mov 2(bx), cx
|
||||
ret
|
27
plat/msdos86/libsys/sys_getmode.c
Normal file
27
plat/msdos86/libsys/sys_getmode.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "libsys.h"
|
||||
|
||||
/*
|
||||
* Say whether a particular fd is currently open in text or binary mode.
|
||||
* Assume that the fd is valid. Return O_TEXT or O_BINARY.
|
||||
*/
|
||||
int _sys_getmode(int fd)
|
||||
{
|
||||
int reqbegfd = fd & ~_FDVECMASK;
|
||||
struct _fdmodes *p = &_sys_fdmodes;
|
||||
_fdvec_t mask;
|
||||
|
||||
while (p->begfd != reqbegfd)
|
||||
{
|
||||
p = p->next;
|
||||
if (!p)
|
||||
return O_TEXT;
|
||||
}
|
||||
mask = (_fdvec_t)1 << (fd & _FDVECMASK);
|
||||
return (p->modevec & mask) ? O_BINARY : O_TEXT;
|
||||
}
|
25
plat/msdos86/libsys/sys_gettime.s
Normal file
25
plat/msdos86/libsys/sys_gettime.s
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Get the current system time from MS-DOS.
|
||||
|
||||
.define __sys_gettime
|
||||
__sys_gettime:
|
||||
movb ah, 0x2c
|
||||
int 0x21
|
||||
mov bx, sp
|
||||
mov bx, 2(bx)
|
||||
mov (bx), cx
|
||||
mov 2(bx), dx
|
||||
ret
|
111
plat/msdos86/libsys/sys_initmain.c
Normal file
111
plat/msdos86/libsys/sys_initmain.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "libsys.h"
|
||||
|
||||
struct for_main {
|
||||
int argc;
|
||||
char **argv;
|
||||
char **envp;
|
||||
};
|
||||
|
||||
/*
|
||||
* Marshal the command line and environment variable data provided by
|
||||
* MS-DOS, into the standard format expected by a C main(...) routine. The
|
||||
* environment variable data has been copied to the near data segment.
|
||||
*
|
||||
* Return zero if everything went well, non-zero otherwise.
|
||||
*/
|
||||
int _sys_initmain(char *arg_data, size_t n_env_vars, char *env_data,
|
||||
unsigned msdos_ver, struct for_main *out)
|
||||
{
|
||||
char **argv, **envp;
|
||||
char c, *p, **pp;
|
||||
unsigned char n;
|
||||
|
||||
/*
|
||||
* Allocate space for argv[] for the maximum possible number of
|
||||
* arguments. We can shrink this later.
|
||||
*/
|
||||
if ((argv = sbrk(65 * sizeof(char *))) == OUT_OF_MEMORY)
|
||||
return -1;
|
||||
out->argv = argv;
|
||||
|
||||
/* Sanity-check the original command line. */
|
||||
p = arg_data;
|
||||
n = (unsigned char)*p;
|
||||
if (n > 0x7E || p[1 + n] != '\r')
|
||||
return -1;
|
||||
|
||||
/* Initialize argv[0] to an empty string first. */
|
||||
*p = 0;
|
||||
argv[0] = p;
|
||||
|
||||
/*
|
||||
* Split the command line string into separate arguments.
|
||||
* TODO: handle double-quoting, backslashes, etc.
|
||||
*/
|
||||
pp = argv + 1;
|
||||
do
|
||||
{
|
||||
do
|
||||
c = *++p;
|
||||
while (c == ' ' || c == '\t');
|
||||
|
||||
if (c != '\r')
|
||||
{
|
||||
*pp++ = p;
|
||||
do
|
||||
c = *++p;
|
||||
while (c != ' ' && c != '\t' && c != '\r');
|
||||
*p = 0;
|
||||
}
|
||||
} while (c != '\r');
|
||||
|
||||
/* Wrap up argv[]. Compute argc. Free up unneeded space. */
|
||||
out->argc = pp - argv;
|
||||
*pp++ = NULL;
|
||||
if (brk(pp) != 0)
|
||||
return -1;
|
||||
|
||||
/* Allocate space for envp[]. */
|
||||
if ((envp = sbrk((n_env_vars + 1) * sizeof(char *))) == OUT_OF_MEMORY)
|
||||
return -1;
|
||||
out->envp = envp;
|
||||
|
||||
/*
|
||||
* Populate envp[]. The environment data is simply a series of ASCIIZ
|
||||
* strings, one after another, terminated by an empty string.
|
||||
*/
|
||||
pp = envp;
|
||||
p = env_data;
|
||||
while (*p)
|
||||
{
|
||||
*pp++ = p;
|
||||
while (*++p);
|
||||
++p;
|
||||
}
|
||||
*pp = NULL;
|
||||
|
||||
/*
|
||||
* If there is a program name (MS-DOS version is 3 or above), point
|
||||
* argv[0] to it.
|
||||
*
|
||||
* p points to the zero byte just before the count of strings (a
|
||||
* shortword) following the environment variables, so advance p by 3
|
||||
* bytes to get at the program name.
|
||||
*/
|
||||
if ((msdos_ver & 0x00ff) >= 3)
|
||||
{
|
||||
p += 3;
|
||||
argv[0] = p;
|
||||
}
|
||||
|
||||
/* We are done. */
|
||||
return 0;
|
||||
}
|
27
plat/msdos86/libsys/sys_iseof.c
Normal file
27
plat/msdos86/libsys/sys_iseof.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "libsys.h"
|
||||
|
||||
/*
|
||||
* Say whether a particular fd is currently open in text mode and has just
|
||||
* hit an MS-DOS end-of-file character (^Z).
|
||||
*/
|
||||
int _sys_iseof(int fd)
|
||||
{
|
||||
int reqbegfd = fd & ~_FDVECMASK;
|
||||
struct _fdmodes *p = &_sys_fdmodes;
|
||||
_fdvec_t mask;
|
||||
|
||||
while (p->begfd != reqbegfd)
|
||||
{
|
||||
p = p->next;
|
||||
if (!p)
|
||||
return 0;
|
||||
}
|
||||
mask = (_fdvec_t)1 << (fd & _FDVECMASK);
|
||||
return p->eofvec & mask;
|
||||
}
|
26
plat/msdos86/libsys/sys_isopen.s
Normal file
26
plat/msdos86/libsys/sys_isopen.s
Normal file
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Say whether a given file descriptor number refers to a valid open file
|
||||
! descriptor.
|
||||
|
||||
.define __sys_isopen
|
||||
__sys_isopen:
|
||||
mov bx, sp
|
||||
mov bx, 2(bx)
|
||||
mov ax, 0x4400
|
||||
int 0x21
|
||||
sbb ax, ax
|
||||
inc ax
|
||||
ret
|
28
plat/msdos86/libsys/sys_isreadyr.s
Normal file
28
plat/msdos86/libsys/sys_isreadyr.s
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Say whether a file descriptor is ready for input, i.e. reading from the
|
||||
! fd will immediately return something.
|
||||
|
||||
.define __sys_isreadyr
|
||||
__sys_isreadyr:
|
||||
mov bx, sp
|
||||
mov ax, 0x4406
|
||||
mov bx, 2(bx)
|
||||
int 0x21
|
||||
jnc ok
|
||||
movb al, 0
|
||||
ok:
|
||||
cbw
|
||||
ret
|
24
plat/msdos86/libsys/sys_rawcreat.s
Normal file
24
plat/msdos86/libsys/sys_rawcreat.s
Normal file
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Create or truncate a file.
|
||||
|
||||
.define __sys_rawcreat
|
||||
__sys_rawcreat:
|
||||
movb ah, 0x3c
|
||||
mov bx, sp
|
||||
mov dx, 2(bx)
|
||||
mov cx, 4(bx)
|
||||
int 0x21
|
||||
jmp .sys_axret
|
26
plat/msdos86/libsys/sys_rawlseek.s
Normal file
26
plat/msdos86/libsys/sys_rawlseek.s
Normal file
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Move the current file position for a file descriptor.
|
||||
|
||||
.define __sys_rawlseek
|
||||
__sys_rawlseek:
|
||||
movb ah, 0x42
|
||||
mov bx, sp
|
||||
mov dx, 4(bx)
|
||||
mov cx, 6(bx)
|
||||
movb al, 8(bx)
|
||||
mov bx, 2(bx)
|
||||
int 0x21
|
||||
jmp .sys_dxaxret
|
24
plat/msdos86/libsys/sys_rawopen.s
Normal file
24
plat/msdos86/libsys/sys_rawopen.s
Normal file
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Open an existing file.
|
||||
|
||||
.define __sys_rawopen
|
||||
__sys_rawopen:
|
||||
movb ah, 0x3d
|
||||
mov bx, sp
|
||||
mov dx, 2(bx)
|
||||
movb al, 4(bx)
|
||||
int 0x21
|
||||
jmp .sys_axret
|
33
plat/msdos86/libsys/sys_rawrw.s
Normal file
33
plat/msdos86/libsys/sys_rawrw.s
Normal file
|
@ -0,0 +1,33 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! Read/write bytes to/to a file descriptor. These routines do not do any
|
||||
! translation between CRLF and LF line endings.
|
||||
!
|
||||
! Note that, for MS-DOS, a raw "write" request of zero bytes will truncate
|
||||
! (or extend) the file to the current file position.
|
||||
|
||||
.define __sys_rawread
|
||||
__sys_rawread:
|
||||
movb ah, 0x3f
|
||||
.data1 0x3d ! eat up the next instruction
|
||||
.define __sys_rawwrite
|
||||
__sys_rawwrite:
|
||||
movb ah, 0x40
|
||||
mov bx, sp
|
||||
mov dx, 4(bx)
|
||||
mov cx, 6(bx)
|
||||
mov bx, 2(bx)
|
||||
int 0x21
|
||||
jmp .sys_axret
|
42
plat/msdos86/libsys/sys_seteof.c
Normal file
42
plat/msdos86/libsys/sys_seteof.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "libsys.h"
|
||||
|
||||
/*
|
||||
* Set or reset the "end-of-file encountered" indicator for a particular fd.
|
||||
* Assume that the fd is valid, and is being read from in text mode.
|
||||
*/
|
||||
int _sys_seteof(int fd, int eof)
|
||||
{
|
||||
int reqbegfd = fd & ~_FDVECMASK;
|
||||
struct _fdmodes *p = &_sys_fdmodes;
|
||||
_fdvec_t mask;
|
||||
|
||||
while (p->begfd != reqbegfd)
|
||||
{
|
||||
p = p->next;
|
||||
if (!p)
|
||||
{
|
||||
if (!eof)
|
||||
return 0;
|
||||
if ((p = sbrk(sizeof(struct _fdmodes)))
|
||||
== OUT_OF_MEMORY)
|
||||
return -1;
|
||||
p->next = _sys_fdmodes.next;
|
||||
p->begfd = reqbegfd;
|
||||
p->modevec = p->eofvec = 0;
|
||||
_sys_fdmodes.next = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mask = (_fdvec_t)1 << (fd & _FDVECMASK);
|
||||
if (eof)
|
||||
p->eofvec |= mask;
|
||||
else
|
||||
p->eofvec &= ~mask;
|
||||
return 0;
|
||||
}
|
45
plat/msdos86/libsys/sys_seterrno.c
Normal file
45
plat/msdos86/libsys/sys_seterrno.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
static const signed char err_map[] =
|
||||
{
|
||||
0, /* 0x00 no error */
|
||||
EINVAL, /* 0x01 function number invalid */
|
||||
ENOENT, /* 0x02 file not found */
|
||||
ENOENT, /* 0x03 path not found */
|
||||
EMFILE, /* 0x04 too many open files */
|
||||
EACCES, /* 0x05 access denied */
|
||||
EBADF, /* 0x06 invalid handle */
|
||||
EFAULT, /* 0x07 mem. control block destroyed */
|
||||
ENOMEM, /* 0x08 insufficient memory */
|
||||
EFAULT, /* 0x09 memory block address invalid */
|
||||
E2BIG, /* 0x0A environment invalid */
|
||||
ENOEXEC, /* 0x0B format invalid */
|
||||
EINVAL, /* 0x0C access code invalid */
|
||||
EINVAL, /* 0x0D data invalid */
|
||||
ENOEXEC, /* 0x0E (?) fixup overflow */
|
||||
ENODEV, /* 0x0F invalid drive */
|
||||
EBUSY, /* 0x10 attempt to remove curr. dir. */
|
||||
EXDEV, /* 0x11 not same device */
|
||||
ENOENT, /* 0x12 no more files */
|
||||
EIO, /* 0x13 disk write-protected */
|
||||
EIO, /* 0x14 unknown unit */
|
||||
ENXIO, /* 0x15 drive not ready */
|
||||
};
|
||||
|
||||
/*
|
||||
* Map an MS-DOS 2+ system error code to an `errno' value and store that in
|
||||
* `errno'. Return a longword -1.
|
||||
*/
|
||||
long _sys_seterrno(unsigned dos_err)
|
||||
{
|
||||
if (dos_err < sizeof(err_map) / sizeof(err_map[0]))
|
||||
errno = err_map[dos_err];
|
||||
else
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
55
plat/msdos86/libsys/sys_setmode.c
Normal file
55
plat/msdos86/libsys/sys_setmode.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "libsys.h"
|
||||
|
||||
/*
|
||||
* Set text/binary mode for a particular fd. Assume that the fd is valid,
|
||||
* and that the mode is either O_TEXT or O_BINARY.
|
||||
*
|
||||
* Return the previous mode (either O_TEXT or O_BINARY) on success, -1 (with
|
||||
* errno set) on error.
|
||||
*/
|
||||
int _sys_setmode(int fd, int mode)
|
||||
{
|
||||
int reqbegfd = fd & ~_FDVECMASK;
|
||||
struct _fdmodes *p = &_sys_fdmodes;
|
||||
_fdvec_t mask;
|
||||
|
||||
while (p->begfd != reqbegfd)
|
||||
{
|
||||
p = p->next;
|
||||
if (!p)
|
||||
{
|
||||
if (mode == O_TEXT)
|
||||
return O_TEXT;
|
||||
if ((p = sbrk(sizeof(struct _fdmodes)))
|
||||
== OUT_OF_MEMORY)
|
||||
return -1;
|
||||
p->next = _sys_fdmodes.next;
|
||||
p->begfd = reqbegfd;
|
||||
p->modevec = p->eofvec = 0;
|
||||
_sys_fdmodes.next = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mask = (_fdvec_t)1 << (fd & _FDVECMASK);
|
||||
if (mode == O_BINARY)
|
||||
{
|
||||
if (p->modevec & mask)
|
||||
return O_BINARY;
|
||||
p->modevec |= mask;
|
||||
p->eofvec &= ~mask;
|
||||
return O_TEXT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(p->modevec & mask))
|
||||
return O_TEXT;
|
||||
p->modevec &= ~mask;
|
||||
return O_BINARY;
|
||||
}
|
||||
}
|
41
plat/msdos86/libsys/sys_xret.s
Normal file
41
plat/msdos86/libsys/sys_xret.s
Normal file
|
@ -0,0 +1,41 @@
|
|||
#
|
||||
! $Source$
|
||||
! $State$
|
||||
! $Revision$
|
||||
|
||||
! Declare segments (the order is important).
|
||||
|
||||
.sect .text
|
||||
.sect .rom
|
||||
.sect .data
|
||||
.sect .bss
|
||||
|
||||
.sect .text
|
||||
|
||||
! .sys_zret: if the carry flag is set, then set `errno' from the DOS error
|
||||
! code in ax, and return a shortword -1. If the carry flag is clear, just
|
||||
! return a shortword zero.
|
||||
!
|
||||
! .sys_axret: if the carry flag is set, then set `errno' from the DOS error
|
||||
! code in ax, and return a shortword -1. If the carry flag is clear, just
|
||||
! return ax as a return value.
|
||||
!
|
||||
! .sys_dxaxret: same as .sys_axret, but return a longword -1 or dx:ax as a
|
||||
! return value.
|
||||
|
||||
.extern .sys_zret
|
||||
.extern .sys_axret
|
||||
.extern .sys_dxaxret
|
||||
.sys_zret:
|
||||
jc error
|
||||
xor ax, ax
|
||||
no_error:
|
||||
ret
|
||||
.sys_axret:
|
||||
.sys_dxaxret:
|
||||
jnc no_error
|
||||
error:
|
||||
push ax
|
||||
call __sys_seterrno
|
||||
pop cx
|
||||
ret
|
61
plat/msdos86/libsys/write.c
Normal file
61
plat/msdos86/libsys/write.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* $Source$
|
||||
* $State$
|
||||
* $Revision$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "libsys.h"
|
||||
|
||||
ssize_t write(int fd, void* buffer, size_t count)
|
||||
{
|
||||
static const char crlf[2] = "\r\n";
|
||||
int i;
|
||||
char *p, *q;
|
||||
size_t left, n;
|
||||
ssize_t r, tot;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (_sys_getmode(fd) == O_BINARY)
|
||||
return _sys_rawwrite(fd, buffer, count);
|
||||
|
||||
/* If the file descriptor is an O_TEXT fd, translate LFs to CRLFs. */
|
||||
p = buffer;
|
||||
left = count;
|
||||
tot = 0;
|
||||
while (left)
|
||||
{
|
||||
q = memchr(p, '\n', left);
|
||||
if (!q)
|
||||
return _sys_rawwrite(fd, p, left);
|
||||
|
||||
n = q - p;
|
||||
if (n)
|
||||
{
|
||||
r = _sys_rawwrite(fd, p, n);
|
||||
if (r <= 0)
|
||||
return tot ? tot : r;
|
||||
tot += r;
|
||||
p += r;
|
||||
left -= r;
|
||||
if (r != n)
|
||||
break;
|
||||
}
|
||||
|
||||
r = _sys_rawwrite(fd, crlf, sizeof crlf);
|
||||
if (r != 2)
|
||||
{
|
||||
if (r > 0)
|
||||
r = 0;
|
||||
return tot ? tot : r;
|
||||
}
|
||||
++tot;
|
||||
++p;
|
||||
--left;
|
||||
}
|
||||
return tot;
|
||||
}
|
Loading…
Reference in a new issue