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
 | 
			
		||||
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…
	
	Add table
		
		Reference in a new issue