Merge pull request #229 from tkchia/tkchia/msdos86
Add support for compiling MS-DOS .com programs (msdos86).
This commit is contained in:
commit
a740f476c2
49 changed files with 1672 additions and 3 deletions
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
|
cpm produces i80 CP/M .COM files
|
||||||
rpi produces Raspberry Pi GPU binaries
|
rpi produces Raspberry Pi GPU binaries
|
||||||
pdpv7 produces PDP/11 V7 Unix binaries
|
pdpv7 produces PDP/11 V7 Unix binaries
|
||||||
|
msdos86 produces i86 MS-DOS .COM files
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ vars.plats = {
|
||||||
"linux68k",
|
"linux68k",
|
||||||
"linuxppc",
|
"linuxppc",
|
||||||
"linuxmips",
|
"linuxmips",
|
||||||
|
"msdos86",
|
||||||
"osx386",
|
"osx386",
|
||||||
"osxppc",
|
"osxppc",
|
||||||
"pc86",
|
"pc86",
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
#define ACKCONF_WANT_STANDARD_O 1
|
#define ACKCONF_WANT_STANDARD_O 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ACKCONF_WANT_O_TEXT_O_BINARY
|
||||||
|
#define ACKCONF_WANT_O_TEXT_O_BINARY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ACKCONF_WANT_STANDARD_SIGNALS
|
#ifndef ACKCONF_WANT_STANDARD_SIGNALS
|
||||||
#define ACKCONF_WANT_STANDARD_SIGNALS 1
|
#define ACKCONF_WANT_STANDARD_SIGNALS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct FILE {
|
||||||
#define _IOREADING 0x080
|
#define _IOREADING 0x080
|
||||||
#define _IOWRITING 0x100
|
#define _IOWRITING 0x100
|
||||||
#define _IOAPPEND 0x200
|
#define _IOAPPEND 0x200
|
||||||
|
#define _IOBINARY 0x400
|
||||||
|
|
||||||
#if !defined BUFSIZ
|
#if !defined BUFSIZ
|
||||||
#define BUFSIZ 1024
|
#define BUFSIZ 1024
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
O_WRONLY = 1,
|
O_WRONLY = 1,
|
||||||
O_RDWR = 2,
|
O_RDWR = 2,
|
||||||
|
|
||||||
|
#if ACKCONF_WANT_O_TEXT_O_BINARY
|
||||||
|
O_TEXT = 010000,
|
||||||
|
O_BINARY = 020000,
|
||||||
|
#endif
|
||||||
O_CREAT = 0100,
|
O_CREAT = 0100,
|
||||||
O_TRUNC = 01000,
|
O_TRUNC = 01000,
|
||||||
O_APPEND = 02000,
|
O_APPEND = 02000,
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.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
|
#if ACKCONF_WANT_STDIO && ACKCONF_WANT_EMULATED_FILE
|
||||||
|
|
||||||
|
@ -38,6 +42,9 @@ FILE* fdopen(int fd, const char* mode)
|
||||||
switch (*mode++)
|
switch (*mode++)
|
||||||
{
|
{
|
||||||
case 'b':
|
case 'b':
|
||||||
|
#if ACKCONF_WANT_O_TEXT_O_BINARY
|
||||||
|
flags |= _IOBINARY;
|
||||||
|
#endif
|
||||||
continue;
|
continue;
|
||||||
case '+':
|
case '+':
|
||||||
flags |= _IOREAD | _IOWRITE;
|
flags |= _IOREAD | _IOWRITE;
|
||||||
|
@ -57,6 +64,17 @@ FILE* fdopen(int fd, const char* mode)
|
||||||
if ((flags & _IOREAD) && (flags & _IOWRITE))
|
if ((flags & _IOREAD) && (flags & _IOWRITE))
|
||||||
flags &= ~(_IOREADING | _IOWRITING);
|
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->_count = 0;
|
||||||
stream->_fd = fd;
|
stream->_fd = fd;
|
||||||
stream->_flags = flags;
|
stream->_flags = flags;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#if ACKCONF_WANT_STDIO && ACKCONF_WANT_EMULATED_FILE
|
#if ACKCONF_WANT_STDIO && ACKCONF_WANT_EMULATED_FILE
|
||||||
|
|
||||||
|
@ -68,6 +67,9 @@ FILE* fopen(const char* name, const char* mode)
|
||||||
switch (*mode++)
|
switch (*mode++)
|
||||||
{
|
{
|
||||||
case 'b':
|
case 'b':
|
||||||
|
#if ACKCONF_WANT_O_TEXT_O_BINARY
|
||||||
|
flags |= _IOBINARY;
|
||||||
|
#endif
|
||||||
continue;
|
continue;
|
||||||
case '+':
|
case '+':
|
||||||
rwmode = O_RDWR;
|
rwmode = O_RDWR;
|
||||||
|
@ -80,6 +82,7 @@ FILE* fopen(const char* name, const char* mode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !ACKCONF_WANT_O_TEXT_O_BINARY
|
||||||
/* Perform a creat() when the file should be truncated or when
|
/* Perform a creat() when the file should be truncated or when
|
||||||
* the file is opened for writing and the open() failed.
|
* 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)
|
|| (((fd = open(name, rwmode)) < 0)
|
||||||
&& (rwflags & O_CREAT)))
|
&& (rwflags & O_CREAT)))
|
||||||
{
|
{
|
||||||
if (((fd = creat(name, PMODE)) > 0) && flags | _IOREAD)
|
if (((fd = creat(name, PMODE)) >= 0) && (flags & _IOREAD))
|
||||||
{
|
{
|
||||||
(void)close(fd);
|
(void)close(fd);
|
||||||
fd = open(name, rwmode);
|
fd = open(name, rwmode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
rwflags |= (flags & _IOBINARY) ? O_BINARY : O_TEXT;
|
||||||
|
fd = open(name, rwmode | rwflags, PMODE);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return (FILE*)NULL;
|
return (FILE*)NULL;
|
||||||
|
|
|
@ -50,6 +50,9 @@ FILE* freopen(const char* name, const char* mode, FILE* stream)
|
||||||
switch (*mode++)
|
switch (*mode++)
|
||||||
{
|
{
|
||||||
case 'b':
|
case 'b':
|
||||||
|
#if ACKCONF_WANT_O_TEXT_O_BINARY
|
||||||
|
flags |= _IOBINARY;
|
||||||
|
#endif
|
||||||
continue;
|
continue;
|
||||||
case '+':
|
case '+':
|
||||||
rwmode = O_RDWR;
|
rwmode = O_RDWR;
|
||||||
|
@ -62,16 +65,21 @@ FILE* freopen(const char* name, const char* mode, FILE* stream)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !ACKCONF_WANT_O_TEXT_O_BINARY
|
||||||
if ((rwflags & O_TRUNC)
|
if ((rwflags & O_TRUNC)
|
||||||
|| (((fd = open(name, rwmode)) < 0)
|
|| (((fd = open(name, rwmode)) < 0)
|
||||||
&& (rwflags & O_CREAT)))
|
&& (rwflags & O_CREAT)))
|
||||||
{
|
{
|
||||||
if (((fd = creat(name, PMODE)) < 0) && flags | _IOREAD)
|
if (((fd = creat(name, PMODE)) >= 0) && (flags & _IOREAD))
|
||||||
{
|
{
|
||||||
(void)close(fd);
|
(void)close(fd);
|
||||||
fd = open(name, rwmode);
|
fd = open(name, rwmode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
rwflags |= (flags & _IOBINARY) ? O_BINARY : O_TEXT;
|
||||||
|
fd = open(name, rwmode | rwflags, PMODE);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fd < 0)
|
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