From a34b362903ca7592c3b7c7803d353fa4be720865 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Sat, 23 Jun 2018 11:58:40 +0200 Subject: [PATCH 01/20] First draft of ELKS own libc Sourced from dev86 libc, tuned to build with GCC-IA16. Tuned the user land to build with both. Build OK but not tested yet at runtime. --- Makefile | 2 + build.sh | 6 +- elks/Makefile-rules | 4 +- elks/arch/i86/boot/bootsect.S | 4 +- elks/arch/i86/boot/crt0.S | 4 +- elks/arch/i86/boot/setup.S | 4 +- elks/arch/i86/mm/malloc.c | 2 +- elks/arch/i86/tools/Makefile | 2 +- elks/elks-small.ld | 6 +- elks/elks-tiny.ld | 4 +- elks/include/linuxmt/kernel.h | 1 + elks/include/linuxmt/socket.h | 1 + elks/include/linuxmt/string.h | 1 + elks/include/linuxmt/types.h | 6 - elks/lib/Makefile | 2 +- elks/tools/list.c | 2 +- {include => elks/tools}/list.h | 6 +- elks/tools/mkromfs.c | 2 +- elkscmd/Make.defs | 22 +- elkscmd/ash/Makefile | 2 +- elkscmd/bc/Makefile | 6 +- elkscmd/disk_utils/Makefile | 5 + elkscmd/file_utils/Makefile | 65 +- elkscmd/inet/httpd/Makefile | 19 +- elkscmd/inet/httpd/httpd.c | 5 +- elkscmd/inet/nettools/Makefile | 4 +- elkscmd/inet/nettools/nslookup.c | 12 +- elkscmd/inet/telnet/Makefile | 10 +- elkscmd/inet/telnet/ttn.c | 1 + elkscmd/inet/telnetd/Makefile | 9 +- elkscmd/inet/telnetd/telnetd.c | 6 +- elkscmd/inet/tinyirc/Makefile | 4 +- elkscmd/inet/tinyirc/tinyirc.c | 5 +- elkscmd/inet/urlget/Makefile | 7 +- elkscmd/inet/urlget/net.c | 3 + elkscmd/ktcp/Makefile | 5 +- elkscmd/ktcp/deveth.c | 2 +- elkscmd/ktcp/ip.c | 2 +- elkscmd/ktcp/ktcp.c | 2 +- elkscmd/ktcp/tcp.h | 4 +- elkscmd/ktcp/tcp_output.c | 2 +- elkscmd/levee/Makefile | 2 +- elkscmd/levee/find.c | 4 - elkscmd/levee/levee.h | 3 +- elkscmd/levee/termcap.i | 2 +- elkscmd/minix1/Makefile | 35 +- elkscmd/minix1/banner.c | 2 - elkscmd/minix1/cksum.c | 4 - elkscmd/minix1/du.c | 5 - elkscmd/minix1/grep.c | 2 +- elkscmd/minix1/uniq.c | 2 + elkscmd/minix2/Makefile | 20 +- elkscmd/minix3/Makefile | 29 + elkscmd/misc_utils/Makefile | 16 +- elkscmd/mtools/Makefile | 19 + elkscmd/mtools/init.c | 6 +- elkscmd/mtools/mtype.c | 2 +- elkscmd/mtools/putfat.c | 2 +- elkscmd/prems/pres/Makefile | 4 +- elkscmd/prems/pres/pres.c | 2 +- elkscmd/sh_utils/Makefile | 58 +- elkscmd/sys_utils/Makefile | 79 +- elkscmd/test/eth/Makefile | 2 +- elkscmd/test/pty/Makefile | 3 + elkscmd/test/select/Makefile | 1 + elkscmd/test/signal/Makefile | 1 + elkscmd/test/signal/test_signal.c | 6 +- elkscmd/test/socket/echo/Makefile | 6 + libc/.gitignore | 3 + libc/Makefile | 48 + libc/Makefile.inc | 34 + libc/crt0.S | 60 + libc/error/Makefile | 16 + libc/error/__assert.c | 30 + libc/error/error.c | 57 + libc/error/perror.c | 19 + libc/gcc/Makefile | 16 + libc/gcc/divmodsi3.s | 92 ++ libc/gcc/ldivmod.s | 200 +++ libc/getent/Makefile | 16 + libc/getent/__getgrent.c | 168 +++ libc/getent/__getpwent.c | 99 ++ libc/getent/config-grp.h | 65 + libc/getent/config.h | 65 + libc/getent/getgrgid.c | 48 + libc/getent/getgrnam.c | 51 + libc/getent/getpwnam.c | 52 + libc/getent/getpwuid.c | 44 + libc/getent/pwent.c | 64 + libc/getent/utent.c | 150 +++ {include/arch => libc/include/asm}/farlist.h | 0 {include/arch => libc/include/asm}/seglist.h | 0 libc/include/asm/types.h | 9 + libc/include/assert.h | 23 + libc/include/ctype.h | 41 + libc/include/dirent.h | 52 + libc/include/errno.h | 48 + libc/include/fcntl.h | 20 + libc/include/features.h | 40 + libc/include/getopt.h | 17 + libc/include/grp.h | 37 + libc/include/inttypes.h | 214 +++ libc/include/malloc.h | 30 + libc/include/memory.h | 1 + libc/include/paths.h | 21 + libc/include/pwd.h | 40 + libc/include/regex.h | 21 + libc/include/setjmp.h | 31 + libc/include/signal.h | 92 ++ libc/include/stdio.h | 139 ++ libc/include/stdlib.h | 58 + libc/include/string.h | 68 + libc/include/sys/cdefs.h | 38 + libc/include/sys/ioctl.h | 9 + libc/include/sys/select.h | 5 + libc/include/sys/socket.h | 15 + libc/include/sys/stat.h | 18 + libc/include/sys/time.h | 3 + libc/include/sys/times.h | 21 + libc/include/sys/types.h | 3 + libc/include/sys/wait.h | 77 ++ libc/include/termcap.h | 21 + libc/include/termios.h | 25 + libc/include/time.h | 68 + {include => libc/include}/types.h | 15 +- libc/include/unistd.h | 53 + libc/include/utime.h | 15 + libc/include/utmp.h | 52 + libc/malloc/Makefile | 22 + libc/malloc/heap.c | 161 +++ libc/malloc/malloc.c | 549 ++++++++ libc/misc/Makefile | 35 + libc/misc/aliases.c | 115 ++ libc/misc/atexit.c | 91 ++ libc/misc/atof.c | 16 + libc/misc/atoi.c | 24 + libc/misc/atol.c | 24 + libc/misc/crypt.c | 73 ++ libc/misc/ctype.c | 55 + libc/misc/getcwd.c | 109 ++ libc/misc/getenv.c | 28 + libc/misc/getopt.c | 122 ++ libc/misc/itoa.c | 24 + libc/misc/ltostr.c | 43 + libc/misc/popen.c | 42 + libc/misc/putenv.c | 56 + libc/misc/qsort.c | 173 +++ libc/misc/strtol.c | 111 ++ libc/misc/system.c | 49 + libc/misc/tmpnam.c | 50 + libc/regex/Makefile | 16 + libc/regex/regex.c | 1213 ++++++++++++++++++ libc/regex/regmagic.h | 5 + libc/stdio/Makefile | 16 + libc/stdio/printf.c | 400 ++++++ libc/stdio/scanf.c | 514 ++++++++ libc/stdio/stdio.c | 833 ++++++++++++ libc/string/Makefile | 29 + libc/string/bzero.c | 6 + libc/string/strcasecmp.c | 26 + libc/string/strcspn.c | 32 + libc/string/string.c | 622 +++++++++ libc/string/strncasecmp.c | 28 + libc/string/strpbrk.c | 21 + libc/string/strspn.c | 44 + libc/string/strstr.c | 57 + libc/string/strtok.c | 69 + libc/system/.gitignore | 1 + libc/system/Makefile | 29 + libc/system/call_tab.v | 75 ++ libc/system/defn_tab.v | 24 + libc/system/dirent.c | 72 ++ libc/system/exec.c | 277 ++++ libc/system/setjmp.S | 40 + libc/system/signal.c | 54 + libc/system/syscall.awk | 45 + libc/system/syscall.dat | 170 +++ libc/system/syscall0.s | 115 ++ libc/system/syscall1.s | 510 ++++++++ libc/system/syslib.c | 304 +++++ libc/termcap/Makefile | 16 + libc/termcap/termcap.c | 816 ++++++++++++ libc/termcap/tparam.c | 319 +++++ libc/termios/Makefile | 16 + libc/termios/termios.c | 199 +++ libc/termios/ttyname.c | 47 + libc/time/Makefile | 16 + libc/time/asc_conv.c | 49 + libc/time/asctime.c | 15 + libc/time/ctime.c | 27 + libc/time/localtime.c | 22 + libc/time/tm_conv.c | 138 ++ 192 files changed, 12549 insertions(+), 165 deletions(-) rename {include => elks/tools}/list.h (82%) create mode 100644 libc/.gitignore create mode 100644 libc/Makefile create mode 100644 libc/Makefile.inc create mode 100644 libc/crt0.S create mode 100644 libc/error/Makefile create mode 100644 libc/error/__assert.c create mode 100644 libc/error/error.c create mode 100644 libc/error/perror.c create mode 100644 libc/gcc/Makefile create mode 100644 libc/gcc/divmodsi3.s create mode 100644 libc/gcc/ldivmod.s create mode 100644 libc/getent/Makefile create mode 100644 libc/getent/__getgrent.c create mode 100644 libc/getent/__getpwent.c create mode 100644 libc/getent/config-grp.h create mode 100644 libc/getent/config.h create mode 100644 libc/getent/getgrgid.c create mode 100644 libc/getent/getgrnam.c create mode 100644 libc/getent/getpwnam.c create mode 100644 libc/getent/getpwuid.c create mode 100644 libc/getent/pwent.c create mode 100644 libc/getent/utent.c rename {include/arch => libc/include/asm}/farlist.h (100%) rename {include/arch => libc/include/asm}/seglist.h (100%) create mode 100644 libc/include/asm/types.h create mode 100644 libc/include/assert.h create mode 100644 libc/include/ctype.h create mode 100644 libc/include/dirent.h create mode 100644 libc/include/errno.h create mode 100644 libc/include/fcntl.h create mode 100644 libc/include/features.h create mode 100644 libc/include/getopt.h create mode 100644 libc/include/grp.h create mode 100644 libc/include/inttypes.h create mode 100644 libc/include/malloc.h create mode 100644 libc/include/memory.h create mode 100644 libc/include/paths.h create mode 100644 libc/include/pwd.h create mode 100644 libc/include/regex.h create mode 100644 libc/include/setjmp.h create mode 100644 libc/include/signal.h create mode 100644 libc/include/stdio.h create mode 100644 libc/include/stdlib.h create mode 100644 libc/include/string.h create mode 100644 libc/include/sys/cdefs.h create mode 100644 libc/include/sys/ioctl.h create mode 100644 libc/include/sys/select.h create mode 100644 libc/include/sys/socket.h create mode 100644 libc/include/sys/stat.h create mode 100644 libc/include/sys/time.h create mode 100644 libc/include/sys/times.h create mode 100644 libc/include/sys/types.h create mode 100644 libc/include/sys/wait.h create mode 100644 libc/include/termcap.h create mode 100644 libc/include/termios.h create mode 100644 libc/include/time.h rename {include => libc/include}/types.h (62%) create mode 100644 libc/include/unistd.h create mode 100644 libc/include/utime.h create mode 100644 libc/include/utmp.h create mode 100644 libc/malloc/Makefile create mode 100644 libc/malloc/heap.c create mode 100644 libc/malloc/malloc.c create mode 100644 libc/misc/Makefile create mode 100644 libc/misc/aliases.c create mode 100644 libc/misc/atexit.c create mode 100644 libc/misc/atof.c create mode 100644 libc/misc/atoi.c create mode 100644 libc/misc/atol.c create mode 100644 libc/misc/crypt.c create mode 100644 libc/misc/ctype.c create mode 100644 libc/misc/getcwd.c create mode 100644 libc/misc/getenv.c create mode 100644 libc/misc/getopt.c create mode 100644 libc/misc/itoa.c create mode 100644 libc/misc/ltostr.c create mode 100644 libc/misc/popen.c create mode 100644 libc/misc/putenv.c create mode 100644 libc/misc/qsort.c create mode 100644 libc/misc/strtol.c create mode 100644 libc/misc/system.c create mode 100644 libc/misc/tmpnam.c create mode 100644 libc/regex/Makefile create mode 100644 libc/regex/regex.c create mode 100644 libc/regex/regmagic.h create mode 100644 libc/stdio/Makefile create mode 100644 libc/stdio/printf.c create mode 100644 libc/stdio/scanf.c create mode 100644 libc/stdio/stdio.c create mode 100644 libc/string/Makefile create mode 100644 libc/string/bzero.c create mode 100644 libc/string/strcasecmp.c create mode 100644 libc/string/strcspn.c create mode 100644 libc/string/string.c create mode 100644 libc/string/strncasecmp.c create mode 100644 libc/string/strpbrk.c create mode 100644 libc/string/strspn.c create mode 100644 libc/string/strstr.c create mode 100644 libc/string/strtok.c create mode 100644 libc/system/.gitignore create mode 100644 libc/system/Makefile create mode 100644 libc/system/call_tab.v create mode 100644 libc/system/defn_tab.v create mode 100644 libc/system/dirent.c create mode 100644 libc/system/exec.c create mode 100644 libc/system/setjmp.S create mode 100644 libc/system/signal.c create mode 100644 libc/system/syscall.awk create mode 100644 libc/system/syscall.dat create mode 100644 libc/system/syscall0.s create mode 100644 libc/system/syscall1.s create mode 100644 libc/system/syslib.c create mode 100644 libc/termcap/Makefile create mode 100644 libc/termcap/termcap.c create mode 100644 libc/termcap/tparam.c create mode 100644 libc/termios/Makefile create mode 100644 libc/termios/termios.c create mode 100644 libc/termios/ttyname.c create mode 100644 libc/time/Makefile create mode 100644 libc/time/asc_conv.c create mode 100644 libc/time/asctime.c create mode 100644 libc/time/ctime.c create mode 100644 libc/time/localtime.c create mode 100644 libc/time/tm_conv.c diff --git a/Makefile b/Makefile index fd1634ae9..134dbf2c9 100644 --- a/Makefile +++ b/Makefile @@ -31,11 +31,13 @@ CFG_SHELL := $(shell \ .PHONY: all clean kconfig defconfig config menuconfig all: .config + $(MAKE) -C libc all $(MAKE) -C elks all $(MAKE) -C elkscmd all $(MAKE) -C image all clean: + $(MAKE) -C libc clean $(MAKE) -C elks clean $(MAKE) -C elkscmd clean $(MAKE) -C image clean diff --git a/build.sh b/build.sh index bdacc0816..567dba81d 100755 --- a/build.sh +++ b/build.sh @@ -29,12 +29,8 @@ clean_exit () { exit $E } -# Disk images cannot be built unless we're UID 0 -if [ "$UID" != "0" ] && [ "$1" != "clean" ] - then echo -e "\nWARNING: Disk images can only be built if you have root permissions" -fi - # Build environment setup +# TODO: check script status on return . tools/env.sh # Check tools diff --git a/elks/Makefile-rules b/elks/Makefile-rules index c292cdcc0..4c82ac180 100644 --- a/elks/Makefile-rules +++ b/elks/Makefile-rules @@ -101,7 +101,7 @@ endif ARCH_DIR = arch/$(ARCH) -INCLUDES = -I$(TOPDIR)/include -I$(TOPDIR)/elks/include +INCLUDES = -I$(TOPDIR)/include -I$(TOPDIR)/elks/include MYDIR = $(shell pwd | sed 's:^$(TOPDIR):.:') @@ -205,6 +205,8 @@ LD = ia16-elf-ld LDFLAGS = $(CPU_LD) -s AR = ia16-elf-ar +INCLUDES += -I$(TOPDIR)/libc/include + else ################################ diff --git a/elks/arch/i86/boot/bootsect.S b/elks/arch/i86/boot/bootsect.S index 310c455e8..ed20f8934 100644 --- a/elks/arch/i86/boot/bootsect.S +++ b/elks/arch/i86/boot/bootsect.S @@ -65,8 +65,8 @@ SWAP_DEV = 0 // ld86 requires an entry symbol. This may as well be the usual one. -.global start -start: +.global entry +entry: #if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */ int 3 #endif diff --git a/elks/arch/i86/boot/crt0.S b/elks/arch/i86/boot/crt0.S index 9849c4fe1..a929133c1 100644 --- a/elks/arch/i86/boot/crt0.S +++ b/elks/arch/i86/boot/crt0.S @@ -9,7 +9,7 @@ .code16 .text - .global start + .global entry .extern start_kernel .extern arch_boot .global early_printk @@ -24,7 +24,7 @@ // Setup patched to pass parameters in registers to avoid clobbering the // kernel when using the 286pmode extender. -start: +entry: /* ! Setup.S already initialized DS and ES (but not SS) ! In addition, registers contain: diff --git a/elks/arch/i86/boot/setup.S b/elks/arch/i86/boot/setup.S index b95e3028d..938d93e2a 100644 --- a/elks/arch/i86/boot/setup.S +++ b/elks/arch/i86/boot/setup.S @@ -120,8 +120,8 @@ .text -.global start -start: +.global entry +entry: #ifdef CONFIG_ROMCODE .byte 0x55, 0xaa //;sign for ROM-Extention .byte 0x04 //;space for lengthcode (promsize/512) diff --git a/elks/arch/i86/mm/malloc.c b/elks/arch/i86/mm/malloc.c index eed82f624..a8609afc4 100644 --- a/elks/arch/i86/mm/malloc.c +++ b/elks/arch/i86/mm/malloc.c @@ -28,7 +28,7 @@ #include #include -#include +#include #define MIN_STACK_SIZE 0x1000 diff --git a/elks/arch/i86/tools/Makefile b/elks/arch/i86/tools/Makefile index b9483e7ce..f43701361 100644 --- a/elks/arch/i86/tools/Makefile +++ b/elks/arch/i86/tools/Makefile @@ -9,7 +9,7 @@ BASEDIR = ../../.. # Define the variables required by the standard rules - see the standard # rules file (below) for details of these variables. -USEBCC = Y +USEBCC = N CLEANDEP = diff --git a/elks/elks-small.ld b/elks/elks-small.ld index e35b79e9f..d5afcc330 100644 --- a/elks/elks-small.ld +++ b/elks/elks-small.ld @@ -11,14 +11,14 @@ SECTIONS { LONG(SIZEOF (.text)); LONG(SIZEOF (.data)); LONG (SIZEOF (.bss)); - LONG (start); /* entry point */ + LONG (entry); /* entry point */ LONG (0); /* total memory allocated */ LONG (0); /* symbol table size */ } _begintext = ALIGN(0x20); - .text 0 : AT(_begintext) { *(.text); . = ALIGN(0x10); } + .text 0 : AT(_begintext) { *(.text*); . = ALIGN(0x10); } _begindata = _begintext + .; - .data 0 : AT(_begindata) { *(.data) *(.rodata*) } + .data 0 : AT(_begindata) { *(.data*) *(.rodata*) } .bss : { *(.bss) *(COMMON) } /DISCARD/ : { *(.comment) } } diff --git a/elks/elks-tiny.ld b/elks/elks-tiny.ld index 248036336..70969ad0d 100644 --- a/elks/elks-tiny.ld +++ b/elks/elks-tiny.ld @@ -11,11 +11,11 @@ SECTIONS { LONG (SIZEOF (.text)); LONG (0); /* .data section size */ LONG (0); /* .bss section size */ - LONG (start); /* entry point */ + LONG (entry); /* entry point */ LONG (0); /* total memory allocated */ LONG (0); /* symbol table size */ } _begintext = ALIGN(0x20); - .text 0 : AT(_begintext) { *(.text) *(.data) *(.rodata*) *(.bss) *(COMMON) } + .text 0 : AT(_begintext) { *(.text*) *(.data*) *(.rodata*) *(.bss) *(COMMON) } /DISCARD/ : { *(.comment) } } diff --git a/elks/include/linuxmt/kernel.h b/elks/include/linuxmt/kernel.h index d6091f88a..473fbb8b9 100644 --- a/elks/include/linuxmt/kernel.h +++ b/elks/include/linuxmt/kernel.h @@ -2,6 +2,7 @@ #define LX86_LINUXMT_KERNEL_H #include +#include /* * 'kernel.h' contains some often-used function prototypes etc diff --git a/elks/include/linuxmt/socket.h b/elks/include/linuxmt/socket.h index 50475ef0e..150a6f225 100644 --- a/elks/include/linuxmt/socket.h +++ b/elks/include/linuxmt/socket.h @@ -1,6 +1,7 @@ #ifndef LX86_LINUXMT_SOCKET_H #define LX86_LINUXMT_SOCKET_H +#include #include #include diff --git a/elks/include/linuxmt/string.h b/elks/include/linuxmt/string.h index 8e0ea1df0..5da59ae29 100644 --- a/elks/include/linuxmt/string.h +++ b/elks/include/linuxmt/string.h @@ -2,6 +2,7 @@ #define LX86_LINUXMT_STRING_H #include +#include /*@-namechecks@*/ diff --git a/elks/include/linuxmt/types.h b/elks/include/linuxmt/types.h index b3d69d8a3..8441de3d7 100644 --- a/elks/include/linuxmt/types.h +++ b/elks/include/linuxmt/types.h @@ -16,8 +16,6 @@ typedef __u32 speed_t; typedef __u32 tcflag_t; typedef __u32 u_ino_t; -typedef __s16 pid_t; - typedef __u16 block_t; typedef __u32 block32_t; typedef __u16 dev_t; @@ -46,10 +44,6 @@ typedef __u8 sig_t; typedef __u32 time_t; -typedef __s16 ptrdiff_t; - -typedef __u16 size_t; - /*@end@*/ #ifdef CONFIG_SHORT_FILES diff --git a/elks/lib/Makefile b/elks/lib/Makefile index 54e6a941a..d1738851f 100644 --- a/elks/lib/Makefile +++ b/elks/lib/Makefile @@ -43,7 +43,7 @@ OBJS = chqueue.o string.o all: lib.a lib.a: $(OBJS) - ar rcs lib.a $(OBJS) + $(AR) rcs lib.a $(OBJS) ######################################################################### # Standard rules. diff --git a/elks/tools/list.c b/elks/tools/list.c index 4ae1e6042..db39e1ef8 100644 --- a/elks/tools/list.c +++ b/elks/tools/list.c @@ -1,6 +1,6 @@ /* Double-linked list with near pointers */ -#include +#include "list.h" void list_init (list_root_t * root) diff --git a/include/list.h b/elks/tools/list.h similarity index 82% rename from include/list.h rename to elks/tools/list.h index e55a33511..5dc71778c 100644 --- a/include/list.h +++ b/elks/tools/list.h @@ -1,10 +1,14 @@ /* Double-linked list with near pointers */ +// TODO: move to top include + #ifndef _LIST_H #define _LIST_H -#include +typedef unsigned char byte_t; +typedef unsigned int u16_t; +typedef unsigned long u32_t; struct list_node_s { diff --git a/elks/tools/mkromfs.c b/elks/tools/mkromfs.c index e450645c6..1bfc403b4 100644 --- a/elks/tools/mkromfs.c +++ b/elks/tools/mkromfs.c @@ -18,7 +18,7 @@ /* Common types */ -#include +#include "list.h" /* Super block in memory */ diff --git a/elkscmd/Make.defs b/elkscmd/Make.defs index cdc40a95c..ca0932744 100644 --- a/elkscmd/Make.defs +++ b/elkscmd/Make.defs @@ -52,7 +52,7 @@ PLATFORM=i86-ELKS ELKS_DIR=$(TOPDIR)/elks ELKSCMD_DIR=$(TOPDIR)/elkscmd -INCLUDES=-I$(TOPDIR)/include -I$(ELKS_DIR)/include +INCLUDES=-I$(TOPDIR)/include -I$(TOPDIR)/libc/include -I$(ELKS_DIR)/include TARGET_MNT=$(TOPDIR)/target @@ -72,10 +72,15 @@ ELKS_VSN=$(shell printf '%s.%s.%s-pre%s' $(E_V) | sed 's/-pre$$//') # Determine compiler variables for this target. ifeq ($(PLATFORM),i86-ELKS) - CC=bcc - CFLBASE=-0 -O -ansi - LD=ld86 - LDFLAGS=-s -ansi +# CC=bcc + CC=ia16-elf-gcc +# CFLBASE=-0 -O -ansi + CFLBASE=-fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding -mtune=i8086 -Wall -Os +# LD=ld86 + LD=ia16-elf-ld +# LDFLAGS=-s -ansi + LDFLAGS= -T $(TOPDIR)/elks/elks-small.ld + LDLIBS='-(' $(TOPDIR)/libc/crt0.o $(TOPDIR)/libc/libc.a '-)' CHECK=gcc -c -o .null.o -Wall -pedantic AS=as86 endif @@ -96,15 +101,12 @@ CFLAGS=$(CFLBASE) $(LOCALFLAGS) $(INCLUDES) -D__ELKS__ -DELKS_VERSION=\"$(ELKS_V # # Standard compilation rules. -.c.s: - $(CC) $(CFLAGS) -S -o $*.o $< +.S.s: + gcc -E -traditional $(INCLUDES) $(CCDEFS) -o $*.s $< .s.o: $(AS) $(ASFLAGS) -o $*.o $< -.S.s: - gcc -E -traditional $(INCLUDES) $(CCDEFS) -o $*.s $< - .c.o: $(CC) $(CFLAGS) -c -o $*.o $< diff --git a/elkscmd/ash/Makefile b/elkscmd/ash/Makefile index d08232c73..d293a5a65 100644 --- a/elkscmd/ash/Makefile +++ b/elkscmd/ash/Makefile @@ -42,7 +42,7 @@ CLEANFILES= $(OBJS) \ all: ash ash: $(OBJS) - $(CC) $(LDFLAGS) -o ash $(OBJS) + $(LD) $(LDFLAGS) -o ash $(OBJS) $(LDLIBS) install: ash ifdef CONFIG_IMG_LINK diff --git a/elkscmd/bc/Makefile b/elkscmd/bc/Makefile index 9c1689008..2ffbeedd7 100644 --- a/elkscmd/bc/Makefile +++ b/elkscmd/bc/Makefile @@ -37,10 +37,10 @@ SUBDIRS = Examples Test all: fbc bc bc: $& config.h bc.o $(OFILES) global.o - $(CC) -o bc $(LDFLAGS) bc.o $(OFILES) global.o + $(LD) -o bc $(LDFLAGS) bc.o $(OFILES) global.o $(LDLIBS) sbc: sbc.o $(OFILES) global.o - $(CC) -o sbc $(LDFLAGS) sbc.o $(OFILES) global.o + $(LD) -o sbc $(LDFLAGS) sbc.o $(OFILES) global.o $(LDLIBS) math.h: libmath.b $(MAKE) -$(MAKEFLAGS) fbc @@ -51,7 +51,7 @@ math.h: libmath.b fbc: $(OFILES) bc.o echo \"\" > math.h $(CC) -c $(CFLAGS) global.c - $(CC) -o fbc $(LDFLAGS) bc.o $(OFILES) global.o + $(LD) -o fbc $(LDFLAGS) bc.o $(OFILES) global.o $(LDLIBS) install: bc fbc sudo install bc $(TARGET_MNT)/bin diff --git a/elkscmd/disk_utils/Makefile b/elkscmd/disk_utils/Makefile index bcd470490..7278d0f82 100644 --- a/elkscmd/disk_utils/Makefile +++ b/elkscmd/disk_utils/Makefile @@ -23,14 +23,19 @@ install: all sudo install $(PROGS) $(TARGET_MNT)/sbin fsck: fsck.o + $(LD) $(LDFLAGS) -o fsck fsck.o $(LDLIBS) fdisk: fdisk.o + $(LD) $(LDFLAGS) -o fdisk fdisk.o $(LDLIBS) mkfs: mkfs.o + $(LD) $(LDFLAGS) -o mkfs mkfs.o $(LDLIBS) partype: partype.o + $(LD) $(LDFLAGS) -o partype partype.o $(LDLIBS) ramdisk: ramdisk.o + $(LD) $(LDFLAGS) -o ramdisk ramdisk.o $(LDLIBS) clean: rm -f *.o $(FORMATMOD) core $(PROGS) diff --git a/elkscmd/file_utils/Makefile b/elkscmd/file_utils/Makefile index 8cf1cd5e8..9993e809a 100644 --- a/elkscmd/file_utils/Makefile +++ b/elkscmd/file_utils/Makefile @@ -13,15 +13,70 @@ include $(BASEDIR)/Make.rules PRGS=cat chgrp chmod chown cmp cp dd grep l ln ls mkdir mkfifo mknod \ more mv rm rmdir sync touch -MIN_PRGS=cat chgrp chmod chown cmp cp ls mknod mkdir mv rm rmdir \ - sync touch +all: $(PRGS) -SMIN_PRGS=cat cp ls mkdir sync +cat: cat.o + $(LD) $(LDFLAGS) -o cat cat.o $(LDLIBS) -all: $(PRGS) +chgrp: chgrp.o + $(LD) $(LDFLAGS) -o chgrp chgrp.o $(LDLIBS) + +chmod: chmod.o + $(LD) $(LDFLAGS) -o chmod chmod.o $(LDLIBS) + +chown: chown.o + $(LD) $(LDFLAGS) -o chown chown.o $(LDLIBS) + +cmp: cmp.o + $(LD) $(LDFLAGS) -o cmp cmp.o $(LDLIBS) + +cp: cp.o + $(LD) $(LDFLAGS) -o cp cp.o $(LDLIBS) + +dd: dd.o + $(LD) $(LDFLAGS) -o dd dd.o $(LDLIBS) + +grep: grep.o + $(LD) $(LDFLAGS) -o grep grep.o $(LDLIBS) + +l: l.o + $(LD) $(LDFLAGS) -o l l.o $(LDLIBS) + +ln: ln.o + $(LD) $(LDFLAGS) -o ln ln.o $(LDLIBS) + +ls: ls.o + $(LD) $(LDFLAGS) -o ls ls.o $(LDLIBS) + +mkdir: mkdir.o + $(LD) $(LDFLAGS) -o mkdir mkdir.o $(LDLIBS) + +mkfifo: mkfifo.o + $(LD) $(LDFLAGS) -o mkfifo mkfifo.o $(LDLIBS) + +mknod: mknod.o + $(LD) $(LDFLAGS) -o mknod mknod.o $(LDLIBS) + +more: more.o + $(LD) $(LDFLAGS) -o more more.o $(LDLIBS) + +mv: mv.o + $(LD) $(LDFLAGS) -o mv mv.o $(LDLIBS) + +rm: rm.o + $(LD) $(LDFLAGS) -o rm rm.o $(LDLIBS) + +rmdir: rmdir.o + $(LD) $(LDFLAGS) -o rmdir rmdir.o $(LDLIBS) + +sync: sync.o + $(LD) $(LDFLAGS) -o sync sync.o $(LDLIBS) + +touch: touch.o + $(LD) $(LDFLAGS) -o touch touch.o $(LDLIBS) install: $(PRGS) sudo install $(PRGS) $(TARGET_MNT)/bin clean: - rm -f $(PRGS) *~ + rm -f *.o $(PRGS) diff --git a/elkscmd/inet/httpd/Makefile b/elkscmd/inet/httpd/Makefile index 7673b9496..9a020eeb6 100644 --- a/elkscmd/inet/httpd/Makefile +++ b/elkscmd/inet/httpd/Makefile @@ -10,24 +10,19 @@ include $(BASEDIR)/Make.rules ############################################################################### -PRGS=httpd - -SPRGS= +PRG=httpd LOCALFLAGS=-I$(ELKSCMD_DIR) -all: $(PRGS) +all: $(PRG) -install_sibo: all - cp -p $(SPRGS) $(TARGET_MNT)/bin +$(PRG): httpd.o + $(LD) $(LDFLAGS) -o $(PRG) httpd.o $(LDLIBS) -install: $(PRGS) - sudo install $(PRGS) $(TARGET_MNT)/bin +install: $(PRG) + sudo install $(PRG) $(TARGET_MNT)/bin sudo mkdir -p $(TARGET_MNT)/var/www sudo install sample_index.html $(TARGET_MNT)/var/www/index.html -netstat: httpd.o - $(CC) $(CFLAGS) $(LDFLAGS) httpd.o -o httpd - clean: - rm -f core *.o $(PRGS) $(SPRGS) + rm -f *.o $(PRG) diff --git a/elkscmd/inet/httpd/httpd.c b/elkscmd/inet/httpd/httpd.c index 202d88dd5..4e1c01552 100644 --- a/elkscmd/inet/httpd/httpd.c +++ b/elkscmd/inet/httpd/httpd.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #ifndef __linux__ #include #include @@ -96,7 +98,6 @@ char *str; void process_request() { - int p; int fin, size; int ret; char *c, *file, fullpath[128]; @@ -159,8 +160,6 @@ int argc; char** argv; { int ret; - unsigned long i; - char *t; struct sockaddr_in localadr; ret = fork(); diff --git a/elkscmd/inet/nettools/Makefile b/elkscmd/inet/nettools/Makefile index 5fcab1f54..8521f48d1 100644 --- a/elkscmd/inet/nettools/Makefile +++ b/elkscmd/inet/nettools/Makefile @@ -20,10 +20,10 @@ install: $(PRGS) sudo install $(PRGS) $(TARGET_MNT)/bin netstat: netstat.o - $(CC) $(CFLAGS) $(LDFLAGS) netstat.o -o netstat + $(LD) $(LDFLAGS) netstat.o -o netstat $(LDLIBS) nslookup: nslookup.o - $(CC) $(CFLAGS) $(LDFLAGS) nslookup.o -o nslookup + $(LD) $(LDFLAGS) nslookup.o -o nslookup $(LDLIBS) clean: rm -f core *.o $(PRGS) diff --git a/elkscmd/inet/nettools/nslookup.c b/elkscmd/inet/nettools/nslookup.c index 6f4d9528c..05941f35b 100644 --- a/elkscmd/inet/nettools/nslookup.c +++ b/elkscmd/inet/nettools/nslookup.c @@ -1,16 +1,18 @@ + #include #include #include +#include + +#include + #ifndef __linux__ -#include #include #include #include "linuxmt/arpa/inet.h" #else #include -#include #include -#include #endif struct DNS_HEADER @@ -104,7 +106,7 @@ char* get_dns_server() //printf("ip adress not read\n"); sprintf(line,"208.67.222.222"); /*default nameserver*/ } - close (fp); + fclose (fp); return &line; } } @@ -119,7 +121,7 @@ int main(int argc, char *argv[]) { const char* nameserver; unsigned char *qname; int query_type; - int fd,rc,i; + int fd,rc; struct sockaddr_in addr; struct DNS_HEADER *dns = NULL; struct QUESTION *qinfo = NULL; diff --git a/elkscmd/inet/telnet/Makefile b/elkscmd/inet/telnet/Makefile index b259966f2..71173ffb2 100644 --- a/elkscmd/inet/telnet/Makefile +++ b/elkscmd/inet/telnet/Makefile @@ -12,16 +12,16 @@ include $(BASEDIR)/Make.rules ############################################################################### -SRC= ttn.c ttn_conf.c +SRCS = ttn.c ttn_conf.c +OBJS = $(SRCS:.c=.o) all: telnet -telnet: $(SRC) - $(CC) $(CFLAGS) $(INCLUDES) $(LDFLAGS) -o $@ $(SRC) +telnet: $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) install: telnet sudo install telnet $(TARGET_MNT)/bin clean: - rm -f telnet - + rm -f $(OBJS) telnet diff --git a/elkscmd/inet/telnet/ttn.c b/elkscmd/inet/telnet/ttn.c index 32f959b61..094850aca 100644 --- a/elkscmd/inet/telnet/ttn.c +++ b/elkscmd/inet/telnet/ttn.c @@ -21,6 +21,7 @@ ttn.c #include #include #include +#include #ifndef __linux__ #include diff --git a/elkscmd/inet/telnetd/Makefile b/elkscmd/inet/telnetd/Makefile index d8e9cf32b..3739bdc57 100644 --- a/elkscmd/inet/telnetd/Makefile +++ b/elkscmd/inet/telnetd/Makefile @@ -12,16 +12,17 @@ include $(BASEDIR)/Make.rules ############################################################################### -SRC= telnetd.c +SRCS = telnetd.c +OBJS = $(SRCS:.c=.o) all: telnetd -telnetd: $(SRC) - $(CC) $(CFLAGS) $(INCLUDES) $(LDFLAGS) -o $@ $(SRC) +telnetd: $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) install: telnetd sudo install telnetd $(TARGET_MNT)/bin clean: - rm -f *.o telnetd + rm -f $(OBJS) telnetd diff --git a/elkscmd/inet/telnetd/telnetd.c b/elkscmd/inet/telnetd/telnetd.c index b4b953699..5a94030df 100644 --- a/elkscmd/inet/telnetd/telnetd.c +++ b/elkscmd/inet/telnetd/telnetd.c @@ -5,15 +5,17 @@ #include #include #include +#include +#include +#include + #ifndef __linux__ #include #include #include #else #include -#include #include -#include #endif #include diff --git a/elkscmd/inet/tinyirc/Makefile b/elkscmd/inet/tinyirc/Makefile index 868cbe09d..c2e9e89e7 100644 --- a/elkscmd/inet/tinyirc/Makefile +++ b/elkscmd/inet/tinyirc/Makefile @@ -25,10 +25,10 @@ all: tinyirc LOCALDEFS = -DDEFAULTSERVER=\"$(SERVER)\" -DDEFAULTPORT=$(PORT) tinyirc: tinyirc.o - $(CC) $(LDFLAGS) -o tinyirc tinyirc.o $(LIBS) + $(LD) $(LDFLAGS) -o tinyirc tinyirc.o $(LDLIBS) tinyircd: tinyircd.o - $(CC) $(LDFLAGS) -o tinyircd tinyircd.o $(LIBS) + $(LD) $(LDFLAGS) -o tinyircd tinyircd.o $(LDLIBS) tinyirccv: tinyirccv.o $(CC) $(LDFLAGS) -o tinyirc tinyirccv.o $(LIBS) diff --git a/elkscmd/inet/tinyirc/tinyirc.c b/elkscmd/inet/tinyirc/tinyirc.c index f2f75de45..9cce13bab 100644 --- a/elkscmd/inet/tinyirc/tinyirc.c +++ b/elkscmd/inet/tinyirc/tinyirc.c @@ -30,7 +30,11 @@ $Log$ */ + #include +#include +#include + #ifndef POSIX #include #define USE_OLD_TTY @@ -50,7 +54,6 @@ #include #include #include -#include #include #include #ifdef ELKS diff --git a/elkscmd/inet/urlget/Makefile b/elkscmd/inet/urlget/Makefile index dadae6e6d..749a07477 100644 --- a/elkscmd/inet/urlget/Makefile +++ b/elkscmd/inet/urlget/Makefile @@ -12,12 +12,13 @@ include $(BASEDIR)/Make.rules ############################################################################### -SRC= net.c urlget.c +SRCS = net.c urlget.c +OBJS = $(SRCS:.c=.o) all: urlget -urlget: $(SRC) - $(CC) $(CFLAGS) $(LDFLAGS) $(INCLUDES) -o urlget $(SRC) +urlget: $(OBJS) + $(LD) $(LDFLAGS) -o urlget $(OBJS) $(LDLIBS) install: urlget sudo install urlget $(TARGET_MNT)/bin diff --git a/elkscmd/inet/urlget/net.c b/elkscmd/inet/urlget/net.c index 347789d71..4ba8ba879 100644 --- a/elkscmd/inet/urlget/net.c +++ b/elkscmd/inet/urlget/net.c @@ -24,6 +24,9 @@ #include #endif +#include + + unsigned long int in_aton(str) const char *str; { diff --git a/elkscmd/ktcp/Makefile b/elkscmd/ktcp/Makefile index 6f44928aa..272f6e45e 100644 --- a/elkscmd/ktcp/Makefile +++ b/elkscmd/ktcp/Makefile @@ -7,13 +7,14 @@ SHELL = /bin/sh CFILES = ktcp.c slip.c ip.c icmp.c tcp.c tcp_cb.c tcp_output.c \ timer.c tcpdev.c netconf.c vjhc.c deveth.c arp.c -OBJ = $(CFILES:.c=.o) +OBJS = $(CFILES:.c=.o) ############################################################################## all: ktcp -ktcp: $(OBJ) +ktcp: $(OBJS) + $(LD) $(LDFLAGS) -o ktcp $(OBJS) $(LDLIBS) lint: @for FILE in *.c ; do \ diff --git a/elkscmd/ktcp/deveth.c b/elkscmd/ktcp/deveth.c index 29b021d56..7226fb71e 100644 --- a/elkscmd/ktcp/deveth.c +++ b/elkscmd/ktcp/deveth.c @@ -45,7 +45,7 @@ void deveth_printhex(char* packet, int len) printf("\n"); } -int deveth_init(char *fdev, int argc, char **argv) +int deveth_init(char *fdev) { int i, err; __u8 *addr; diff --git a/elkscmd/ktcp/ip.c b/elkscmd/ktcp/ip.c index 4cb7be355..25371f5d5 100644 --- a/elkscmd/ktcp/ip.c +++ b/elkscmd/ktcp/ip.c @@ -31,7 +31,7 @@ #endif /*#define DEBUG*/ -#define USE_ASM +//#define USE_ASM static char ipbuf[TCPDEV_BUFSIZE]; diff --git a/elkscmd/ktcp/ktcp.c b/elkscmd/ktcp/ktcp.c index b50cf12fe..dccb70a54 100644 --- a/elkscmd/ktcp/ktcp.c +++ b/elkscmd/ktcp/ktcp.c @@ -129,7 +129,7 @@ int main(int argc,char **argv) if (strcmp(argv[2],dname) == 0) { debug("Init /dev/eth\n"); dev->type = 1; - intfd = deveth_init(dname, argc, argv); + intfd = deveth_init(dname); if (intfd < 0) { printf("failed to open /dev/eth [%d]\n", intfd); exit(1); diff --git a/elkscmd/ktcp/tcp.h b/elkscmd/ktcp/tcp.h index 825269c86..d3362de0e 100644 --- a/elkscmd/ktcp/tcp.h +++ b/elkscmd/ktcp/tcp.h @@ -148,8 +148,8 @@ int tcpcb_need_push; int tcp_retrans_memory; struct tcpcb_list_s *tcpcb_new(); -struct tcpcb_list_s *tcpcb_find(); -struct tcpcb_list_s *tcpcb_find_by_sock(); +struct tcpcb_list_s *tcpcb_find(__u32 addr, __u16 lport, __u16 rport); +struct tcpcb_list_s *tcpcb_find_by_sock(__u16 sock); void tcpcb_remove(); __u16 tcp_chksum(struct iptcp_s *h); diff --git a/elkscmd/ktcp/tcp_output.c b/elkscmd/ktcp/tcp_output.c index 684c05c7a..ce5f90051 100644 --- a/elkscmd/ktcp/tcp_output.c +++ b/elkscmd/ktcp/tcp_output.c @@ -22,7 +22,7 @@ char buf[128]; -#define USE_ASM +//#define USE_ASM static struct tcp_retrans_list_s *retrans_list; diff --git a/elkscmd/levee/Makefile b/elkscmd/levee/Makefile index cb34400f8..ba8564d06 100644 --- a/elkscmd/levee/Makefile +++ b/elkscmd/levee/Makefile @@ -21,7 +21,7 @@ OBJS = blockio.o display.o editcor.o exec.o find.o \ all: lev lev: $(OBJS) - $(CC) $(LDFLAGS) -o lev $(OBJS) + $(LD) $(LDFLAGS) -o lev $(OBJS) $(LDLIBS) install: lev sudo install lev $(TARGET_MNT)/bin/vi diff --git a/elkscmd/levee/find.c b/elkscmd/levee/find.c index 754ceb0be..7fb1d798c 100644 --- a/elkscmd/levee/find.c +++ b/elkscmd/levee/find.c @@ -19,7 +19,6 @@ #include "levee.h" #include "extern.h" #include "grep.h" -#include static int arg; /* arguments inside of a RE */ @@ -57,9 +56,6 @@ omatch(pattern, cp, endp) case TOKENE: return !isalnum(**cp); case LITCHAR: -#ifdef TOUPPER_FTN -#undef toupper -#endif if (ignorecase) flag = (toupper(**cp) == toupper(*(pattern+1))); else diff --git a/elkscmd/levee/levee.h b/elkscmd/levee/levee.h index ef1d0d99f..b26795a99 100644 --- a/elkscmd/levee/levee.h +++ b/elkscmd/levee/levee.h @@ -122,6 +122,7 @@ extern long gemdos(); #include #include +#include #define OPEN_OLD(n) open(n, O_RDONLY) #define OPEN_NEW(n) open(n, O_WRONLY|O_CREAT|O_TRUNC, 0666) @@ -132,7 +133,7 @@ extern long gemdos(); #define zwrite(p,s) WRITE_TEXT(fileno(stdout), p, s) -#endif /*MSDOS*/ +#endif /*UNIX*/ #if FLEXOS diff --git a/elkscmd/levee/termcap.i b/elkscmd/levee/termcap.i index 81fb3a272..64207b05f 100644 --- a/elkscmd/levee/termcap.i +++ b/elkscmd/levee/termcap.i @@ -218,7 +218,7 @@ tc_init() #else if (tgetent(lp, p) < 1) { - puts("lv: no termcap for %s\n", p); + printf("lv: no termcap for %s\n", p); exit(1); } if ((LINES=tgetnum("li")) <= 0) { diff --git a/elkscmd/minix1/Makefile b/elkscmd/minix1/Makefile index 1f21a96c4..dd4d348eb 100644 --- a/elkscmd/minix1/Makefile +++ b/elkscmd/minix1/Makefile @@ -18,8 +18,41 @@ NETPRGS = decomp16 du grep wc all: $(PRGS) +banner: banner.o + $(LD) $(LDFLAGS) -o banner banner.o $(LDLIBS) + +cksum: cksum.o + $(LD) $(LDFLAGS) -o cksum cksum.o $(LDLIBS) + +cut: cut.o + $(LD) $(LDFLAGS) -o cut cut.o $(LDLIBS) + +decomp16: decomp16.o + $(LD) $(LDFLAGS) -o decomp16 decomp16.o $(LDLIBS) + +du: du.o + $(LD) $(LDFLAGS) -o du du.o $(LDLIBS) + +fgrep: fgrep.o + $(LD) $(LDFLAGS) -o fgrep fgrep.o $(LDLIBS) + +grep: grep.o + $(LD) $(LDFLAGS) -o grep grep.o $(LDLIBS) + +proto: proto.o + $(LD) $(LDFLAGS) -o proto proto.o $(LDLIBS) + +sum: sum.o + $(LD) $(LDFLAGS) -o sum sum.o $(LDLIBS) + +uniq: uniq.o + $(LD) $(LDFLAGS) -o uniq uniq.o $(LDLIBS) + +wc: wc.o + $(LD) $(LDFLAGS) -o wc wc.o $(LDLIBS) + install: $(PRGS) sudo install $(PRGS) $(TARGET_MNT)/bin clean: - rm -f $(PRGS) + rm -f *.o $(PRGS) diff --git a/elkscmd/minix1/banner.c b/elkscmd/minix1/banner.c index a56a98e23..8e2c52700 100644 --- a/elkscmd/minix1/banner.c +++ b/elkscmd/minix1/banner.c @@ -23,8 +23,6 @@ #include #include -_PROTOTYPE(int main, (int argc, char **argv)); - char *glyphs[] = { " @@@ @@ @@ @ @ @@@@@ @@ @@@ ", " @@@ @@ @@ @ @ @ @ @@@ @ @ @ @@@ ", diff --git a/elkscmd/minix1/cksum.c b/elkscmd/minix1/cksum.c index c886fd921..d5f222e0d 100644 --- a/elkscmd/minix1/cksum.c +++ b/elkscmd/minix1/cksum.c @@ -72,10 +72,6 @@ unsigned long crctab[] = { 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; -_PROTOTYPE(int main, (int argc, char **argv)); -_PROTOTYPE(void crc, (int fd, char *name)); -_PROTOTYPE(unsigned long strncrc, (unsigned char *b, int n, unsigned long s)); - static int aux; /* Routine straight out of 4.9.10 */ diff --git a/elkscmd/minix1/du.c b/elkscmd/minix1/du.c index d5da3a1c3..6e30741b4 100644 --- a/elkscmd/minix1/du.c +++ b/elkscmd/minix1/du.c @@ -62,11 +62,6 @@ typedef struct already { nlink_t al_nlink; } ALREADY; -_PROTOTYPE(int main, (int argc, char **argv)); -_PROTOTYPE(int makedname, (char *d, char *f, char *out, int outlen)); -_PROTOTYPE(int done, (int dev, Ino_t inum, Nlink_t nlink)); -_PROTOTYPE(long dodir, (char *d, int thislev)); - char *prog; /* program name */ char *optstr = "asl:"; /* -a and -s arguments */ int silent = 0; /* silent mode */ diff --git a/elkscmd/minix1/grep.c b/elkscmd/minix1/grep.c index 2370b7d90..2296a2bbb 100644 --- a/elkscmd/minix1/grep.c +++ b/elkscmd/minix1/grep.c @@ -33,7 +33,7 @@ /* External interfaces */ #include -#include /* Thanks to Henry Spencer */ +#include /* Thanks to Henry Spencer */ #include #include #include diff --git a/elkscmd/minix1/uniq.c b/elkscmd/minix1/uniq.c index 3aea89247..864a2953c 100644 --- a/elkscmd/minix1/uniq.c +++ b/elkscmd/minix1/uniq.c @@ -27,6 +27,8 @@ static int chars = 0; /* The meat of the whole affair */ static char *nowline, *prevline, buf1[1024], buf2[1024]; +static int getline(char *buf, int count); + static FILE *xfopen(const char *fn, const char *mode) { FILE *p; diff --git a/elkscmd/minix2/Makefile b/elkscmd/minix2/Makefile index 528f7bfdf..399af7a7e 100644 --- a/elkscmd/minix2/Makefile +++ b/elkscmd/minix2/Makefile @@ -13,7 +13,24 @@ include $(BASEDIR)/Make.rules ############################################################################### PRGS=env lp pwdauth remsync synctree tget -RFS_PRGS=env install lp pwdauth tget + +env: env.o + $(LD) $(LDFLAGS) -o env env.o $(LDLIBS) + +pwdauth: pwdauth.o + $(LD) $(LDFLAGS) -o pwdauth pwdauth.o $(LDLIBS) + +lp: lp.o + $(LD) $(LDFLAGS) -o lp lp.o $(LDLIBS) + +remsync: remsync.o + $(LD) $(LDFLAGS) -o remsync remsync.o $(LDLIBS) + +synctree: synctree.o + $(LD) $(LDFLAGS) -o synctree synctree.o $(LDLIBS) + +tget: tget.o + $(LD) $(LDFLAGS) -o tget tget.o $(LDLIBS) # install # Same name as phony target install # lpd mt # Do not compile. @@ -23,6 +40,7 @@ NETPRGS=env all: $(PRGS) lpd: lpd.o ../lib/mktemp.o + $(LD) $(LDFLAGS) -o lpd lpd.o ../lib/mktemp.o $(LDLIBS) ../lib/mktemp.o: make -C ../lib mktemp.o diff --git a/elkscmd/minix3/Makefile b/elkscmd/minix3/Makefile index d9fe053b1..2eac1f338 100644 --- a/elkscmd/minix3/Makefile +++ b/elkscmd/minix3/Makefile @@ -18,10 +18,39 @@ PRGS=cal diff file find head sed sort tail tee # Rules # +cal: cal.o + $(LD) $(LDFLAGS) -o cal cal.o $(LDLIBS) + +diff: diff.o + $(LD) $(LDFLAGS) -o diff diff.o $(LDLIBS) + +file: file.o + $(LD) $(LDFLAGS) -o file file.o $(LDLIBS) + +find: find.o + $(LD) $(LDFLAGS) -o find find.o $(LDLIBS) + +head: head.o + $(LD) $(LDFLAGS) -o head head.o $(LDLIBS) + +sed: sed.o + $(LD) $(LDFLAGS) -o sed sed.o $(LDLIBS) + +sort: sort.o + $(LD) $(LDFLAGS) -o sort sort.o $(LDLIBS) + +tail: tail.o + $(LD) $(LDFLAGS) -o tail tail.o $(LDLIBS) + +tee: tee.o + $(LD) $(LDFLAGS) -o tee tee.o $(LDLIBS) + + include $(BASEDIR)/Make.rules all: $(PRGS) + install: $(PRGS) sudo install $(PRGS) $(TARGET_MNT)/bin diff --git a/elkscmd/misc_utils/Makefile b/elkscmd/misc_utils/Makefile index bafc32726..d5e119b48 100644 --- a/elkscmd/misc_utils/Makefile +++ b/elkscmd/misc_utils/Makefile @@ -13,14 +13,24 @@ HOST_CFLAGS = -O2 ############################################################################### -PRGS=ed tar compress uncompress zcat miniterm +PRGS=ed tar miniterm PRGS_HOST=compress.host -LOCALFLAGS=-H0xe000 +#compress uncompress zcat disabled all: $(PRGS) $(PRGS_HOST) -compress: compress.c +ed: ed.o + $(LD) $(LDFLAGS) -o ed ed.o $(LDLIBS) + +tar: tar.o + $(LD) $(LDFLAGS) -o tar tar.o $(LDLIBS) + +compress: compress.o + $(LD) $(LDFLAGS) -o compress compress.o $(LDLIBS) + +miniterm: miniterm.o + $(LD) $(LDFLAGS) -o miniterm miniterm.o $(LDLIBS) compress.host: compress.c $(HOSTCC) $(HOST_CFLAGS) -s compress.c -o $@ diff --git a/elkscmd/mtools/Makefile b/elkscmd/mtools/Makefile index bf8769537..e5c8b4996 100644 --- a/elkscmd/mtools/Makefile +++ b/elkscmd/mtools/Makefile @@ -27,15 +27,34 @@ CMNOBJ = init.o search.o unixname.o subdir.o getfat.o devices.o all: $(PROGS) mkdfs: mkdfs.o + $(LD) $(LDFLAGS) -o mkdfs mkdfs.o $(LDLIBS) + mdir: mdir.o match.o convdate.o isdir.o $(CMNOBJ) + $(LD) $(LDFLAGS) -o mdir mdir.o match.o convdate.o isdir.o $(CMNOBJ) $(LDLIBS) + mread: mread.o match.o convdate.o $(CMNOBJ) + $(LD) $(LDFLAGS) -o mread mread.o match.o convdate.o $(CMNOBJ) $(LDLIBS) + mwrite: mwrite.o fixname.o putfat.o mkentry.o isdir.o $(CMNOBJ) + $(LD) $(LDFLAGS) -o mwrite mwrite.o fixname.o putfat.o mkentry.o isdir.o $(CMNOBJ) $(LDLIBS) + mdel: mdel.o match.o putfat.o $(CMNOBJ) + $(LD) $(LDFLAGS) -o mdel mdel.o match.o putfat.o $(CMNOBJ) $(LDLIBS) + mtype: mtype.o match.o $(CMNOBJ) + $(LD) $(LDFLAGS) -o mtype mtype.o match.o $(CMNOBJ) $(LDLIBS) + mmd: mmd.o fixname.o putfat.o mkentry.o $(CMNOBJ) + $(LD) $(LDFLAGS) -o mmd mmd.o fixname.o putfat.o mkentry.o $(CMNOBJ) $(LDLIBS) + mrd: mrd.o putfat.o $(CMNOBJ) + $(LD) $(LDFLAGS) -o mrd mrd.o putfat.o $(CMNOBJ) $(LDLIBS) + mren: mren.o fixname.o putfat.o isdir.o $(CMNOBJ) + $(LD) $(LDFLAGS) -o mren mren.o fixname.o putfat.o isdir.o $(CMNOBJ) $(LDLIBS) + mcopy: mcopy.o + $(LD) $(LDFLAGS) -o mcopy mcopy.o $(LDLIBS) install: $(PROGS) sudo install $(PROGS) $(TARGET_MNT)/$(BINDIR)/ diff --git a/elkscmd/mtools/init.c b/elkscmd/mtools/init.c index dd6f2b621..cb42a87df 100644 --- a/elkscmd/mtools/init.c +++ b/elkscmd/mtools/init.c @@ -28,9 +28,8 @@ init(mode) int mode; { int code, buflen, intr(); - void perror(), exit(), move(), reset_dir(); + void perror(), move(), reset_dir(); char *getenv(), *fixmcwd(), *malloc(), *dummy; - long lseek(); struct device *try; int ncyl = 0, nsect = 0, ntrack =0 ; char *floppy = getenv("FLOPPY"); @@ -122,9 +121,6 @@ void move(sector) int sector; { - long lseek(); - void exit(), perror(); - if (lseek(fd, (long)sector*MSECSIZ, 0) < 0) { perror("move: lseek"); exit(1); diff --git a/elkscmd/mtools/mtype.c b/elkscmd/mtools/mtype.c index ef5674610..514ae97c1 100644 --- a/elkscmd/mtools/mtype.c +++ b/elkscmd/mtools/mtype.c @@ -36,7 +36,7 @@ char *argv[]; int fat, i, ismatch, entry, c, oops; char *filename, *newfile, text[4], tname[9], *getname(), *unixname(); char *strncpy(), *pathname, *getpath(); - void exit(), readit(), free(); + void readit(), free(); struct directory *dir, *search(); if (init(0)) { diff --git a/elkscmd/mtools/putfat.c b/elkscmd/mtools/putfat.c index ca9f8c70d..29133b294 100644 --- a/elkscmd/mtools/putfat.c +++ b/elkscmd/mtools/putfat.c @@ -60,7 +60,7 @@ struct directory *dir; { int skip, entry; struct directory dirs[16]; - void exit(), perror(), move(); + void perror(), move(); /* which sector */ skip = dir_chain[num / 16]; diff --git a/elkscmd/prems/pres/Makefile b/elkscmd/prems/pres/Makefile index 8c6150586..30db57d01 100644 --- a/elkscmd/prems/pres/Makefile +++ b/elkscmd/prems/pres/Makefile @@ -30,7 +30,7 @@ all: pres flparc pres: $(POBJS) $(LIBS) @echo -n "Loading pres ... " - $(CC) $(LDFLAGS) $(POBJS) $(LIBS) -o pres + $(LD) $(LDFLAGS) $(POBJS) $(LIBS) -o pres $(LDLIBS) @echo "done" xpres: $(POBJS) $(XLIBS) @@ -40,7 +40,7 @@ xpres: $(POBJS) $(XLIBS) flparc: $(FOBJS) $(LIBS) @echo -n "Loading flparc ... " - @$(CC) $(LDFLAGS) $(FOBJS) $(LIBS) -o flparc + @$(LD) $(LDFLAGS) $(FOBJS) $(LIBS) -o flparc $(LDLIBS) @echo "done" clean:; @rm -f $(OBJS) pres flparc diff --git a/elkscmd/prems/pres/pres.c b/elkscmd/prems/pres/pres.c index 492eff54f..3d76f8604 100644 --- a/elkscmd/prems/pres/pres.c +++ b/elkscmd/prems/pres/pres.c @@ -401,7 +401,7 @@ int main(register int argc, char **argv) int overwrite = 0; /* Do not recreate existing file(s) */ char tempname[MAXFNAMEL]; char **filelist, **fileptr; - char *cp, *strrchr(const char *, int); + char *cp; struct stat statbuf; extern int onintr(); diff --git a/elkscmd/sh_utils/Makefile b/elkscmd/sh_utils/Makefile index 0d97843b7..fa9d5dfa6 100644 --- a/elkscmd/sh_utils/Makefile +++ b/elkscmd/sh_utils/Makefile @@ -15,16 +15,64 @@ PRGS=basename date dirname echo false printenv pwd true which whoami yes \ # uname write # Do not compile -NETPRGS=date echo false true yes stty test pwd - -MIN_PRGS=date pwd printenv test - write: write.o ../sys_utils/utent.o all: $(PRGS) +basename: basename.o + $(LD) $(LDFLAGS) -o basename basename.o $(LDLIBS) + +date: date.o + $(LD) $(LDFLAGS) -o date date.o $(LDLIBS) + +dirname: dirname.o + $(LD) $(LDFLAGS) -o dirname dirname.o $(LDLIBS) + +echo: echo.o + $(LD) $(LDFLAGS) -o echo echo.o $(LDLIBS) + +false: false.o + $(LD) $(LDFLAGS) -o false false.o $(LDLIBS) + +printenv: printenv.o + $(LD) $(LDFLAGS) -o printenv printenv.o $(LDLIBS) + +pwd: pwd.o + $(LD) $(LDFLAGS) -o pwd pwd.o $(LDLIBS) + +true: true.o + $(LD) $(LDFLAGS) -o true true.o $(LDLIBS) + +which: which.o + $(LD) $(LDFLAGS) -o which which.o $(LDLIBS) + +whoami: whoami.o + $(LD) $(LDFLAGS) -o whoami whoami.o $(LDLIBS) + +yes: yes.o + $(LD) $(LDFLAGS) -o yes yes.o $(LDLIBS) + +logname: logname.o + $(LD) $(LDFLAGS) -o logname logname.o $(LDLIBS) + +tr: tr.o + $(LD) $(LDFLAGS) -o tr tr.o $(LDLIBS) + +xargs: xargs.o + $(LD) $(LDFLAGS) -o xargs xargs.o $(LDLIBS) + +mesg: mesg.o + $(LD) $(LDFLAGS) -o mesg mesg.o $(LDLIBS) + +stty: stty.o + $(LD) $(LDFLAGS) -o stty stty.o $(LDLIBS) + +test: test.o + $(LD) $(LDFLAGS) -o test test.o $(LDLIBS) + + install: $(PRGS) sudo install $(PRGS) $(TARGET_MNT)/bin clean: - rm -f core $(PRGS) + rm -f *.o $(PRGS) diff --git a/elkscmd/sys_utils/Makefile b/elkscmd/sys_utils/Makefile index a68d231d3..91105f3bc 100644 --- a/elkscmd/sys_utils/Makefile +++ b/elkscmd/sys_utils/Makefile @@ -2,8 +2,6 @@ BASEDIR=.. include $(BASEDIR)/Make.defs -LOCALFLAGS = - ############################################################################### # # Include standard packaging commands. @@ -13,40 +11,69 @@ include $(BASEDIR)/Make.rules ############################################################################### PRGS = init getty login kill mount umount passwd reboot shutdown ps \ - swapon meminfo who clock exitemu knl man poweroff + swapon meminfo who knl man poweroff -all: $(PRGS) +# clock disabled because direct I/O port access +# exitemu disabled because it calls INT directly to DOSEMU -install: $(PRGS) - sudo install $(PRGS) $(TARGET_MNT)/bin +init: init.o + $(LD) $(LDFLAGS) -o init init.o $(LDLIBS) -clean: - rm -f *.o core $(PRGS) +getty: getty.o + $(LD) $(LDFLAGS) -o getty getty.o $(LDLIBS) + +login: getpass.o login.o + $(LD) $(LDFLAGS) -o login getpass.o login.o $(LDLIBS) + +kill: kill.o + $(LD) $(LDFLAGS) -o kill kill.o $(LDLIBS) + +mount: mount.o + $(LD) $(LDFLAGS) -o mount mount.o $(LDLIBS) + +umount: umount.o + $(LD) $(LDFLAGS) -o umount umount.o $(LDLIBS) passwd: getpass.o passwd.o putpwent.o + $(LD) $(LDFLAGS) -o passwd getpass.o passwd.o putpwent.o $(LDLIBS) +reboot: reboot.o + $(LD) $(LDFLAGS) -o reboot reboot.o $(LDLIBS) -# Trim stack space of core programs. -# The -H option is the maximum size the data segment can be. -# If the code is modified, this value has to be carefully trimmed -# to fit the programs requirements. At the moment it is data + bss + -# 1024 bytes at least for even the smallest programs. Binaries which -# call malloc will need much more than this. +shutdown: shutdown.o + $(LD) $(LDFLAGS) -o shutdown shutdown.o $(LDLIBS) -getty: getty.c - $(CC) $(CFLAGS) $(LDFLAGS) getty.c -o getty -H 0x1800 +ps: ps.o + $(LD) $(LDFLAGS) -o ps ps.o $(LDLIBS) -meminfo: meminfo.c - $(CC) $(CFLAGS) $(LDFLAGS) meminfo.c -o meminfo -H 0x100 +swapon: swapon.o + $(LD) $(LDFLAGS) -o swapon swapon.o $(LDLIBS) -swapon: swapon.c - $(CC) $(CFLAGS) $(LDFLAGS) swapon.c -o swapon -H 0x100 +meminfo: meminfo.o + $(LD) $(LDFLAGS) -o meminfo meminfo.o $(LDLIBS) -init: init.c - $(CC) $(CFLAGS) $(LDFLAGS) init.c -o init -H 0x8000 +who: who.o + $(LD) $(LDFLAGS) -o who who.o $(LDLIBS) -rdev: rdev.c - $(CC) $(CFLAGS) $(LDFLAGS) rdev.c -o rdev +clock: clock.o + $(LD) $(LDFLAGS) -o clock clock.o $(LDLIBS) -login: getpass.o login.o - $(CC) $(CFLAGS) $(LDFLAGS) getpass.o login.o -o login -H 0x8000 +exitemu: exitemu.o + $(LD) $(LDFLAGS) -o exitemu exitemu.o $(LDLIBS) + +knl: knl.o + $(LD) $(LDFLAGS) -o knl knl.o $(LDLIBS) + +man: man.o + $(LD) $(LDFLAGS) -o man man.o $(LDLIBS) + +poweroff: poweroff.o + $(LD) $(LDFLAGS) -o poweroff poweroff.o $(LDLIBS) + +all: $(PRGS) + +install: $(PRGS) + sudo install $(PRGS) $(TARGET_MNT)/bin + +clean: + rm -f *.o core $(PRGS) diff --git a/elkscmd/test/eth/Makefile b/elkscmd/test/eth/Makefile index 511c46121..0ea8b94e0 100644 --- a/elkscmd/test/eth/Makefile +++ b/elkscmd/test/eth/Makefile @@ -15,7 +15,7 @@ include $(BASEDIR)/Make.rules all: eth eth: $(OBJS) - + $(LD) $(LDFLAGS) -o eth eth.o $(LDLIBS) install: eth sudo install eth $(TARGET_MNT)/bin diff --git a/elkscmd/test/pty/Makefile b/elkscmd/test/pty/Makefile index e85c16f45..7bb452fe6 100644 --- a/elkscmd/test/pty/Makefile +++ b/elkscmd/test/pty/Makefile @@ -14,6 +14,9 @@ include $(BASEDIR)/Make.rules all: ptyshell +ptyshell: $(OBJS) + $(LD) $(LDFLAGS) -o ptyshell ptyshell.o $(LDLIBS) + install: ptyshell sudo install ptyshell $(TARGET_MNT)/bin diff --git a/elkscmd/test/select/Makefile b/elkscmd/test/select/Makefile index 63d49b547..ec32f0f47 100644 --- a/elkscmd/test/select/Makefile +++ b/elkscmd/test/select/Makefile @@ -16,6 +16,7 @@ include $(BASEDIR)/Make.rules all: $(PGM) $(PGM): $(OBJS) + $(LD) $(LDFLAGS) -o $(PGM) $(OBJS) $(LDLIBS) install: $(PGM) sudo install $(PGM) $(TARGET_MNT)/bin diff --git a/elkscmd/test/signal/Makefile b/elkscmd/test/signal/Makefile index d2a573aca..3b503e063 100644 --- a/elkscmd/test/signal/Makefile +++ b/elkscmd/test/signal/Makefile @@ -16,6 +16,7 @@ include $(BASEDIR)/Make.rules all: $(PGM) $(PGM): $(OBJS) + $(LD) $(LDFLAGS) -o $(PGM) $(OBJS) $(LDLIBS) install: $(PGM) sudo install $(PGM) $(TARGET_MNT)/bin diff --git a/elkscmd/test/signal/test_signal.c b/elkscmd/test/signal/test_signal.c index 35a6a621a..5ba691427 100644 --- a/elkscmd/test/signal/test_signal.c +++ b/elkscmd/test/signal/test_signal.c @@ -9,18 +9,18 @@ void sigint (int signo) _signo = signo; } -extern __sighandler_t __sigtable [15]; +extern __sighandler_t _sigtable [15]; int main (int argc, char ** argv) { sig_t sigold; puts ("before signal()"); - printf ("SIGINT=%u\n", __sigtable [1]); + printf ("SIGINT=%u\n", _sigtable [1]); sigold = signal (SIGINT, sigint); puts ("after signal()"); - printf ("SIGINT=%u\n", __sigtable [1]); + printf ("SIGINT=%u\n", _sigtable [1]); printf ("sigint=%u\n", sigint); while (!_signo) sleep (1); diff --git a/elkscmd/test/socket/echo/Makefile b/elkscmd/test/socket/echo/Makefile index 9328b899e..d2a01310f 100644 --- a/elkscmd/test/socket/echo/Makefile +++ b/elkscmd/test/socket/echo/Makefile @@ -14,6 +14,12 @@ PRGS=echoserver echoclient all: $(PRGS) +echoserver: echoserver.o + $(LD) $(LDFLAGS) -o echoserver echoserver.o $(LDLIBS) + +echoclient: echoclient.o + $(LD) $(LDFLAGS) -o echoclient echoclient.o $(LDLIBS) + install: $(PRGS) sudo install $(PRGS) $(TARGET_MNT)/bin diff --git a/libc/.gitignore b/libc/.gitignore new file mode 100644 index 000000000..981dbb488 --- /dev/null +++ b/libc/.gitignore @@ -0,0 +1,3 @@ +crt0.s +crt0.o +libc.a diff --git a/libc/Makefile b/libc/Makefile new file mode 100644 index 000000000..c81bdb4e2 --- /dev/null +++ b/libc/Makefile @@ -0,0 +1,48 @@ +# Makefile of ELKS C Library + +ifndef TOPDIR +$(error TOPDIR is not defined) +endif + +include $(TOPDIR)/Make.defs + +include Makefile.inc + +# Defines + +SUBDIRS = \ + error \ + gcc \ + getent \ + malloc \ + misc \ + regex \ + stdio \ + string \ + system \ + termcap \ + termios \ + time \ + # end of list + +#SUBDIRS=list + +# Rules + +.PHONY: all $(SUBDIRS) + +all: $(LIBC) crt0.o + +$(LIBC):: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ all + +crt0.s: crt0.S +crt0.o: crt0.s + +.PHONY: clean + +clean: + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR clean || exit 1; done + rm -f crt0.s *.o libc.a diff --git a/libc/Makefile.inc b/libc/Makefile.inc new file mode 100644 index 000000000..352552910 --- /dev/null +++ b/libc/Makefile.inc @@ -0,0 +1,34 @@ + +VERSION=elks-0.0 + +INCLUDES=-I$(TOPDIR)/include -I$(TOPDIR)/libc/include -I$(TOPDIR)/elks/include +DEFINES=-D__LIBC__ -D__LIBC_VER__='"$(VERSION)"' -D__HAS_NO_FLOATS__ + +SDEFS=$(DEFINES) +CDEFS=$(DEFINES) + +ARCH=-mtune=i8086 -fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding + +CC=ia16-elf-gcc +AS=ia16-elf-as +AR=ia16-elf-ar +LD=ia16-elf-ld + +CFLAGS=$(ARCH) $(INCLUDES) $(CDEFS) -Os -Wall +ASFLAGS=-mtune=i8086 +LDFLAGS=-mtune=i8086 + +LIBC=$(TOPDIR)/libc/libc.a +LIB_CPU=i86 +LIB_OS=ELKS + +.S.o: ; + +.S.s: + gcc -E -traditional $(INCS) $(SDEFS) -o $*.s $< + +.s.o: + $(AS) $(ASFLAGS) -o $*.o $< + +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< diff --git a/libc/crt0.S b/libc/crt0.S new file mode 100644 index 000000000..0f14f1d4b --- /dev/null +++ b/libc/crt0.S @@ -0,0 +1,60 @@ +# C runtime bootstrap + + .code16 + + .text + + .extern main + .extern _exit + +// This is the program entry point + + .global entry + +entry: + jmp _startup + + .global exit + +// C runtime startup + +_startup: + push %bp + mov %sp,%bp + lea 6(%bp),%bx // argv [0] + mov 4(%bp),%cx // argc + mov %cx,%ax + shl $1,%ax + add %bx,%ax // envp [0] + mov %ax,environ + push %ax + push %bx + push %cx + call main + add $4,%sp + push %ax // main return value + call exit // no return + int $3 + +exit: + push %bp + mov %sp,%bp + mov _cleanup,%bx + or %bx,%bx + jz _exit_end + call *%bx + +_exit_end: + push 4(%bp) // exit code + call _exit // kernel one - no return + int $3 + + .data + + .extern environ + .extern _cleanup + +// Zero data for null pointers (near & far) + + .word 0 + .word 0 diff --git a/libc/error/Makefile b/libc/error/Makefile new file mode 100644 index 000000000..c573f51e5 --- /dev/null +++ b/libc/error/Makefile @@ -0,0 +1,16 @@ +# Makefile of /libc/misc module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS= __assert.c error.c perror.c +OBJS= $(SRCS:.c=.o) + +all: $(LIBC) + +$(OBJS): $(SRCS) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +clean: + rm -f $(OBJS) diff --git a/libc/error/__assert.c b/libc/error/__assert.c new file mode 100644 index 000000000..4021b871a --- /dev/null +++ b/libc/error/__assert.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include +#include +#include + +static void errput(str) +const char * str; +{ + write(2, str, strlen(str)); +} + +void +__assert(assertion, filename, linenumber) +const char * assertion; +const char * filename; +int linenumber; +{ + errput("Failed assertion '"); + errput(assertion); + errput("' in file "); + errput(filename); + errput(" at line "); + errput(itoa(linenumber)); + errput(".\n"); + abort(); +} diff --git a/libc/error/error.c b/libc/error/error.c new file mode 100644 index 000000000..4be2a5628 --- /dev/null +++ b/libc/error/error.c @@ -0,0 +1,57 @@ +/* Copyright (C) 1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ +#include + +char **__sys_errlist =0; +int __sys_nerr = 0; + +char * +strerror(err) +int err; +{ + int fd; + static char retbuf[80]; + char inbuf[256]; + int cc; + int bufoff = 0; + + if( __sys_nerr ) + { + if( err < 0 || err >= __sys_nerr ) goto unknown; + return __sys_errlist[err]; + } + + if( err <= 0 ) goto unknown; /* NB the <= allows comments in the file */ + fd = open("/lib/liberror.txt", 0); + if( fd < 0 ) goto unknown; + + while( (cc=read(fd, inbuf, sizeof(inbuf))) > 0 ) + { + int i; + for(i=0; i= 0 ) close(fd); + strcpy(retbuf, "Unknown error "); + strcpy(retbuf+14, itoa(err)); + return retbuf; +} diff --git a/libc/error/perror.c b/libc/error/perror.c new file mode 100644 index 000000000..f9b096564 --- /dev/null +++ b/libc/error/perror.c @@ -0,0 +1,19 @@ + +#include + +void +perror(str) +__const char * str; +{ + register char * ptr; + if(str) + { + write(2, str, strlen(str)); + write(2, ": ", 2); + } + else write(2, "perror: ", 8); + + ptr = strerror(errno); + write(2, ptr, strlen(ptr)); + write(2, "\n", 1); +} diff --git a/libc/gcc/Makefile b/libc/gcc/Makefile new file mode 100644 index 000000000..2efb929e4 --- /dev/null +++ b/libc/gcc/Makefile @@ -0,0 +1,16 @@ +# Makefile of /libc/gcc module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS = divmodsi3.s ldivmod.s +OBJS = $(SRCS:.s=.o) + +all: $(LIBC) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +$(OBJS): $(SRCS) + +clean: + rm -f *.o diff --git a/libc/gcc/divmodsi3.s b/libc/gcc/divmodsi3.s new file mode 100644 index 000000000..95fb3fb99 --- /dev/null +++ b/libc/gcc/divmodsi3.s @@ -0,0 +1,92 @@ + + .code16 + + .text + .extern ldivmod + .extern ludivmod + + .global __divsi3 + .align 1 + +__divsi3: + push %bp + mov %sp,%bp + push %bx + push %cx + push %di + mov 4(%bp),%ax + mov 6(%bp),%bx + mov 8(%bp),%cx + mov 10(%bp),%di + call ldivmod + mov %di,%dx + mov %cx,%ax + pop %di + pop %cx + pop %bx + pop %bp + ret + + .global __modsi3 + .align 1 + +__modsi3: + push %bp + mov %sp,%bp + push %bx + push %cx + push %di + mov 4(%bp),%ax + mov 6(%bp),%bx + mov 8(%bp),%cx + mov 10(%bp),%di + call ldivmod + mov %bx,%dx + pop %di + pop %cx + pop %bx + pop %bp + ret + + .global __udivsi3 + .align 1 + +__udivsi3: + push %bp + mov %sp,%bp + push %bx + push %cx + push %di + mov 4(%bp),%ax + mov 6(%bp),%bx + mov 8(%bp),%cx + mov 10(%bp),%di + call ludivmod + mov %di,%dx + mov %cx,%ax + pop %di + pop %cx + pop %bx + pop %bp + ret + + .global __umodsi3 + .align 1 + +__umodsi3: + push %bp + mov %sp,%bp + push %bx + push %cx + push %di + mov 4(%bp),%ax + mov 6(%bp),%bx + mov 8(%bp),%cx + mov 10(%bp),%di + call ludivmod + mov %bx,%dx + pop %di + pop %cx + pop %bx + pop %bp + ret diff --git a/libc/gcc/ldivmod.s b/libc/gcc/ldivmod.s new file mode 100644 index 000000000..6ce386cd7 --- /dev/null +++ b/libc/gcc/ldivmod.s @@ -0,0 +1,200 @@ +/* +! ldivmod.s - 32 over 32 to 32 bit division and remainder for 8086 + +! ldivmod( dividend bx:ax, divisor di:cx ) [ signed quot di:cx, rem bx:ax ] +! ludivmod( dividend bx:ax, divisor di:cx ) [ unsigned quot di:cx, rem bx:ax ] + +! dx is not preserved + + +! NB negatives are handled correctly, unlike by the processor +! divison by zero does not trap + + +! let dividend = a, divisor = b, quotient = q, remainder = r +! a = b * q + r mod 2^32 +! where: + +! if b = 0, q = 0 and r = a + +! otherwise, q and r are uniquely determined by the requirements: +! r has the same sign as b and absolute value smaller than that of b, i.e. +! if b > 0, then 0 <= r < b +! if b < 0, then 0 >= r > b +! (the absoulute value and its comparison depend on signed/unsigned) + +! the rule for the sign of r means that the quotient is truncated towards +! negative infinity in the usual case of a positive divisor + +! if the divisor is negative, the division is done by negating a and b, +! doing the division, then negating q and r +*/ + + .code16 + + .global ldivmod + .text + .align 1 + +ldivmod: + mov %di,%dx // sign byte of b in dh + mov %bh,%dl // sign byte of a in dl + test %di,%di + jns set_asign + neg %di + neg %cx + sbb $0,%di + +set_asign: + test %bx,%bx + jns got_signs // leave r = a positive + neg %bx + neg %ax + sbb $0,%bx + jmp got_signs + + .global ludivmod + .align 1 + +ludivmod: + xor %dx,%dx // both sign bytes 0 + +got_signs: + push %bp + push %si + mov %sp,%bp + push %di // remember b + push %cx + +b0 = -4 +b16 = -2 + + test %di,%di + jne divlarge + test %cx,%cx + je divzero + cmp %cx,%bx + jae divlarge // would overflow + xchg %bx,%dx // a in dx:ax, signs in bx + div %cx + xchg %ax,%cx // q in di:cx, junk in ax + xchg %bx,%ax // signs in ax, junk in bx + xchg %dx,%ax // r in ax, signs back in dx + mov %di,%bx // r in bx:ax + jmp zdivu1 + +divzero: // return q = 0 and r = a + test %dl,%dl + jns return + jmp negr // a initially minus, restore it + +divlarge: + push %dx // remember sign bytes + mov %di,%si // w in si:dx, initially b from di:cx + mov %cx,%dx + xor %cx,%cx // q in di:cx, initially 0 + mov %cx,%di + +// r in bx:ax, initially a +// use di:cx rather than dx:cx in order to +// have dx free for a byte pair later + + cmp %bx,%si + jb loop1 + ja zdivu // finished if b > r + cmp %ax,%dx + ja zdivu + +// rotate w (= b) to greatest dyadic multiple of b <= r + +loop1: + shl $1,%dx // w = 2*w + rcl $1,%si + jc loop1_exit // w was > r counting overflow (unsigned) + cmp %bx,%si // while w <= r (unsigned) + jb loop1 + ja loop1_exit + cmp %ax,%dx + jbe loop1 // else exit with carry clear for rcr + +loop1_exit: + rcr $1,%si + rcr $1,%dx + +loop2: + shl $1,%cx // q = 2*q + rcl $1,%di + cmp %bx,%si // if w <= r + jb loop2_over + ja loop2_test + cmp %ax,%dx + ja loop2_test + +loop2_over: + add $1,%cx // q++ + adc $0,%di + sub %dx,%ax // r = r-w + sbb %si,%bx + +loop2_test: + shr $1,%si // w = w/2 + rcr $1,%dx + cmp b16(%bp),%si // while w >= b + ja loop2 + jb zdivu + cmp b0(%bp),%dx + jae loop2 + +zdivu: + pop %dx // sign bytes + +zdivu1: + test %dh,%dh + js zbminus + test %dl,%dl + jns return // else a initially minus, b plus + mov %ax,%dx // -a = b * q + r ==> a = b * (-q) + (-r) + or %bx,%dx + je negq // use if r = 0 + sub b0(%bp),%ax // use a = b * (-1 - q) + (b - r) + sbb b16(%bp),%bx + not %cx // q = -1 - q (same as complement) + not %di + +negr: + neg %bx + neg %ax + sbb $0,%bx +return: + mov %bp,%sp + pop %si + pop %bp + ret + + .align 1 + +zbminus: + test %dl,%dl // (-a) = (-b) * q + r ==> a = b * q + (-r) + js negr // use if initial a was minus + mov %ax,%dx // a = (-b) * q + r ==> a = b * (-q) + r + or %bx,%dx + je negq // use if r = 0 + sub b0(%bp),%ax // use a = b * (-1 - q) + (b + r) (b is now -b) + sbb b16(%bp),%bx + not %cx + not %di + mov %bp,%sp + pop %si + pop %bp + ret + + .align 1 + +negq: + neg %di + neg %cx + sbb $0,%di + mov %bp,%sp + pop %si + pop %bp + ret diff --git a/libc/getent/Makefile b/libc/getent/Makefile new file mode 100644 index 000000000..6d59bfe62 --- /dev/null +++ b/libc/getent/Makefile @@ -0,0 +1,16 @@ +# Makefile of /libc/termios module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS= utent.c pwent.c getpwuid.c getpwnam.c __getpwent.c getgrgid.c getgrnam.c __getgrent.c +OBJS= $(SRCS:.c=.o) + +all: $(LIBC) + +$(OBJS): $(SRCS) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +clean: + rm -f *.o diff --git a/libc/getent/__getgrent.c b/libc/getent/__getgrent.c new file mode 100644 index 000000000..612f1124d --- /dev/null +++ b/libc/getent/__getgrent.c @@ -0,0 +1,168 @@ +/* + * __getgrent.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include "config.h" + +/* + * This is the core group-file read function. It behaves exactly like + * getgrent() except that it is passed a file descriptor. getgrent() + * is just a wrapper for this function. + */ +struct group * +__getgrent(int grp_fd) +{ +#ifndef GR_SCALE_DYNAMIC + static char line_buff[GR_MAX_LINE_LEN]; + static char * members[GR_MAX_MEMBERS]; +#else + static char * line_buff = NULL; + static char ** members = NULL; + short line_index; + short buff_size; +#endif + static struct group group; + register char * ptr; + char * field_begin; + short member_num; + char * endptr; + int line_len; + + + /* We use the restart label to handle malformatted lines */ +restart: +#ifdef GR_SCALE_DYNAMIC + line_index=0; + buff_size=256; +#endif + +#ifndef GR_SCALE_DYNAMIC + /* Read the line into the static buffer */ + if ((line_len=read(grp_fd, line_buff, GR_MAX_LINE_LEN))<=0) + return NULL; + field_begin=strchr(line_buff, '\n'); + if (field_begin!=NULL) + lseek(grp_fd, (long) (1+field_begin-(line_buff+line_len)), SEEK_CUR); + else /* The line is too long - skip it :-\ */ + { + do { if ((line_len=read(grp_fd, line_buff, GR_MAX_LINE_LEN))<=0) + return NULL; + } while (!(field_begin=strchr(line_buff, '\n'))); + lseek(grp_fd, (long) ((field_begin-line_buff)-line_len+1), SEEK_CUR); + goto restart; + } + if (*line_buff=='#' || *line_buff==' ' || *line_buff=='\n' || + *line_buff=='\t') + goto restart; + *field_begin='\0'; + +#else /* !GR_SCALE_DYNAMIC */ + line_buff=realloc(line_buff, buff_size); + while (1) + { + if ((line_len=read(grp_fd, line_buff+line_index, + buff_size-line_index))<=0) + return NULL; + field_begin=strchr(line_buff, '\n'); + if (field_begin!=NULL) + { + lseek(grp_fd, (long) (1+field_begin-(line_len+line_index+line_buff)), + SEEK_CUR); + *field_begin='\0'; + if (*line_buff=='#' || *line_buff==' ' || *line_buff=='\n' || + *line_buff=='\t') + goto restart; + break; + } + else /* Allocate some more space */ + { + line_index=buff_size; + buff_size+=256; + line_buff=realloc(line_buff, buff_size); + } + } +#endif /* GR_SCALE_DYNAMIC */ + + /* Now parse the line */ + group.gr_name=line_buff; + ptr=strchr(line_buff, ':'); + if (ptr==NULL) goto restart; + *ptr++='\0'; + + group.gr_passwd=ptr; + ptr=strchr(ptr, ':'); + if (ptr==NULL) goto restart; + *ptr++='\0'; + + field_begin=ptr; + ptr=strchr(ptr, ':'); + if (ptr==NULL) goto restart; + *ptr++='\0'; + + group.gr_gid=(gid_t) strtoul(field_begin, &endptr, 10); + if (*endptr!='\0') goto restart; + + member_num=0; + field_begin=ptr; + +#ifndef GR_SCALE_DYNAMIC + while ((ptr=strchr(ptr, ','))!=NULL) + { + *ptr='\0'; + ptr++; + members[member_num]=field_begin; + field_begin=ptr; + member_num++; + } + if (*field_begin=='\0') + members[member_num]=NULL; + else + { + members[member_num]=field_begin; + members[member_num+1]=NULL; + } +#else /* !GR_SCALE_DYNAMIC */ + if (members!=NULL) + free (members); + members=(char **) malloc(1*sizeof(char *)); + while ((ptr=strchr(ptr, ','))!=NULL) + { + *ptr='\0'; + ptr++; + members[member_num]=field_begin; + field_begin=ptr; + member_num++; + members=(char **)realloc((void *)members, (member_num+1)*sizeof(char *)); + } + if (*field_begin=='\0') + members[member_num]=NULL; + else + { + members[member_num]=field_begin; + members[member_num+1]=NULL; + } +#endif /* GR_SCALE_DYNAMIC */ + + group.gr_mem=members; + return &group; +} diff --git a/libc/getent/__getpwent.c b/libc/getent/__getpwent.c new file mode 100644 index 000000000..9836ca7b5 --- /dev/null +++ b/libc/getent/__getpwent.c @@ -0,0 +1,99 @@ +/* + * __getpwent.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +#define PWD_BUFFER_SIZE 256 + +/* This isn't as flash as my previous version -- it doesn't dynamically + scale down the gecos on too-long lines, but it also makes fewer syscalls, + so it's probably nicer. Write me if you want the old version. Maybe I + should include it as a build-time option... ? + -Nat */ + +struct passwd * +__getpwent(int pwd_fd) +{ + static char line_buff[PWD_BUFFER_SIZE]; + static struct passwd passwd; + char * field_begin; + char * endptr; + char * gid_ptr; + char * uid_ptr; + int line_len; + int i; + + /* We use the restart label to handle malformatted lines */ +restart: + /* Read the passwd line into the static buffer using a minimal of + syscalls. */ + if ((line_len=read(pwd_fd, line_buff, PWD_BUFFER_SIZE))<=0) + return NULL; + field_begin=strchr(line_buff, '\n'); + if (field_begin!=NULL) + lseek(pwd_fd, (long) (1+field_begin-(line_buff+line_len)), SEEK_CUR); + else /* The line is too long - skip it. :-\ */ + { + do { if ((line_len=read(pwd_fd, line_buff, PWD_BUFFER_SIZE))<=0) + return NULL; + } while (!(field_begin=strchr(line_buff, '\n'))); + lseek(pwd_fd, (long) (field_begin-line_buff)-line_len+1, SEEK_CUR); + goto restart; + } + if (*line_buff=='#' || *line_buff==' ' || *line_buff=='\n' || + *line_buff=='\t') + goto restart; + *field_begin='\0'; + + /* We've read the line; now parse it. */ + field_begin=line_buff; + for (i=0;i<7;i++) + { + switch(i) + { + case 0: passwd.pw_name=field_begin; break; + case 1: passwd.pw_passwd=field_begin; break; + case 2: uid_ptr=field_begin; break; + case 3: gid_ptr=field_begin; break; + case 4: passwd.pw_gecos=field_begin; break; + case 5: passwd.pw_dir=field_begin; break; + case 6: passwd.pw_shell=field_begin; break; + } + if (i<6) + { + field_begin=strchr(field_begin, ':'); + if (field_begin==NULL) goto restart; + *field_begin++='\0'; + } + } + passwd.pw_gid=(gid_t) strtoul(gid_ptr, &endptr, 10); + if (*endptr!='\0') goto restart; + + passwd.pw_uid=(uid_t) strtoul(uid_ptr, &endptr, 10); + if (*endptr!='\0') goto restart; + + return &passwd; +} + + diff --git a/libc/getent/config-grp.h b/libc/getent/config-grp.h new file mode 100644 index 000000000..337d54b89 --- /dev/null +++ b/libc/getent/config-grp.h @@ -0,0 +1,65 @@ +/* + * config-grp.h - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef _CONFIG_GRP_H +#define _CONFIG_GRP_H + +/* + * Define GR_SCALE_DYNAMIC if you want grp to dynamically scale its read buffer + * so that lines of any length can be used. On very very small systems, + * you may want to leave this undefined becasue it will make the grp functions + * somewhat larger (because of the inclusion of malloc and the code necessary). + * On larger systems, you will want to define this, because grp will _not_ + * deal with long lines gracefully (they will be skipped). + */ +#define GR_SCALE_DYNAMIC + +#ifndef GR_SCALE_DYNAMIC +/* + * If scaling is not dynamic, the buffers will be statically allocated, and + * maximums must be chosen. GR_MAX_LINE_LEN is the maximum number of + * characters per line in the group file. GR_MAX_MEMBERS is the maximum + * number of members of any given group. + */ +#define GR_MAX_LINE_LEN 128 +/* GR_MAX_MEMBERS = (GR_MAX_LINE_LEN-(24+3+6))/9 */ +#define GR_MAX_MEMBERS 11 + +#endif /* !GR_SCALE_DYNAMIC */ + + +/* + * Define GR_DYNAMIC_GROUP_LIST to make initgroups() dynamically allocate + * space for it's GID array before calling setgroups(). This is probably + * unnecessary scalage, so it's undefined by default. + */ +#undef GR_DYNAMIC_GROUP_LIST + +#ifndef GR_DYNAMIC_GROUP_LIST +/* + * GR_MAX_GROUPS is the size of the static array initgroups() uses for + * its static GID array if GR_DYNAMIC_GROUP_LIST isn't defined. + */ +#define GR_MAX_GROUPS 64 + +#endif /* !GR_DYNAMIC_GROUP_LIST */ + +#endif /* !_CONFIG_GRP_H */ diff --git a/libc/getent/config.h b/libc/getent/config.h new file mode 100644 index 000000000..337d54b89 --- /dev/null +++ b/libc/getent/config.h @@ -0,0 +1,65 @@ +/* + * config-grp.h - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef _CONFIG_GRP_H +#define _CONFIG_GRP_H + +/* + * Define GR_SCALE_DYNAMIC if you want grp to dynamically scale its read buffer + * so that lines of any length can be used. On very very small systems, + * you may want to leave this undefined becasue it will make the grp functions + * somewhat larger (because of the inclusion of malloc and the code necessary). + * On larger systems, you will want to define this, because grp will _not_ + * deal with long lines gracefully (they will be skipped). + */ +#define GR_SCALE_DYNAMIC + +#ifndef GR_SCALE_DYNAMIC +/* + * If scaling is not dynamic, the buffers will be statically allocated, and + * maximums must be chosen. GR_MAX_LINE_LEN is the maximum number of + * characters per line in the group file. GR_MAX_MEMBERS is the maximum + * number of members of any given group. + */ +#define GR_MAX_LINE_LEN 128 +/* GR_MAX_MEMBERS = (GR_MAX_LINE_LEN-(24+3+6))/9 */ +#define GR_MAX_MEMBERS 11 + +#endif /* !GR_SCALE_DYNAMIC */ + + +/* + * Define GR_DYNAMIC_GROUP_LIST to make initgroups() dynamically allocate + * space for it's GID array before calling setgroups(). This is probably + * unnecessary scalage, so it's undefined by default. + */ +#undef GR_DYNAMIC_GROUP_LIST + +#ifndef GR_DYNAMIC_GROUP_LIST +/* + * GR_MAX_GROUPS is the size of the static array initgroups() uses for + * its static GID array if GR_DYNAMIC_GROUP_LIST isn't defined. + */ +#define GR_MAX_GROUPS 64 + +#endif /* !GR_DYNAMIC_GROUP_LIST */ + +#endif /* !_CONFIG_GRP_H */ diff --git a/libc/getent/getgrgid.c b/libc/getent/getgrgid.c new file mode 100644 index 000000000..c1dd20e35 --- /dev/null +++ b/libc/getent/getgrgid.c @@ -0,0 +1,48 @@ +/* + * getgrgid.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +struct group * +getgrgid(const gid_t gid) +{ + struct group * group; + int grp_fd; + + if ((grp_fd=open("/etc/group", O_RDONLY))<0) + return NULL; + + while ((group=__getgrent(grp_fd))!=NULL) + if (group->gr_gid==gid) + { + close(grp_fd); + return group; + } + + close(grp_fd); + return NULL; +} + + + + diff --git a/libc/getent/getgrnam.c b/libc/getent/getgrnam.c new file mode 100644 index 000000000..e6c27fc57 --- /dev/null +++ b/libc/getent/getgrnam.c @@ -0,0 +1,51 @@ +/* + * getgrnam.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +struct group * +getgrnam(const char * name) +{ + int grp_fd; + struct group * group; + + if (name==NULL) + { + errno=EINVAL; + return NULL; + } + + if ((grp_fd=open("/etc/group", O_RDONLY))<0) + return NULL; + + while ((group=__getgrent(grp_fd))!=NULL) + if (!strcmp(group->gr_name, name)) + { + close(grp_fd); + return group; + } + + close(grp_fd); + return NULL; +} diff --git a/libc/getent/getpwnam.c b/libc/getent/getpwnam.c new file mode 100644 index 000000000..85dbc8ed8 --- /dev/null +++ b/libc/getent/getpwnam.c @@ -0,0 +1,52 @@ +/* + * getpwnam.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + + +struct passwd * +getpwnam(const char * name) +{ + int passwd_fd; + struct passwd * passwd; + + if (name==NULL) + { + errno=EINVAL; + return NULL; + } + + if ((passwd_fd=open("/etc/passwd", O_RDONLY))<0) + return NULL; + + while ((passwd=__getpwent(passwd_fd))!=NULL) + if (!strcmp(passwd->pw_name, name)) + { + close(passwd_fd); + return passwd; + } + + close(passwd_fd); + return NULL; +} diff --git a/libc/getent/getpwuid.c b/libc/getent/getpwuid.c new file mode 100644 index 000000000..ffd58c1f0 --- /dev/null +++ b/libc/getent/getpwuid.c @@ -0,0 +1,44 @@ +/* + * getpwuid.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +struct passwd * +getpwuid(uid_t uid) +{ + int passwd_fd; + struct passwd * passwd; + + if ((passwd_fd=open("/etc/passwd", O_RDONLY))<0) + return NULL; + + while ((passwd=__getpwent(passwd_fd))!=NULL) + if (passwd->pw_uid==uid) + { + close(passwd_fd); + return passwd; + } + + close (passwd_fd); + return NULL; +} diff --git a/libc/getent/pwent.c b/libc/getent/pwent.c new file mode 100644 index 000000000..738c87af0 --- /dev/null +++ b/libc/getent/pwent.c @@ -0,0 +1,64 @@ +/* + * pwent.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +/* + * setpwent(), endpwent(), and getpwent() are included in the same object + * file, since one cannot be used without the other two, so it makes sense to + * link them all in together. + */ + +/* file descriptor for the password file currently open */ +static int pw_fd = -1; + +void +setpwent(void) +{ + if (pw_fd!=-1) + close(pw_fd); + + pw_fd=open("/etc/passwd", O_RDONLY); +} + +void +endpwent(void) +{ + if (pw_fd!=-1) + close(pw_fd); + pw_fd=-1; +} + +struct passwd * +getpwent(void) +{ + if (pw_fd==-1) + setpwent(); + if (pw_fd!=-1) + return __getpwent(pw_fd); + return NULL; +} + + + diff --git a/libc/getent/utent.c b/libc/getent/utent.c new file mode 100644 index 000000000..f4c2ebc0f --- /dev/null +++ b/libc/getent/utent.c @@ -0,0 +1,150 @@ +/* utent.c */ +/* Let it be known that this is very possibly the worst standard ever. HP-UX + does one thing, someone else does another, linux another... If anyone + actually has the standard, please send it to me. + + Note that because of the way this stupid stupid standard works, you + have to call endutent() to close the file even if you've not called + setutent -- getutid and family use the same file descriptor. */ + +#include +#include +#include +#include +#include +#include + +static const char * ut_name=_PATH_UTMP; + +static int ut_fd=-1; + +struct utmp * +getutent(void) +{ + static struct utmp utmp; + if (ut_fd==-1) setutent(); + if (ut_fd==-1) return NULL; + + if (read(ut_fd, (char *) &utmp, sizeof(struct utmp))!=sizeof(struct utmp)) + return NULL; + return &utmp; +} + +void +setutent(void) +{ + int xerrno = errno; + if (ut_fd!=-1) + close(ut_fd); /* ... Should this be an Lseek ? */ + + if ((ut_fd=open(ut_name, O_RDWR))<0) + { + if (errno!=EACCES || (ut_fd=open(ut_name, O_RDONLY))<0) + { + /* No, this is a library function, it should not do this! */ + /* perror("setutent: Can't open utmp file"); */ + ut_fd=-1; + } + } + if (ut_fd!= -1) errno=xerrno; +} + +void +endutent(void) +{ + if (ut_fd!=-1) + close(ut_fd); + ut_fd=-1; +} + +struct utmp * +getutid(const struct utmp * utmp_entry) +{ + struct utmp * utmp; + + while ((utmp=getutent())!=NULL) + { + if ((utmp_entry->ut_type==RUN_LVL || + utmp_entry->ut_type==BOOT_TIME || + utmp_entry->ut_type==NEW_TIME || + utmp_entry->ut_type==OLD_TIME) && + utmp->ut_type==utmp_entry->ut_type) + return utmp; + if ((utmp_entry->ut_type==INIT_PROCESS || + utmp_entry->ut_type==DEAD_PROCESS || + utmp_entry->ut_type==LOGIN_PROCESS || + utmp_entry->ut_type==USER_PROCESS) && + !strncmp(utmp->ut_id, utmp_entry->ut_id,sizeof(utmp->ut_id))) + return utmp; + } + + return NULL; +} + +struct utmp * +getutline(const struct utmp * utmp_entry) +{ + struct utmp * utmp; + +#if 0 /* This is driving me nuts. It's not an implementation problem - + it's a matter of how things _SHOULD_ behave. Groan. */ + if (ut_fd!=-1) + lseek(ut_fd, (off_t) -sizeof(struct utmp), SEEK_CUR); +#endif + + while ((utmp=getutent())!=NULL) + { + if ((utmp->ut_type==USER_PROCESS || + utmp->ut_type==LOGIN_PROCESS) && + !strcmp(utmp->ut_line, utmp_entry->ut_line)) + return utmp; + } + + return NULL; +} + +struct utmp * +pututline(const struct utmp * utmp_entry) +{ + struct utmp * ut; + int xerrno=errno; + +#if 0 + /* Ignore the return value. That way, if they've already positioned + the file pointer where they want it, everything will work out. */ + if (ut_fd!=-1) + (void) lseek(ut_fd, (off_t) -sizeof(struct utmp), SEEK_CUR); +#endif + + if ((ut=getutid(utmp_entry))!=NULL) + lseek(ut_fd, (off_t) -sizeof(struct utmp), SEEK_CUR); + else if( ut_fd==-1 ) + return NULL; + else + lseek(ut_fd, (off_t) 0, SEEK_END); + + /* + * At this point I could make sure the offset we're at is an exact multiple + * of the sizeof struct utmp. Should I? Up or down? --RdB + */ + + if (write(ut_fd, (char *) utmp_entry, sizeof(struct utmp)) + != sizeof(struct utmp)) + return NULL; + + /* I think this final lseek gets the result Nat was after ... RdB */ + lseek(ut_fd, (off_t) -sizeof(struct utmp), SEEK_CUR); + + /* Ignoring untrapped errors */ + errno=xerrno; + return utmp_entry; +} + +void +utmpname(const char * new_ut_name) +{ + endutent(); + + if (new_ut_name!=NULL) + ut_name=new_ut_name; +} diff --git a/include/arch/farlist.h b/libc/include/asm/farlist.h similarity index 100% rename from include/arch/farlist.h rename to libc/include/asm/farlist.h diff --git a/include/arch/seglist.h b/libc/include/asm/seglist.h similarity index 100% rename from include/arch/seglist.h rename to libc/include/asm/seglist.h diff --git a/libc/include/asm/types.h b/libc/include/asm/types.h new file mode 100644 index 000000000..9a960b373 --- /dev/null +++ b/libc/include/asm/types.h @@ -0,0 +1,9 @@ +// Machine dependent types + +#pragma once + +// For GCC stddef.h + +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ unsigned int +#endif diff --git a/libc/include/assert.h b/libc/include/assert.h new file mode 100644 index 000000000..aef6cdf08 --- /dev/null +++ b/libc/include/assert.h @@ -0,0 +1,23 @@ +#ifndef __ASSERT_H +#define __ASSERT_H +#include + +/* If NDEBUG is defined, do nothing. + If not, and EXPRESSION is zero, print an error message and abort. */ + +#ifdef NDEBUG + +#define assert(expr) ((void) 0) + +#else /* Not NDEBUG. */ + +extern void __assert __P((const char *, const char *, int)); + +#define assert(expr) \ + ((void) ((expr) || \ + (__assert (__STRING(expr), \ + __FILE__, __LINE__), 0))) + +#endif /* NDEBUG. */ + +#endif /* __ASSERT_H */ diff --git a/libc/include/ctype.h b/libc/include/ctype.h new file mode 100644 index 000000000..245b1c0c5 --- /dev/null +++ b/libc/include/ctype.h @@ -0,0 +1,41 @@ +/* + * ctype.h Character classification and conversion + */ + +#ifndef __CTYPE_H +#define __CTYPE_H + +extern unsigned char __ctype[]; + +#define __CT_d 0x01 /* numeric digit */ +#define __CT_u 0x02 /* upper case */ +#define __CT_l 0x04 /* lower case */ +#define __CT_c 0x08 /* control character */ +#define __CT_s 0x10 /* whitespace */ +#define __CT_p 0x20 /* punctuation */ +#define __CT_x 0x40 /* hexadecimal */ + +/* Define these as simple old style ascii versions */ +#define toupper(c) (((c)>='a'&&(c)<='z') ? (c)^0x20 : (c)) +#define tolower(c) (((c)>='A'&&(c)<='Z') ? (c)^0x20 : (c)) +#define _toupper(c) ((c)^0x20) +#define _tolower(c) ((c)^0x20) +#define toascii(c) ((c)&0x7F) + +#define __CT(c) (__ctype[1+(unsigned char)c]) + +/* Note the '!!' is a cast to 'bool' and even BCC deletes it in an if() */ +#define isalnum(c) (!!(__CT(c)&(__CT_u|__CT_l|__CT_d))) +#define isalpha(c) (!!(__CT(c)&(__CT_u|__CT_l))) +#define isascii(c) (!((c)&~0x7F)) +#define iscntrl(c) (!!(__CT(c)&__CT_c)) +#define isdigit(c) (!!(__CT(c)&__CT_d)) +#define isgraph(c) (!(__CT(c)&(__CT_c|__CT_s))) +#define islower(c) (!!(__CT(c)&__CT_l)) +#define isprint(c) (!(__CT(c)&__CT_c)) +#define ispunct(c) (!!(__CT(c)&__CT_p)) +#define isspace(c) (!!(__CT(c)&__CT_s)) +#define isupper(c) (!!(__CT(c)&__CT_u)) +#define isxdigit(c) (!!(__CT(c)&__CT_x)) + +#endif /* __CTYPE_H */ diff --git a/libc/include/dirent.h b/libc/include/dirent.h new file mode 100644 index 000000000..c2e8f37c8 --- /dev/null +++ b/libc/include/dirent.h @@ -0,0 +1,52 @@ + +#ifndef __DIRENT_H +#define __DIRENT_H + +#include +#include + +#ifndef MAXNAMLEN +#define MAXNAMLEN 255 +#endif + +/* Directory stream type. */ +typedef struct { + int dd_fd; /* file descriptor */ + int dd_loc; /* offset in buffer */ + int dd_size; /* # of valid entries in buffer */ + struct dirent *dd_buf; /* -> directory buffer */ +} DIR; /* stream data from opendir() */ + +typedef int (*__dir_select_fn_t) __P ((__const struct dirent *)); + +typedef int (*__dir_compar_fn_t) __P (( + __const struct dirent * __const *, + __const struct dirent * __const * + )); + +struct dirent { + long d_ino; + off_t d_off; + unsigned short d_reclen; + char d_name[MAXNAMLEN+1]; +}; + +extern DIR *opendir __P ((__const char *__name)); +extern int closedir __P ((DIR * __dirp)); +extern struct dirent *readdir __P ((DIR * __dirp)); +extern void rewinddir __P ((DIR * __dirp)); + +extern void seekdir __P ((DIR * __dirp, off_t __pos)); +extern off_t telldir __P ((DIR * __dirp)); + +/* Scan the directory DIR, calling SELECT on each directory entry. + Entries for which SELECT returns nonzero are individually malloc'd, + sorted using qsort with CMP, and collected in a malloc'd array in + *NAMELIST. Returns the number of entries selected, or -1 on error. */ +extern int scandir __P ((__const char *__dir, + struct dirent ***__namelist, + __dir_select_fn_t __select, + __dir_compar_fn_t __compar)); + +#endif /* dirent.h */ + diff --git a/libc/include/errno.h b/libc/include/errno.h new file mode 100644 index 000000000..26209c39b --- /dev/null +++ b/libc/include/errno.h @@ -0,0 +1,48 @@ +#pragma once + +// From asm-generic/errno-base.h + +#define EPERM 1 // Operation not permitted +#define ENOENT 2 // No such file or directory +#define EINTR 4 // Interrupted system call +#define EIO 5 // I/O error +#define ENXIO 6 // No such device or address +#define E2BIG 7 // Argument list too long +#define ENOEXEC 8 // Exec format error +#define EAGAIN 11 // Try again +#define ENOMEM 12 // Out of memory +#define EACCES 13 // Permission denied +#define EBUSY 16 // Device or resource busy +#define EEXIST 17 // File exists +#define EXDEV 18 // Cross-device link +#define ENOTDIR 20 // Not a directory +#define EISDIR 21 // Is a directory +#define EINVAL 22 // Invalid argument +#define ENFILE 23 // File table overflow +#define EMFILE 24 // Too many open files +#define ENOTTY 25 // Not a typewriter +#define ETXTBSY 26 // Text file busy +#define ENOSPC 28 // No space left on device +#define EROFS 30 // Read-only file system +#define ERANGE 34 // Math result not representable + +/* +#define ESRCH 3 // No such process +#define EBADF 9 // Bad file number +#define ECHILD 10 // No child processes +#define EFAULT 14 // Bad address +#define ENOTBLK 15 // Block device required +#define ENODEV 19 // No such device +#define EFBIG 27 // File too large +#define ESPIPE 29 // Illegal seek +#define EMLINK 31 // Too many links +#define EPIPE 32 // Broken pipe +#define EDOM 33 // Math argument out of domain of func +*/ + +// From ??? + +#define ENOSYS 38 // Function not implemented + + +extern int errno; diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h new file mode 100644 index 000000000..2cba55018 --- /dev/null +++ b/libc/include/fcntl.h @@ -0,0 +1,20 @@ +#ifndef __FCNTL__H +#define __FCNTL__H + +#include +#include +#include __SYSINC__(fcntl.h) + +#ifndef FNDELAY +#define FNDELAY O_NDELAY +#endif + +__BEGIN_DECLS + +extern int creat __P ((__const char * __filename, mode_t __mode)); +extern int fcntl __P ((int __fildes,int __cmd, ...)); +extern int open __P ((__const char * __filename, int __flags, ...)); + +__END_DECLS + +#endif diff --git a/libc/include/features.h b/libc/include/features.h new file mode 100644 index 000000000..b8d09c983 --- /dev/null +++ b/libc/include/features.h @@ -0,0 +1,40 @@ + +#ifndef __FEATURES_H +#define __FEATURES_H + +#ifdef __STDC__ + +#define __P(x) x +#define __const const + +/* Not really ansi */ +#ifdef __BCC__ +#define const +#define volatile +#endif + +#else /* K&R */ + +#define __P(x) () +#define __const +#define const +#define volatile + +#endif + +/* Pick an OS sysinclude directory */ +/* Use with #include __SYSINC__(errno.h) */ + +#define __SYSINC__(_h_file_) + +/* No C++ */ +#define __BEGIN_DECLS +#define __END_DECLS + +/* GNUish things */ +#define __CONSTVALUE +#define __CONSTVALUE2 + +#include + +#endif diff --git a/libc/include/getopt.h b/libc/include/getopt.h new file mode 100644 index 000000000..0d71ff6bd --- /dev/null +++ b/libc/include/getopt.h @@ -0,0 +1,17 @@ +/* Copyright (C) 1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#ifndef __GETOPT_H +#define __GETOPT_H + +#include + +extern char *optarg; +extern int opterr; +extern int optind; + +extern int getopt __P((int argc, char *const *argv, const char *shortopts)); + +#endif /* __GETOPT_H */ diff --git a/libc/include/grp.h b/libc/include/grp.h new file mode 100644 index 000000000..96b2b4b65 --- /dev/null +++ b/libc/include/grp.h @@ -0,0 +1,37 @@ +#ifndef __GRP_H +#define __GRP_H + +#include +#include +#include + +/* The group structure */ +struct group +{ + char *gr_name; /* Group name. */ + char *gr_passwd; /* Password. */ + gid_t gr_gid; /* Group ID. */ + char **gr_mem; /* Member list. */ +}; + +extern void setgrent __P ((void)); +extern void endgrent __P ((void)); +extern struct group * getgrent __P ((void)); + +extern struct group * getgrgid __P ((__const gid_t gid)); +extern struct group * getgrnam __P ((__const char * name)); + +extern struct group * fgetgrent __P ((FILE * file)); + +extern int setgroups __P ((size_t n, __const gid_t * groups)); +extern int initgroups __P ((__const char * user, gid_t gid)); + + +#ifdef __LIBC__ +extern struct group * __getgrent __P ((int grp_fd)); +#endif + +#endif /* _GRP_H */ + + + diff --git a/libc/include/inttypes.h b/libc/include/inttypes.h new file mode 100644 index 000000000..44226e7b7 --- /dev/null +++ b/libc/include/inttypes.h @@ -0,0 +1,214 @@ +/* Copyright (C) 1997-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* Modified for Dev86 by Jody Bruchon + Note that Dev86 does not support 64-bit data types! */ + +/* + * ISO C99: 7.8 Format conversion of integer types + */ + +#ifndef _INTTYPES_H +#define _INTTYPES_H 1 + +#include +/* Get the type definitions. */ +#include + +/* Macros for printing format specifiers. */ + +/* Decimal notation. */ +# define PRId8 "d" +# define PRId16 "d" +# define PRId32 "d" + +# define PRIdLEAST8 "d" +# define PRIdLEAST16 "d" +# define PRIdLEAST32 "d" + +# define PRIdFAST8 "d" +# define PRIdFAST16 "d" +# define PRIdFAST32 "d" + + +# define PRIi8 "i" +# define PRIi16 "i" +# define PRIi32 "i" + +# define PRIiLEAST8 "i" +# define PRIiLEAST16 "i" +# define PRIiLEAST32 "i" + +# define PRIiFAST8 "i" +# define PRIiFAST16 "i" +# define PRIiFAST32 "i" + +/* Octal notation. */ +# define PRIo8 "o" +# define PRIo16 "o" +# define PRIo32 "o" + +# define PRIoLEAST8 "o" +# define PRIoLEAST16 "o" +# define PRIoLEAST32 "o" + +# define PRIoFAST8 "o" +# define PRIoFAST16 "o" +# define PRIoFAST32 "o" + +/* Unsigned integers. */ +# define PRIu8 "u" +# define PRIu16 "u" +# define PRIu32 "u" + +# define PRIuLEAST8 "u" +# define PRIuLEAST16 "u" +# define PRIuLEAST32 "u" + +# define PRIuFAST8 "u" +# define PRIuFAST16 "u" +# define PRIuFAST32 "u" + +/* lowercase hexadecimal notation. */ +# define PRIx8 "x" +# define PRIx16 "x" +# define PRIx32 "x" + +# define PRIxLEAST8 "x" +# define PRIxLEAST16 "x" +# define PRIxLEAST32 "x" + +# define PRIxFAST8 "x" +# define PRIxFAST16 "x" +# define PRIxFAST32 "x" + +/* UPPERCASE hexadecimal notation. */ +# define PRIX8 "X" +# define PRIX16 "X" +# define PRIX32 "X" + +# define PRIXLEAST8 "X" +# define PRIXLEAST16 "X" +# define PRIXLEAST32 "X" + +# define PRIXFAST8 "X" +# define PRIXFAST16 "X" +# define PRIXFAST32 "X" + + +/* Macros for printing `intmax_t' and `uintmax_t'. */ +# define PRIdMAX "d" +# define PRIiMAX "i" +# define PRIoMAX "o" +# define PRIuMAX "u" +# define PRIxMAX "x" +# define PRIXMAX "X" + + +/* Macros for printing `intptr_t' and `uintptr_t'. */ +# define PRIdPTR "d" +# define PRIiPTR "i" +# define PRIoPTR "o" +# define PRIuPTR "u" +# define PRIxPTR "x" +# define PRIXPTR "X" + + +/* Macros for scanning format specifiers. */ + +/* Signed decimal notation. */ +# define SCNd8 "hhd" +# define SCNd16 "hd" +# define SCNd32 "d" + +# define SCNdLEAST8 "hhd" +# define SCNdLEAST16 "hd" +# define SCNdLEAST32 "d" + +# define SCNdFAST8 "hhd" +# define SCNdFAST16 "d" +# define SCNdFAST32 "d" + +/* Signed decimal notation. */ +# define SCNi8 "hhi" +# define SCNi16 "hi" +# define SCNi32 "i" + +# define SCNiLEAST8 "hhi" +# define SCNiLEAST16 "hi" +# define SCNiLEAST32 "i" + +# define SCNiFAST8 "hhi" +# define SCNiFAST16 "i" +# define SCNiFAST32 "i" + +/* Unsigned decimal notation. */ +# define SCNu8 "hhu" +# define SCNu16 "hu" +# define SCNu32 "u" + +# define SCNuLEAST8 "hhu" +# define SCNuLEAST16 "hu" +# define SCNuLEAST32 "u" + +# define SCNuFAST8 "hhu" +# define SCNuFAST16 "u" +# define SCNuFAST32 "u" + +/* Octal notation. */ +# define SCNo8 "hho" +# define SCNo16 "ho" +# define SCNo32 "o" + +# define SCNoLEAST8 "hho" +# define SCNoLEAST16 "ho" +# define SCNoLEAST32 "o" + +# define SCNoFAST8 "hho" +# define SCNoFAST16 "o" +# define SCNoFAST32 "o" + +/* Hexadecimal notation. */ +# define SCNx8 "hhx" +# define SCNx16 "hx" +# define SCNx32 "x" + +# define SCNxLEAST8 "hhx" +# define SCNxLEAST16 "hx" +# define SCNxLEAST32 "x" + +# define SCNxFAST8 "hhx" +# define SCNxFAST16 "x" +# define SCNxFAST32 "x" + + +/* Macros for scanning `intmax_t' and `uintmax_t'. */ +# define SCNdMAX "d" +# define SCNiMAX "i" +# define SCNoMAX "o" +# define SCNuMAX "u" +# define SCNxMAX "x" + +/* Macros for scaning `intptr_t' and `uintptr_t'. */ +# define SCNdPTR "d" +# define SCNiPTR "i" +# define SCNoPTR "o" +# define SCNuPTR "u" +# define SCNxPTR "x" + + +#endif /* inttypes.h */ diff --git a/libc/include/malloc.h b/libc/include/malloc.h new file mode 100644 index 000000000..e8fdb0a24 --- /dev/null +++ b/libc/include/malloc.h @@ -0,0 +1,30 @@ + +#ifndef __MALLOC_H +#define __MALLOC_H +#include +#include + +/* + * Mini malloc allows you to use a less efficient but smaller malloc the + * cost is about 100 bytes of code in free but malloc (700bytes) doesn't + * have to be linked. Unfortunatly memory can only be reused if everything + * above it has been freed + * + */ + +extern void free __P((void *)); +extern void *malloc __P((size_t)); +extern void *realloc __P((void *, size_t)); +extern void *alloca __P((size_t)); + +extern void *(*__alloca_alloc) __P((size_t)); + +#ifdef __LIBC__ +#define __MINI_MALLOC__ +#endif + +#ifdef __MINI_MALLOC__ +#define malloc(x) ((*__alloca_alloc)(x)) +#endif + +#endif diff --git a/libc/include/memory.h b/libc/include/memory.h new file mode 100644 index 000000000..3b2f59002 --- /dev/null +++ b/libc/include/memory.h @@ -0,0 +1 @@ +#include diff --git a/libc/include/paths.h b/libc/include/paths.h new file mode 100644 index 000000000..dc7693933 --- /dev/null +++ b/libc/include/paths.h @@ -0,0 +1,21 @@ +/* paths.h */ + +#ifndef ___PATHS_H +#define ___PATHS_H + + +#define _PATH_CONSOLE "/dev/console" +#define _PATH_TTY "/dev/tty" +#define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_LOGIN "/bin/login" +#define _PATH_BSHELL "/bin/sh" +#define _PATH_UTMP "/var/run/utmp" +#define _PATH_WTMP "/var/log/wtmp" +#define _PATH_DEFPATH "/bin:/usr/bin:/usr/local/bin:." +#define _PATH_DEV "/dev/" +#define _PATH_DEVNULL "/dev/null" +#define _PATH_TMP "/tmp/" +#define _PATH_LASTLOG "/var/log/lastlog" +#define _PATH_LOCALE "/usr/lib/locale" + +#endif /* __PATHS_H */ diff --git a/libc/include/pwd.h b/libc/include/pwd.h new file mode 100644 index 000000000..1b48c6a6e --- /dev/null +++ b/libc/include/pwd.h @@ -0,0 +1,40 @@ +#ifndef __PWD_H +#define __PWD_H + +#include +#include +#include + +/* The passwd structure. */ +struct passwd +{ + char *pw_name; /* Username. */ + char *pw_passwd; /* Password. */ + uid_t pw_uid; /* User ID. */ + gid_t pw_gid; /* Group ID. */ + char *pw_gecos; /* Real name. */ + char *pw_dir; /* Home directory. */ + char *pw_shell; /* Shell program. */ +}; + + +extern void setpwent __P ((void)); +extern void endpwent __P ((void)); +extern struct passwd * getpwent __P ((void)); + +extern int putpwent __P ((__const struct passwd * __p, FILE * __f)); +extern int getpw __P ((uid_t uid, char *buf)); + +extern struct passwd * fgetpwent __P ((FILE * file)); + +extern struct passwd * getpwuid __P ((__const uid_t)); +extern struct passwd * getpwnam __P ((__const char *)); + +#ifdef __LIBC__ +extern struct passwd * __getpwent __P ((__const int passwd_fd)); +#endif + +#endif /* pwd.h */ + + + diff --git a/libc/include/regex.h b/libc/include/regex.h new file mode 100644 index 000000000..73d6bf412 --- /dev/null +++ b/libc/include/regex.h @@ -0,0 +1,21 @@ +/* + * Definitions etc. for regexp(3) routines. + * + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], + * not the System V one. + */ +#define NSUBEXP 10 +typedef struct regexp { + char *startp[NSUBEXP]; + char *endp[NSUBEXP]; + char regstart; /* Internal use only. */ + char reganch; /* Internal use only. */ + char *regmust; /* Internal use only. */ + int regmlen; /* Internal use only. */ + char program[1]; /* Unwarranted chumminess with compiler. */ +} regexp; + +extern regexp *regcomp(); +extern int regexec(); +extern void regsub(); +extern void regerror(); diff --git a/libc/include/setjmp.h b/libc/include/setjmp.h new file mode 100644 index 000000000..3b5307847 --- /dev/null +++ b/libc/include/setjmp.h @@ -0,0 +1,31 @@ + +#ifndef __SETJMP_H +#define __SETJMP_H + +#include + +/* + * I know most systems use an array of ints here, but I prefer this - RDB + */ + +typedef struct +{ + unsigned int pc; + unsigned int sp; + unsigned int bp; + unsigned int si; + unsigned int di; + unsigned int es; +} jmp_buf[1]; + +int _setjmp __P((jmp_buf env)); +void _longjmp __P((jmp_buf env, int rv)); + +/* LATER: Seems GNU beat me to it, must be OK then :-) + * Humm, what's this about setjmp being a macro !? + * Ok, use the BSD names as normal use the ANSI as macros + */ + +#define setjmp(a_env) _setjmp(a_env) +#define longjmp(a_env, a_rv) _longjmp(a_env, a_rv) +#endif diff --git a/libc/include/signal.h b/libc/include/signal.h new file mode 100644 index 000000000..86e8614ab --- /dev/null +++ b/libc/include/signal.h @@ -0,0 +1,92 @@ + +#ifndef __SIGNAL_H +#define __SIGNAL_H + +#include +#include + +typedef unsigned long sigset_t; /* at least 32 bits */ + +#define _NSIG 32 +#define NSIG _NSIG + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGUNUSED 31 + +/* + * sa_flags values: SA_STACK is not currently supported, but will allow the + * usage of signal stacks by using the (now obsolete) sa_restorer field in + * the sigaction structure as a stack pointer. This is now possible due to + * the changes in signal handling. LBT 010493. + * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the + * SA_RESTART flag to get restarting signals (which were the default long ago) + */ +#define SA_NOCLDSTOP 1 +#define SA_STACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_INTERRUPT 0x20000000 +#define SA_NOMASK 0x40000000 +#define SA_ONESHOT 0x80000000 + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +/* Type of a signal handler. */ +typedef void (*__sighandler_t)(int); + +#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ +#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ + +struct sigaction { + __sighandler_t sa_handler; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)( /*void*/ ); +}; + +/* BSDisms */ +#ifdef BSD +extern __const char * __const sys_siglist[]; +#define sig_t __sighandler_t +#endif + +__sighandler_t signal(int number, __sighandler_t pointer); +int kill (pid_t pid, int sig); + +#endif diff --git a/libc/include/stdio.h b/libc/include/stdio.h new file mode 100644 index 000000000..39d2e6b40 --- /dev/null +++ b/libc/include/stdio.h @@ -0,0 +1,139 @@ + +#ifndef __STDIO_H +#define __STDIO_H + +#include +#include + +#ifndef SEEK_SET +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#define _IOFBF 0x00 /* full buffering */ +#define _IOLBF 0x01 /* line buffering */ +#define _IONBF 0x02 /* no buffering */ +#define __MODE_BUF 0x03 /* Modal buffering dependent on isatty */ + +#define __MODE_FREEBUF 0x04 /* Buffer allocated with malloc, can free */ +#define __MODE_FREEFIL 0x08 /* FILE allocated with malloc, can free */ + +#define __MODE_READ 0x10 /* Opened in read only */ +#define __MODE_WRITE 0x20 /* Opened in write only */ +#define __MODE_RDWR 0x30 /* Opened in read/write */ + +#define __MODE_READING 0x40 /* Buffer has pending read data */ +#define __MODE_WRITING 0x80 /* Buffer has pending write data */ + +#define __MODE_EOF 0x100 /* EOF status */ +#define __MODE_ERR 0x200 /* Error status */ +#define __MODE_UNGOT 0x400 /* Buffer has been polluted by ungetc */ + +#ifdef __MSDOS__ +#define __MODE_IOTRAN 0x1000 /* MSDOS nl <-> cr,nl translation */ +#else +#define __MODE_IOTRAN 0 +#endif + +/* when you add or change fields here, be sure to change the initialization + * in stdio_init and fopen */ +struct __stdio_file { + unsigned char *bufpos; /* the next byte to write to or read from */ + unsigned char *bufread; /* the end of data returned by last read() */ + unsigned char *bufwrite; /* highest address writable by macro */ + unsigned char *bufstart; /* the start of the buffer */ + unsigned char *bufend; /* the end of the buffer; ie the byte after the last + malloc()ed byte */ + + int fd; /* the file descriptor associated with the stream */ + int mode; + + char unbuf[8]; /* The buffer for 'unbuffered' streams */ + + struct __stdio_file * next; +}; + +#define EOF (-1) +#ifndef NULL +#define NULL ((void*)0) +#endif + +typedef struct __stdio_file FILE; + +#ifdef __AS386_16__ +#define BUFSIZ (256) +#else +#define BUFSIZ (2048) +#endif + +extern FILE stdin[1]; +extern FILE stdout[1]; +extern FILE stderr[1]; + +#ifdef __MSDOS__ +#define putc(c, fp) fputc(c, fp) +#define getc(fp) fgetc(fp) +#else +#define putc(c, stream) \ + (((stream)->bufpos >= (stream)->bufwrite) ? fputc((c), (stream)) \ + : (unsigned char) (*(stream)->bufpos++ = (c)) ) + +#define getc(stream) \ + (((stream)->bufpos >= (stream)->bufread) ? fgetc(stream): \ + (*(stream)->bufpos++)) +#endif + +#define putchar(c) putc((c), stdout) +#define getchar() getc(stdin) + +#define ferror(fp) (((fp)->mode&__MODE_ERR) != 0) +#define feof(fp) (((fp)->mode&__MODE_EOF) != 0) +#define clearerr(fp) ((fp)->mode &= ~(__MODE_EOF|__MODE_ERR),0) +#define fileno(fp) ((fp)->fd) + +/* declare functions; not like it makes much difference without ANSI */ +/* RDB: The return values _are_ important, especially if we ever use + 8086 'large' model + */ + +/* These two call malloc */ +#define setlinebuf(__fp) setvbuf((__fp), (char*)0, _IOLBF, 0) +extern int setvbuf __P((FILE*, char*, int, size_t)); + +/* These don't */ +#define setbuf(__fp, __buf) setbuffer((__fp), (__buf), BUFSIZ) +extern void setbuffer __P((FILE*, char*, int)); + +extern int fgetc __P((FILE*)); +extern int fputc __P((int, FILE*)); + +extern int fclose __P((FILE*)); +extern int fflush __P((FILE*)); +extern char *fgets __P((char*, size_t, FILE*)); + +extern FILE *fopen __P((char*, char*)); +extern FILE *fdopen __P((int, char*)); +extern FILE *freopen __P((char*, char*, FILE*)); + +#ifdef __LIBC__ +extern FILE *__fopen __P((char*, int, FILE*, char*)); +#endif + +extern int fputs __P((char*, FILE*)); +extern int puts __P((char*)); + +extern int printf __P ((__const char*, ...)); +extern int fprintf __P ((FILE*, __const char*, ...)); +extern int sprintf __P ((char*, __const char*, ...)); + +#define stdio_pending(fp) ((fp)->bufread>(fp)->bufpos) + +void perror (const char * s); + +int scanf (const char * format, ...); +int sscanf (const char * str, const char * format, ...); + +int ungetc (int c, FILE *stream); + +#endif /* __STDIO_H */ diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h new file mode 100644 index 000000000..282d57c67 --- /dev/null +++ b/libc/include/stdlib.h @@ -0,0 +1,58 @@ +/* stdlib.h */ +#include +#include + +#ifndef __STDLIB_H +#define __STDLIB_H + +/* Don't overwrite user definitions of NULL */ +#ifndef NULL +#define NULL ((void *) 0) +#endif + +/* For program termination */ +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +#include + +extern int rand __P ((void)); +extern void srand __P ((unsigned int seed)); + +extern long strtol __P ((const char * nptr, char ** endptr, int base)); +extern unsigned long strtoul __P ((const char * nptr, + char ** endptr, int base)); +#ifndef __HAS_NO_FLOATS__ +extern double strtod __P ((const char * nptr, char ** endptr)); +extern double atof __P ((__const char *__nptr)); +#endif + +extern long int atol __P ((__const char *__nptr)); +extern int atoi __P ((__const char *__nptr)); + +/* Returned by `div'. */ +typedef struct + { + int quot; /* Quotient. */ + int rem; /* Remainder. */ + } div_t; + +/* Returned by `ldiv'. */ +typedef struct + { + long int quot; /* Quotient. */ + long int rem; /* Remainder. */ + } ldiv_t; + + +extern char *getenv __P ((__const char *__name)); +extern char *mktemp __P ((char *__template)); + +void abort (void); +int atexit (void (* function) ()); +void exit (int status); + +void * malloc (size_t size); +void free (void * ptr); + +#endif /* __STDLIB_H */ diff --git a/libc/include/string.h b/libc/include/string.h new file mode 100644 index 000000000..e239e4d81 --- /dev/null +++ b/libc/include/string.h @@ -0,0 +1,68 @@ + +#ifndef __STRING_H +#define __STRING_H + +#pragma once + +#include +#include + +/* Basic string functions */ + +extern char * strcpy __P ((char*, __const char*)); +extern int strcmp __P ((__const char*, __const char*)); + +extern char * strncat __P ((char*, char*, size_t)); +extern char * strncpy __P ((char*, char*, size_t)); + +char * strchr (const char * s, int c); +char * strrchr (const char * s, int c); + +extern char * strdup __P ((char*)); + +/* Basic mem functions */ +extern void * memccpy __P ((void*, void*, int, size_t)); +extern void * memchr __P ((__const void*, __const int, size_t)); +extern void * memset __P ((void*, int, size_t)); +extern int memcmp __P ((__const void*, __const void*, size_t)); + +extern void * memmove __P ((void*, void*, size_t)); + +/* Minimal (very!) locale support */ +#define strcoll strcmp +#define strxfrm strncpy + +/* BSDisms */ +#define index strchr +#define rindex strrchr + +/* Other common BSD functions */ +extern int strcasecmp __P ((char*, char*)); +extern int strncasecmp __P ((char*, char*, size_t)); +char *strpbrk __P ((char *, char *)); +char *strsep __P ((char **, char *)); + +char * strstr (const char *, const char *); + +size_t strcspn __P ((char *, char *)); +size_t strspn __P ((char *, char *)); + +/* Linux silly hour */ +char *strfry __P ((char *)); + +void bzero (void * s, size_t n); + +// TODO: this is removed in POSIX-1.2008 +// TODO: replace by memcpy or memmove +#define bcopy(s, d, n) memcpy ((d), (s), (n)) + +void * memcpy (void * dest, const void * src, size_t n); + +char *strcat (char * dest, const char * src); +size_t strlen (const char * s); +int strncmp (const char * s1, const char * s2, size_t n); +char *strtok (char * str, const char * delim); + +int sprintf (char * str, const char * format, ...); + +#endif diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h new file mode 100644 index 000000000..bf41935c8 --- /dev/null +++ b/libc/include/sys/cdefs.h @@ -0,0 +1,38 @@ + +#ifndef __SYS_CDEFS_H +#define __SYS_CDEFS_H +#include + +#if __STDC__ + +#define __CONCAT(x,y) x ## y +#define __STRING(x) #x + +/* This is not a typedef so `const __ptr_t' does the right thing. */ +#define __ptr_t void * +#ifndef __HAS_NO_FLOATS__ +typedef long double __long_double_t; +#endif + +#else + +#define __CONCAT(x,y) x/**/y +#define __STRING(x) "x" + +#define __ptr_t char * + +#ifndef __HAS_NO_FLOATS__ +typedef double __long_double_t; +#endif + +#endif + +/* No C++ */ +#define __BEGIN_DECLS +#define __END_DECLS + +/* GNUish things */ +#define __CONSTVALUE +#define __CONSTVALUE2 + +#endif diff --git a/libc/include/sys/ioctl.h b/libc/include/sys/ioctl.h new file mode 100644 index 000000000..198d57840 --- /dev/null +++ b/libc/include/sys/ioctl.h @@ -0,0 +1,9 @@ + +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H +#include +#include __SYSINC__(ioctl.h) + +extern int ioctl __P((int __fildes, int __cmd, ...)); + +#endif diff --git a/libc/include/sys/select.h b/libc/include/sys/select.h new file mode 100644 index 000000000..1f83a8929 --- /dev/null +++ b/libc/include/sys/select.h @@ -0,0 +1,5 @@ +#pragma once + +int select (int nfds, fd_set * restrict readfds, + fd_set * restrict writefds, fd_set * restrict errorfds, + struct timeval * restrict timeout); diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h new file mode 100644 index 000000000..3bfdc213c --- /dev/null +++ b/libc/include/sys/socket.h @@ -0,0 +1,15 @@ + +#ifndef __SYS_SOCKET_H +#define __SYS_SOCKET_H +#include +#include __SYSINC__(socket.h) + +typedef unsigned int socklen_t; + +int accept (int socket, struct sockaddr * restrict address, socklen_t * restrict address_len); +int bind (int socket, const struct sockaddr * address, socklen_t address_len); +int connect (int socket, const struct sockaddr * address, socklen_t address_len); +int listen (int socket, int backlog); +int socket (int domain, int type, int protocol); + +#endif diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h new file mode 100644 index 000000000..0f8d2a33d --- /dev/null +++ b/libc/include/sys/stat.h @@ -0,0 +1,18 @@ +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +#include +#include +#include __SYSINC__(stat.h) + +int lstat __P((__const char * __path, struct stat * __statbuf)); +int fstat __P((int __fd, struct stat * __statbuf)); + +/* hysterical raisins */ +#define S_IREAD S_IRUSR /* read permission, owner */ +#define S_IWRITE S_IWUSR /* write permission, owner */ +#define S_IEXEC S_IXUSR /* execute/search permission, owner */ + +int stat (const char * restrict path, struct stat * restrict buf); + +#endif diff --git a/libc/include/sys/time.h b/libc/include/sys/time.h new file mode 100644 index 000000000..2074b06da --- /dev/null +++ b/libc/include/sys/time.h @@ -0,0 +1,3 @@ +#include + +int gettimeofday (struct timeval * restrict tp, void * restrict tzp); diff --git a/libc/include/sys/times.h b/libc/include/sys/times.h new file mode 100644 index 000000000..760247864 --- /dev/null +++ b/libc/include/sys/times.h @@ -0,0 +1,21 @@ +#ifndef _SYS_TIMES_H +#define _SYS_TIMES_H + +#include +#include +#include + +struct tms { + clock_t tms_utime; + clock_t tms_stime; + clock_t tms_cutime; + clock_t tms_cstime; +}; + +__BEGIN_DECLS + +clock_t times (struct tms * buffer); + +__END_DECLS + +#endif diff --git a/libc/include/sys/types.h b/libc/include/sys/types.h new file mode 100644 index 000000000..273b56bb7 --- /dev/null +++ b/libc/include/sys/types.h @@ -0,0 +1,3 @@ +#include +#include +#include __SYSINC__(types.h) diff --git a/libc/include/sys/wait.h b/libc/include/sys/wait.h new file mode 100644 index 000000000..09583b78c --- /dev/null +++ b/libc/include/sys/wait.h @@ -0,0 +1,77 @@ + +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include + +/* Bits in the third argument to `waitpid'. */ +#define WNOHANG 1 /* Don't block waiting. */ +#define WUNTRACED 2 /* Report status of stopped children. */ + +/* Everything extant so far uses these same bits. */ +/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */ +#define WEXITSTATUS(status) (((status) & 0xff00) >> 8) + +/* If WIFSIGNALED(STATUS), the terminating signal. */ +#define WTERMSIG(status) ((status) & 0x7f) + +/* If WIFSTOPPED(STATUS), the signal that stopped the child. */ +#define WSTOPSIG(status) WEXITSTATUS(status) + +/* Nonzero if STATUS indicates normal termination. */ +#define WIFEXITED(status) (((status) & 0xff) == 0) + +/* Nonzero if STATUS indicates termination by a signal. */ +#define WIFSIGNALED(status) (((unsigned int)((status)-1) & 0xFFFF) < 0xFF) + +/* Nonzero if STATUS indicates the child is stopped. */ +#define WIFSTOPPED(status) (((status) & 0xff) == 0x7f) + +/* Nonzero if STATUS indicates the child dumped core. */ +#define WCOREDUMP(status) ((status) & 0200) + +/* Macros for constructing status values. */ +#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) +#define W_STOPCODE(sig) ((sig) << 8 | 0x7f) + +/* Wait for a child to die. When one does, put its status in *STAT_LOC + and return its process ID. For errors, return (pid_t) -1. */ +extern pid_t wait (int * stat_loc); + +/* Special values for the PID argument to `waitpid' and `wait4'. */ +#define WAIT_ANY (-1) /* Any process. */ +#define WAIT_MYPGRP 0 /* Any process in my process group. */ + +/* Wait for a child matching PID to die. + If PID is greater than 0, match any process whose process ID is PID. + If PID is (pid_t) -1, match any process. + If PID is (pid_t) 0, match any process with the + same process group as the current process. + If PID is less than -1, match any process whose + process group is the absolute value of PID. + If the WNOHANG bit is set in OPTIONS, and that child + is not already dead, return (pid_t) 0. If successful, + return PID and store the dead child's status in STAT_LOC. + Return (pid_t) -1 for errors. If the WUNTRACED bit is + set in OPTIONS, return status for stopped children; otherwise don't. */ + +extern pid_t waitpid __P ((pid_t __pid, int *__stat_loc, + int __options)); + +/* This being here makes the prototypes valid whether or not + we have already included to define `struct rusage'. */ +struct rusage; + +/* Wait for a child to exit. When one does, put its status in *STAT_LOC and + return its process ID. For errors return (pid_t) -1. If USAGE is not + nil, store information about the child's resource usage there. If the + WUNTRACED bit is set in OPTIONS, return status for stopped children; + otherwise don't. */ +extern pid_t wait3 __P ((int * __stat_loc, + int __options, struct rusage * __usage)); + +/* PID is like waitpid. Other args are like wait3. */ +extern pid_t wait4 __P ((pid_t __pid, int * __stat_loc, + int __options, struct rusage *__usage)); + +#endif /* sys/wait.h */ diff --git a/libc/include/termcap.h b/libc/include/termcap.h new file mode 100644 index 000000000..a7ae37b72 --- /dev/null +++ b/libc/include/termcap.h @@ -0,0 +1,21 @@ + +#ifndef _TERMCAP_H +#define _TERMCAP_H + +#include +#include + +extern char PC; +extern char *UP; +extern char *BC; +extern int ospeed; + +extern int tgetent __P((char *, const char *)); +extern int tgetflag __P((const char *)); +extern int tgetnum __P((const char *)); +extern char *tgetstr __P((const char *, char **)); + +extern int tputs __P((const char *, int, int (*)(int))); +extern char *tgoto __P((const char *, int, int)); + +#endif /* _TERMCAP_H */ diff --git a/libc/include/termios.h b/libc/include/termios.h new file mode 100644 index 000000000..9fb251a15 --- /dev/null +++ b/libc/include/termios.h @@ -0,0 +1,25 @@ +#ifndef __TERMIOS_H +#define __TERMIOS_H + +#include +#include +#include __SYSINC__(termios.h) + +extern speed_t cfgetispeed __P ((struct termios *__termios_p)); +extern speed_t cfgetospeed __P ((struct termios *__termios_p)); +extern int cfsetispeed __P ((struct termios *__termios_p, speed_t __speed)); +extern int cfsetospeed __P ((struct termios *__termios_p, speed_t __speed)); + +extern void cfmakeraw __P ((struct termios *__t)); + +int tcgetattr (int fd, struct termios * termios_p); +int tcsetattr (int fd, int optional_actions, const struct termios * termios_p); + +extern int tcdrain __P ((int __fildes)); +extern int tcflow __P ((int __fildes, int __action)); +extern int tcflush __P ((int __fildes, int __queue_selector)); +extern int tcsendbreak __P ((int __fildes, int __duration)); +extern pid_t tcgetpgrp __P ((int __fildes)); +extern int tcsetpgrp __P ((int __fildes, pid_t __pgrp_id)); + +#endif diff --git a/libc/include/time.h b/libc/include/time.h new file mode 100644 index 000000000..30ae4bc33 --- /dev/null +++ b/libc/include/time.h @@ -0,0 +1,68 @@ +#ifndef __TIME_H +#define __TIME_H + +#include +#include +#include + +#ifndef _CLOCK_T +#define _CLOCK_T +typedef long clock_t; +#endif + +#define CLOCKS_PER_SEC 100 +#define CLK_TCK 100 /* That must be the same as HZ ???? */ + +struct timeval { + long tv_sec; + long tv_usec; +}; + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +#define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +extern char *tzname[2]; +extern int daylight; +extern long int timezone; + +__BEGIN_DECLS + +extern int stime __P ((time_t* __tptr)); + +extern clock_t clock __P ((void)); +extern time_t time __P ((time_t * __tp)); +#ifndef __HAS_NO_FLOATS__ +extern __CONSTVALUE double difftime __P ((time_t __time2, + time_t __time1)) __CONSTVALUE2; +#endif +extern time_t mktime __P ((struct tm * __tp)); + +extern char * asctime __P ((__const struct tm * __tp)); +extern char * ctime __P ((__const time_t * __tp)); +extern size_t strftime __P ((char * __s, size_t __smax, + __const char * __fmt, __const struct tm * __tp)); +extern void tzset __P ((void)); + +extern struct tm* gmtime __P ((__const time_t *__tp)); +extern struct tm* localtime __P ((__const time_t * __tp)); + +__END_DECLS + +#endif diff --git a/include/types.h b/libc/include/types.h similarity index 62% rename from include/types.h rename to libc/include/types.h index 77dfee996..10e992d95 100644 --- a/include/types.h +++ b/libc/include/types.h @@ -3,8 +3,14 @@ #ifndef _TYPES_H #define _TYPES_H +#pragma once + +// Machine dependent types + +#include + /* Portable types */ -/* More concise than C99 standard ones */ +/* Shorter than the C99 standard ones */ typedef unsigned char u8_t; /* 8 bits */ typedef unsigned short u16_t; /* 16 bits */ @@ -14,4 +20,11 @@ typedef unsigned int u32_t; /* 32 bits */ typedef u8_t byte_t; +/* LIBC types */ + +typedef u16_t pid_t; + +typedef u16_t uid_t; +typedef u16_t gid_t; + #endif /* !_TYPES_H */ diff --git a/libc/include/unistd.h b/libc/include/unistd.h new file mode 100644 index 000000000..c4988043d --- /dev/null +++ b/libc/include/unistd.h @@ -0,0 +1,53 @@ + +#pragma once + +#include +#include + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +extern size_t read __P ((int __fd, char * __buf, size_t __nbytes)); +extern size_t write __P ((int __fd, __const char * __buf, size_t __n)); +extern int pipe __P ((int __pipedes[2])); +extern unsigned int alarm __P ((unsigned int __seconds)); +extern unsigned int sleep __P ((unsigned int __seconds)); +extern int pause __P ((void)); +extern char* crypt __P((__const char *__key, __const char *__salt)); + +#ifndef SEEK_SET +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#ifndef R_OK +#define R_OK 4 /* Test for read permission. */ +#define W_OK 2 /* Test for write permission. */ +#define X_OK 1 /* Test for execute permission. */ +#define F_OK 0 /* Test for existence. */ +#endif + +#define _POSIX_VDISABLE '\0' + +// Types + +typedef int intptr_t; + +// Functions + +int brk (void * addr); +void *sbrk (intptr_t increment); + +int close (int fildes); +int dup2 (int oldfd, int newfd); +int isatty (int fd); +off_t lseek (int fildes, off_t offset, int whence); + +pid_t fork (); +pid_t getpid (); +pid_t setsid (); + +uid_t getuid (void); + diff --git a/libc/include/utime.h b/libc/include/utime.h new file mode 100644 index 000000000..7f82b9fa6 --- /dev/null +++ b/libc/include/utime.h @@ -0,0 +1,15 @@ +#ifndef __UTIME_H +#define __UTIME_H + +#include +#include + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +extern int utime __P ((char *__filename, struct utimbuf *__utimebuf)); + +#endif + diff --git a/libc/include/utmp.h b/libc/include/utmp.h new file mode 100644 index 000000000..baf6f9e57 --- /dev/null +++ b/libc/include/utmp.h @@ -0,0 +1,52 @@ +/* utmp.h */ + +#ifndef __UTMP_H +#define __UTMP_H + +#include +#include +#include +#include + +#define UT_UNKNOWN 0 +#define UT_LINESIZE 12 +#define UT_NAMESIZE 8 +#define UT_HOSTSIZE 16 + +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 + +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +struct utmp +{ + short ut_type; /* type of login */ + pid_t ut_pid; /* pid of login-process */ + char ut_line[UT_LINESIZE]; /* devicename of tty -"/dev/", null-term */ + char ut_id[2]; /* abbrev. ttyname, as 01, s1 etc. */ + time_t ut_time; /* login time */ + char ut_user[UT_NAMESIZE]; /* username, not null-term */ + char ut_host[UT_HOSTSIZE]; /* hostname for remote login... */ + long ut_addr; /* IP addr of remote host */ + +}; + +extern void setutent __P ((void)); +extern void utmpname __P ((__const char *)); +extern struct utmp * getutent __P ((void)); +extern struct utmp * getutid __P ((__const struct utmp *)); +extern struct utmp * getutline __P ((__const struct utmp *)); +extern struct utmp * pututline __P ((__const struct utmp *)); +extern void endutent __P ((void)); + +#ifdef __LIBC__ +struct utmp * __getutent __P ((int)); +#endif + +#endif /* __UTMP_H */ + diff --git a/libc/malloc/Makefile b/libc/malloc/Makefile new file mode 100644 index 000000000..73891e709 --- /dev/null +++ b/libc/malloc/Makefile @@ -0,0 +1,22 @@ +# Makefile of /libc/malloc module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS = \ + heap.c \ + malloc.c \ + # end of list + +OBJS = $(SRCS:.c=.o) + +.PHONY: all + +all: $(LIBC) + +$(OBJS): $(SRCS) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +clean: + rm -f *.o diff --git a/libc/malloc/heap.c b/libc/malloc/heap.c new file mode 100644 index 000000000..4c5a355fd --- /dev/null +++ b/libc/malloc/heap.c @@ -0,0 +1,161 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include +#include + +/****************************************************************************/ + +#ifdef L_errno +int errno = 0; /* libc error value */ +#endif + +/****************************************************************************/ + +#ifdef __AS386_16__ + +#ifdef L___brk_addr +#asm +.data +export brk_addr +brk_addr: .word __end ! This holds the current return for sbrk(0) +.text +#endasm +#endif + +/****************************************************************************/ + +#ifdef L_sbrk +int sbrk(brk_off) +int brk_off; +{ +#asm + mov bx,sp +#if !__FIRST_ARG_IN_AX__ + mov ax,[bx+2] ! Fetch the requested value +#endif + test ax,ax + jnz has_change + mov ax,[brk_addr] ! Simple one, read current - can`t fail. + jmp eof + +has_change: + js go_down + add ax,[brk_addr] ! Goin up! + jc Enomem + sub bx,#511 ! Safety space 512 bytes + cmp bx,ax ! Too close ? + jb Enomem + +sbrk_ok: +#if !defined(__MSDOS__) && !defined(__STANDALONE__) + push ax ! MSDOS `kernel` doesn`t care + call ___brk ! Tell the kernel + test ax,ax + pop ax ! ASSUME ___brk doesn`t alter stack! + jnz Enomem ! Ugh! kernel didn`t like the idea! +#endif + xchg [brk_addr],ax ! Save away new val + jmp eof ! Return it +go_down: + add ax,[brk_addr] + jnc Enomem + cmp ax,#__end + jae sbrk_ok + +Enomem: + mov ax,#12 ! This should be ENOMEM not a magic. + mov [_errno],ax + mov ax,#-1 +eof: +#endasm +} +#endif + +/****************************************************************************/ + +#ifdef L_brk +int +brk(new_brk) +char * new_brk; +{ +#asm + mov bx,sp +#if !__FIRST_ARG_IN_AX__ + mov ax,[bx+2] ! Fetch the requested value +#endif + sub bx,#512 ! Safety space 512 bytes + cmp bx,ax ! Too close ? + jb Enomem + cmp ax,#__end + jae brk_ok +Enomem: + mov ax,#12 ! This should be ENOMEM not a magic. + mov [_errno],ax + mov ax,#-1 + ret +brk_ok: +#if !defined(__MSDOS__) && !defined(__STANDALONE__) + push ax + call ___brk ! Tell the kernel + test ax,ax + pop bx ! ASSUME ___brk doesn`t alter stack! + jnz Enomem ! Ugh! kernel didn`t like the idea! + mov [brk_addr],bx ! Save away new val +#else + mov [brk_addr],ax ! MSDOS `kernel` doesn`t care + mov ax,#0 +#endif +#endasm +} +#endif + +#endif + +//----------------------------------------------------------------------------- + +char * __brk_addr = 0; /* This holds the current return for sbrk(0) */ + +__brk_addr_init() +{ + if( __brk_addr == 0 && (__brk_addr = _brk(0)) == 0 ) + { + errno = ENOMEM; + return -1; + } + return 0; +} + +//----------------------------------------------------------------------------- + +void * sbrk (intptr_t increment) +{ + char * new_brk; + if( __brk_addr_init() ) return (char*)-1; + if( increment == 0 ) return __brk_addr; + + new_brk = __brk_addr + increment; + __brk_addr = _brk(new_brk); + if( __brk_addr != new_brk ) + { + errno = ENOMEM; + return (char*)-1; + } + return __brk_addr - increment; +} + +//----------------------------------------------------------------------------- + +int brk (void * addr) +{ + if( __brk_addr_init() ) return -1; + + __brk_addr = _brk(addr); + if( __brk_addr == addr ) return 0; + errno = ENOMEM; + return -1; +} + +//----------------------------------------------------------------------------- diff --git a/libc/malloc/malloc.c b/libc/malloc/malloc.c new file mode 100644 index 000000000..4c2e9be6e --- /dev/null +++ b/libc/malloc/malloc.c @@ -0,0 +1,549 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* + * This is a combined alloca/malloc package. It uses a classic algorithm + * and so may be seen to be quite slow compared to more modern routines + * with 'nasty' distributions. + */ + +#include +#include +#include +#include + +#define MCHUNK 2048 /* Allocation unit in 'mem' elements */ +#define XLAZY_FREE /* If set frees can be infinitly defered */ +#define XMINALLOC 32 /* Smallest chunk to alloc in 'mem's */ +#define XVERBOSE /* Lots of noise, debuging ? */ + +#undef malloc +#define MAX_INT ((int)(((unsigned)-1)>>1)) + +#ifdef VERBOSE +#define noise __noise +#else +#define noise(y,x) +#endif + +typedef union mem_cell +{ + union mem_cell *next; /* A pointer to the next mem */ + unsigned int size; /* An int >= sizeof pointer */ + char *depth; /* For the alloca hack */ +} +mem; + +#define m_size(p) ((p) [0].size) /* For malloc */ +#define m_next(p) ((p) [1].next) /* For malloc and alloca */ +#define m_deep(p) ((p) [0].depth) /* For alloca */ + +extern void *__mini_malloc __P ((size_t)); +extern void *(*__alloca_alloc) __P ((size_t)); + +/* Start the alloca with just the dumb version of malloc */ + +void *(*__alloca_alloc) __P ((size_t)) = __mini_malloc; +mem *__freed_list = 0; + +#ifdef VERBOSE +/* NB: Careful here, stdio may use malloc - so we can't */ +static +phex(val) +{ + static char hex[] = "0123456789ABCDEF"; + int i; + for (i = sizeof(int)*8-4; i >= 0; i -= 4) + write(2, hex + ((val >> i) & 0xF), 1); +} + +noise(y, x) +char *y; +mem *x; +{ + write(2, "Malloc ", 7); + phex(x); + write(2, " sz ", 4); + if(x) phex(m_size(x)); else phex(0); + write(2, " nxt ", 5); + if(x) phex(m_next(x)); else phex(0); + write(2, " is ", 4); + write(2, y, strlen(y)); + write(2, "\n", 1); +} +#endif + +//----------------------------------------------------------------------------- + +#ifdef L_alloca +/* This alloca is based on the same concept as the EMACS fallback alloca. + * It should probably be considered Copyright the FSF under the GPL. + */ +static mem *alloca_stack = 0; + +void * +alloca(size) +size_t size; +{ + auto char probe; /* Probes stack depth: */ + register mem *hp; + + /* + * Reclaim garbage, defined as all alloca'd storage that was allocated + * from deeper in the stack than currently. + */ + + for (hp = alloca_stack; hp != 0;) + if (m_deep(hp) < &probe) + { + register mem *np = m_next(hp); + free((void *) hp); /* Collect garbage. */ + hp = np; /* -> next header. */ + } + else + break; /* Rest are not deeper. */ + + alloca_stack = hp; /* -> last valid storage. */ + if (size == 0) + return 0; /* No allocation required. */ + + hp = (mem *) (*__alloca_alloc) (sizeof(mem)*2 + size); + if (hp == 0) + return hp; + + m_next(hp) = alloca_stack; + m_deep(hp) = &probe; + alloca_stack = hp; + + /* User storage begins just after header. */ + return (void *) (hp + 2); +} +#endif /* L_alloca */ + +//----------------------------------------------------------------------------- + +void +free(ptr) +void *ptr; +{ + register mem *top; + register mem *chk = (mem *) ptr; + + if (chk == 0) + return; /* free(NULL) - be nice */ + chk--; + + try_this:; + top = (mem *) sbrk(0); + if (chk + m_size(chk) == top) + { + noise("FREE brk", chk); + brk(top-m_size(chk)); + /* + * Adding this code allow free to release blocks in any order; they + * can still only be allocated from the top of the heap tho. + */ +#ifdef __MINI_MALLOC__ + if (__alloca_alloc == __mini_malloc && __freed_list) + { + mem *prev, *curr; + chk = __freed_list; + __freed_list = m_next(__freed_list); + goto try_this; + } +#endif + } + else + { /* Nope, not sure where this goes, leave + * it for malloc to deal with */ +#ifdef __MINI_MALLOC__ + if( __freed_list || chk > __freed_list ) + { m_next(chk) = __freed_list; __freed_list = chk; } + else + { + register mem *prev; + prev=__freed_list; + for(top=__freed_list; top && top > chk; prev=top, top=m_next(top)) + ; + m_next(chk) = top; + m_next(prev) = chk; + } +#else + m_next(chk) = __freed_list; + __freed_list = chk; +#endif + noise("ADD LIST", chk); + } +} + +void * +__mini_malloc(size) +size_t size; +{ + register mem *ptr; + register unsigned int sz; + + /* First time round this _might_ be odd, But we won't do that! */ + sz = (unsigned int) sbrk(0); + if (sz & (sizeof(mem) - 1)) + sbrk(4 - (sz & (sizeof(mem) - 1))); + + if (size <= 0) + return 0; + /* Minor oops here, sbrk has a signed argument */ + if( size > (((unsigned)-1)>>1)-sizeof(mem)*3 ) + { + errno = ENOMEM; + return 0; + } + + size += sizeof(mem) * 2 - 1; /* Round up and leave space for size field */ + size /= sizeof(mem); + + ptr = (mem *) sbrk(size * sizeof(mem)); + if ((int) ptr == -1) + return 0; + + m_size(ptr) = size; + noise("CREATE", ptr); + return ptr + 1; +} + +//----------------------------------------------------------------------------- + +/* + * The chunk_list pointer is either NULL or points to a chunk in a + * circular list of all the free blocks in memory + */ + +#define Static static + +static mem *chunk_list = 0; +Static void __insert_chunk(); +Static mem *__search_chunk(); + +void * +malloc(size) +size_t size; +{ + register mem *ptr = 0; + register unsigned int sz; + + if (size == 0) + return 0; /* ANSI STD */ + + sz = size + sizeof(mem) * 2 - 1; + sz /= sizeof(mem); + +#ifdef MINALLOC + if (sz < MINALLOC) + sz = MINALLOC; +#endif + +#ifdef VERBOSE + { + static mem arr[2]; + m_size(arr) = sz; + noise("WANTED", arr); + } +#endif + + __alloca_alloc = malloc; /* We'll be messing with the heap now TVM */ + +#ifdef LAZY_FREE + ptr = __search_chunk(sz); + if (ptr == 0) + { +#endif + + /* First deal with the freed list */ + if (__freed_list) + { + while (__freed_list) + { + ptr = __freed_list; + __freed_list = m_next(__freed_list); + + if (m_size(ptr) == sz) /* Oh! Well that's lucky ain't it + * :-) */ + { + noise("LUCKY MALLOC", ptr); + return ptr + 1; + } + + __insert_chunk(ptr); + } + ptr = m_next(chunk_list); + if (ptr + m_size(ptr) == (void *) sbrk(0)) + { + /* Time to free for real */ + m_next(chunk_list) = m_next(ptr); + if (ptr == m_next(ptr)) + chunk_list = 0; + free(ptr + 1); + } +#ifdef LAZY_FREE + ptr = __search_chunk(sz); +#endif + } +#ifndef LAZY_FREE + ptr = __search_chunk(sz); +#endif + if (ptr == 0) + { +#ifdef MCHUNK + unsigned int alloc; + alloc = sizeof(mem) * (MCHUNK * ((sz + MCHUNK - 1) / MCHUNK) - 1); + ptr = __mini_malloc(alloc); + if (ptr) + __insert_chunk(ptr - 1); + else /* Oooo, near end of RAM */ + { + unsigned int needed = alloc; + for(alloc/=2; alloc>256 && needed; ) + { + ptr = __mini_malloc(alloc); + if (ptr) + { + if( alloc > needed ) needed = 0; else needed -= alloc; + __insert_chunk(ptr - 1); + } + else alloc/=2; + } + } + ptr = __search_chunk(sz); + if (ptr == 0) +#endif + { +#ifndef MCHUNK + ptr = __mini_malloc(size); +#endif +#ifdef VERBOSE + if( ptr == 0 ) + noise("MALLOC FAIL", 0); + else + noise("MALLOC NOW", ptr - 1); +#endif + return ptr; + } + } +#ifdef LAZY_FREE + } +#endif + +#ifdef VERBOSE + ptr[1].size = 0x55555555; +#endif + noise("MALLOC RET", ptr); + return ptr + 1; +} + +/* + * This function takes a pointer to a block of memory and inserts it into + * the chain of memory chunks + */ + +Static void +__insert_chunk(mem_chunk) +mem *mem_chunk; +{ + register mem *p1, *p2; + if (chunk_list == 0) /* Simple case first */ + { + m_next(mem_chunk) = chunk_list = mem_chunk; + noise("FIRST CHUNK", mem_chunk); + return; + } + p1 = mem_chunk; + p2 = chunk_list; + + do + { + if (p1 > p2) + { + if (m_next(p2) <= p2) + { /* We're at the top of the chain, p1 is + * higher */ + + if (p2 + m_size(p2) == p1) + { /* Good, stick 'em together */ + noise("INSERT CHUNK", mem_chunk); + m_size(p2) += m_size(p1); + noise("JOIN 1", p2); + } + else + { + m_next(p1) = m_next(p2); + m_next(p2) = p1; + noise("INSERT CHUNK", mem_chunk); + noise("FROM", p2); + } + return; + } + if (m_next(p2) > p1) + { + /* In chain, p1 between p2 and next */ + + m_next(p1) = m_next(p2); + m_next(p2) = p1; + noise("INSERT CHUNK", mem_chunk); + noise("FROM", p2); + + /* Try to join above */ + if (p1 + m_size(p1) == m_next(p1)) + { + m_size(p1) += m_size(m_next(p1)); + m_next(p1) = m_next(m_next(p1)); + noise("JOIN 2", p1); + } + /* Try to join below */ + if (p2 + m_size(p2) == p1) + { + m_size(p2) += m_size(p1); + m_next(p2) = m_next(p1); + noise("JOIN 3", p2); + } + chunk_list = p2; /* Make sure it's valid */ + return; + } + } + else if (p1 < p2) + { + if (m_next(p2) <= p2 && p1 < m_next(p2)) + { + /* At top of chain, next is bottom of chain, p1 is below next */ + + m_next(p1) = m_next(p2); + m_next(p2) = p1; + noise("INSERT CHUNK", mem_chunk); + noise("FROM", p2); + chunk_list = p2; + + if (p1 + m_size(p1) == m_next(p1)) + { + if (p2 == m_next(p1)) + chunk_list = p1; + m_size(p1) += m_size(m_next(p1)); + m_next(p1) = m_next(m_next(p1)); + noise("JOIN 4", p1); + } + return; + } + } + chunk_list = p2; /* Save for search */ + p2 = m_next(p2); + } + while (p2 != chunk_list); + + /* If we get here we have a problem, ignore it, maybe it'll go away */ + noise("DROPPED CHUNK", mem_chunk); +} + +/* + * This function will search for a chunk in memory of at least 'mem_size' + * when found, if the chunk is too big it'll be split, and pointer to the + * chunk returned. If none is found NULL is returned. + */ + +Static mem * +__search_chunk(mem_size) +unsigned int mem_size; +{ + register mem *p1, *p2; + if (chunk_list == 0) /* Simple case first */ + return 0; + + /* Search for a block >= the size we want */ + p1 = m_next(chunk_list); + p2 = chunk_list; + do + { + noise("CHECKED", p1); + if (m_size(p1) >= mem_size) + break; + + p2 = p1; + p1 = m_next(p1); + } + while (p2 != chunk_list); + + /* None found, exit */ + if (m_size(p1) < mem_size) + return 0; + + /* If it's exactly right remove it */ + if (m_size(p1) < mem_size + 2) + { + noise("FOUND RIGHT", p1); + chunk_list = m_next(p2) = m_next(p1); + if (chunk_list == p1) + chunk_list = 0; + return p1; + } + + noise("SPLIT", p1); + /* Otherwise split it */ + m_next(p2) = p1 + mem_size; + chunk_list = p2; + + p2 = m_next(p2); + m_size(p2) = m_size(p1) - mem_size; + m_next(p2) = m_next(p1); + m_size(p1) = mem_size; + if (chunk_list == p1) + chunk_list = p2; +#ifdef VERBOSE + p1[1].size = 0xAAAAAAAA; +#endif + noise("INSERT CHUNK", p2); + noise("FOUND CHUNK", p1); + noise("LIST IS", chunk_list); + return p1; +} + +//----------------------------------------------------------------------------- + +void * +calloc(elm, sz) +unsigned int elm, sz; +{ + register unsigned int v; + register void *ptr; + ptr = malloc(v = elm * sz); + if (ptr) + memset(ptr, 0, v); + return ptr; +} + +//------------------------------------------------------------------------------ + +void * +realloc(ptr, size) +void *ptr; +size_t size; +{ + void *nptr; + unsigned int osize; + if (ptr == 0) + return malloc(size); + + osize = (m_size(((mem *) ptr) - 1) - 1) * sizeof(mem); + if (size <= osize) + { + return ptr; + } + + nptr = malloc(size); + + if (nptr == 0) + return 0; + + memcpy(nptr, ptr, osize); + free(ptr); + + return nptr; +} + +//------------------------------------------------------------------------------ diff --git a/libc/misc/Makefile b/libc/misc/Makefile new file mode 100644 index 000000000..3dbd48677 --- /dev/null +++ b/libc/misc/Makefile @@ -0,0 +1,35 @@ +# Makefile of /libc/misc module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS= \ + aliases.c \ + atexit.c \ + atoi.c \ + atol.c \ + crypt.c \ + ctype.c \ + getcwd.c \ + getenv.c \ + getopt.c \ + itoa.c \ + ltostr.c \ + popen.c \ + putenv.c \ + qsort.c \ + strtol.c \ + system.c \ + tmpnam.c \ + # end of list + +OBJS= $(SRCS:.c=.o) + +all: $(LIBC) + +$(OBJS): $(SRCS) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +clean: + rm -f *.o diff --git a/libc/misc/aliases.c b/libc/misc/aliases.c new file mode 100644 index 000000000..4cd8acfe7 --- /dev/null +++ b/libc/misc/aliases.c @@ -0,0 +1,115 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ +#include +#include + +#ifdef L_abs +int +abs(arg1) +int arg1; +{ + return arg1>0?arg1:-arg1; +} +#endif + +#ifdef L_labs +long +labs(arg1) +long arg1; +{ + return arg1>0?arg1:-arg1; +} +#endif + +#ifdef L_raise +int +raise(signo) +int signo; +{ + return kill(getpid(), signo); +} +#endif + +#ifdef L_bcopy +#undef bcopy +void +bcopy(src, dest, len) +__const void * src; +void *dest; +int len; +{ + (void) memcpy(dest, src, len); +} +#endif + +#ifdef L_bzero +#undef bzero +void +bzero(dest, len) +void *dest; +int len; +{ + (void) memset(dest, '\0', len); +} +#endif + +#ifdef L_bcmp +#undef bcmp +int +bcmp(dest, src, len) +__const void * src, *dest; +int len; +{ + return memcmp(dest, src, len); +} +#endif + +#ifdef L_index +#undef index +char * +index(src, chr) +__const char *src; +int chr; +{ + return strchr(src, chr); +} +#endif + +#undef rindex +char * +rindex(src, chr) +__const char *src; +int chr; +{ + return strrchr(src, chr); +} + +#ifdef L_remove +#include + +int +remove(src) +__const char *src; +{ + extern int errno; + int er = errno; + int rv = unlink(src); + if( rv < 0 && errno == EISDIR ) + rv = rmdir(src); + if( rv >= 0 ) errno = er; + return rv; +} +#endif + +#include + +int +creat(file, mode) +__const char * file; +mode_t mode; +{ + return open(file, O_TRUNC|O_CREAT|O_WRONLY, mode); +} + diff --git a/libc/misc/atexit.c b/libc/misc/atexit.c new file mode 100644 index 000000000..06c274b2d --- /dev/null +++ b/libc/misc/atexit.c @@ -0,0 +1,91 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* + * This deals with both the atexit and on_exit function calls + * + * Note calls installed with atexit are called with the same args as on_exit + * fuctions; the void* is given the NULL value. + * + */ + +#include + +/* ATEXIT.H */ +#define MAXONEXIT 20 /* AIUI Posix requires 10 */ + +typedef void (*vfuncp) (); + +extern vfuncp _cleanup; +extern void __do_exit(); + +extern struct exit_table +{ + vfuncp called; + void *argument; +} +__on_exit_table[MAXONEXIT]; + +extern int __on_exit_count; + +/* End ATEXIT.H */ + +int atexit (vfuncp ptr) +{ + if( __on_exit_count < 0 || __on_exit_count >= MAXONEXIT) + { + errno = ENOMEM; + return -1; + } + _cleanup = __do_exit; + if( ptr ) + { + __on_exit_table[__on_exit_count].called = ptr; + __on_exit_table[__on_exit_count].argument = 0; + __on_exit_count++; + } + return 0; +} + +#ifdef L_on_exit +int +on_exit(ptr, arg) +vfuncp ptr; +void *arg; +{ + if( __on_exit_count < 0 || __on_exit_count >= MAXONEXIT) + { + errno = ENOMEM; + return -1; + } + __cleanup = __do_exit; + if( ptr ) + { + __on_exit_table[__on_exit_count].called = ptr; + __on_exit_table[__on_exit_count].argument = arg; + __on_exit_count++; + } + return 0; +} + +#endif + +int __on_exit_count = 0; +struct exit_table __on_exit_table[MAXONEXIT]; + +void __do_exit (int rv) +{ + register int count = __on_exit_count-1; + register vfuncp ptr; + __on_exit_count = -1; /* ensure no more will be added */ + _cleanup = 0; /* Calling exit won't re-do this */ + + /* In reverse order */ + for (; count >= 0; count--) + { + ptr = __on_exit_table[count].called; + (*ptr) (rv, __on_exit_table[count].argument); + } +} diff --git a/libc/misc/atof.c b/libc/misc/atof.c new file mode 100644 index 000000000..aeadaa531 --- /dev/null +++ b/libc/misc/atof.c @@ -0,0 +1,16 @@ +/* Copyright (C) Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +double +#ifdef __STDC__ +atof(const char *p) +#else +atof(p) +char *p; +#endif +{ + return strtod(p, (char**)0); +} + diff --git a/libc/misc/atoi.c b/libc/misc/atoi.c new file mode 100644 index 000000000..52726468b --- /dev/null +++ b/libc/misc/atoi.c @@ -0,0 +1,24 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +int +atoi(number) +register char *number; +{ + register int n = 0, neg = 0; + + while (*number <= ' ' && *number > 0) + ++number; + if (*number == '-') + { + neg = 1; + ++number; + } + else if (*number == '+') + ++number; + while (*number>='0' && *number<='9') + n = (n * 10) + ((*number++) - '0'); + return (neg ? -n : n); +} diff --git a/libc/misc/atol.c b/libc/misc/atol.c new file mode 100644 index 000000000..901dfe22a --- /dev/null +++ b/libc/misc/atol.c @@ -0,0 +1,24 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +long +atol(number) +register char *number; +{ + register long n = 0, neg = 0; + + while (*number <= ' ' && *number > 0) + ++number; + if (*number == '-') + { + neg = 1; + ++number; + } + else if (*number == '+') + ++number; + while (*number>='0' && *number<='9') + n = (n * 10) + ((*number++) - '0'); + return (neg ? -n : n); +} diff --git a/libc/misc/crypt.c b/libc/misc/crypt.c new file mode 100644 index 000000000..be51948e0 --- /dev/null +++ b/libc/misc/crypt.c @@ -0,0 +1,73 @@ +/* TEA based crypt(), version 0.0 + * It looks like there are problems with key bits carrying through + * to the encryted data, and I want to get rid of that libc call.. + * This is just so rob could see it ;) */ + +/* + * I've: + * Compared the TEA implementation to a reference source - OK + * Reduced the cycles count from 64 to 32 (the suggested value) + * Changed the types of 'n' and 'i' for better code with bcc. + * Removed a possible overrun of rkey by looping the values, it's now + * possible to _choose_ every bit of the 128bit PW with a 32 character word. + * Corrected the output transformation, it lost bits between words. + * Cleaned out all trace of the uncrypted PW from rkey. + * + * RDB. + */ + +#include + +char * +crypt(const char * key, const char * salt) +{ + /* n is the number of cycles (2 rounds/cycle), + delta is a golden # derivative, + k is the key, v is the data to be encrypted. */ + + unsigned long v[2], sum=0, delta=0x9e3779b9, k[4]; + int n=32, i, j; + static char rkey[16]; + + /* Our constant string will be a string of zeros .. */ + v[0]=v[1]=k[0]=k[1]=k[2]=k[3]=0; + for(i=0;i<16;i++) rkey[i]=0; + + rkey[0]=*salt; + rkey[1]=salt[1]; + for (j=2,i=0;key[i];i++,j=((j+1)&15)) + rkey[j]=(rkey[j]<<4)+(rkey[j]>>4)+ key[i]; + + memcpy(k, rkey, 4*sizeof(long)); + + while (n-->0) { + sum += delta; + v[0] += (v[1]<<4)+k[0] ^ v[1]+sum ^ (v[1]>>5)+k[1]; + v[1] += (v[0]<<4)+k[2] ^ v[0]+sum ^ (v[0]>>5)+k[3]; + } + + /* Remove any trace of key */ + for(i=0;i<16;i++) rkey[i]=0; + *rkey=*salt; rkey[1]=salt[1]; + + /* Now we need to unpack the bits and map it to "A-Za-z0-9./" for printing + in /etc/passwd */ + sum=v[0]; + for (i=2;i<13;i++) + { + /* This unpacks the 6 bit data, each cluster into its own byte */ + rkey[i]=(sum&0x3F); + sum>>=6; + if(i==0+2) sum |= (v[1]<<26); + if(i==5+2) sum |= (v[1]>>4); + + /* Now we map to the proper chars */ + if (rkey[i]>=0 && rkey[i]<12) rkey[i]+=46; + else if (rkey[i]>11 && rkey[i]<38) rkey[i]+=53; + else if (rkey[i]>37 && rkey[i]<64) rkey[i]+=59; + else return NULL; + } + + rkey[13]='\0'; + return rkey; +} diff --git a/libc/misc/ctype.c b/libc/misc/ctype.c new file mode 100644 index 000000000..d684e1565 --- /dev/null +++ b/libc/misc/ctype.c @@ -0,0 +1,55 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* + * CTYPE.C Character classification and conversion + */ + +#include + +unsigned char __ctype[257] = +{ + 0, /* -1 */ + __CT_c, __CT_c, __CT_c, __CT_c, /* 0x00..0x03 */ + __CT_c, __CT_c, __CT_c, __CT_c, /* 0x04..0x07 */ + __CT_c, __CT_c|__CT_s, __CT_c|__CT_s, __CT_c|__CT_s, /* 0x08..0x0B */ + __CT_c|__CT_s, __CT_c|__CT_s, __CT_c, __CT_c, /* 0x0C..0x0F */ + + __CT_c, __CT_c, __CT_c, __CT_c, /* 0x10..0x13 */ + __CT_c, __CT_c, __CT_c, __CT_c, /* 0x14..0x17 */ + __CT_c, __CT_c, __CT_c, __CT_c, /* 0x18..0x1B */ + __CT_c, __CT_c, __CT_c, __CT_c, /* 0x1C..0x1F */ + + __CT_s, __CT_p, __CT_p, __CT_p, /* 0x20..0x23 */ + __CT_p, __CT_p, __CT_p, __CT_p, /* 0x24..0x27 */ + __CT_p, __CT_p, __CT_p, __CT_p, /* 0x28..0x2B */ + __CT_p, __CT_p, __CT_p, __CT_p, /* 0x2C..0x2F */ + + __CT_d|__CT_x, __CT_d|__CT_x, __CT_d|__CT_x, __CT_d|__CT_x,/* 0x30..0x33 */ + __CT_d|__CT_x, __CT_d|__CT_x, __CT_d|__CT_x, __CT_d|__CT_x,/* 0x34..0x37 */ + __CT_d|__CT_x, __CT_d|__CT_x, __CT_p, __CT_p, /* 0x38..0x3B */ + __CT_p, __CT_p, __CT_p, __CT_p, /* 0x3C..0x3F */ + + __CT_p, __CT_u|__CT_x, __CT_u|__CT_x, __CT_u|__CT_x, /* 0x40..0x43 */ + __CT_u|__CT_x, __CT_u|__CT_x, __CT_u|__CT_x, __CT_u, /* 0x44..0x47 */ + __CT_u, __CT_u, __CT_u, __CT_u, /* 0x48..0x4B */ + __CT_u, __CT_u, __CT_u, __CT_u, /* 0x4C..0x4F */ + + __CT_u, __CT_u, __CT_u, __CT_u, /* 0x50..0x53 */ + __CT_u, __CT_u, __CT_u, __CT_u, /* 0x54..0x57 */ + __CT_u, __CT_u, __CT_u, __CT_p, /* 0x58..0x5B */ + __CT_p, __CT_p, __CT_p, __CT_p, /* 0x5C..0x5F */ + + __CT_p, __CT_l|__CT_x, __CT_l|__CT_x, __CT_l|__CT_x, /* 0x60..0x63 */ + __CT_l|__CT_x, __CT_l|__CT_x, __CT_l|__CT_x, __CT_l, /* 0x64..0x67 */ + __CT_l, __CT_l, __CT_l, __CT_l, /* 0x68..0x6B */ + __CT_l, __CT_l, __CT_l, __CT_l, /* 0x6C..0x6F */ + + __CT_l, __CT_l, __CT_l, __CT_l, /* 0x70..0x73 */ + __CT_l, __CT_l, __CT_l, __CT_l, /* 0x74..0x77 */ + __CT_l, __CT_l, __CT_l, __CT_p, /* 0x78..0x7B */ + __CT_p, __CT_p, __CT_p, __CT_c /* 0x7C..0x7F */ +}; + diff --git a/libc/misc/getcwd.c b/libc/misc/getcwd.c new file mode 100644 index 000000000..351214cf4 --- /dev/null +++ b/libc/misc/getcwd.c @@ -0,0 +1,109 @@ + +#include +#include +#include +#include +/* + * These functions find the absolute path to the current working directory. + * + * They don't use malloc or large amounts of stack space. + */ + +static char * recurser(); /* Routine to go up tree */ +static char * search_dir(); /* Routine to find the step back down */ +static char * path_buf; +static int path_size; + +static dev_t root_dev; +static ino_t root_ino; + +static struct stat st; + +char * +getcwd(buf, size) +char * buf; +int size; +{ + path_buf = buf; + path_size = size; + + if( size < 3 ) { errno = ERANGE; return 0; } + strcpy(path_buf, "."); + + if( stat("/", &st) < 0 ) return 0; + + root_dev = st.st_dev; + root_ino = st.st_ino; + + return recurser(); +} + +static char * +recurser() +{ + dev_t this_dev; + ino_t this_ino; + if( stat(path_buf, &st) < 0 ) return 0; + this_dev = st.st_dev; + this_ino = st.st_ino; + if( this_dev == root_dev && this_ino == root_ino ) + { + strcpy(path_buf, "/"); + return path_buf; + } + if( strlen(path_buf) + 4 > path_size ) { errno = ERANGE; return 0; } + strcat(path_buf, "/.."); + if( recurser() == 0 ) return 0; + + return search_dir(this_dev, this_ino); +} + +static char * +search_dir(this_dev, this_ino) +dev_t this_dev; +ino_t this_ino; +{ + DIR * dp; + struct dirent * d; + char * ptr; + int slen; + /* The test is for ELKS lib 0.0.9, this should be fixed in the real kernel*/ + int slow_search = (sizeof(ino_t) != sizeof(d->d_ino)); + + if( stat(path_buf, &st) < 0 ) return 0; + if( this_dev != st.st_dev ) slow_search = 1; + + slen = strlen(path_buf); + ptr = path_buf + slen -1; + if( *ptr != '/' ) + { + if( slen + 2 > path_size ) { errno = ERANGE; return 0; } + strcpy(++ptr, "/"); + slen++; + } + slen++; + + dp = opendir(path_buf); + if( dp == 0 ) return 0; + + while( (d=readdir(dp)) != 0 ) + { + if( slow_search || this_ino == d->d_ino ) + { + if( slen + strlen(d->d_name) > path_size ) + { errno = ERANGE; return 0; } + strcpy(ptr+1, d->d_name); + if( stat(path_buf, &st) < 0 ) + continue; + if( st.st_ino == this_ino && st.st_dev == this_dev ) + { + closedir(dp); + return path_buf; + } + } + } + + closedir(dp); + errno = ENOENT; + return 0; +} diff --git a/libc/misc/getenv.c b/libc/misc/getenv.c new file mode 100644 index 000000000..1fa7defba --- /dev/null +++ b/libc/misc/getenv.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include + +extern char ** environ; + +char * +getenv(name) +char * name; +{ + register int l; + register char ** ep = environ; + l = strlen(name); + + if( ep == 0 || l == 0 ) return 0; + + while(*ep) + { + if( **ep == *name && memcmp(name, *ep, l) == 0 && (*ep)[l] == '=' ) + return *ep+l+1; + ep++; + } + return 0; +} + diff --git a/libc/misc/getopt.c b/libc/misc/getopt.c new file mode 100644 index 000000000..d9512147f --- /dev/null +++ b/libc/misc/getopt.c @@ -0,0 +1,122 @@ + +/* + * From: gwyn@brl-tgr.ARPA (Doug Gwyn ) Newsgroups: net.sources + * Subject: getopt library routine Date: 30 Mar 85 04:45:33 GMT + */ +/* + * getopt -- public domain version of standard System V routine + * + * Strictly enforces the System V Command Syntax Standard; provided by D A + * Gwyn of BRL for generic ANSI C implementations + * + * #define STRICT to prevent acceptance of clustered options with arguments + * and ommision of whitespace between option and arg. + */ + +#include +#include + +int opterr = 1; /* error => print message */ +int optind = 1; /* next argv[] index */ +char *optarg = NULL; /* option parameter if any */ + +static int +Err(name, mess, c) /* returns '?' */ +char *name; /* program name argv[0] */ +char *mess; /* specific message */ +int c; /* defective option letter */ +{ + if (opterr) + { + (void) fprintf(stderr, + "%s: %s -- %c\n", + name, mess, c + ); + } + + return '?'; /* erroneous-option marker */ +} + +int +getopt(argc, argv, optstring) /* returns letter, '?', EOF */ +int argc; /* argument count from main */ +char *argv[]; /* argument vector from main */ +char *optstring; /* allowed args, e.g. "ab:c" */ +{ + static int sp = 1; /* position within argument */ + register int osp; /* saved `sp' for param test */ +#ifndef STRICT + register int oind; /* saved `optind' for param test */ +#endif + register int c; /* option letter */ + register char *cp; /* -> option in `optstring' */ + + optarg = NULL; + + if (sp == 1) /* fresh argument */ + if (optind >= argc /* no more arguments */ + || argv[optind][0] != '-' /* no more options */ + || argv[optind][1] == '\0' /* not option; stdin */ + ) + return EOF; + else if (strcmp(argv[optind], "--") == 0) + { + ++optind; /* skip over "--" */ + return EOF; /* "--" marks end of options */ + } + + c = argv[optind][sp]; /* option letter */ + osp = sp++; /* get ready for next letter */ + +#ifndef STRICT + oind = optind; /* save optind for param test */ +#endif + if (argv[optind][sp] == '\0')/* end of argument */ + { + ++optind; /* get ready for next try */ + sp = 1; /* beginning of next argument */ + } + + if (c == ':' || c == '?' /* optstring syntax conflict */ + || (cp = strchr(optstring, c)) == NULL /* not found */ + ) + return Err(argv[0], "illegal option", c); + + if (cp[1] == ':') /* option takes parameter */ + { +#ifdef STRICT + if (osp != 1) + return Err(argv[0], + "option must not be clustered", + c + ); + + if (sp != 1) /* reset by end of argument */ + return Err(argv[0], + "option must be followed by white space", + c + ); + +#else + if (oind == optind) /* argument w/o whitespace */ + { + optarg = &argv[optind][sp]; + sp = 1; /* beginning of next argument */ + } + + else +#endif + if (optind >= argc) + return Err(argv[0], + "option requires an argument", + c + ); + + else /* argument w/ whitespace */ + optarg = argv[optind]; + + ++optind; /* skip over parameter */ + } + + return c; +} diff --git a/libc/misc/itoa.c b/libc/misc/itoa.c new file mode 100644 index 000000000..0822cfcdf --- /dev/null +++ b/libc/misc/itoa.c @@ -0,0 +1,24 @@ +/* itoa.c */ +#define __MAX_INT_CHARS 7 + +char * +itoa(i) +int i; +{ + static char a[__MAX_INT_CHARS]; + char *b = a + sizeof(a) - 1; + int sign = (i < 0); + + if (sign) + i = -i; + *b = 0; + do + { + *--b = '0' + (i % 10); + i /= 10; + } + while (i); + if (sign) + *--b = '-'; + return b; +} diff --git a/libc/misc/ltostr.c b/libc/misc/ltostr.c new file mode 100644 index 000000000..c8966d9ef --- /dev/null +++ b/libc/misc/ltostr.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +static char buf[34]; + +extern char * ultostr(); + +char * ltostr(val, radix) +long val; +int radix; +{ + char *p; + int flg = 0; + if( val < 0 ) { flg++; val= -val; } + p = ultostr(val, radix); + if(p && flg) *--p = '-'; + return p; +} + +char * ultostr(val, radix) +unsigned long val; +int radix; +{ + register char *p; + register int c; + + if( radix > 36 || radix < 2 ) return 0; + + p = buf+sizeof(buf); + *--p = '\0'; + + do + { + c = val%radix; + val/=radix; + if( c > 9 ) *--p = 'a'-10+c; else *--p = '0'+c; + } + while(val); + return p; +} + diff --git a/libc/misc/popen.c b/libc/misc/popen.c new file mode 100644 index 000000000..c848ca47c --- /dev/null +++ b/libc/misc/popen.c @@ -0,0 +1,42 @@ + +#include + + +FILE * popen(command, rw) +char * command; +char * rw; +{ + int pipe_fd[2]; + int pid, reading; + + if( pipe(pipe_fd) < 0 ) return NULL; + reading = (rw[0] == 'r'); + + pid = vfork(); + if( pid < 0 ) { close(pipe_fd[0]); close(pipe_fd[1]); return NULL; } + if( pid == 0 ) + { + close(pipe_fd[!reading]); + close(reading); + if( pipe_fd[reading] != reading ) + { + dup2(pipe_fd[reading], reading); + close(pipe_fd[reading]); + } + + execl("/bin/sh", "sh", "-c", command, (char*)0); + _exit(255); + } + + close(pipe_fd[reading]); + return fdopen(pipe_fd[!reading], rw); +} + +int pclose(fd) +FILE *fd; +{ + int waitstat; + if( fclose(fd) != 0 ) return EOF; + wait(&waitstat); +} + diff --git a/libc/misc/putenv.c b/libc/misc/putenv.c new file mode 100644 index 000000000..09a68d6be --- /dev/null +++ b/libc/misc/putenv.c @@ -0,0 +1,56 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ +#include +#include +#include + +extern char ** environ; +#define ADD_NUM 4 + +int +putenv(var) +char * var; +{ +static char ** mall_env = 0; +static int extras = 0; + char **p, **d; + char * r; + int len; + + r = strchr(var, '='); + if( r == 0 ) len = strlen(var); + else len = r-var; + + for(p=environ; *p; p++) + { + if( memcmp(var, *p, len) == 0 && (*p)[len] == '=' ) + { + while( p[0] = p[1] ) p++; + extras++; + break; + } + } + if( r == 0 ) return 0; + if( extras <= 0 ) /* Need more space */ + { + d = malloc((p-environ+1+ADD_NUM)*sizeof(char*)); + if( d == 0 ) return -1; + + memcpy((void*) d, (void*) environ, (p-environ+1)*sizeof(char*)); + p = d + (p-environ); + extras=ADD_NUM; + + if( mall_env ) free(mall_env); + environ = d; + mall_env = d; + } + *p++ = var; + *p = '\0'; + extras--; + + return 0; +} + + diff --git a/libc/misc/qsort.c b/libc/misc/qsort.c new file mode 100644 index 000000000..f41644da8 --- /dev/null +++ b/libc/misc/qsort.c @@ -0,0 +1,173 @@ +/* + * This file lifted in toto from 'Dlibs' on the atari ST (RdeBath) + * + * + * Dale Schumacher 399 Beacon Ave. + * (alias: Dalnefre') St. Paul, MN 55104 + * dal@syntel.UUCP United States of America + * "It's not reality that's important, but how you perceive things." + */ + +/* + * Sun Feb 8 21:02:15 EST 1998 claudio@pos.inf.ufpr.br (Claudio Matsuoka) + * Changed sort direction + */ + +#include + +char *_qbuf = 0; /* pointer to storage for qsort() */ + +#define PIVOT ((i+j)>>1) +#define moveitem(dst,src,size) if(dst != src) memcpy(dst, src, size) + +static void +_wqsort(base, lo, hi, cmp) +register int *base; +register int lo; +register int hi; +register int (*cmp) (); +{ + int k; + register int i, j, t; + register int *p = &k; + + while (hi > lo) + { + i = lo; + j = hi; + t = PIVOT; + *p = base[t]; + base[t] = base[i]; + base[i] = *p; + while (i < j) + { + while (((*cmp) ((base + j), p)) <= 0) + --j; + base[i] = base[j]; + while ((i < j) && (((*cmp) ((base + i), p)) > 0)) + ++i; + base[j] = base[i]; + } + base[i] = *p; + if ((i - lo) < (hi - i)) + { + _wqsort(base, lo, (i - 1), cmp); + lo = i + 1; + } + else + { + _wqsort(base, (i + 1), hi, cmp); + hi = i - 1; + } + } +} + +static void +_lqsort(base, lo, hi, cmp) +register long *base; +register int lo; +register int hi; +register int (*cmp) (); +{ + long k; + register int i, j, t; + register long *p = &k; + + while (hi > lo) + { + i = lo; + j = hi; + t = PIVOT; + *p = base[t]; + base[t] = base[i]; + base[i] = *p; + while (i < j) + { + while (((*cmp) ((base + j), p)) <= 0) + --j; + base[i] = base[j]; + while ((i < j) && (((*cmp) ((base + i), p)) > 0)) + ++i; + base[j] = base[i]; + } + base[i] = *p; + if ((i - lo) < (hi - i)) + { + _lqsort(base, lo, (i - 1), cmp); + lo = i + 1; + } + else + { + _lqsort(base, (i + 1), hi, cmp); + hi = i - 1; + } + } +} + +static void +_nqsort(base, lo, hi, size, cmp) +register char *base; +register int lo; +register int hi; +register int size; +register int (*cmp) (); +{ + register int i, j; + register char *p = _qbuf; + + while (hi > lo) + { + i = lo; + j = hi; + p = (base + size * PIVOT); + moveitem(_qbuf, p, size); + moveitem(p, (base + size * i), size); + moveitem((base + size * i), _qbuf, size); + p = _qbuf; + while (i < j) + { + while (((*cmp) ((base + size * j), p)) <= 0) + --j; + moveitem((base + size * i), (base + size * j), size); + while ((i < j) && (((*cmp) ((base + size * i), p)) > 0)) + ++i; + moveitem((base + size * j), (base + size * i), size); + } + moveitem((base + size * i), p, size); + if ((i - lo) < (hi - i)) + { + _nqsort(base, lo, (i - 1), size, cmp); + lo = i + 1; + } + else + { + _nqsort(base, (i + 1), hi, size, cmp); + hi = i - 1; + } + } +} + +void +qsort(base, num, size, cmp) +char *base; +int num; +int size; +int (*cmp) (); +{ + char _qtemp[128]; + + if (_qbuf == 0) + { + if (size > sizeof(_qtemp))/* records too large! */ + return; + _qbuf = _qtemp; + } + if (size == 2) + _wqsort(base, 0, num - 1, cmp); + else if (size == 4) + _lqsort(base, 0, num - 1, cmp); + else + _nqsort(base, 0, num - 1, size, cmp); + if (_qbuf == _qtemp) + _qbuf = 0; +} diff --git a/libc/misc/strtol.c b/libc/misc/strtol.c new file mode 100644 index 000000000..25ea0ea49 --- /dev/null +++ b/libc/misc/strtol.c @@ -0,0 +1,111 @@ +/* + * strtol.c - This file is part of the libc-8086 package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* TODO: This needs range clamping and setting errno when it's done. */ + +#include +#include + +long int +strtol(const char *nptr, char **endptr, int base) +{ + const char * ptr; + unsigned short negative; + long int number; + + ptr=nptr; + + while (isspace(*ptr)) + ptr++; + + negative=0; + if (*ptr=='-') + negative=1; + + number=(long int)strtoul(nptr, endptr, base); + + return (negative ? -number:number); +} + +unsigned long int +strtoul(const char *nptr, char **endptr, int base) +{ + unsigned long int number; + + /* Sanity check the arguments */ + if (base==1 || base>36 || base<0) + base=0; + + /* advance beyond any leading whitespace */ + while (isspace(*nptr)) + nptr++; + + /* check for optional '+' or '-' */ + if (*nptr=='-') + nptr++; + else + if (*nptr=='+') + nptr++; + + /* If base==0 and the string begins with "0x" then we're supposed + to assume that it's hexadecimal (base 16). */ + if (base==0 && *nptr=='0') + { + if (toupper(*(nptr+1))=='X') + { + base=16; + nptr+=2; + } + /* If base==0 and the string begins with "0" but not "0x", + then we're supposed to assume that it's octal (base 8). */ + else + { + base=8; + nptr++; + } + } + + /* If base is still 0 (it was 0 to begin with and the string didn't begin + with "0"), then we are supposed to assume that it's base 10 */ + if (base==0) + base=10; + + number=0; + while (isascii(*nptr) && isalnum(*nptr)) + { + int ch = *nptr; + if (islower(ch)) ch = toupper(ch); + ch -= (ch<='9' ? '0' : 'A'-10); + if (ch>base) + break; + + number= (number*base)+ch; + nptr++; + } + + /* Some code is simply _impossible_ to write with -Wcast-qual .. :-\ */ + if (endptr!=NULL) + *endptr=(char *)nptr; + + /* All done */ + return number; +} + + diff --git a/libc/misc/system.c b/libc/misc/system.c new file mode 100644 index 000000000..f48f68d51 --- /dev/null +++ b/libc/misc/system.c @@ -0,0 +1,49 @@ + +#include +#include + +int +system(command) +char * command; +{ + int wait_val, wait_ret, pid; + __sighandler_t save_quit; + __sighandler_t save_int; + + if( command == 0 ) return 1; + + save_quit = signal(SIGQUIT, SIG_IGN); + save_int = signal(SIGINT, SIG_IGN); + + if( (pid=vfork()) < 0 ) + { + signal(SIGQUIT, save_quit); + signal(SIGINT, save_int); + return -1; + } + if( pid == 0 ) + { + signal(SIGQUIT, SIG_DFL); + signal(SIGINT, SIG_DFL); + + execl("/bin/sh", "sh", "-c", command, (char*)0); + _exit(127); + } + /* Signals are not absolutly guarenteed with vfork */ + signal(SIGQUIT, SIG_IGN); + signal(SIGINT, SIG_IGN); + + do + { + if( (wait_ret = wait(&wait_val)) == -1 ) + { + wait_val = -1; + break; + } + } + while( wait_ret != pid ); + + signal(SIGQUIT, save_quit); + signal(SIGINT, save_int); + return wait_val; +} diff --git a/libc/misc/tmpnam.c b/libc/misc/tmpnam.c new file mode 100644 index 000000000..5bb72c580 --- /dev/null +++ b/libc/misc/tmpnam.c @@ -0,0 +1,50 @@ +/* + * (C) Shane Kerr under terms of LGPL + */ + +#include +#include +#include + +#ifndef P_tmpdir +#define P_tmpdir "/tmp" +#endif + +#ifndef L_tmpnam +#define L_tmpnam 20 +#endif + +char *tmpnam(s) +char *s; +{ + static char ret_val[L_tmpnam]; + static char c1 = 0; + static char c2 = 0; + static char c3 = 0; + static char uniq_ch[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + struct stat stbuf; + + do { + sprintf(ret_val, "%s/%05d%c%c%c", P_tmpdir, getpid(), + uniq_ch[c1], uniq_ch[c2], uniq_ch[c3]); + if (++c1 >= 62) { + c1 = 0; + if (++c2 >= 62) { + c2 = 0; + if (++c3 >= 62) { + errno = EEXIST; + return 0; + } + } + } + } while (stat(ret_val, &stbuf) == 0); + + if (s != 0) { + strcpy(s, ret_val); + return s; + } else { + return ret_val; + } +} + diff --git a/libc/regex/Makefile b/libc/regex/Makefile new file mode 100644 index 000000000..c0e6491cd --- /dev/null +++ b/libc/regex/Makefile @@ -0,0 +1,16 @@ +# Makefile of /libc/termcap module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS= regex.c +OBJS= $(SRCS:.c=.o) + +all: $(LIBC) + +$(OBJS): $(SRCS) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +clean: + rm -f *.o diff --git a/libc/regex/regex.c b/libc/regex/regex.c new file mode 100644 index 000000000..e0e8d3e4c --- /dev/null +++ b/libc/regex/regex.c @@ -0,0 +1,1213 @@ +/* + * regcomp and regexec -- regsub and regerror are elsewhere + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * Beware that some of this code is subtly aware of the way operator + * precedence is structured in regular expressions. Serious changes in + * regular-expression syntax might require a total rethink. + */ +#include +#include +#include +#include +#include "regmagic.h" + +/* + * The "internal use only" fields in regexp.h are present to pass info from + * compile to execute that permits the execute phase to run lots faster on + * simple cases. They are: + * + * regstart char that must begin a match; '\0' if none obvious + * reganch is the match anchored (at beginning-of-line only)? + * regmust string (pointer into program) that match must include, or NULL + * regmlen length of regmust string + * + * Regstart and reganch permit very fast decisions on suitable starting points + * for a match, cutting down the work a lot. Regmust permits fast rejection + * of lines that cannot possibly match. The regmust tests are costly enough + * that regcomp() supplies a regmust only if the r.e. contains something + * potentially expensive (at present, the only such thing detected is * or + + * at the start of the r.e., which can involve a lot of backup). Regmlen is + * supplied because the test in regexec() needs it and regcomp() is computing + * it anyway. + */ + +/* + * Structure for regexp "program". This is essentially a linear encoding + * of a nondeterministic finite-state machine (aka syntax charts or + * "railroad normal form" in parsing technology). Each node is an opcode + * plus a "next" pointer, possibly plus an operand. "Next" pointers of + * all nodes except BRANCH implement concatenation; a "next" pointer with + * a BRANCH on both ends of it is connecting two alternatives. (Here we + * have one of the subtle syntax dependencies: an individual BRANCH (as + * opposed to a collection of them) is never concatenated with anything + * because of operator precedence.) The operand of some types of node is + * a literal string; for others, it is a node leading into a sub-FSM. In + * particular, the operand of a BRANCH node is the first node of the branch. + * (NB this is *not* a tree structure: the tail of the branch connects + * to the thing following the set of BRANCHes.) The opcodes are: + */ + +/* definition number opnd? meaning */ +#define END 0 /* no End of program. */ +#define BOL 1 /* no Match "" at beginning of line. */ +#define EOL 2 /* no Match "" at end of line. */ +#define ANY 3 /* no Match any one character. */ +#define ANYOF 4 /* str Match any character in this string. */ +#define ANYBUT 5 /* str Match any character not in this string. */ +#define BRANCH 6 /* node Match this alternative, or the next... */ +#define BACK 7 /* no Match "", "next" ptr points backward. */ +#define EXACTLY 8 /* str Match this string. */ +#define NOTHING 9 /* no Match empty string. */ +#define STAR 10 /* node Match this (simple) thing 0 or more times. */ +#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ +#define OPEN 20 /* no Mark this point in input as start of #n. */ + /* OPEN+1 is number 1, etc. */ +#define CLOSE 30 /* no Analogous to OPEN. */ + +/* + * Opcode notes: + * + * BRANCH The set of branches constituting a single choice are hooked + * together with their "next" pointers, since precedence prevents + * anything being concatenated to any individual branch. The + * "next" pointer of the last BRANCH in a choice points to the + * thing following the whole choice. This is also where the + * final "next" pointer of each individual branch points; each + * branch starts with the operand node of a BRANCH node. + * + * BACK Normal "next" pointers all implicitly point forward; BACK + * exists to make loop structures possible. + * + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular + * BRANCH structures using BACK. Simple cases (one character + * per match) are implemented with STAR and PLUS for speed + * and to minimize recursive plunges. + * + * OPEN,CLOSE ...are numbered at compile time. + */ + +/* + * A node is one char of opcode followed by two chars of "next" pointer. + * "Next" pointers are stored as two 8-bit pieces, high order first. The + * value is a positive offset from the opcode of the node containing it. + * An operand, if any, simply follows the node. (Note that much of the + * code generation knows about this implicit relationship.) + * + * Using two bytes for the "next" pointer is vast overkill for most things, + * but allows patterns to get big without disasters. + */ +#define OP(p) (*(p)) +#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) +#define OPERAND(p) ((p) + 3) + +/* + * See regmagic.h for one further detail of program structure. + */ + + +/* + * Utility definitions. + */ +#ifndef CHARBITS +#define UCHARAT(p) ((int)*(unsigned char *)(p)) +#else +#define UCHARAT(p) ((int)*(p)&CHARBITS) +#endif + +#define FAIL(m) { regerror(m); return(NULL); } +#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') +#define META "^$.[()|?+*\\" + +/* + * Flags to be passed up and down. + */ +#define HASWIDTH 01 /* Known never to match null string. */ +#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ +#define SPSTART 04 /* Starts with * or +. */ +#define WORST 0 /* Worst case. */ + +/* + * Global work variables for regcomp(). + */ +static char *regparse; /* Input-scan pointer. */ +static int regnpar; /* () count. */ +static char regdummy; +static char *regcode; /* Code-emit pointer; ®dummy = don't. */ +static long regsize; /* Code size. */ + +/* + * Forward declarations for regcomp()'s friends. + */ +#ifndef STATIC +#define STATIC static +#endif +STATIC char *reg(); +STATIC char *regbranch(); +STATIC char *regpiece(); +STATIC char *regatom(); +STATIC char *regnode(); +STATIC char *regnext(); +STATIC void regc(); +STATIC void reginsert(); +STATIC void regtail(); +STATIC void regoptail(); +#ifdef STRCSPN +STATIC int strcspn(); +#endif + +/* + - regcomp - compile a regular expression into internal code + * + * We can't allocate space until we know how big the compiled form will be, + * but we can't compile it (and thus know how big it is) until we've got a + * place to put the code. So we cheat: we compile it twice, once with code + * generation turned off and size counting turned on, and once "for real". + * This also means that we don't allocate space until we are sure that the + * thing really will compile successfully, and we never have to move the + * code and thus invalidate pointers into it. (Note that it has to be in + * one piece because free() must be able to free it all.) + * + * Beware that the optimization-preparation code in here knows about some + * of the structure of the compiled regexp. + */ +regexp * +regcomp(exp) +char *exp; +{ + register regexp *r; + register char *scan; + register char *longest; + register int len; + int flags; + + if (exp == NULL) + FAIL("NULL argument"); + + /* First pass: determine size, legality. */ + regparse = exp; + regnpar = 1; + regsize = 0L; + regcode = ®dummy; + regc(MAGIC); + if (reg(0, &flags) == NULL) + return(NULL); + + /* Small enough for pointer-storage convention? */ + if (regsize >= 32767L) /* Probably could be 65535L. */ + FAIL("regexp too big"); + + /* Allocate space. */ + r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); + if (r == NULL) + FAIL("out of space"); + + /* Second pass: emit code. */ + regparse = exp; + regnpar = 1; + regcode = r->program; + regc(MAGIC); + if (reg(0, &flags) == NULL) + return(NULL); + + /* Dig out information for optimizations. */ + r->regstart = '\0'; /* Worst-case defaults. */ + r->reganch = 0; + r->regmust = NULL; + r->regmlen = 0; + scan = r->program+1; /* First BRANCH. */ + if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ + scan = OPERAND(scan); + + /* Starting-point info. */ + if (OP(scan) == EXACTLY) + r->regstart = *OPERAND(scan); + else if (OP(scan) == BOL) + r->reganch++; + + /* + * If there's something expensive in the r.e., find the + * longest literal string that must appear and make it the + * regmust. Resolve ties in favor of later strings, since + * the regstart check works with the beginning of the r.e. + * and avoiding duplication strengthens checking. Not a + * strong reason, but sufficient in the absence of others. + */ + if (flags&SPSTART) { + longest = NULL; + len = 0; + for (; scan != NULL; scan = regnext(scan)) + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { + longest = OPERAND(scan); + len = strlen(OPERAND(scan)); + } + r->regmust = longest; + r->regmlen = len; + } + } + + return(r); +} + +/* + - reg - regular expression, i.e. main body or parenthesized thing + * + * Caller must absorb opening parenthesis. + * + * Combining parenthesis handling with the base level of regular expression + * is a trifle forced, but the need to tie the tails of the branches to what + * follows makes it hard to avoid. + */ +static char * +reg(paren, flagp) +int paren; /* Parenthesized? */ +int *flagp; +{ + register char *ret; + register char *br; + register char *ender; + register int parno; + int flags; + + *flagp = HASWIDTH; /* Tentatively. */ + + /* Make an OPEN node, if parenthesized. */ + if (paren) { + if (regnpar >= NSUBEXP) + FAIL("too many ()"); + parno = regnpar; + regnpar++; + ret = regnode(OPEN+parno); + } else + ret = NULL; + + /* Pick up the branches, linking them together. */ + br = regbranch(&flags); + if (br == NULL) + return(NULL); + if (ret != NULL) + regtail(ret, br); /* OPEN -> first. */ + else + ret = br; + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags&SPSTART; + while (*regparse == '|') { + regparse++; + br = regbranch(&flags); + if (br == NULL) + return(NULL); + regtail(ret, br); /* BRANCH -> BRANCH. */ + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags&SPSTART; + } + + /* Make a closing node, and hook it on the end. */ + ender = regnode((paren) ? CLOSE+parno : END); + regtail(ret, ender); + + /* Hook the tails of the branches to the closing node. */ + for (br = ret; br != NULL; br = regnext(br)) + regoptail(br, ender); + + /* Check for proper termination. */ + if (paren && *regparse++ != ')') { + FAIL("unmatched ()"); + } else if (!paren && *regparse != '\0') { + if (*regparse == ')') { + FAIL("unmatched ()"); + } else + FAIL("junk on end"); /* "Can't happen". */ + /* NOTREACHED */ + } + + return(ret); +} + +/* + - regbranch - one alternative of an | operator + * + * Implements the concatenation operator. + */ +static char * +regbranch(flagp) +int *flagp; +{ + register char *ret; + register char *chain; + register char *latest; + int flags; + + *flagp = WORST; /* Tentatively. */ + + ret = regnode(BRANCH); + chain = NULL; + while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { + latest = regpiece(&flags); + if (latest == NULL) + return(NULL); + *flagp |= flags&HASWIDTH; + if (chain == NULL) /* First piece. */ + *flagp |= flags&SPSTART; + else + regtail(chain, latest); + chain = latest; + } + if (chain == NULL) /* Loop ran zero times. */ + (void) regnode(NOTHING); + + return(ret); +} + +/* + - regpiece - something followed by possible [*+?] + * + * Note that the branching code sequences used for ? and the general cases + * of * and + are somewhat optimized: they use the same NOTHING node as + * both the endmarker for their branch list and the body of the last branch. + * It might seem that this node could be dispensed with entirely, but the + * endmarker role is not redundant. + */ +static char * +regpiece(flagp) +int *flagp; +{ + register char *ret; + register char op; + register char *next; + int flags; + + ret = regatom(&flags); + if (ret == NULL) + return(NULL); + + op = *regparse; + if (!ISMULT(op)) { + *flagp = flags; + return(ret); + } + + if (!(flags&HASWIDTH) && op != '?') + FAIL("*+ operand could be empty"); + *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); + + if (op == '*' && (flags&SIMPLE)) + reginsert(STAR, ret); + else if (op == '*') { + /* Emit x* as (x&|), where & means "self". */ + reginsert(BRANCH, ret); /* Either x */ + regoptail(ret, regnode(BACK)); /* and loop */ + regoptail(ret, ret); /* back */ + regtail(ret, regnode(BRANCH)); /* or */ + regtail(ret, regnode(NOTHING)); /* null. */ + } else if (op == '+' && (flags&SIMPLE)) + reginsert(PLUS, ret); + else if (op == '+') { + /* Emit x+ as x(&|), where & means "self". */ + next = regnode(BRANCH); /* Either */ + regtail(ret, next); + regtail(regnode(BACK), ret); /* loop back */ + regtail(next, regnode(BRANCH)); /* or */ + regtail(ret, regnode(NOTHING)); /* null. */ + } else if (op == '?') { + /* Emit x? as (x|) */ + reginsert(BRANCH, ret); /* Either x */ + regtail(ret, regnode(BRANCH)); /* or */ + next = regnode(NOTHING); /* null. */ + regtail(ret, next); + regoptail(ret, next); + } + regparse++; + if (ISMULT(*regparse)) + FAIL("nested *?+"); + + return(ret); +} + +/* + - regatom - the lowest level + * + * Optimization: gobbles an entire sequence of ordinary characters so that + * it can turn them into a single node, which is smaller to store and + * faster to run. Backslashed characters are exceptions, each becoming a + * separate node; the code is simpler that way and it's not worth fixing. + */ +static char * +regatom(flagp) +int *flagp; +{ + register char *ret; + int flags; + + *flagp = WORST; /* Tentatively. */ + + switch (*regparse++) { + case '^': + ret = regnode(BOL); + break; + case '$': + ret = regnode(EOL); + break; + case '.': + ret = regnode(ANY); + *flagp |= HASWIDTH|SIMPLE; + break; + case '[': { + register int class; + register int classend; + + if (*regparse == '^') { /* Complement of range. */ + ret = regnode(ANYBUT); + regparse++; + } else + ret = regnode(ANYOF); + if (*regparse == ']' || *regparse == '-') + regc(*regparse++); + while (*regparse != '\0' && *regparse != ']') { + if (*regparse == '-') { + regparse++; + if (*regparse == ']' || *regparse == '\0') + regc('-'); + else { + class = UCHARAT(regparse-2)+1; + classend = UCHARAT(regparse); + if (class > classend+1) + FAIL("invalid [] range"); + for (; class <= classend; class++) + regc(class); + regparse++; + } + } else + regc(*regparse++); + } + regc('\0'); + if (*regparse != ']') + FAIL("unmatched []"); + regparse++; + *flagp |= HASWIDTH|SIMPLE; + } + break; + case '(': + ret = reg(1, &flags); + if (ret == NULL) + return(NULL); + *flagp |= flags&(HASWIDTH|SPSTART); + break; + case '\0': + case '|': + case ')': + FAIL("internal urp"); /* Supposed to be caught earlier. */ + break; + case '?': + case '+': + case '*': + FAIL("?+* follows nothing"); + break; + case '\\': + if (*regparse == '\0') + FAIL("trailing \\"); + ret = regnode(EXACTLY); + regc(*regparse++); + regc('\0'); + *flagp |= HASWIDTH|SIMPLE; + break; + default: { + register int len; + register char ender; + + regparse--; + len = strcspn(regparse, META); + if (len <= 0) + FAIL("internal disaster"); + ender = *(regparse+len); + if (len > 1 && ISMULT(ender)) + len--; /* Back off clear of ?+* operand. */ + *flagp |= HASWIDTH; + if (len == 1) + *flagp |= SIMPLE; + ret = regnode(EXACTLY); + while (len > 0) { + regc(*regparse++); + len--; + } + regc('\0'); + } + break; + } + + return(ret); +} + +/* + - regnode - emit a node + */ +static char * /* Location. */ +regnode(op) +char op; +{ + register char *ret; + register char *ptr; + + ret = regcode; + if (ret == ®dummy) { + regsize += 3; + return(ret); + } + + ptr = ret; + *ptr++ = op; + *ptr++ = '\0'; /* Null "next" pointer. */ + *ptr++ = '\0'; + regcode = ptr; + + return(ret); +} + +/* + - regc - emit (if appropriate) a byte of code + */ +static void +regc(b) +char b; +{ + if (regcode != ®dummy) + *regcode++ = b; + else + regsize++; +} + +/* + - reginsert - insert an operator in front of already-emitted operand + * + * Means relocating the operand. + */ +static void +reginsert(op, opnd) +char op; +char *opnd; +{ + register char *src; + register char *dst; + register char *place; + + if (regcode == ®dummy) { + regsize += 3; + return; + } + + src = regcode; + regcode += 3; + dst = regcode; + while (src > opnd) + *--dst = *--src; + + place = opnd; /* Op node, where operand used to be. */ + *place++ = op; + *place++ = '\0'; + *place++ = '\0'; +} + +/* + - regtail - set the next-pointer at the end of a node chain + */ +static void +regtail(p, val) +char *p; +char *val; +{ + register char *scan; + register char *temp; + register int offset; + + if (p == ®dummy) + return; + + /* Find last node. */ + scan = p; + for (;;) { + temp = regnext(scan); + if (temp == NULL) + break; + scan = temp; + } + + if (OP(scan) == BACK) + offset = scan - val; + else + offset = val - scan; + *(scan+1) = (offset>>8)&0377; + *(scan+2) = offset&0377; +} + +/* + - regoptail - regtail on operand of first argument; nop if operandless + */ +static void +regoptail(p, val) +char *p; +char *val; +{ + /* "Operandless" and "op != BRANCH" are synonymous in practice. */ + if (p == NULL || p == ®dummy || OP(p) != BRANCH) + return; + regtail(OPERAND(p), val); +} + +/* + * regexec and friends + */ + +/* + * Global work variables for regexec(). + */ +static char *reginput; /* String-input pointer. */ +static char *regbol; /* Beginning of input, for ^ check. */ +static char **regstartp; /* Pointer to startp array. */ +static char **regendp; /* Ditto for endp. */ + +/* + * Forwards. + */ +STATIC int regtry(); +STATIC int regmatch(); +STATIC int regrepeat(); + +#ifdef DEBUG +int regnarrate = 0; +void regdump(); +STATIC char *regprop(); +#endif + +/* + - regexec - match a regexp against a string + */ +int +regexec(prog, string) +register regexp *prog; +register char *string; +{ + register char *s; + + /* Be paranoid... */ + if (prog == NULL || string == NULL) { + regerror("NULL parameter"); + return(0); + } + + /* Check validity of program. */ + if (UCHARAT(prog->program) != MAGIC) { + regerror("corrupted program"); + return(0); + } + + /* If there is a "must appear" string, look for it. */ + if (prog->regmust != NULL) { + s = string; + while ((s = strchr(s, prog->regmust[0])) != NULL) { + if (strncmp(s, prog->regmust, prog->regmlen) == 0) + break; /* Found it. */ + s++; + } + if (s == NULL) /* Not present. */ + return(0); + } + + /* Mark beginning of line for ^ . */ + regbol = string; + + /* Simplest case: anchored match need be tried only once. */ + if (prog->reganch) + return(regtry(prog, string)); + + /* Messy cases: unanchored match. */ + s = string; + if (prog->regstart != '\0') + /* We know what char it must start with. */ + while ((s = strchr(s, prog->regstart)) != NULL) { + if (regtry(prog, s)) + return(1); + s++; + } + else + /* We don't -- general case. */ + do { + if (regtry(prog, s)) + return(1); + } while (*s++ != '\0'); + + /* Failure. */ + return(0); +} + +/* + - regtry - try match at specific point + */ +static int /* 0 failure, 1 success */ +regtry(prog, string) +regexp *prog; +char *string; +{ + register int i; + register char **sp; + register char **ep; + + reginput = string; + regstartp = prog->startp; + regendp = prog->endp; + + sp = prog->startp; + ep = prog->endp; + for (i = NSUBEXP; i > 0; i--) { + *sp++ = NULL; + *ep++ = NULL; + } + if (regmatch(prog->program + 1)) { + prog->startp[0] = string; + prog->endp[0] = reginput; + return(1); + } else + return(0); +} + +/* + - regmatch - main matching routine + * + * Conceptually the strategy is simple: check to see whether the current + * node matches, call self recursively to see whether the rest matches, + * and then act accordingly. In practice we make some effort to avoid + * recursion, in particular by going through "ordinary" nodes (that don't + * need to know whether the rest of the match failed) by a loop instead of + * by recursion. + */ +static int /* 0 failure, 1 success */ +regmatch(prog) +char *prog; +{ + register char *scan; /* Current node. */ + char *next; /* Next node. */ + extern char *strchr(); + + scan = prog; +#ifdef DEBUG + if (scan != NULL && regnarrate) + fprintf(stderr, "%s(\n", regprop(scan)); +#endif + while (scan != NULL) { +#ifdef DEBUG + if (regnarrate) + fprintf(stderr, "%s...\n", regprop(scan)); +#endif + next = regnext(scan); + + switch (OP(scan)) { + case BOL: + if (reginput != regbol) + return(0); + break; + case EOL: + if (*reginput != '\0') + return(0); + break; + case ANY: + if (*reginput == '\0') + return(0); + reginput++; + break; + case EXACTLY: { + register int len; + register char *opnd; + + opnd = OPERAND(scan); + /* Inline the first character, for speed. */ + if (*opnd != *reginput) + return(0); + len = strlen(opnd); + if (len > 1 && strncmp(opnd, reginput, len) != 0) + return(0); + reginput += len; + } + break; + case ANYOF: + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) + return(0); + reginput++; + break; + case ANYBUT: + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) + return(0); + reginput++; + break; + case NOTHING: + break; + case BACK: + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: { + register int no; + register char *save; + + no = OP(scan) - OPEN; + save = reginput; + + if (regmatch(next)) { + /* + * Don't set startp if some later + * invocation of the same parentheses + * already has. + */ + if (regstartp[no] == NULL) + regstartp[no] = save; + return(1); + } else + return(0); + } + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: { + register int no; + register char *save; + + no = OP(scan) - CLOSE; + save = reginput; + + if (regmatch(next)) { + /* + * Don't set endp if some later + * invocation of the same parentheses + * already has. + */ + if (regendp[no] == NULL) + regendp[no] = save; + return(1); + } else + return(0); + } + break; + case BRANCH: { + register char *save; + + if (OP(next) != BRANCH) /* No choice. */ + next = OPERAND(scan); /* Avoid recursion. */ + else { + do { + save = reginput; + if (regmatch(OPERAND(scan))) + return(1); + reginput = save; + scan = regnext(scan); + } while (scan != NULL && OP(scan) == BRANCH); + return(0); + /* NOTREACHED */ + } + } + break; + case STAR: + case PLUS: { + register char nextch; + register int no; + register char *save; + register int min; + + /* + * Lookahead to avoid useless match attempts + * when we know what character comes next. + */ + nextch = '\0'; + if (OP(next) == EXACTLY) + nextch = *OPERAND(next); + min = (OP(scan) == STAR) ? 0 : 1; + save = reginput; + no = regrepeat(OPERAND(scan)); + while (no >= min) { + /* If it could work, try it. */ + if (nextch == '\0' || *reginput == nextch) + if (regmatch(next)) + return(1); + /* Couldn't or didn't -- back up. */ + no--; + reginput = save + no; + } + return(0); + } + break; + case END: + return(1); /* Success! */ + break; + default: + regerror("memory corruption"); + return(0); + break; + } + + scan = next; + } + + /* + * We get here only if there's trouble -- normally "case END" is + * the terminating point. + */ + regerror("corrupted pointers"); + return(0); +} + +/* + - regrepeat - repeatedly match something simple, report how many + */ +static int +regrepeat(p) +char *p; +{ + register int count = 0; + register char *scan; + register char *opnd; + + scan = reginput; + opnd = OPERAND(p); + switch (OP(p)) { + case ANY: + count = strlen(scan); + scan += count; + break; + case EXACTLY: + while (*opnd == *scan) { + count++; + scan++; + } + break; + case ANYOF: + while (*scan != '\0' && strchr(opnd, *scan) != NULL) { + count++; + scan++; + } + break; + case ANYBUT: + while (*scan != '\0' && strchr(opnd, *scan) == NULL) { + count++; + scan++; + } + break; + default: /* Oh dear. Called inappropriately. */ + regerror("internal foulup"); + count = 0; /* Best compromise. */ + break; + } + reginput = scan; + + return(count); +} + +/* + - regnext - dig the "next" pointer out of a node + */ +static char * +regnext(p) +register char *p; +{ + register int offset; + + if (p == ®dummy) + return(NULL); + + offset = NEXT(p); + if (offset == 0) + return(NULL); + + if (OP(p) == BACK) + return(p-offset); + else + return(p+offset); +} + +#ifdef DEBUG + +STATIC char *regprop(); + +/* + - regdump - dump a regexp onto stdout in vaguely comprehensible form + */ +void +regdump(r) +regexp *r; +{ + register char *s; + register char op = EXACTLY; /* Arbitrary non-END op. */ + register char *next; + extern char *strchr(); + + + s = r->program + 1; + while (op != END) { /* While that wasn't END last time... */ + op = OP(s); + printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ + next = regnext(s); + if (next == NULL) /* Next ptr. */ + printf("(0)"); + else + printf("(%d)", (s-r->program)+(next-s)); + s += 3; + if (op == ANYOF || op == ANYBUT || op == EXACTLY) { + /* Literal string, where present. */ + while (*s != '\0') { + putchar(*s); + s++; + } + s++; + } + putchar('\n'); + } + + /* Header fields of interest. */ + if (r->regstart != '\0') + printf("start `%c' ", r->regstart); + if (r->reganch) + printf("anchored "); + if (r->regmust != NULL) + printf("must have \"%s\"", r->regmust); + printf("\n"); +} + +/* + - regprop - printable representation of opcode + */ +static char * +regprop(op) +char *op; +{ + register char *p; + static char buf[50]; + + (void) strcpy(buf, ":"); + + switch (OP(op)) { + case BOL: + p = "BOL"; + break; + case EOL: + p = "EOL"; + break; + case ANY: + p = "ANY"; + break; + case ANYOF: + p = "ANYOF"; + break; + case ANYBUT: + p = "ANYBUT"; + break; + case BRANCH: + p = "BRANCH"; + break; + case EXACTLY: + p = "EXACTLY"; + break; + case NOTHING: + p = "NOTHING"; + break; + case BACK: + p = "BACK"; + break; + case END: + p = "END"; + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: + sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN); + p = NULL; + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: + sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE); + p = NULL; + break; + case STAR: + p = "STAR"; + break; + case PLUS: + p = "PLUS"; + break; + default: + regerror("corrupted opcode"); + break; + } + if (p != NULL) + (void) strcat(buf, p); + return(buf); +} +#endif + +/* + * The following is provided for those people who do not have strcspn() in + * their C libraries. They should get off their butts and do something + * about it; at least one public-domain implementation of those (highly + * useful) string routines has been published on Usenet. + */ +#ifdef STRCSPN +/* + * strcspn - find length of initial segment of s1 consisting entirely + * of characters not from s2 + */ + +static int +strcspn(s1, s2) +char *s1; +char *s2; +{ + register char *scan1; + register char *scan2; + register int count; + + count = 0; + for (scan1 = s1; *scan1 != '\0'; scan1++) { + for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ + if (*scan1 == *scan2++) + return(count); + count++; + } + return(count); +} +#endif diff --git a/libc/regex/regmagic.h b/libc/regex/regmagic.h new file mode 100644 index 000000000..5acf4478f --- /dev/null +++ b/libc/regex/regmagic.h @@ -0,0 +1,5 @@ +/* + * The first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. + */ +#define MAGIC 0234 diff --git a/libc/stdio/Makefile b/libc/stdio/Makefile new file mode 100644 index 000000000..f65e00ce4 --- /dev/null +++ b/libc/stdio/Makefile @@ -0,0 +1,16 @@ +# Makefile of /libc/stdio module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS = stdio.c printf.c scanf.c +OBJS = $(SRCS:.c=.o) + +all: $(LIBC) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +$(OBJS): $(SRCS) + +clean: + rm -f *.o diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c new file mode 100644 index 000000000..29509ba96 --- /dev/null +++ b/libc/stdio/printf.c @@ -0,0 +1,400 @@ +/* + * This file based on printf.c from 'Dlibs' on the atari ST (RdeBath) + * + * 19-OCT-88: Dale Schumacher + * > John Stanley has again been a great help in debugging, particularly + * > with the printf/scanf functions which are his creation. + * + * Dale Schumacher 399 Beacon Ave. + * (alias: Dalnefre') St. Paul, MN 55104 + * dal@syntel.UUCP United States of America + * "It's not reality that's important, but how you perceive things." + * + */ + +/* Altered to use stdarg, made the core function vfprintf. + * Hooked into the stdio package using 'inside information' + * Altered sizeof() assumptions, now assumes all integers except chars + * will be either + * sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short) + * + * -RDB + */ + +#include + +#include +#include +#include +#include + +int sprintf (char * sp, const char * fmt, ...) +{ +static FILE string[1] = +{ + {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1, + _IOFBF | __MODE_WRITE} +}; + + va_list ptr; + int rv; + va_start(ptr, fmt); + string->bufpos = sp; + rv = vfprintf(string,fmt,ptr); + va_end(ptr); + *(string->bufpos) = 0; + return rv; +} + +#ifdef L_vprintf +int vprintf(fmt, ap) +__const char *fmt; +va_list ap; +{ + return vfprintf(stdout,fmt,ap); +} +#endif + +int vsprintf(sp, fmt, ap) +char * sp; +__const char *fmt; +va_list ap; +{ +static FILE string[1] = +{ + {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1, + _IOFBF | __MODE_WRITE} +}; + + int rv; + string->bufpos = sp; + rv = vfprintf(string,fmt,ap); + *(string->bufpos) = 0; + return rv; +} + +#ifndef __HAS_NO_FLOATS__ +int (*__fp_print)() = 0; +#endif + +static int prtfld(FILE *op, unsigned char *buf, + int ljustf, char sign, char pad, int width, int preci, int buffer_mode) +/* + * Output the given field in the manner specified by the arguments. Return + * the number of characters output. + */ +{ + register int cnt = 0, len; + register unsigned char ch; + + len = strlen(buf); + + if (*buf == '-') + sign = *buf++; + else if (sign) + len++; + + if ((preci != -1) && (len > preci)) /* limit max data width */ + len = preci; + + if (width < len) /* flexible field width or width overflow */ + width = len; + + /* + * at this point: width = total field width len = actual data width + * (including possible sign character) + */ + cnt = width; + width -= len; + + while (width || len) + { + if (!ljustf && width) /* left padding */ + { + if (len && sign && (pad == '0')) + goto showsign; + ch = pad; + --width; + } + else if (len) + { + if (sign) + { + showsign:ch = sign; /* sign */ + sign = '\0'; + } + else + ch = *buf++; /* main field */ + --len; + } + else + { + ch = pad; /* right padding */ + --width; + } + putc(ch, op); + if( ch == '\n' && buffer_mode == _IOLBF ) fflush(op); + } + + return (cnt); +} + +int vfprintf(FILE *op, const char *fmt, va_list ap) +{ + register int i, cnt = 0, ljustf, lval; + int preci, dpoint, width; + char pad, sign, radix, hash; + register char *ptmp; + char tmp[64], *ltostr(), *ultostr(); + int buffer_mode; + + /* This speeds things up a bit for unbuffered */ + buffer_mode = (op->mode&__MODE_BUF); + op->mode &= (~__MODE_BUF); + + while (*fmt) + { + if (*fmt == '%') + { + if( buffer_mode == _IONBF ) fflush(op); + ljustf = 0; /* left justify flag */ + sign = '\0'; /* sign char & status */ + pad = ' '; /* justification padding char */ + width = -1; /* min field width */ + dpoint = 0; /* found decimal point */ + preci = -1; /* max data width */ + radix = 10; /* number base */ + ptmp = tmp; /* pointer to area to print */ + hash = 0; + lval = (sizeof(int)==sizeof(long)); /* long value flaged */ + fmtnxt: + i = 0; + for(;;) + { + ++fmt; + if(*fmt < '0' || *fmt > '9' ) break; + i = (i * 10) + (*fmt - '0'); + if (dpoint) + preci = i; + else if (!i && (pad == ' ')) + { + pad = '0'; + goto fmtnxt; + } + else + width = i; + } + + switch (*fmt) + { + case '\0': /* early EOS */ + --fmt; + goto charout; + + case '-': /* left justification */ + ljustf = 1; + goto fmtnxt; + + case ' ': + case '+': /* leading sign flag */ + sign = *fmt; + goto fmtnxt; + + case '*': /* parameter width value */ + i = va_arg(ap, int); + if (dpoint) + preci = i; + else + width = i; + goto fmtnxt; + + case '.': /* secondary width field */ + dpoint = 1; + goto fmtnxt; + + case 'l': /* long data */ + lval = 1; + goto fmtnxt; + + case 'h': /* short data */ + lval = 0; + goto fmtnxt; + + case 'd': /* Signed decimal */ + case 'i': + ptmp = ltostr((long) ((lval) + ? va_arg(ap, long) + : va_arg(ap, short)), + 10); + goto printit; + + case 'b': /* Unsigned binary */ + radix = 2; + goto usproc; + + case 'o': /* Unsigned octal */ + radix = 8; + goto usproc; + + case 'p': /* Pointer */ + lval = (sizeof(char*) == sizeof(long)); + pad = '0'; + width = 6; + preci = 8; + /* fall thru */ + + case 'x': /* Unsigned hexadecimal */ + case 'X': + radix = 16; + /* fall thru */ + + case 'u': /* Unsigned decimal */ + usproc: + ptmp = ultostr((unsigned long) ((lval) + ? va_arg(ap, unsigned long) + : va_arg(ap, unsigned short)), + radix); + if( hash && radix == 8 ) { width = strlen(ptmp)+1; pad='0'; } + goto printit; + + case '#': + hash=1; + goto fmtnxt; + + case 'c': /* Character */ + ptmp[0] = va_arg(ap, int); + ptmp[1] = '\0'; + goto nopad; + + case 's': /* String */ + ptmp = va_arg(ap, char*); + nopad: + sign = '\0'; + pad = ' '; + printit: + cnt += prtfld(op, ptmp, ljustf, + sign, pad, width, preci, buffer_mode); + break; + +#ifndef __HAS_NO_FLOATS__ + case 'e': /* float */ + case 'f': + case 'g': + case 'E': + case 'G': + if ( __fp_print ) + { + (*__fp_print)(&va_arg(ap, double), *fmt, preci, ptmp); + preci = -1; + goto printit; + } + /* FALLTHROUGH if no floating printf available */ +#endif + + default: /* unknown character */ + goto charout; + } + } + else + { + charout: + putc(*fmt, op); /* normal char out */ + ++cnt; + if( *fmt == '\n' && buffer_mode == _IOLBF ) fflush(op); + } + ++fmt; + } + op->mode |= buffer_mode; + if( buffer_mode == _IONBF ) fflush(op); + if( buffer_mode == _IOLBF ) op->bufwrite = op->bufstart; + return (cnt); +} + +int printf(const char * fmt, ...) +{ + va_list ptr; + int rv; + va_start(ptr, fmt); + rv = vfprintf(stdout,fmt,ptr); + va_end(ptr); + return rv; +} + +int fprintf(FILE * fp, const char * fmt, ...) +{ + va_list ptr; + int rv; + va_start(ptr, fmt); + rv = vfprintf(fp,fmt,ptr); + va_end(ptr); + return rv; +} + +#ifdef L_fp_print +#ifndef __HAS_NO_FLOATS__ + +#ifdef __AS386_16__ +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .word ___xfpcvt ! Pointer to the autorun function + .text ! So the function after is also in the correct seg. +#endasm +#endif + +#ifdef __AS386_32__ +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .long ___xfpcvt ! Pointer to the autorun function + .text ! So the function after is also in the correct seg. +#endasm +#endif + +void +__fp_print_func(pval, style, preci, ptmp) + double * pval; + int style; + int preci; + char * ptmp; +{ + int decpt, negative; + char * cvt; + double val = *pval; + + if (preci < 0) preci = 6; + + cvt = fcvt(val, preci, &decpt, &negative); + if(negative) + *ptmp++ = '-'; + + if (decpt<0) { + *ptmp++ = '0'; + *ptmp++ = '.'; + while(decpt<0) { + *ptmp++ = '0'; decpt++; + } + } + + while(*cvt) { + *ptmp++ = *cvt++; + if (decpt == 1) + *ptmp++ = '.'; + decpt--; + } + + while(decpt > 0) { + *ptmp++ = '0'; + decpt--; + } +} + +void +__xfpcvt() +{ + extern int (*__fp_print)(); + __fp_print = __fp_print_func; +} + +#endif +#endif diff --git a/libc/stdio/scanf.c b/libc/stdio/scanf.c new file mode 100644 index 000000000..14598fb07 --- /dev/null +++ b/libc/stdio/scanf.c @@ -0,0 +1,514 @@ +/* + * This file based on scanf.c from 'Dlibs' on the atari ST (RdeBath) + * + * 19-OCT-88: Dale Schumacher + * > John Stanley has again been a great help in debugging, particularly + * > with the printf/scanf functions which are his creation. + * + * Dale Schumacher 399 Beacon Ave. + * (alias: Dalnefre') St. Paul, MN 55104 + * dal@syntel.UUCP United States of America + * "It's not reality that's important, but how you perceive things." + * + */ + +#include +#include +#include + +#if defined(__STDC__) && !defined(__FIRST_ARG_IN_AX__) +#include +#define va_strt va_start +#else +#include +#define va_strt(p,i) va_start(p) +#endif + +//----------------------------------------------------------------------------- + +int scanf (const char * fmt, ...) +{ + va_list ptr; + int rv; + va_strt(ptr, fmt); + rv = vfscanf(stdin,fmt,ptr); + va_end(ptr); + return rv; +} + +//----------------------------------------------------------------------------- + +int sscanf (const char * str, const char * format, ...) +{ +static FILE string[1] = +{ + {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1, + _IOFBF | __MODE_READ} +}; + + va_list ptr; + int rv; + va_strt(ptr, format); + string->bufpos = str; + rv = vfscanf(string,format,ptr); + va_end(ptr); + return rv; +} + +//----------------------------------------------------------------------------- + +int fscanf(FILE * fp, const char * fmt, ...) +{ + va_list ptr; + int rv; + va_strt(ptr, fmt); + rv = vfscanf(fp,fmt,ptr); + va_end(ptr); + return rv; +} + +#ifdef L_vscanf +int vscanf(fmt, ap) +__const char *fmt; +va_list ap; +{ + return vfscanf(stdin,fmt,ap); +} +#endif + +#ifdef L_vsscanf +int vsscanf(sp, fmt, ap) +char * sp; +__const char *fmt; +{ +static FILE string[1] = +{ + {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1, + _IOFBF | __MODE_READ} +}; + + string->bufpos = sp; + return vfscanf(string,fmt,ap); +} +#endif + +/* #define skip() do{c=getc(fp); if (c<1) goto done;}while(isspace(c))*/ + +#define skip() while(isspace(c)) { if ((c=getc(fp))<1) goto done; } + +#if FLOATS +/* fp scan actions */ +#define F_NADA 0 /* just change state */ +#define F_SIGN 1 /* set sign */ +#define F_ESIGN 2 /* set exponent's sign */ +#define F_INT 3 /* adjust integer part */ +#define F_FRAC 4 /* adjust fraction part */ +#define F_EXP 5 /* adjust exponent part */ +#define F_QUIT 6 + +#define NSTATE 8 +#define FS_INIT 0 /* initial state */ +#define FS_SIGNED 1 /* saw sign */ +#define FS_DIGS 2 /* saw digits, no . */ +#define FS_DOT 3 /* saw ., no digits */ +#define FS_DD 4 /* saw digits and . */ +#define FS_E 5 /* saw 'e' */ +#define FS_ESIGN 6 /* saw exp's sign */ +#define FS_EDIGS 7 /* saw exp's digits */ + +#define FC_DIG 0 +#define FC_DOT 1 +#define FC_E 2 +#define FC_SIGN 3 + +/* given transition,state do what action? */ +int fp_do[][NSTATE] = { + {F_INT,F_INT,F_INT, + F_FRAC,F_FRAC, + F_EXP,F_EXP,F_EXP}, /* see digit */ + {F_NADA,F_NADA,F_NADA, + F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT}, /* see '.' */ + {F_QUIT,F_QUIT, + F_NADA,F_QUIT,F_NADA, + F_QUIT,F_QUIT,F_QUIT}, /* see e/E */ + {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT, + F_ESIGN,F_QUIT,F_QUIT}, /* see sign */ +}; +/* given transition,state what is new state? */ +int fp_ns[][NSTATE] = { + {FS_DIGS,FS_DIGS,FS_DIGS, + FS_DD,FS_DD, + FS_EDIGS,FS_EDIGS,FS_EDIGS}, /* see digit */ + {FS_DOT,FS_DOT,FS_DD, + }, /* see '.' */ + {0,0, + FS_E,0,FS_E, + }, /* see e/E */ + {FS_SIGNED,0,0,0,0, + FS_ESIGN,0,0}, /* see sign */ +}; +/* which states are valid terminators? */ +int fp_sval[NSTATE] = { + 0,0,1,0,1,0,0,1 +}; +#endif + +vfscanf(fp, fmt, ap) +register FILE *fp; +register char *fmt; +va_list ap; + +{ + register long n; + register int c, width, lval, cnt = 0; + int store, neg, base, wide1, endnull, rngflag, c2; + register unsigned char *p; + unsigned char delim[128], digits[17], *q; +#if FLOATS + long frac, expo; + int eneg, fraclen, fstate, trans; + double fx, fp_scan(); +#endif + + if (!*fmt) + return (0); + + c = getc(fp); + while (c > 0) + { + store = 0; + if (*fmt == '%') + { + n = 0; + width = -1; + wide1 = 1; + base = 10; + lval = (sizeof(long) == sizeof(int)); + store = 1; + endnull = 1; + neg = -1; + + strcpy(delim, "\011\012\013\014\015 "); + strcpy(digits, "0123456789ABCDEF"); + + if (fmt[1] == '*') + { + endnull = store = 0; + ++fmt; + } + + while (isdigit(*++fmt))/* width digit(s) */ + { + if (width == -1) + width = 0; + wide1 = width = (width * 10) + (*fmt - '0'); + } + --fmt; + fmtnxt: + ++fmt; + switch (tolower(*fmt)) /* tolower() is a MACRO! */ + { + case '*': + endnull = store = 0; + goto fmtnxt; + + case 'l': /* long data */ + lval = 1; + goto fmtnxt; + case 'h': /* short data */ + lval = 0; + goto fmtnxt; + + case 'i': /* any-base numeric */ + base = 0; + goto numfmt; + + case 'b': /* unsigned binary */ + base = 2; + goto numfmt; + + case 'o': /* unsigned octal */ + base = 8; + goto numfmt; + + case 'x': /* unsigned hexadecimal */ + base = 16; + goto numfmt; + + case 'd': /* SIGNED decimal */ + neg = 0; + /* FALL-THRU */ + + case 'u': /* unsigned decimal */ + numfmt:skip(); + + if (isupper(*fmt)) + lval = 1; + + if (!base) + { + base = 10; + neg = 0; + if (c == '%') + { + base = 2; + goto skip1; + } + else if (c == '0') + { + c = getc(fp); + if (c < 1) + goto savnum; + if ((c != 'x') + && (c != 'X')) + { + base = 8; + digits[8] = '\0'; + goto zeroin; + } + base = 16; + goto skip1; + } + } + + if ((neg == 0) && (base == 10) + && ((neg = (c == '-')) || (c == '+'))) + { + skip1: + c = getc(fp); + if (c < 1) + goto done; + } + + digits[base] = '\0'; + p = ((unsigned char *) + strchr(digits, toupper(c))); + + if ((!c || !p) && width) + goto done; + + while (p && width-- && c) + { + n = (n * base) + (p - digits); + c = getc(fp); + zeroin: + p = ((unsigned char *) + strchr(digits, toupper(c))); + } + savnum: + if (store) + { + if (neg == 1) + n = -n; + if (lval) + *va_arg(ap, long*) = n; + else + *va_arg(ap, short*) = n; + ++cnt; + } + break; + +#if FLOATS + case 'e': /* float */ + case 'f': + case 'g': + skip(); + + if (isupper(*fmt)) + lval = 1; + + fstate = FS_INIT; + neg = 0; + eneg = 0; + n = 0; + frac = 0; + expo = 0; + fraclen = 0; + + while (c && width--) + { + if (c >= '0' && c <= '9') + trans = FC_DIG; + else if (c == '.') + trans = FC_DOT; + else if (c == '+' || c == '-') + trans = FC_SIGN; + else if (tolower(c) == 'e') + trans = FC_E; + else + goto fdone; + + switch (fp_do[trans][fstate]) + { + case F_SIGN: + neg = (c == '-'); + break; + case F_ESIGN: + eneg = (c == '-'); + break; + case F_INT: + n = 10 * n + (c - '0'); + break; + case F_FRAC: + frac = 10 * frac + (c - '0'); + fraclen++; + break; + case F_EXP: + expo = 10 * expo + (c - '0'); + break; + case F_QUIT: + goto fdone; + } + fstate = fp_ns[trans][fstate]; + c = getc(fp); + } + + fdone: + if (!fp_sval[fstate]) + goto done; + if (store) + { + fx = fp_scan(neg, eneg, n, frac, expo, fraclen); + if (lval) + *va_arg(ap, double *) = fx; + else + *va_arg(ap, float *) = fx; + ++cnt; + } + break; +#endif + + case 'c': /* character data */ + width = wide1; + lval = endnull = 0; + delim[0] = '\0'; + goto strproc; + + case '[': /* string w/ delimiter set */ + + /* get delimiters */ + p = delim; + + if (*++fmt == '^') + { + fmt++; + lval = 0; + } + else + lval = 1; + + rngflag = 2; + if ((*fmt == ']') || (*fmt == '-')) + { + *p++ = *fmt++; + rngflag = 0; + } + + while (*fmt != ']') + { + if (*fmt == '\0') + goto done; + switch (rngflag) + { + case 1: + c2 = *(p - 2); + if (c2 <= *fmt) + { + p -= 2; + while (c2 < *fmt) + *p++ = c2++; + rngflag = 2; + break; + } + /* fall thru intentional */ + + case 0: + rngflag = (*fmt == '-'); + break; + + case 2: + rngflag = 0; + } + + *p++ = *fmt++; + } + + *p = '\0'; + goto strproc; + + case 's': /* string data */ + lval = 0; + skip(); + strproc: + /* process string */ + p = va_arg(ap, unsigned char *); + + /* if the 1st char fails, match fails */ + if (width) + { + q = ((unsigned char *) + strchr(delim, c)); + if ((c < 1) || lval == (q==0)) + { + if (endnull) + *p = '\0'; + goto done; + } + } + + for (;;) /* FOREVER */ + { + if (store) + *p++ = c; + if (((c = getc(fp)) < 1) || + (--width == 0)) + break; + + q = ((unsigned char *) + strchr(delim, c)); + if (lval == (q==0)) + break; + } + + if (store) + { + if (endnull) + *p = '\0'; + ++cnt; + } + break; + + case '\0': /* early EOS */ + --fmt; + /* FALL THRU */ + + default: + goto cmatch; + } + } + else if (isspace(*fmt)) /* skip whitespace */ + { + skip(); + } + else + { /* normal match char */ + cmatch: + if (c != *fmt) + break; + c = getc(fp); + } + + if (!*++fmt) + break; + } + + done: /* end of scan */ + if ((c == EOF) && (cnt == 0)) + return (EOF); + + if( c != EOF ) + ungetc(c, fp); + return (cnt); +} + +//----------------------------------------------------------------------------- diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c new file mode 100644 index 000000000..f15a9dff3 --- /dev/null +++ b/libc/stdio/stdio.c @@ -0,0 +1,833 @@ +/* Copyright (C) 1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* This is an implementation of the C standard IO package. + */ + +#include + +#include +#include +#include +#include +#include +#include + + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +extern FILE *__IO_list; /* For fflush at exit */ + +#ifdef __AS386_16__ +#define Inline_init +#endif + +#ifdef __AS386_32__ +#define Inline_init +#endif + +#ifndef Inline_init +#define Inline_init __io_init_vars() +#endif + +#define buferr (stderr->unbuf) /* Stderr is unbuffered */ + +FILE *__IO_list = 0; /* For fflush at exit */ + +static char bufin[BUFSIZ]; +static char bufout[BUFSIZ]; +#ifndef buferr +static char buferr[BUFSIZ]; +#endif + +FILE stdin[1] = +{ + {bufin, bufin, bufin, bufin, bufin + sizeof(bufin), + 0, _IOFBF | __MODE_READ | __MODE_IOTRAN} +}; + +FILE stdout[1] = +{ + {bufout, bufout, bufout, bufout, bufout + sizeof(bufout), + 1, _IOFBF | __MODE_WRITE | __MODE_IOTRAN} +}; + +FILE stderr[1] = +{ + {buferr, buferr, buferr, buferr, buferr + sizeof(buferr), + 2, _IONBF | __MODE_WRITE | __MODE_IOTRAN} +}; + +/* Call the stdio initiliser; it's main job it to call atexit */ + +#ifdef __AS386_16__ +#define STATIC static + +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .word ___io_init_vars ! Pointer to the autorun function + .text ! So the function after is also in the correct seg. +#endasm +#endif + +#ifdef __AS386_32__ +#define STATIC static + +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .long ___io_init_vars ! Pointer to the autorun function + .text ! So the function after is also in the correct seg. +#endasm +#endif + +#ifndef STATIC +#define STATIC +#endif + +STATIC int +__stdio_close_all() +{ + FILE *fp; + fflush(stdout); + fflush(stderr); + for (fp = __IO_list; fp; fp = fp->next) + { + fflush(fp); + close(fp->fd); + /* Note we're not de-allocating the memory */ + /* There doesn't seem to be much point :-) */ + fp->fd = -1; + } +} + +STATIC void +__io_init_vars() +{ +#ifndef __AS386_16__ +#ifndef __AS386_32__ + static int first_time = 1; + if( !first_time ) return ; + first_time = 0; +#endif +#endif + if (isatty(1)) + stdout->mode |= _IOLBF; + atexit(__stdio_close_all); +} + +int fputc (int ch, FILE *fp) +{ + register int v; + Inline_init; + + /* If last op was a read ... note fflush may change fp->mode and ret OK */ + if ((fp->mode & __MODE_READING) && fflush(fp)) + return EOF; + + v = fp->mode; + /* Can't write if there's been an EOF or error then return EOF */ + if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE) + return EOF; + + /* In MSDOS translation mode */ +#if __MODE_IOTRAN && !O_BINARY + if (ch == '\n' && (v & __MODE_IOTRAN) && fputc('\r', fp) == EOF) + return EOF; +#endif + + /* Buffer is full */ + if (fp->bufpos >= fp->bufend && fflush(fp)) + return EOF; + + /* Right! Do it! */ + *(fp->bufpos++) = ch; + fp->mode |= __MODE_WRITING; + + /* Unbuffered or Line buffered and end of line */ + if (((ch == '\n' && (v & _IOLBF)) || (v & _IONBF)) + && fflush(fp)) + return EOF; + + /* Can the macro handle this by itself ? */ + if (v & (__MODE_IOTRAN | _IOLBF | _IONBF)) + fp->bufwrite = fp->bufstart; /* Nope */ + else + fp->bufwrite = fp->bufend; /* Yup */ + + /* Correct return val */ + return (unsigned char) ch; +} + +int fgetc(FILE *fp) +{ + int ch; + + if (fp->mode & __MODE_WRITING) + fflush(fp); + + try_again: + /* Can't read or there's been an EOF or error then return EOF */ + if ((fp->mode & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ) + return EOF; + + /* Nothing in the buffer - fill it up */ + if (fp->bufpos >= fp->bufread) + { + /* Bind stdin to stdout if it's open and line buffered */ + if( fp == stdin && stdout->fd >= 0 && (stdout->mode & _IOLBF )) + fflush(stdout); + + fp->bufpos = fp->bufread = fp->bufstart; + ch = fread(fp->bufpos, 1, fp->bufend - fp->bufstart, fp); + if (ch == 0) + return EOF; + fp->bufread += ch; + fp->mode |= __MODE_READING; + fp->mode &= ~__MODE_UNGOT; + } + ch = *(fp->bufpos++); + +#if __MODE_IOTRAN && !O_BINARY + /* In MSDOS translation mode; WARN: Doesn't work with UNIX macro */ + if (ch == '\r' && (fp->mode & __MODE_IOTRAN)) + goto try_again; +#endif + + return ch; +} + +int fflush(FILE *fp) +{ + int len, cc, rv=0; + char * bstart; + if (fp == NULL) /* On NULL flush the lot. */ + { + if (fflush(stdin)) + return EOF; + if (fflush(stdout)) + return EOF; + if (fflush(stderr)) + return EOF; + + for (fp = __IO_list; fp; fp = fp->next) + if (fflush(fp)) + return EOF; + + return 0; + } + + /* If there's output data pending */ + if (fp->mode & __MODE_WRITING) + { + len = fp->bufpos - fp->bufstart; + + if (len) + { + bstart = fp->bufstart; + /* + * The loop is so we don't get upset by signals or partial writes. + */ + do + { + cc = write(fp->fd, bstart, len); + if( cc > 0 ) + { + bstart+=cc; len-=cc; + } + } + while ( len>0 && (cc>0 || (cc == -1 && errno == EINTR))); + /* + * If we get here with len!=0 there was an error, exactly what to + * do about it is another matter ... + * + * I'll just clear the buffer. + */ + if (len) + { + fp->mode |= __MODE_ERR; + rv = EOF; + } + } + } + /* If there's data in the buffer sychronise the file positions */ + else if (fp->mode & __MODE_READING) + { + /* Humm, I think this means sync the file like fpurge() ... */ + /* Anyway the user isn't supposed to call this function when reading */ + + len = fp->bufread - fp->bufpos; /* Bytes buffered but unread */ + /* If it's a file, make it good */ + if (len > 0 && lseek(fp->fd, (long)-len, 1) < 0) + { + /* Hummm - Not certain here, I don't think this is reported */ + /* + * fp->mode |= __MODE_ERR; return EOF; + */ + } + } + + /* All done, no problem */ + fp->mode &= (~(__MODE_READING|__MODE_WRITING|__MODE_EOF|__MODE_UNGOT)); + fp->bufread = fp->bufwrite = fp->bufpos = fp->bufstart; + return rv; +} + +/* Nothing special here ... */ +char *fgets(char *s, size_t count, FILE *f) +{ + char *ret; + register size_t i; + register int ch; + + ret = s; + for (i = count-1; i > 0; i--) + { + ch = getc(f); + if (ch == EOF) + { + if (s == ret) + return 0; + break; + } + *s++ = (char) ch; + if (ch == '\n') + break; + } + *s = 0; + + if (ferror(f)) + return 0; + return ret; +} + +char * +gets(str) /* BAD function; DON'T use it! */ +char *str; +{ + /* Auwlright it will work but of course _your_ program will crash */ + /* if it's given a too long line */ + register char *p = str; + register int c; + + while (((c = getc(stdin)) != EOF) && (c != '\n')) + *p++ = c; + *p = '\0'; + return (((c == EOF) && (p == str)) ? NULL : str); /* NULL == EOF */ +} + +int fputs(char *str, FILE *fp) +{ + register int n = 0; + while (*str) + { + if (putc(*str++, fp) == EOF) + return (EOF); + ++n; + } + return (n); +} + +int +puts(str) +char *str; +{ + register int n; + + if (((n = fputs(str, stdout)) == EOF) + || (putc('\n', stdout) == EOF)) + return (EOF); + return (++n); +} + +/* + * fread will often be used to read in large chunks of data calling read() + * directly can be a big win in this case. Beware also fgetc calls this + * function to fill the buffer. + * + * This ignores __MODE__IOTRAN; probably exactly what you want. (It _is_ what + * fgetc wants) + */ +int fread(char *buf, int size, int nelm, FILE *fp) +{ + int len, v; + unsigned bytes, got = 0; + Inline_init; + + v = fp->mode; + + /* Want to do this to bring the file pointer up to date */ + if (v & __MODE_WRITING) + fflush(fp); + + /* Can't read or there's been an EOF or error then return zero */ + if ((v & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ) + return 0; + + /* This could be long, doesn't seem much point tho */ + bytes = size * nelm; + + len = fp->bufread - fp->bufpos; + if (len >= bytes) /* Enough buffered */ + { + memcpy(buf, fp->bufpos, (unsigned) bytes); + fp->bufpos += bytes; + return nelm; + } + else if (len > 0) /* Some buffered */ + { + memcpy(buf, fp->bufpos, len); + fp->bufpos += len; + got = len; + } + + /* Need more; do it with a direct read */ + len = read(fp->fd, buf + got, (unsigned) (bytes - got)); + + /* Possibly for now _or_ later */ + if (len < 0) + { + fp->mode |= __MODE_ERR; + len = 0; + } + else if (len == 0) + fp->mode |= __MODE_EOF; + + return (got + len) / size; +} + +/* + * Like fread, fwrite will often be used to write out large chunks of + * data; calling write() directly can be a big win in this case. + * + * But first we check to see if there's space in the buffer. + * + * Again this ignores __MODE__IOTRAN. + */ +int fwrite(char *buf, int size, int nelm, FILE *fp) +{ + register int v; + int len; + unsigned bytes, put; + + /* If last op was a read ... note fflush may change fp->mode and ret OK */ + if ((fp->mode & __MODE_READING) && fflush(fp)) + return 0; + + v = fp->mode; + /* Can't write or there's been an EOF or error then return 0 */ + if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE) + return 0; + + /* This could be long, doesn't seem much point tho */ + bytes = size * nelm; + + len = fp->bufend - fp->bufpos; + + /* Flush the buffer if not enough room */ + if (bytes > len) + if (fflush(fp)) + return 0; + + len = fp->bufend - fp->bufpos; + if (bytes <= len) /* It'll fit in the buffer ? */ + { + register int do_flush=0; + fp->mode |= __MODE_WRITING; + memcpy(fp->bufpos, buf, bytes); + if (v & _IOLBF) + { + if(memchr(fp->bufpos, '\n', bytes)) + do_flush=1; + } + fp->bufpos += bytes; + + /* If we're unbuffered or line buffered and have seen nl */ + if (do_flush || (v & _IONBF) != 0) + fflush(fp); + + return nelm; + } + else + /* Too big for the buffer */ + { + put = bytes; + do + { + len = write(fp->fd, buf, bytes); + if( len > 0 ) + { + buf+=len; bytes-=len; + } + } + while (len > 0 || (len == -1 && errno == EINTR)); + + if (len < 0) + fp->mode |= __MODE_ERR; + + put -= bytes; + } + + return put / size; +} + +#ifdef L_rewind +void +rewind(fp) +FILE * fp; +{ + fseek(fp, (long)0, 0); + clearerr(fp); +} +#endif + +int +fseek(fp, offset, ref) +FILE *fp; +long offset; +int ref; +{ +#if 1 + /* if __MODE_READING and no ungetc ever done can just move pointer */ + + if ( (fp->mode &(__MODE_READING | __MODE_UNGOT)) == __MODE_READING && + ( ref == SEEK_SET || ref == SEEK_CUR )) + { + long fpos = lseek(fp->fd, 0L, SEEK_CUR); + if( fpos == -1 ) return EOF; + + if( ref == SEEK_CUR ) + { + ref = SEEK_SET; + offset = fpos + offset + fp->bufpos - fp->bufread; + } + if( ref == SEEK_SET ) + { + if ( offset < fpos && offset >= fpos + fp->bufstart - fp->bufread ) + { + fp->bufpos = offset - fpos + fp->bufread; + return 0; + } + } + } +#endif + + /* Use fflush to sync the pointers */ + + if (fflush(fp) == EOF) + return EOF; + if (lseek(fp->fd, offset, ref) < 0) + return EOF; + return 0; +} + +#ifdef L_ftell +long ftell(fp) +FILE * fp; +{ + long rv; + if (fflush(fp) == EOF) + return EOF; + return lseek(fp->fd, 0L, SEEK_CUR); +} +#endif + +//----------------------------------------------------------------------------- + +FILE * fopen (char * file, char * mode) +{ + return __fopen(file, -1, (FILE*)0, mode); +} + +//----------------------------------------------------------------------------- + +FILE * +freopen(file, mode, fp) +char * file; +char * mode; +FILE * fp; +{ + return __fopen(file, -1, fp, mode); +} + +//----------------------------------------------------------------------------- + +FILE * +fdopen(file, mode) +int file; +char * mode; +{ + return __fopen((char*)0, file, (FILE*)0, mode); +} + +//----------------------------------------------------------------------------- + +FILE * __fopen (char * fname, int fd, FILE * fp, char * mode) +{ + int open_mode = 0; +#if __MODE_IOTRAN && !O_BINARY + int do_iosense = 1; +#endif + int fopen_mode = 0; + FILE *nfp = 0; + + /* If we've got an fp close the old one (freopen) */ + if (fp) + { + /* Careful, don't de-allocate it */ + fopen_mode |= (fp->mode & (__MODE_BUF | __MODE_FREEFIL | __MODE_FREEBUF)); + fp->mode &= ~(__MODE_FREEFIL | __MODE_FREEBUF); + fclose(fp); + } + + /* decode the new open mode */ + while (*mode) + switch (*mode++) + { + case 'r': + fopen_mode |= __MODE_READ; + break; + case 'w': + fopen_mode |= __MODE_WRITE; + open_mode = (O_CREAT | O_TRUNC); + break; + case 'a': + fopen_mode |= __MODE_WRITE; + open_mode = (O_CREAT | O_APPEND); + break; + case '+': + fopen_mode |= __MODE_RDWR; + break; +#if __MODE_IOTRAN || O_BINARY + case 'b': /* Binary */ + fopen_mode &= ~__MODE_IOTRAN; + open_mode |= O_BINARY; +#if __MODE_IOTRAN && !O_BINARY + do_iosense=0; +#endif + break; + case 't': /* Text */ + fopen_mode |= __MODE_IOTRAN; +#if __MODE_IOTRAN && !O_BINARY + do_iosense=0; +#endif + break; +#endif + } + + /* Add in the read/write options to mode for open() */ + switch (fopen_mode & (__MODE_READ | __MODE_WRITE)) + { + case 0: + return 0; + case __MODE_READ: + open_mode |= O_RDONLY; + break; + case __MODE_WRITE: + open_mode |= O_WRONLY; + break; + default: + open_mode |= O_RDWR; + break; + } + + /* Allocate the (FILE) before we do anything irreversable */ + if (fp == 0) + { + nfp = malloc(sizeof(FILE)); + if (nfp == 0) + return 0; + } + + /* Open the file itself */ + if (fname) + fd = open(fname, open_mode, 0666); + if (fd < 0) /* Grrrr */ + { + if (nfp) + free(nfp); + if (fp) + { + fp->mode |= fopen_mode; + fclose(fp); /* Deallocate if required */ + } + return 0; + } + + /* If this isn't freopen create a (FILE) and buffer for it */ + if (fp == 0) + { + fp = nfp; + fp->next = __IO_list; + __IO_list = fp; + + fp->mode = __MODE_FREEFIL; + if( isatty(fd) ) + { + fp->mode |= _IOLBF; +#if __MODE_IOTRAN && !O_BINARY + if( do_iosense ) fopen_mode |= __MODE_IOTRAN; +#endif + } + else + fp->mode |= _IOFBF; + fp->bufstart = malloc(BUFSIZ); + if (fp->bufstart == 0) /* Oops, no mem */ + { /* Humm, full buffering with a two(!) byte + * buffer. */ + fp->bufstart = fp->unbuf; + fp->bufend = fp->unbuf + sizeof(fp->unbuf); + } + else + { + fp->bufend = fp->bufstart + BUFSIZ; + fp->mode |= __MODE_FREEBUF; + } + } + + /* Ok, file's ready clear the buffer and save important bits */ + fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; + fp->mode |= fopen_mode; + fp->fd = fd; + + return fp; +} + +//----------------------------------------------------------------------------- + +int fclose (FILE *fp) +{ + int rv = 0; + + if (fp == 0) + { + errno = EINVAL; + return EOF; + } + if (fp->fd != -1) + { + if (fflush(fp)) + return EOF; + + if (close(fp->fd)) + rv = EOF; + fp->fd = -1; + } + + if (fp->mode & __MODE_FREEBUF) + { + free(fp->bufstart); + fp->mode &= ~__MODE_FREEBUF; + fp->bufstart = fp->bufend = 0; + } + + if (fp->mode & __MODE_FREEFIL) + { + FILE *prev = 0, *ptr; + fp->mode = 0; + + for (ptr = __IO_list; ptr && ptr != fp; ptr = ptr->next) + ; + if (ptr == fp) + { + if (prev == 0) + __IO_list = fp->next; + else + prev->next = fp->next; + } + free(fp); + } + else + fp->mode = 0; + + return rv; +} + +void +setbuffer(fp, buf, size) +FILE * fp; +char * buf; +int size; +{ + fflush(fp); + if( fp->mode & __MODE_FREEBUF ) free(fp->bufstart); + fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF); + + if( buf == 0 ) + { + fp->bufstart = fp->unbuf; + fp->bufend = fp->unbuf + sizeof(fp->unbuf); + fp->mode |= _IONBF; + } + else + { + fp->bufstart = buf; + fp->bufend = buf+size; + fp->mode |= _IOFBF; + } + fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; +} + +int setvbuf(fp, buf, mode, size) +FILE * fp; +char * buf; +int mode; +size_t size; +{ + int rv = 0; + fflush(fp); + if( fp->mode & __MODE_FREEBUF ) free(fp->bufstart); + fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF); + fp->bufstart = fp->unbuf; + fp->bufend = fp->unbuf + sizeof(fp->unbuf); + fp->mode |= _IONBF; + + if( mode == _IOFBF || mode == _IOLBF ) + { + if( size <= 0 ) size = BUFSIZ; + if( buf == 0 ) + { + if( (buf = malloc(size)) != 0 ) + fp->mode |= __MODE_FREEBUF; + else rv = EOF; + } + if( buf ) + { + fp->bufstart = buf; + fp->bufend = buf+size; + fp->mode &= ~__MODE_BUF; + fp->mode |= mode; + } + } + fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; + return rv; +} + +//----------------------------------------------------------------------------- + +int ungetc (int c, FILE * fp) +{ + if (fp->mode & __MODE_WRITING) + fflush(fp); + + /* Can't read or there's been an error then return EOF */ + if ((fp->mode & (__MODE_READ | __MODE_ERR)) != __MODE_READ) + return EOF; + + /* Can't do fast fseeks */ + fp->mode |= __MODE_UNGOT; + + if( fp->bufpos > fp->bufstart ) + return *--fp->bufpos = (unsigned char) c; + else if( fp->bufread == fp->bufstart ) + return *fp->bufread++ = (unsigned char) c; + else + return EOF; +} + +//----------------------------------------------------------------------------- diff --git a/libc/string/Makefile b/libc/string/Makefile new file mode 100644 index 000000000..7d648870f --- /dev/null +++ b/libc/string/Makefile @@ -0,0 +1,29 @@ +# Makefile of /libc/string module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS = \ + bzero.c \ + strcasecmp.c \ + strcspn.c \ + string.c \ + strncasecmp.c \ + strpbrk.c \ + strspn.c \ + strstr.c \ + strtok.c \ + # end of list + +OBJS = $(SRCS:.c=.o) + +.PHONY: all + +all: $(LIBC) + +$(OBJS): $(SRCS) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +clean: + rm -f *.o diff --git a/libc/string/bzero.c b/libc/string/bzero.c new file mode 100644 index 000000000..21853df59 --- /dev/null +++ b/libc/string/bzero.c @@ -0,0 +1,6 @@ +#include + +void bzero (void * s, size_t n) +{ + (void) memset (s, '\0', n); +} diff --git a/libc/string/strcasecmp.c b/libc/string/strcasecmp.c new file mode 100644 index 000000000..0e7b0388f --- /dev/null +++ b/libc/string/strcasecmp.c @@ -0,0 +1,26 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include +#include + +int +strcasecmp(s, d) +char *s; +char *d; +{ + for(;;) + { + if( *s != *d ) + { + if( tolower(*s) != tolower(*d) ) + return *s - *d; + } + else if( *s == '\0' ) break; + s++; d++; + } + return 0; +} + diff --git a/libc/string/strcspn.c b/libc/string/strcspn.c new file mode 100644 index 000000000..619c8be6b --- /dev/null +++ b/libc/string/strcspn.c @@ -0,0 +1,32 @@ +/* strcspn.c */ + +/* from Schumacher's Atari library, improved */ + +#include + +size_t strcspn(string, set) +register char *string; +char *set; +/* + * Return the length of the sub-string of that consists + * entirely of characters not found in . The terminating '\0' + * in is not considered part of the match set. If the first + * character if is in , 0 is returned. + */ +{ + register char *setptr; + char *start; + + start = string; + while (*string) + { + setptr = set; + do + if (*setptr == *string) + goto break2; + while (*setptr++); + ++string; + } +break2: + return string - start; +} diff --git a/libc/string/string.c b/libc/string/string.c new file mode 100644 index 000000000..1b4f77092 --- /dev/null +++ b/libc/string/string.c @@ -0,0 +1,622 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include +#include + +#ifdef __AS386_16__ +#if __FIRST_ARG_IN_AX__ +#define BCC_AX_ASM /* BCC Assembler that can cope with arg in AX */ +#else +#define BCC_AX_ASM +#define BCC_ASM /* Use 16 bit BCC assembler */ +#endif + +#define PARANOID /* Include extra code for cld and ES register */ +#endif + +/* This is a basic string package; it includes the most used functions + + strlen strcat strcpy strcmp strncat strncpy strncmp strchr strrchr strdup + memcpy memccpy memchr memset memcmp memmove + + These functions are in seperate files. + strpbrk.o strsep.o strstr.o strtok.o strcspn.o + strspn.o strcasecmp.o strncasecmp.o + */ + +/********************** Function strlen ************************************/ + +size_t strlen(const char * str) +{ +#ifdef BCC_AX_ASM +#asm +#if !__FIRST_ARG_IN_AX__ + mov bx,sp +#endif + push di + +#ifdef PARANOID + push es + push ds ! Im not sure if this is needed, so just in case. + pop es + cld +#endif + ! This is almost the same as memchr, but it can + ! stay as a special. + +#if __FIRST_ARG_IN_AX__ + mov di,ax +#else + mov di,[bx+2] +#endif + mov cx,#-1 + xor ax,ax + repne + scasb + not cx + dec cx + mov ax,cx + +#ifdef PARANOID + pop es +#endif + pop di +#endasm +#else + register char * p =(char *) str; + while(*p) p++; + return p-str; +#endif /* ifdef BCC_AX_ASM */ +} + +/********************** Function strcat ************************************/ + +char * strcat(char *d, const char * s) +{ + (void) strcpy(d+strlen(d), s); + return d; +} + +/********************** Function strcpy ************************************/ + +char * strcpy(d, s) +char *d; +const char * s; +{ + /* This is probably the quickest on an 8086 but a CPU with a cache will + * prefer to do this in one pass */ + return memcpy(d, s, strlen(s)+1); +} + +/********************** Function strcmp ************************************/ + +int strcmp(const char *d, const char * s) +{ + /* There are a number of ways to do this and it really does depend on the + types of strings given as to which is better, nevertheless the Glib + method is quite reasonable so we'll take that */ + +#ifdef BCC_AX_ASM +#asm + mov bx,sp + push di + push si + +#ifdef PARANOID + push es + push ds ; Im not sure if this is needed, so just in case. + pop es + cld +#endif + +#if __FIRST_ARG_IN_AX__ + mov di,ax ; dest + mov si,[bx+2] ; source +#else + mov di,[bx+2] ; dest + mov si,[bx+4] ; source +#endif +sc_1: + lodsb + scasb + jne sc_2 ; If bytes are diff skip out. + testb al,al + jne sc_1 ; If this byte in str1 is nul the strings are equal + xor ax,ax ; so return zero + jmp sc_3 +sc_2: + cmc + sbb ax,ax ; Collect correct val (-1,1). + orb al,#1 +sc_3: + +#ifdef PARANOID + pop es +#endif + pop si + pop di +#endasm +#else /* ifdef BCC_AX_ASM */ + register char *s1=(char *)d, *s2=(char *)s, c1,c2; + while((c1= *s1++) == (c2= *s2++) && c1 ); + return c1 - c2; +#endif /* ifdef BCC_AX_ASM */ +} + +/********************** Function strncat ************************************/ + +char * strncat(char *d, char *s, size_t l) +{ + register char *s1=d+strlen(d), *s2; + + s2 = memchr(s, l, 0); + if( s2 ) + memcpy(s1, s, s2-s+1); + else + { + memcpy(s1, s, l); + s1[l] = '\0'; + } + return d; +} + +//----------------------------------------------------------------------------- + +char * strncpy (char * d, char * s, size_t l) +{ + register char *s1=d, *s2=s; + while(l > 0) + { + l--; + if( (*s1++ = *s2++) == '\0') + break; + } + + /* This _is_ correct strncpy is supposed to zap */ + for(; l>0; l--) *s1++ = '\0'; + return d; +} + +//----------------------------------------------------------------------------- + +int strncmp (const char * d, const char * s, size_t l) +{ +#ifdef BCC_AX_ASM +#asm + mov bx,sp + push si + push di + +#ifdef PARANOID + push es + push ds ! Im not sure if this is needed, so just in case. + pop es + cld +#endif + +#if __FIRST_ARG_IN_AX__ + mov si,ax + mov di,[bx+2] + mov cx,[bx+4] +#else + mov si,[bx+2] ! Fetch + mov di,[bx+4] + mov cx,[bx+6] +#endif + + inc cx +lp1: + dec cx + je lp2 + lodsb + scasb + jne lp3 + testb al,al + jne lp1 +lp2: + xor ax,ax + jmp lp4 +lp3: + sbb ax,ax + or al,#1 +lp4: + +#ifdef PARANOID + pop es +#endif + pop di + pop si +#endasm +#else + register char c1=0, c2=0; + while(l-- >0) + if( (c1= *d++) != (c2= *s++) || c1 == '\0' ) + break; + return c1-c2; +#endif +} + +/********************** Function strchr ************************************/ + +char * strchr (const char * s, int c) +{ +#ifdef BCC_AX_ASM +#asm + mov bx,sp + push si +#if __FIRST_ARG_IN_AX__ + mov bx,[bx+2] + mov si,ax +#else + mov si,[bx+2] + mov bx,[bx+4] +#endif + xor ax,ax + +#ifdef PARANOID + cld +#endif + +in_loop: + lodsb + cmp al,bl + jz got_it + or al,al + jnz in_loop + pop si + ret +got_it: + lea ax,[si-1] + pop si + +#endasm +#else /* ifdef BCC_AX_ASM */ + register char ch; + for(;;) + { + if( (ch= *s) == c ) return s; + if( ch == 0 ) return 0; + s++; + } +#endif /* ifdef BCC_AX_ASM */ +} + +//----------------------------------------------------------------------------- + +char * strrchr (const char * s, int c) +{ + register char * prev = 0; + register char * p = s; + /* For null it's just like strlen */ + if( c == '\0' ) return p+strlen(p); + + /* everything else just step along the string. */ + while( (p=strchr(p, c)) != 0 ) + { + prev = p; p++; + } + return prev; +} + +/********************** Function strdup ************************************/ + +char * strdup(s) +char * s; +{ + register size_t len; + register char * p; + + len = strlen(s)+1; + p = (char *) malloc(len); + if(p) memcpy(p, s, len); /* Faster than strcpy */ + return p; +} + +/********************** Function memcpy ************************************/ + +void *memcpy(void *d, const void *s, size_t l) +{ +#ifdef BCC_AX_ASM +#asm + mov bx,sp + push di + push si + +#ifdef PARANOID + push es + push ds ; Im not sure if this is needed, so just in case. + pop es + cld +#endif + +#if __FIRST_ARG_IN_AX__ + mov di,ax ; dest + mov si,[bx+2] ; source + mov cx,[bx+4] ; count +#else + mov di,[bx+2] ; dest + mov si,[bx+4] ; source + mov cx,[bx+6] ; count + + mov ax,di +#endif + ; If di is odd we could mov 1 byte before doing word move + ; as this would speed the copy slightly but its probably + ; too rare to be worthwhile. + ; NB 8086 has no problem with mis-aligned access. + + shr cx,#1 ; Do this faster by doing a mov word + rep + movsw + adc cx,cx ; Retrieve the leftover 1 bit from cflag. + rep + movsb + +#ifdef PARANOID + pop es +#endif + pop si + pop di +#endasm +#else /* ifdef BCC_AX_ASM */ + register char *s1=d, *s2=(char *)s; + for( ; l>0; l--) *((unsigned char*)s1++) = *((unsigned char*)s2++); + return d; +#endif /* ifdef BCC_AX_ASM */ +} + +/********************** Function memccpy ************************************/ + +#ifdef L_memccpy +void * memccpy(d, s, c, l) /* Do we need a fast one ? */ +void *s, *d; +int c; +size_t l; +{ + register char *s1=d, *s2=s; + while(l-- > 0) + if((*s1++ = *s2++) == c ) + return s1; + return 0; +} +#endif + +/********************** Function memchr ************************************/ + +void * memchr(const void * str, int c, size_t l) +{ +#ifdef BCC_ASM +#asm + mov bx,sp + push di + +#ifdef PARANOID + push es + push ds ; Im not sure if this is needed, so just in case. + pop es + cld +#endif + + mov di,[bx+2] + mov ax,[bx+4] + mov cx,[bx+6] + test cx,cx + je is_z ! Zero length, do not find. + + repne ! Scan + scasb + jne is_z ! Not found, ret zero + dec di ! Adjust ptr + mov ax,di ! return + jmp xit +is_z: + xor ax,ax +xit: + +#ifdef PARANOID + pop es +#endif + pop di +#endasm +#else /* ifdef BCC_ASM */ + register char *p=(char *)str; + while(l-- > 0) + { + if(*p == c) return p; + p++; + } + return 0; +#endif /* ifdef BCC_ASM */ +} + +//----------------------------------------------------------------------------- + +void * memset (void * str, int c, size_t l) +{ +#ifdef BCC_AX_ASM +#asm + mov bx,sp + push di + +#ifdef PARANOID + push es + push ds ; Im not sure if this is needed, so just in case. + pop es + cld +#endif + +#if __FIRST_ARG_IN_AX__ + mov di,ax ; Fetch + mov ax,[bx+2] + mov cx,[bx+4] +#else + mov di,[bx+2] ; Fetch + mov ax,[bx+4] + mov cx,[bx+6] +#endif + +; How much difference does this alignment make ? +; I don`t think it`s significant cause most will already be aligned. + +; test cx,cx ; Zero size - skip +; je xit +; +; test di,#1 ; Line it up +; je s_1 +; stosb +; dec cx +;s_1: + + mov ah,al ; Replicate byte + shr cx,#1 ; Do this faster by doing a sto word + rep ; Bzzzzz ... + stosw + adc cx,cx ; Retrieve the leftover 1 bit from cflag. + + rep ; ... z + stosb + +xit: + mov ax,[bx+2] +#ifdef PARANOID + pop es +#endif + pop di +#endasm +#else /* ifdef BCC_AX_ASM */ + register char *s1=str; + while(l-->0) *s1++ = c; + return str; +#endif /* ifdef BCC_AX_ASM */ +} + +/********************** Function memcmp ************************************/ + +int memcmp(const void *s, const void *d, size_t l) +{ +#ifdef BCC_ASM +#asm + mov bx,sp + push di + push si + +#ifdef PARANOID + push es + push ds ! Im not sure if this is needed, so just in case. + pop es + cld +#endif + + mov si,[bx+2] ! Fetch + mov di,[bx+4] + mov cx,[bx+6] + xor ax,ax + + rep ! Bzzzzz + cmpsb + je xit ! All the same! + sbb ax,ax + sbb ax,#-1 ! choose +/-1 +xit: +#ifdef PARANOID + pop es +#endif + pop si + pop di +#endasm +#else /* ifdef BCC_ASM */ + register const char *s1=d, *s2=s; + register char c1=0, c2=0; + while(l-- > 0) + if( (c1= *s1++) != (c2= *s2++) ) + break; + return c1-c2; +#endif /* ifdef BCC_ASM */ +} + +/********************** Function memmove ************************************/ + +void * +memmove(d, s, l) +void *d, *s; +size_t l; +{ + register char *s1=d, *s2=s; + /* This bit of sneakyness c/o Glibc, it assumes the test is unsigned */ + if( s1-s2 >= l ) return memcpy(d,s,l); + + /* This reverse copy only used if we absolutly have to */ + s1+=l; s2+=l; + while(l-- >0) + *(--s1) = *(--s2); + return d; +} + +/********************** Function movedata ***********************************/ + +#ifdef L_movedata + +/* NB There isn't any C version of this function ... */ + +#ifdef BCC_AX_ASM +void +__movedata(srcseg, srcoff, destseg, destoff, len) +unsigned int srcseg, srcoff, destseg, destoff, len; +{ +#asm + push bp + mov bp,sp + push si + push di + push ds +#ifdef PARANOID + push es + cld +#endif + + ! sti ! Are we _really_ paranoid ? + +#if !__FIRST_ARG_IN_AX__ + mov ds,[bp+4] ! Careful, [bp+xx] is SS based. + mov si,[bp+6] + mov es,[bp+8] + mov di,[bp+10] + mov cx,[bp+12] +#else + mov ds,ax + mov si,[bp+4] + mov es,[bp+6] + mov di,[bp+8] + mov cx,[bp+10] +#endif + + ; Would it me a good idea to normalise the pointers ? + ; How about allowing for overlapping moves ? + + shr cx,#1 ; Do this faster by doing a mov word + rep + movsw + adc cx,cx ; Retrieve the leftover 1 bit from cflag. + rep + movsb + + ! cli ! Are we _really_ paranoid ? + +#ifdef PARANOID + pop es +#endif + pop ds + pop di + pop si + pop bp +#endasm +} +#endif + +#endif + +/********************** THE END ********************************************/ + diff --git a/libc/string/strncasecmp.c b/libc/string/strncasecmp.c new file mode 100644 index 000000000..561f72a76 --- /dev/null +++ b/libc/string/strncasecmp.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include +#include + +int +strncasecmp(s, d, l) +char *s; +char *d; +size_t l; +{ + while(l>0) + { + if( *s != *d ) + { + if( tolower(*s) != tolower(*d) ) + return *s - *d; + } + else + if( *s == '\0' ) return 0; + s++; d++; l--; + } + return 0; +} + diff --git a/libc/string/strpbrk.c b/libc/string/strpbrk.c new file mode 100644 index 000000000..3fc27ec70 --- /dev/null +++ b/libc/string/strpbrk.c @@ -0,0 +1,21 @@ +/* Copyright (C) 1995,1996 Robert de Bath + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include + +/* This uses strchr, strchr should be in assembler */ + +char *strpbrk(str, set) +register char *str; +char *set; +{ + while (*str != '\0') + if (strchr(set, *str) == 0) + ++str; + else + return (char *) str; + + return 0; +} diff --git a/libc/string/strspn.c b/libc/string/strspn.c new file mode 100644 index 000000000..2094caa86 --- /dev/null +++ b/libc/string/strspn.c @@ -0,0 +1,44 @@ +/* Copyright (C) 1992, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include + +/* Return the length of the maximum initial segment + of S which contains only characters in ACCEPT. */ +size_t +strspn(s, accept) +char *s; +char *accept; +{ + register char *p; + register char *a; + register size_t count = 0; + + for (p = s; *p != '\0'; ++p) + { + for (a = accept; *a != '\0'; ++a) + if (*p == *a) + break; + if (*a == '\0') + return count; + else + ++count; + } + + return count; +} diff --git a/libc/string/strstr.c b/libc/string/strstr.c new file mode 100644 index 000000000..4ab3a227c --- /dev/null +++ b/libc/string/strstr.c @@ -0,0 +1,57 @@ +/* + * Jody Bruchon's two-way strstr() function + * + * This implementation attempts to exclude substrings faster by scanning + * them from both directions at once. It is faster than naive one-by-one + * comparison implementations but slower than larger, more complex ones + * seen in C libraries such as glibc and musl. The big advantage over the + * faster versions is that resource usage is very low, making it more + * suitable for embedded, low-memory, or small-cache systems. + * + * Copyright (C) 2014-2015 by Jody Bruchon + * Released under the terms of the GNU GPL version 2 + * + * K&R-ified for bcc compiler in Dev86 + */ + +#include +#include + +char * +strstr(s1, s2) +const char *s1; const char *s2; +{ + register const char *haystack = s1; + register const char *needle = s2; + int pos = 0; + register int cnt; + size_t hay_len; + size_t n_len; + + if (!*needle) return (char *) s1; + n_len = strlen(needle); + hay_len = strlen(haystack); + + cnt = n_len; + do { + /* Give up if needle is longer than remaining haystack */ + if ((pos + n_len - 1) > hay_len) return NULL; + + /* Scan for match in both directions */ + while (*needle == *haystack) { + cnt--; + if (!cnt) return (char *) (s1 + pos); + if (*(needle + cnt) == *(haystack + cnt)) { + cnt--; + if (!cnt) return (char *) (s1 + pos); + } else break; + needle++; + haystack++; + } + pos++; + haystack = s1 + pos; + needle = s2; + cnt = n_len; + } while (1); + +} diff --git a/libc/string/strtok.c b/libc/string/strtok.c new file mode 100644 index 000000000..318f4776b --- /dev/null +++ b/libc/string/strtok.c @@ -0,0 +1,69 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include + + +static char *olds = 0; + +/* Parse S into tokens separated by characters in DELIM. + If S is NULL, the last string strtok() was called with is + used. For example: + char s[] = "-abc=-def"; + x = strtok(s, "-"); // x = "abc" + x = strtok(NULL, "=-"); // x = "def" + x = strtok(NULL, "="); // x = NULL + // s = "abc\0-def\0" +*/ + +char * strtok (char *s, const char * delim) +{ + char *token; + + if (s == 0) + { + if (olds == 0) + { + return 0; + } + else + s = olds; + } + + /* Scan leading delimiters. */ + s += strspn(s, delim); + if (*s == '\0') + { + olds = 0; + return 0; + } + + /* Find the end of the token. */ + token = s; + s = strpbrk(token, delim); + if (s == 0) + /* This token finishes the string. */ + olds = 0; + else + { + /* Terminate the token and make OLDS point past it. */ + *s = '\0'; + olds = s + 1; + } + return token; +} diff --git a/libc/system/.gitignore b/libc/system/.gitignore new file mode 100644 index 000000000..b7ad22105 --- /dev/null +++ b/libc/system/.gitignore @@ -0,0 +1 @@ +setjmp.s diff --git a/libc/system/Makefile b/libc/system/Makefile new file mode 100644 index 000000000..aa5b969c5 --- /dev/null +++ b/libc/system/Makefile @@ -0,0 +1,29 @@ +# Makefile of /libc/syscall module + +include $(TOPDIR)/libc/Makefile.inc + +SYSCALLDAT=${TOPDIR}/elks/arch/i86/kernel/syscall.dat + +OBJS = syscall0.o syscall1.o syslib.o signal.o exec.o dirent.o setjmp.o + +all: $(LIBC) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +syscall1.s: syscall.awk $(SYSCALLDAT) + tr '[A-Z]' '[a-z]' < $(SYSCALLDAT) > syscall.dat + awk -f syscall.awk syscall.dat > syscall1.s + +syscall0.o: syscall0.s +syscall1.o: syscall1.s +syslib.o: syslib.c +signal.o: signal.c +exec.o: exec.c +setjmp.o: setjmp.s +setjmp.s: setjmp.S + +clean: + rm -f *.o setjmp.s + rm -f syscall.dat syscall1.s + rm -f call_tab.v defn_tab.v diff --git a/libc/system/call_tab.v b/libc/system/call_tab.v new file mode 100644 index 000000000..0cb6ffa0b --- /dev/null +++ b/libc/system/call_tab.v @@ -0,0 +1,75 @@ +/* 0 */ sys_enosys, /* */ +/* 1 */ sys_enosys, /* */ +/* 2 */ sys_enosys, /* */ +/* 3 */ sys_enosys, /* */ +/* 4 */ sys_enosys, /* */ +/* 5 */ sys_enosys, /* */ +/* 6 */ sys_enosys, /* */ +/* 7 */ sys_enosys, /* */ +/* 8 */ sys_enosys, /* creat */ +/* 9 */ sys_enosys, /* */ +/* 10 */ sys_enosys, /* */ +/* 11 */ sys_enosys, /* */ +/* 12 */ sys_enosys, /* */ +/* 13 */ sys_enosys, /* time */ +/* 14 */ sys_enosys, /* */ +/* 15 */ sys_enosys, /* */ +/* 16 */ sys_enosys, /* */ +/* 17 */ sys_enosys, /* */ +/* 18 */ sys_enosys, /* */ +/* 19 */ sys_enosys, /* */ +/* 20 */ sys_enosys, /* */ +/* 21 */ sys_enosys, /* */ +/* 22 */ sys_enosys, /* */ +/* 23 */ sys_enosys, /* */ +/* 24 */ sys_enosys, /* */ +/* 25 */ sys_enosys, /* stime */ +/* 26 */ sys_enosys, /* ptrace */ +/* 27 */ sys_alarm, +/* 28 */ sys_enosys, /* */ +/* 29 */ sys_pause, +/* 30 */ sys_enosys, /* */ +/* 31 */ sys_enosys, /* */ +/* 32 */ sys_enosys, /* */ +/* 33 */ sys_enosys, /* */ +/* 34 */ sys_nice, +/* 35 */ sys_sleep, +/* 36 */ sys_enosys, /* */ +/* 37 */ sys_enosys, /* */ +/* 38 */ sys_enosys, /* */ +/* 39 */ sys_enosys, /* */ +/* 40 */ sys_enosys, /* */ +/* 41 */ sys_enosys, /* */ +/* 42 */ sys_enosys, /* */ +/* 43 */ sys_times, +/* 44 */ sys_enosys, /* profil */ +/* 45 */ sys_enosys, /* */ +/* 46 */ sys_enosys, /* */ +/* 47 */ sys_getgid, +/* 48 */ sys_enosys, /* */ +/* 49 */ sys_enosys, /* getinfo */ +/* 50 */ sys_enosys, /* */ +/* 51 */ sys_enosys, /* acct */ +/* 52 */ sys_enosys, /* phys */ +/* 53 */ sys_enosys, /* lock */ +/* 54 */ sys_enosys, /* */ +/* 55 */ sys_enosys, /* */ +/* 56 */ sys_enosys, /* mpx */ +/* 57 */ sys_enosys, /* */ +/* 58 */ sys_enosys, /* */ +/* 59 */ sys_enosys, /* */ +/* 60 */ sys_enosys, /* */ +/* 61 */ sys_enosys, /* */ +/* 62 */ sys_enosys, /* */ +/* 63 */ sys_enosys, /* */ +/* 64 */ sys_enosys, /* */ +/* 65 */ sys_enosys, /* insmod */ +/* 66 */ sys_enosys, /* */ +/* 67 */ sys_enosys, /* */ +/* 68 */ sys_enosys, /* */ +/* 69 */ sys_enosys, /* */ +/* 70 */ sys_enosys, /* */ +/* 71 */ sys_enosys, /* */ +/* 72 */ sys_enosys, /* */ +/* 73 */ sys_enosys, /* */ +/* 74 */ sys_enosys, /* */ diff --git a/libc/system/defn_tab.v b/libc/system/defn_tab.v new file mode 100644 index 000000000..c26096d0f --- /dev/null +++ b/libc/system/defn_tab.v @@ -0,0 +1,24 @@ +#ifndef sys_alarm +#define sys_alarm sys_enosys +#endif + +#ifndef sys_pause +#define sys_pause sys_enosys +#endif + +#ifndef sys_nice +#define sys_nice sys_enosys +#endif + +#ifndef sys_sleep +#define sys_sleep sys_enosys +#endif + +#ifndef sys_times +#define sys_times sys_enosys +#endif + +#ifndef sys_getgid +#define sys_getgid sys_enosys +#endif + diff --git a/libc/system/dirent.c b/libc/system/dirent.c new file mode 100644 index 000000000..087ddfebe --- /dev/null +++ b/libc/system/dirent.c @@ -0,0 +1,72 @@ + +#include +#include +#include +#include +#include +#include + +DIR * +opendir(dname) +const char *dname; +{ + struct stat st; + int fd; + DIR *p; + + if (stat(dname, &st) < 0) + return 0; + + if (!S_ISDIR(st.st_mode)) + { + errno = ENOTDIR; + return 0; + } + if ((fd = open(dname, O_RDONLY)) < 0) + return 0; + + p = malloc(sizeof(DIR)); + if (p == 0) + { + close(fd); + return 0; + } + + p->dd_buf = malloc(sizeof(struct dirent)); + if (p->dd_buf == 0) + { + free(p); + close(fd); + return 0; + } + p->dd_fd = fd; + p->dd_loc = p->dd_size = 0; + + return p; +} + +int +closedir(dirp) +DIR *dirp; +{ + int fd; + fd = dirp->dd_fd; + free(dirp->dd_buf); + free(dirp); + return close(fd); +} + +struct dirent * +readdir(dirp) +DIR *dirp; +{ + int cc; + + cc = _readdir(dirp->dd_fd, dirp->dd_buf, 1); + if (cc <= 0) + return 0; + if (cc>1) dirp->dd_buf->d_name[cc] = 0; + + return dirp->dd_buf; +} + diff --git a/libc/system/exec.c b/libc/system/exec.c new file mode 100644 index 000000000..23a53a703 --- /dev/null +++ b/libc/system/exec.c @@ -0,0 +1,277 @@ + +#include + +#include +#include + + +extern char ** environ; + +int +execl(fname, arg0) +char * fname, *arg0; +{ + return execve(fname, &arg0, environ); +} + +int execv(char * fname, char **argv) +{ + return execve(fname, argv, environ); +} + +int execle(char *fname, char *arg0) +{ + char ** envp = &arg0; + while(*envp) envp++; + return execve(fname, &arg0, envp+1); +} + +int execve(char * fname, char ** argv, char ** envp) +{ + char **p; + int argv_len=0, argv_count=0; + int envp_len=0, envp_count=0; + int stack_bytes; + unsigned short * pip; + char * pcp, * stk_ptr, *baseoff; + int rv; + + /* How much space for argv */ + for(p=argv; p && *p && argv_len >= 0; p++) + { + argv_count++; argv_len += strlen(*p)+1; + } + + /* How much space for envp */ + for(p=envp; p && *p && envp_len >= 0; p++) + { + envp_count++; envp_len += strlen(*p)+1; + } + + /* tot it all up */ + stack_bytes = 2 /* argc */ + + argv_count * 2 + 2 /* argv */ + + argv_len + + envp_count * 2 + 2 /* envp */ + + envp_len; + + /* Allocate it */ + if( argv_len < 0 || envp_len < 0 || stack_bytes <= 0 + || (int)(stk_ptr = (char*)sbrk(stack_bytes)) == -1) + { + errno = ENOMEM; + return -1; + } + +/* Sanity check + printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n", + argv_count, argv_len, envp_count, envp_len, stack_bytes); +*/ + + /* Now copy in the strings */ + pip=(unsigned short *) stk_ptr; + pcp=stk_ptr+2*(1+argv_count+1+envp_count+1); + + /* baseoff = stk_ptr + stack_bytes; */ + baseoff = stk_ptr; + *pip++ = argv_count; + for(p=argv; p && *p; p++) + { + int l; + *pip++ = pcp-baseoff; + l = strlen(*p)+1; + memcpy(pcp, *p, l); + pcp += l; + } + *pip++ = 0; + + for(p=envp; p && *p; p++) + { + int l; + *pip++ = pcp-baseoff; + l = strlen(*p)+1; + memcpy(pcp, *p, l); + pcp += l; + } + *pip++ = 0; + + rv = _execve(fname, stk_ptr, stack_bytes); + /* FIXME: This will probably have to interpret '#!' style exe's */ + sbrk(-stack_bytes); + return rv; +} + +#ifdef L_execlp +int +execlp(fname, arg0) +char * fname, *arg0; +{ + return execvp(fname, &arg0); +} +#endif + +static int tryrun(pname, argv) +char * pname; +char ** argv; +{ +static char *shprog[] = {"/bin/sh", "", 0}; + struct stat st; + + if( stat(pname, &st) < 0 ) return; + if( !S_ISREG(st.st_mode) ) return; + +#ifdef __AS386_16__ + __execvve(pname, (void*)0, argv, environ); + if( errno == ENOEXEC ) + { + shprog[1] = pname; + __execvve(shprog[0], shprog, argv, environ); + } +#else + execve(pname, argv, environ); + /* FIXME - running /bin/sh in 386 mode */ +#endif +} + +int execvp(char * fname, char **argv) +{ + char *pname = fname, *path; + int besterr = ENOENT; + int flen, plen; + char * bp = sbrk(0); + + if( *fname != '/' && (path = getenv("PATH")) != 0 ) + { + flen = strlen(fname)+2; + + for(;path;) + { + if( *path == ':' || *path == '\0' ) + { + tryrun(fname, argv); + if( errno == EACCES ) besterr = EACCES; + if( *path ) path++; else break; + } + else + { + char * p = strchr(path, ':'); + if(p) *p = '\0'; + plen = strlen(path); + pname = sbrk(plen+flen); + + strcpy(pname, path); + strcat(pname, "/"); + strcat(pname, fname); + + tryrun(pname, argv); + if( errno == EACCES ) besterr = EACCES; + + brk(pname); + pname = fname; + if(p) *p++ = ':'; + path=p; + } + } + } + + tryrun(pname, argv); + brk(bp); + if( errno == ENOENT || errno == 0 ) errno = besterr; + return -1; +} + +//----------------------------------------------------------------------------- + +#ifdef __AS386_16__ +static int +__execvve(fname, interp, argv, envp) +char * fname; +char ** interp; +char ** argv; +char ** envp; +{ + char **p; + int argv_len=0, argv_count=0; + int envp_len=0, envp_count=0; + int stack_bytes; + unsigned short * pip; + char * pcp, * stk_ptr, *baseoff; + int rv; + + /* How much space for argv */ + for(p=interp; p && *p && argv_len >= 0; p++) + { + argv_count++; argv_len += strlen(*p)+1; + } + for(p=argv; p && *p && argv_len >= 0; p++) + { + argv_count++; argv_len += strlen(*p)+1; + } + + /* How much space for envp */ + for(p=envp; p && *p && envp_len >= 0; p++) + { + envp_count++; envp_len += strlen(*p)+1; + } + + /* tot it all up */ + stack_bytes = 2 /* argc */ + + argv_count * 2 + 2 /* argv */ + + argv_len + + envp_count * 2 + 2 /* envp */ + + envp_len; + + /* Allocate it */ + if( argv_len < 0 || envp_len < 0 || stack_bytes <= 0 + || (int)(stk_ptr = (char*)sbrk(stack_bytes)) == -1) + { + errno = ENOMEM; + return -1; + } + +/* Sanity check + printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n", + argv_count, argv_len, envp_count, envp_len, stack_bytes); +*/ + + /* Now copy in the strings */ + pip=(unsigned short *) stk_ptr; + pcp=stk_ptr+2*(1+argv_count+1+envp_count+1); + + /* baseoff = stk_ptr + stack_bytes; */ + baseoff = stk_ptr; + *pip++ = argv_count; + for(p=interp; p && *p; p++) + { + int l; + *pip++ = pcp-baseoff; + l = strlen(*p)+1; + memcpy(pcp, *p, l); + pcp += l; + } + for(p=argv; p && *p; p++) + { + int l; + *pip++ = pcp-baseoff; + l = strlen(*p)+1; + memcpy(pcp, *p, l); + pcp += l; + } + *pip++ = 0; + + for(p=envp; p && *p; p++) + { + int l; + *pip++ = pcp-baseoff; + l = strlen(*p)+1; + memcpy(pcp, *p, l); + pcp += l; + } + *pip++ = 0; + + rv = _execve(fname, stk_ptr, stack_bytes); + /* FIXME: This will probably have to interpret '#!' style exe's */ + sbrk(-stack_bytes); + return rv; +} +#endif diff --git a/libc/system/setjmp.S b/libc/system/setjmp.S new file mode 100644 index 000000000..4e7b21fe0 --- /dev/null +++ b/libc/system/setjmp.S @@ -0,0 +1,40 @@ + + .code16 + + .text + + .global _setjmp + +_setjmp: + + pop %cx // PC + mov %sp,%bx + mov (%bx),%bx // TOS is prt -> env + + mov %cx,0(%bx) // PC + mov %sp,2(%bx) // This registers are all that may be constant. + mov %bp,4(%bx) + mov %si,6(%bx) // SI, DI & ES must be saved for GCC + mov %di,8(%bx) + mov %es,10(%bx) + + xor %ax,%ax + jmp *%cx + + + .global _longjmp + +_longjmp: + + pop %cx // PC + pop %bx // env-> + pop %ax // rv + + mov 0(%bx),%cx // PC + mov 2(%bx),%sp + mov 4(%bx),%bp + mov 6(%bx),%si + mov 8(%bx),%di + mov 10(%bx),%es + + jmp *%cx diff --git a/libc/system/signal.c b/libc/system/signal.c new file mode 100644 index 000000000..b415b9c43 --- /dev/null +++ b/libc/system/signal.c @@ -0,0 +1,54 @@ + +#include +#include + +typedef __sighandler_t Sig; + +extern int _signal (int, __sighandler_t); +extern Sig _syscall_signal (); + +Sig _sigtable[_NSIG-1]; + +/* + * Signal handler. + * + */ + +/* + * KERNEL INTERFACE: + * It is assumed the kernel will never give us a signal we haven't + * _explicitly_ asked for! + * + * The Kernel need only save space for _one_ function pointer + * (to _syscall_signal) and must deal with SIG_DFL and SIG_IGN + * in kernel space. + * + * When a signal is required the kernel must set all the registers as if + * returning from a interrupt normally then push the number of the signal + * to be generated, push the current pc value, then set the pc to the + * address of the '_syscall_signal' function. + */ + +Sig signal(int number, Sig pointer) +{ + Sig old_sig; + int rv; + if( number < 1 || number >= _NSIG ) { errno=EINVAL; return SIG_ERR; } + + if( pointer == SIG_DFL || pointer == SIG_IGN ) + rv = _signal(number, pointer); + else + rv = _signal(number, (__sighandler_t) _syscall_signal); + + if( rv < 0 ) return SIG_ERR; + + old_sig = _sigtable[number-1]; + _sigtable[number-1] = pointer; + + switch(rv) + { + case 0: return SIG_DFL; + case 1: return SIG_IGN; + return old_sig; + } +} diff --git a/libc/system/syscall.awk b/libc/system/syscall.awk new file mode 100644 index 000000000..5f9656a17 --- /dev/null +++ b/libc/system/syscall.awk @@ -0,0 +1,45 @@ +BEGIN { + print "// This file is automatically generated from syscall.dat"; + print "// See syscall.awk for details\n"; + print "\t.code16\n"; + print "\t.text\n"; + print "\t.extern _syscall_0"; + print "\t.extern _syscall_1"; + print "\t.extern _syscall_2"; + print "\t.extern _syscall_3"; + print "\t.extern _syscall_4"; + print "\t.extern _syscall_5\n"; +} +/^[ ]*#/ { next; } +/^[ ]*$/ { next; } +{ + callno = $2; + if (!(callno in calltab)) + callwas [callno] = $1; + + if ($3 == "x" || $3 == "") next; + else if ($4 == "@" || $4 == "-") next; + else if ($4 == "*") funcname = "_" $1; + else funcname = $1; + + if (callno > max_call) max_call = callno; + calltab [callno] = $1; + + printf ("// CALL %s \n\n", $0); + printf ("\t.global %s\n\n", funcname); + printf ("%s:\n", funcname); + printf ("\tmov $%d,%ax\n", callno); + printf ("\tjmp _syscall_%d\n\n", $3); +} +END { + for (i = 0; i <= max_call; i++) + if (i in calltab) { + printf ("#ifndef sys_%s\n", calltab [i]) > "defn_tab.v"; + printf ("#define sys_%s sys_enosys\n", calltab [i]) > "defn_tab.v"; + printf ("#endif\n\n") > "defn_tab.v"; + + printf ("/* %3d */ sys_%s,\n", i, calltab [i]) > "call_tab.v"; + } + else + printf("/* %3d */ sys_enosys, /* %s */\n", i, callwas [i]) > "call_tab.v"; +} \ No newline at end of file diff --git a/libc/system/syscall.dat b/libc/system/syscall.dat new file mode 100644 index 000000000..3aa1ef7ae --- /dev/null +++ b/libc/system/syscall.dat @@ -0,0 +1,170 @@ +# +# warning! +# this file is used to generate the system call lists for dev86(elks) +# elksemu and elks itself. changes to this may require changes in +# all three of those packages. +# +# '.' = ok, with comment +# '*' = needs libc code (prefix __) +# '-' = obsolete/not required +# '@' = may be required later +# '=' = depends on stated config variable +# +# an initial plus on the call number specifies that this call is +# implemented in the kernel. +# +# package versions are matched. +# dev86/elksemu version - 0.13.1 +# elks version - 0.0.66 +# +# name no args flag, comment +# +exit +1 1 * c exit does stdio, _exit in crt0 +fork +2 0 +read +3 3 +write +4 3 +open +5 3 +close +6 1 +wait4 +7 4 +creat 8 0 - not needed alias for open +link +9 2 +unlink +10 1 +execve +11 3 * execve minix style +chdir +12 1 +time 13 1 - use settimeofday +mknod +14 3 +chmod +15 2 +chown +16 3 +brk +17 1 * this is only to tell the system +stat +18 2 +lseek +19 3 * nb 2nd arg is an io ptr to long not a long. +getpid +20 1 * this gets both pid & ppid +mount +21 5 +umount +22 1 +setuid +23 1 +getuid +24 1 * this gets both uid and euid +stime 25 2 - this must not exist - even as a libc. +ptrace 26 4 @ adb/sdb/dbx need this. +alarm 27 2 +fstat +28 2 +pause 29 0 +utime +30 2 +chroot +31 1 +vfork +32 0 +access +33 2 +nice 34 1 +sleep 35 1 +sync +36 0 +kill +37 2 +rename +38 2 +mkdir +39 2 +rmdir +40 1 +dup +41 1 . there is a fcntl lib function too. +pipe +42 1 = config_pipe +times 43 2 * 2nd arg is pointer for long ret val. +profil 44 4 @ +dup2 +45 2 +setgid +46 1 +getgid 47 1 * this gets both gid and egid +signal +48 2 * have put the despatch table in user space. +getinfo 49 1 @ possible? gets pid,ppid,uid,euid etc +fcntl +50 3 +acct 51 1 @ accounting to named file (off if null) +phys 52 3 - replaced by mmap() +lock 53 1 @ prevent swapping for this proc if flg!=0 +ioctl +54 3 . make this and fcntl the same ? +reboot +55 3 . the magic number is 0xfee1,0xdead,... +mpx 56 2 - replaced by fifos and select. +lstat +57 2 +symlink +58 2 +readlink +59 3 +umask +60 1 +settimeofday +61 2 +gettimeofday +62 2 +select +63 5 . 5 paramaters is possible +readdir +64 3 * +insmod 65 1 - removed support for modules +fchown +66 3 +dlload +67 2 - removed support for dynamic libraries +setsid +68 0 +socket +69 3 = config_socket +bind +70 3 = config_socket +listen +71 2 = config_socket +accept +72 3 = config_socket +connect +73 3 = config_socket +knlvsn +74 1 = config_sys_version +# +# name no args flag&comment +# +# ( awk '{$2=nr+500;ofs="\t";print ;}'| expand -24,32,40 | unexpand ) < +#include +#include +#include + +#include +#include +#include +#include + +void (* _cleanup)() = 0; // called by exit() + +int errno; +char ** environ; + +//----------------------------------------------------------------------------- + +extern pid_t _getpid (pid_t *); + +pid_t getpid () +{ + pid_t ppid; + return _getpid (&ppid); +} + +//----------------------------------------------------------------------------- + +extern int _lseek (int fd, off_t * posn, int where); + +off_t lseek (int fd, off_t posn, int where) +{ + if ( _lseek (fd, &posn, where) < 0) return -1; + else return posn; +} + +/********************** Function getppid ************************************/ + +#ifdef L_getppid +int getppid() +{ + int ppid; + __getpid(&ppid); + return ppid; +} +#endif + +/********************** Function getuid ************************************/ + +uid_t getuid (void) +{ + int euid; + return _getuid(&euid); +} + +/********************** Function geteuid ************************************/ + +int geteuid() +{ + int euid; + _getuid(&euid); + return euid; +} + +/********************** Function getgid ************************************/ + +#ifdef L_getgid +int getgid() +{ + int egid; + return __getgid(&egid); +} +#endif + +/********************** Function getegid ************************************/ + +int getegid() +{ + int egid; + _getgid(&egid); + return egid; +} + +/********************** Function dup2 ************************************/ + +#ifdef L_dup2 + +#include + +int dup2(ifd, ofd) +int ifd; +{ + return fcntl(ifd, F_DUPFD, ofd); +} +#endif + +/********************** Function dup ************************************/ + +#ifdef L_dup +#include +#include +#include + +/* This is horribly complicated, there _must_ be a better way! */ + +int +dup(fd) +int fd; +{ + int nfd; + extern int errno; + int oerr = errno; + + errno = 0; + for(nfd=0; nfd 1) + return kill(-pid, sig); + errno = EINVAL; + return -1; +} +#endif + +/********************** Function setpgrp ************************************/ + +#ifdef L_setpgrp +int +setpgrp() +{ + return setpgid(0,0); +} +#endif + +/********************** Function sleep ************************************/ + +#ifdef L_sleep + +#ifdef __ELKS__ +/* This uses SIGALRM, it does keep the previous alarm call but will lose + * any alarms that go off during the sleep + */ + +static void alrm() { } + +unsigned int sleep(seconds) +unsigned int seconds; +{ + void (*last_alarm)(); + unsigned int prev_sec; + + prev_sec = alarm(0); + if( prev_sec <= seconds ) prev_sec = 1; else prev_sec -= seconds; + + last_alarm = signal(SIGALRM, alrm); + alarm(seconds); + pause(); + seconds = alarm(prev_sec); + signal(SIGALRM, last_alarm); + return seconds; +} + +#else + /* Is this a better way ? If we have select of course :-) */ +unsigned int +sleep(seconds) +unsigned int seconds; +{ + struct timeval timeout; + time_t start = time((void*)0); + timeout.tv_sec = seconds; + timeout.tv_usec = 0; + select(1, NULL, NULL, NULL, &timeout); + return seconds - (time((void*)0) - start); +} +#endif + +#endif + +/********************** Function usleep ************************************/ + +#ifdef L_usleep +void +usleep(useconds) +unsigned long useconds; +{ + struct timeval timeout; + timeout.tv_sec = useconds%1000000L; + timeout.tv_usec = useconds/1000000L; + select(1, NULL, NULL, NULL, &timeout); +} +#endif + +/********************** Function mkfifo ************************************/ + +#ifdef L_mkfifo +int +mkfifo(path, mode) +char * path; +int mode; +{ + return mknod(path, mode | S_IFIFO, 0); +} +#endif + +/********************** THE END ********************************************/ diff --git a/libc/termcap/Makefile b/libc/termcap/Makefile new file mode 100644 index 000000000..0075581e6 --- /dev/null +++ b/libc/termcap/Makefile @@ -0,0 +1,16 @@ +# Makefile of /libc/termcap module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS= termcap.c tparam.c +OBJS= $(SRCS:.c=.o) + +all: $(LIBC) + +$(OBJS): $(SRCS) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +clean: + rm -f *.o diff --git a/libc/termcap/termcap.c b/libc/termcap/termcap.c new file mode 100644 index 000000000..ae46b7579 --- /dev/null +++ b/libc/termcap/termcap.c @@ -0,0 +1,816 @@ +/* Work-alike for termcap, plus extra features. + Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Emacs config.h may rename various library functions such as malloc. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#else /* not HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#ifdef __linux__ +#undef STDC_HEADERS +#define STDC_HEADERS +#define HAVE_UNISTD_H +#define HAVE_SYS_IOCTL_H +#else +#if defined(HAVE_STRING_H) || defined(STDC_HEADERS) +#define bcopy(s, d, n) memcpy ((d), (s), (n)) +#endif +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include +#include +#endif + +#endif /* not HAVE_CONFIG_H */ + +#ifndef NULL +#define NULL (char *) 0 +#endif + +/* BUFSIZE is the initial size allocated for the buffer + for reading the termcap file. + It is not a limit. + Make it large normally for speed. + Make it variable when debugging, so can exercise + increasing the space dynamically. */ + +#ifndef BUFSIZE +#ifdef DEBUG +#define BUFSIZE bufsize + +int bufsize = 128; +#else +#define BUFSIZE 2048 +#endif +#endif + +#ifdef TIOCGWINSZ +#define ADJUST_WIN_EXTENT +#endif + +#ifndef emacs +static void +memory_out () +{ + write (2, "virtual memory exhausted\n", 25); + exit (1); +} + +static char * +xmalloc (size) + unsigned size; +{ + register char *tem = malloc (size); + + if (!tem) + memory_out (); + return tem; +} + +static char * +xrealloc (ptr, size) + char *ptr; + unsigned size; +{ + register char *tem = realloc (ptr, size); + + if (!tem) + memory_out (); + return tem; +} +#endif /* not emacs */ + +/* Looking up capabilities in the entry already found. */ + +/* The pointer to the data made by tgetent is left here + for tgetnum, tgetflag and tgetstr to find. */ +static char *term_entry; + +static char *tgetst1 (); + +/* Search entry BP for capability CAP. + Return a pointer to the capability (in BP) if found, + 0 if not found. */ + +static char * +find_capability (bp, cap) + register char *bp, *cap; +{ + for (; *bp; bp++) + if (bp[0] == ':' + && bp[1] == cap[0] + && bp[2] == cap[1]) + return &bp[4]; + return NULL; +} + +int +tgetnum (cap) + char *cap; +{ + register char *ptr = find_capability (term_entry, cap); + if (!ptr || ptr[-1] != '#') + return -1; + return atoi (ptr); +} + +int +tgetflag (cap) + char *cap; +{ + register char *ptr = find_capability (term_entry, cap); + return ptr && ptr[-1] == ':'; +} + +/* Look up a string-valued capability CAP. + If AREA is non-null, it points to a pointer to a block in which + to store the string. That pointer is advanced over the space used. + If AREA is null, space is allocated with `malloc'. */ + +char * +tgetstr (cap, area) + char *cap; + char **area; +{ + register char *ptr = find_capability (term_entry, cap); + if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~')) + return NULL; + return tgetst1 (ptr, area); +} + +/* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted, + gives meaning of character following \, or a space if no special meaning. + Eight characters per line within the string. */ + +static char esctab[] + = " \007\010 \033\014 \ + \012 \ + \015 \011 \013 \ + "; + +/* PTR points to a string value inside a termcap entry. + Copy that value, processing \ and ^ abbreviations, + into the block that *AREA points to, + or to newly allocated storage if AREA is NULL. + Return the address to which we copied the value, + or NULL if PTR is NULL. */ + +static char * +tgetst1 (ptr, area) + char *ptr; + char **area; +{ + register char *p, *r; + register int c; + register int size; + char *ret; + register int c1; + + if (!ptr) + return NULL; + + /* `ret' gets address of where to store the string. */ + if (!area) + { + /* Compute size of block needed (may overestimate). */ + p = ptr; + while ((c = *p++) && c != ':' && c != '\n') + ; + ret = (char *) xmalloc (p - ptr + 1); + } + else + ret = *area; + + /* Copy the string value, stopping at null or colon. + Also process ^ and \ abbreviations. */ + p = ptr; + r = ret; + while ((c = *p++) && c != ':' && c != '\n') + { + if (c == '^') + c = *p++ & 037; + else if (c == '\\') + { + c = *p++; + if (c >= '0' && c <= '7') + { + c -= '0'; + size = 0; + + while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7') + { + c *= 8; + c += c1 - '0'; + p++; + } + } + else if (c >= 0100 && c < 0200) + { + c1 = esctab[(c & ~040) - 0100]; + if (c1 != ' ') + c = c1; + } + } + *r++ = c; + } + *r = '\0'; + /* Update *AREA. */ + if (area) + *area = r + 1; + return ret; +} + +/* Outputting a string with padding. */ + +#ifdef __linux__ +speed_t ospeed; +#else +short ospeed; +#endif +/* If OSPEED is 0, we use this as the actual baud rate. */ +int tputs_baud_rate; +char PC; + +/* Actual baud rate if positive; + - baud rate / 100 if negative. */ + +static short speeds[] = + { +#ifdef VMS + 0, 50, 75, 110, 134, 150, -3, -6, -12, -18, + -20, -24, -36, -48, -72, -96, -192 +#else /* not VMS */ + 0, 50, 75, 110, 135, 150, -2, -3, -6, -12, + -18, -24, -48, -96, -192, -384 +#endif /* not VMS */ + }; + +void +tputs (str, nlines, outfun) + register char *str; + int nlines; + register int (*outfun) (); +{ + register int padcount = 0; + register int speed; + +#ifdef emacs + extern baud_rate; + speed = baud_rate; +#else + if (ospeed == 0) + speed = tputs_baud_rate; + else + speed = speeds[ospeed]; +#endif + + if (!str) + return; + + while (*str >= '0' && *str <= '9') + { + padcount += *str++ - '0'; + padcount *= 10; + } + if (*str == '.') + { + str++; + padcount += *str++ - '0'; + } + if (*str == '*') + { + str++; + padcount *= nlines; + } + while (*str) + (*outfun) (*str++); + + /* padcount is now in units of tenths of msec. */ + padcount *= speeds[ospeed]; + padcount += 500; + padcount /= 1000; + if (speeds[ospeed] < 0) + padcount = -padcount; + else + { + padcount += 50; + padcount /= 100; + } + + while (padcount-- > 0) + (*outfun) (PC); +} + +/* Finding the termcap entry in the termcap data base. */ + +struct buffer + { + char *beg; + int size; + char *ptr; + int ateof; + int full; + }; + +/* Forward declarations of static functions. */ + +static int scan_file (); +static char *gobble_line (); +static int compare_contin (); +static int name_match (); + +#ifdef ADJUST_WIN_EXTENT +#ifdef TIOCGWINSZ +static int +get_win_extent(li, co) +int *li, *co; +{ + struct winsize ws; + + /* Some TIOCGWINSZ may be broken. Make sure ws.ws_row and + * ws.ws_col are not zero. + */ + if (ioctl(0, TIOCGWINSZ, &ws) != 0 || !ws.ws_row || !ws.ws_col) + return -1; + *li = ws.ws_row; + *co = ws.ws_col; + return 0; +} +#endif /* TIOCGWINSZ */ + +static int +adjust_win_extent(bpp, howalloc, li, co) +char **bpp; +int howalloc; /* 0 must do in place, 1 must use malloc, 2 must use realloc */ +int li, co; +{ + int licolen, o_len, t, colon; + char *licobuf, *s; + + if (li < 0 || co < 0) + return 0; + for (s = *bpp, colon = -1; *s; ++s) + if (*s == ':' && colon < 0) + colon = s - *bpp; + o_len = s - *bpp; + licolen = 11; + for (t = li; (t /= 10) > 0; ++licolen); + for (t = co; (t /= 10) > 0; ++licolen); + + licobuf = xmalloc(licolen + 1); + sprintf(licobuf, ":li#%d:co#%d:", li, co); + + if (howalloc == 0) + { + bcopy(*bpp + colon, *bpp + colon + licolen, o_len - colon + 1); + bcopy(licobuf, *bpp + colon, licolen); + } + else if (howalloc == 1) + { + char *newbp; + + newbp = xmalloc(o_len + licolen + 1); + bcopy(*bpp, newbp, colon); + bcopy(licobuf, newbp + colon, licolen); + strcpy(newbp + colon + licolen, *bpp + colon); + *bpp = newbp; + } + else /* (howalloc == 2) */ + { + char *newbp; + + newbp = xrealloc(*bpp, o_len + licolen + 1); + bcopy(newbp + colon, newbp + colon + licolen, o_len - colon + 1); + bcopy(licobuf, newbp + colon, licolen); + *bpp = newbp; + } + + free(licobuf); + return 1; +} +#endif /* ADJUST_WIN_EXTENT */ + +#ifdef VMS + +#include +#include +#include + +static int +valid_filename_p (fn) + char *fn; +{ + struct FAB fab = cc$rms_fab; + struct NAM nam = cc$rms_nam; + char esa[NAM$C_MAXRSS]; + + fab.fab$l_fna = fn; + fab.fab$b_fns = strlen(fn); + fab.fab$l_nam = &nam; + fab.fab$l_fop = FAB$M_NAM; + + nam.nam$l_esa = esa; + nam.nam$b_ess = sizeof esa; + + return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL; +} + +#else /* !VMS */ + +#define valid_filename_p(fn) (*(fn) == '/') + +#endif /* !VMS */ + +/* Find the termcap entry data for terminal type NAME + and store it in the block that BP points to. + Record its address for future use. + + If BP is null, space is dynamically allocated. + + Return -1 if there is some difficulty accessing the data base + of terminal types, + 0 if the data base is accessible but the type NAME is not defined + in it, and some other value otherwise. */ + +int +tgetent (bp, name) + char *bp, *name; +{ + register char *termcap_name; + register int fd; + struct buffer buf; + register char *bp1; + char *bp2; + char *term; + int malloc_size = 0; + register int c; + char *tcenv; /* TERMCAP value, if it contains :tc=. */ + char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */ + int filep; +#ifdef ADJUST_WIN_EXTENT + int li, co; /* #lines and columns on this tty */ + + if (get_win_extent(&li, &co) != 0) + li = co = -1; +#endif /* ADJUST_WIN_EXTENT */ + + termcap_name = getenv ("TERMCAP"); + if (termcap_name && *termcap_name == '\0') + termcap_name = NULL; + + filep = termcap_name && valid_filename_p (termcap_name); + + /* If termcap_name is non-null and starts with / (in the un*x case, that is), + it is a file name to use instead of /etc/termcap. + If it is non-null and does not start with /, + it is the entry itself, but only if + the name the caller requested matches the TERM variable. */ + + if (termcap_name && !filep && !strcmp (name, getenv ("TERM"))) + { + indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0); + if (!indirect) + { + if (!bp) + { + bp = termcap_name; +#ifdef ADJUST_WIN_EXTENT + if (adjust_win_extent(&bp, 1, li, co)) + malloc_size = 1; /* force return of bp */ +#endif /* ADJUST_WIN_EXTENT */ + } + else + { + strcpy (bp, termcap_name); +#ifdef ADJUST_WIN_EXTENT + adjust_win_extent(&bp, 0, li, co); +#endif /* ADJUST_WIN_EXTENT */ + } + goto ret; + } + else + { /* It has tc=. Need to read /etc/termcap. */ + tcenv = termcap_name; + termcap_name = NULL; + } + } + + if (!termcap_name || !filep) +#ifdef VMS + termcap_name = "emacs_library:[etc]termcap.dat"; +#else + termcap_name = "/etc/termcap"; +#endif + + /* Here we know we must search a file and termcap_name has its name. */ + + fd = open (termcap_name, 0, 0); + if (fd < 0) + return -1; + + buf.size = BUFSIZE; + /* Add 1 to size to ensure room for terminating null. */ + buf.beg = (char *) xmalloc (buf.size + 1); + term = indirect ? indirect : name; + + if (!bp) + { + malloc_size = indirect ? strlen (tcenv) + 1 : buf.size; + bp = (char *) xmalloc (malloc_size); + } + bp1 = bp; + + if (indirect) + /* Copy the data from the environment variable. */ + { + strcpy (bp, tcenv); + bp1 += strlen (tcenv); + } + + while (term) + { + /* Scan the file, reading it via buf, till find start of main entry. */ + if (scan_file (term, fd, &buf) == 0) + { + close (fd); + free (buf.beg); + if (malloc_size) + free (bp); + return 0; + } + + /* Free old `term' if appropriate. */ + if (term != name) + free (term); + + /* If BP is malloc'd by us, make sure it is big enough. */ + if (malloc_size) + { + malloc_size = bp1 - bp + buf.size; + termcap_name = (char *) xrealloc (bp, malloc_size); + bp1 += termcap_name - bp; + bp = termcap_name; + } + + bp2 = bp1; + + /* Copy the line of the entry from buf into bp. */ + termcap_name = buf.ptr; + while ((*bp1++ = c = *termcap_name++) && c != '\n') + /* Drop out any \ newline sequence. */ + if (c == '\\' && *termcap_name == '\n') + { + bp1--; + termcap_name++; + } + *bp1 = '\0'; + + /* Does this entry refer to another terminal type's entry? + If something is found, copy it into heap and null-terminate it. */ + term = tgetst1 (find_capability (bp2, "tc"), (char **) 0); + } + + close (fd); + free (buf.beg); + + if (malloc_size) + bp = (char *) xrealloc (bp, bp1 - bp + 1); +#ifdef ADJUST_WIN_EXTENT + adjust_win_extent(&bp, malloc_size ? 2 : 0, li, co); +#endif /* ADJUST_WIN_EXTENT */ + + ret: + term_entry = bp; + if (malloc_size) + return (int) bp; + return 1; +} + +/* Given file open on FD and buffer BUFP, + scan the file from the beginning until a line is found + that starts the entry for terminal type STR. + Return 1 if successful, with that line in BUFP, + or 0 if no entry is found in the file. */ + +static int +scan_file (str, fd, bufp) + char *str; + int fd; + register struct buffer *bufp; +{ + register char *end; + + bufp->ptr = bufp->beg; + bufp->full = 0; + bufp->ateof = 0; + *bufp->ptr = '\0'; + + lseek (fd, 0L, 0); + + while (!bufp->ateof) + { + /* Read a line into the buffer. */ + end = NULL; + do + { + /* if it is continued, append another line to it, + until a non-continued line ends. */ + end = gobble_line (fd, bufp, end); + } + while (!bufp->ateof && end[-2] == '\\'); + + if (*bufp->ptr != '#' + && name_match (bufp->ptr, str)) + return 1; + + /* Discard the line just processed. */ + bufp->ptr = end; + } + return 0; +} + +/* Return nonzero if NAME is one of the names specified + by termcap entry LINE. */ + +static int +name_match (line, name) + char *line, *name; +{ + register char *tem; + + if (!compare_contin (line, name)) + return 1; + /* This line starts an entry. Is it the right one? */ + for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++) + if (*tem == '|' && !compare_contin (tem + 1, name)) + return 1; + + return 0; +} + +static int +compare_contin (str1, str2) + register char *str1, *str2; +{ + register int c1, c2; + while (1) + { + c1 = *str1++; + c2 = *str2++; + while (c1 == '\\' && *str1 == '\n') + { + str1++; + while ((c1 = *str1++) == ' ' || c1 == '\t'); + } + if (c2 == '\0') + { + /* End of type being looked up. */ + if (c1 == '|' || c1 == ':') + /* If end of name in data base, we win. */ + return 0; + else + return 1; + } + else if (c1 != c2) + return 1; + } +} + +/* Make sure that the buffer <- BUFP contains a full line + of the file open on FD, starting at the place BUFP->ptr + points to. Can read more of the file, discard stuff before + BUFP->ptr, or make the buffer bigger. + + Return the pointer to after the newline ending the line, + or to the end of the file, if there is no newline to end it. + + Can also merge on continuation lines. If APPEND_END is + non-null, it points past the newline of a line that is + continued; we add another line onto it and regard the whole + thing as one line. The caller decides when a line is continued. */ + +static char * +gobble_line (fd, bufp, append_end) + int fd; + register struct buffer *bufp; + char *append_end; +{ + register char *end; + register int nread; + register char *buf = bufp->beg; + register char *tem; + + if (!append_end) + append_end = bufp->ptr; + + while (1) + { + end = append_end; + while (*end && *end != '\n') end++; + if (*end) + break; + if (bufp->ateof) + return buf + bufp->full; + if (bufp->ptr == buf) + { + if (bufp->full == bufp->size) + { + bufp->size *= 2; + /* Add 1 to size to ensure room for terminating null. */ + tem = (char *) xrealloc (buf, bufp->size + 1); + bufp->ptr = (bufp->ptr - buf) + tem; + append_end = (append_end - buf) + tem; + bufp->beg = buf = tem; + } + } + else + { + append_end -= bufp->ptr - buf; + bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf); + bufp->ptr = buf; + } + if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full))) + bufp->ateof = 1; + bufp->full += nread; + buf[bufp->full] = '\0'; + } + return end + 1; +} + +#ifdef TEST + +#ifdef NULL +#undef NULL +#endif + +#include + +main (argc, argv) + int argc; + char **argv; +{ + char *term; + char *buf; + + term = argv[1]; + printf ("TERM: %s\n", term); + + buf = (char *) tgetent (0, term); + if ((int) buf <= 0) + { + printf ("No entry.\n"); + return 0; + } + + printf ("Entry: %s\n", buf); + + tprint ("cm"); + tprint ("AL"); + + printf ("co: %d\n", tgetnum ("co")); + printf ("am: %d\n", tgetflag ("am")); +} + +tprint (cap) + char *cap; +{ + char *x = tgetstr (cap, 0); + register char *y; + + printf ("%s: ", cap); + if (x) + { + for (y = x; *y; y++) + if (*y <= ' ' || *y == 0177) + printf ("\\%0o", *y); + else + putchar (*y); + free (x); + } + else + printf ("none"); + putchar ('\n'); +} + +#endif /* TEST */ + diff --git a/libc/termcap/tparam.c b/libc/termcap/tparam.c new file mode 100644 index 000000000..2caf11bcd --- /dev/null +++ b/libc/termcap/tparam.c @@ -0,0 +1,319 @@ +/* Merge parameters into a termcap entry string. + Copyright (C) 1985, 1987, 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include + +/* Emacs config.h may rename various library functions such as malloc. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#else /* not HAVE_CONFIG_H */ + + +#endif /* not HAVE_CONFIG_H */ + +#ifndef NULL +#define NULL (char *) 0 +#endif + +#ifndef emacs +static void +memory_out () +{ + write (2, "virtual memory exhausted\n", 25); + exit (1); +} + +static char * +xmalloc (size) + unsigned size; +{ + register char *tem = malloc (size); + + if (!tem) + memory_out (); + return tem; +} + +static char * +xrealloc (ptr, size) + char *ptr; + unsigned size; +{ + register char *tem = realloc (ptr, size); + + if (!tem) + memory_out (); + return tem; +} +#endif /* not emacs */ + +/* Assuming STRING is the value of a termcap string entry + containing `%' constructs to expand parameters, + merge in parameter values and store result in block OUTSTRING points to. + LEN is the length of OUTSTRING. If more space is needed, + a block is allocated with `malloc'. + + The value returned is the address of the resulting string. + This may be OUTSTRING or may be the address of a block got with `malloc'. + In the latter case, the caller must free the block. + + The fourth and following args to tparam serve as the parameter values. */ + +static char *tparam1 (); + +/* VARARGS 2 */ +char * +tparam (string, outstring, len, arg0, arg1, arg2, arg3) + char *string; + char *outstring; + int len; + int arg0, arg1, arg2, arg3; +{ +#ifdef NO_ARG_ARRAY + int arg[4]; + arg[0] = arg0; + arg[1] = arg1; + arg[2] = arg2; + arg[3] = arg3; + return tparam1 (string, outstring, len, NULL, NULL, arg); +#else + return tparam1 (string, outstring, len, NULL, NULL, &arg0); +#endif +} + +char *BC; +char *UP; + +static char tgoto_buf[50]; + +char * +tgoto (cm, hpos, vpos) + char *cm; + int hpos, vpos; +{ + int args[2]; + if (!cm) + return NULL; + args[0] = vpos; + args[1] = hpos; + return tparam1 (cm, tgoto_buf, 50, UP, BC, args); +} + +static char * +tparam1 (string, outstring, len, up, left, argp) + char *string; + char *outstring; + int len; + char *up, *left; + register int *argp; +{ + register int c; + register char *p = string; + register char *op = outstring; + char *outend; + int outlen = 0; + + register int tem; + int *old_argp = argp; + int doleft = 0; + int doup = 0; + + outend = outstring + len; + + while (1) + { + /* If the buffer might be too short, make it bigger. */ + if (op + 5 >= outend) + { + register char *new; + if (outlen == 0) + { + outlen = len + 40; + new = (char *) xmalloc (outlen); + outend += 40; + bcopy (outstring, new, op - outstring); + } + else + { + outend += outlen; + outlen *= 2; + new = (char *) xrealloc (outstring, outlen); + } + op += new - outstring; + outend += new - outstring; + outstring = new; + } + c = *p++; + if (!c) + break; + if (c == '%') + { + c = *p++; + tem = *argp; + switch (c) + { + case 'd': /* %d means output in decimal. */ + if (tem < 10) + goto onedigit; + if (tem < 100) + goto twodigit; + case '3': /* %3 means output in decimal, 3 digits. */ + if (tem > 999) + { + *op++ = tem / 1000 + '0'; + tem %= 1000; + } + *op++ = tem / 100 + '0'; + case '2': /* %2 means output in decimal, 2 digits. */ + twodigit: + tem %= 100; + *op++ = tem / 10 + '0'; + onedigit: + *op++ = tem % 10 + '0'; + argp++; + break; + + case 'C': + /* For c-100: print quotient of value by 96, if nonzero, + then do like %+. */ + if (tem >= 96) + { + *op++ = tem / 96; + tem %= 96; + } + case '+': /* %+x means add character code of char x. */ + tem += *p++; + case '.': /* %. means output as character. */ + if (left) + { + /* If want to forbid output of 0 and \n and \t, + and this is one of them, increment it. */ + while (tem == 0 || tem == '\n' || tem == '\t') + { + tem++; + if (argp == old_argp) + doup++, outend -= strlen (up); + else + doleft++, outend -= strlen (left); + } + } + *op++ = tem ? tem : 0200; + case 'f': /* %f means discard next arg. */ + argp++; + break; + + case 'b': /* %b means back up one arg (and re-use it). */ + argp--; + break; + + case 'r': /* %r means interchange following two args. */ + argp[0] = argp[1]; + argp[1] = tem; + old_argp++; + break; + + case '>': /* %>xy means if arg is > char code of x, */ + if (argp[0] > *p++) /* then add char code of y to the arg, */ + argp[0] += *p; /* and in any case don't output. */ + p++; /* Leave the arg to be output later. */ + break; + + case 'a': /* %a means arithmetic. */ + /* Next character says what operation. + Add or subtract either a constant or some other arg. */ + /* First following character is + to add or - to subtract + or = to assign. */ + /* Next following char is 'p' and an arg spec + (0100 plus position of that arg relative to this one) + or 'c' and a constant stored in a character. */ + tem = p[2] & 0177; + if (p[1] == 'p') + tem = argp[tem - 0100]; + if (p[0] == '-') + argp[0] -= tem; + else if (p[0] == '+') + argp[0] += tem; + else if (p[0] == '*') + argp[0] *= tem; + else if (p[0] == '/') + argp[0] /= tem; + else + argp[0] = tem; + + p += 3; + break; + + case 'i': /* %i means add one to arg, */ + argp[0] ++; /* and leave it to be output later. */ + argp[1] ++; /* Increment the following arg, too! */ + break; + + case '%': /* %% means output %; no arg. */ + goto ordinary; + + case 'n': /* %n means xor each of next two args with 140. */ + argp[0] ^= 0140; + argp[1] ^= 0140; + break; + + case 'm': /* %m means xor each of next two args with 177. */ + argp[0] ^= 0177; + argp[1] ^= 0177; + break; + + case 'B': /* %B means express arg as BCD char code. */ + argp[0] += 6 * (tem / 10); + break; + + case 'D': /* %D means weird Delta Data transformation. */ + argp[0] -= 2 * (tem % 16); + break; + } + } + else + /* Ordinary character in the argument string. */ + ordinary: + *op++ = c; + } + *op = 0; + while (doup-- > 0) + strcat (op, up); + while (doleft-- > 0) + strcat (op, left); + return outstring; +} + +#ifdef DEBUG + +main (argc, argv) + int argc; + char **argv; +{ + char buf[50]; + int args[3]; + args[0] = atoi (argv[2]); + args[1] = atoi (argv[3]); + args[2] = atoi (argv[4]); + tparam1 (argv[1], buf, "LEFT", "UP", args); + printf ("%s\n", buf); + return 0; +} + +#endif /* DEBUG */ diff --git a/libc/termios/Makefile b/libc/termios/Makefile new file mode 100644 index 000000000..35989a96f --- /dev/null +++ b/libc/termios/Makefile @@ -0,0 +1,16 @@ +# Makefile of /libc/termios module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS= termios.c ttyname.c +OBJS= $(SRCS:.c=.o) + +all: $(LIBC) + +$(OBJS): $(SRCS) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +clean: + rm -f *.o diff --git a/libc/termios/termios.c b/libc/termios/termios.c new file mode 100644 index 000000000..fc087a373 --- /dev/null +++ b/libc/termios/termios.c @@ -0,0 +1,199 @@ +/* Copyright (C) 1996 Robert de Bath This + * file is part of the Linux-8086 C library and is distributed under the + * GNU Library General Public License. + */ + +/* Note: This is based loosely on the Glib termios routines. */ + +#include +#include +#include +#include +#include + +//----------------------------------------------------------------------------- + +int isatty (int fd) +{ + struct termios term; + int rv, err = errno; + rv= (ioctl(fd, TCGETS, &term)==0); + if( rv==0 && errno == ENOSYS ) + rv = (fd<3); + errno = err; + return rv; +} + +//----------------------------------------------------------------------------- + +int tcgetattr (int fd, struct termios * termios_p) +{ + return ioctl(fd, TCGETS, termios_p); +} + +//----------------------------------------------------------------------------- + +int tcsetattr (int fd, int optional_actions, const struct termios * termios_p) +{ + switch (optional_actions) + { + case TCSANOW: + return ioctl(fd, TCSETS, termios_p); + case TCSADRAIN: + return ioctl(fd, TCSETSW, termios_p); + case TCSAFLUSH: + return ioctl(fd, TCSETSF, termios_p); + default: + errno = EINVAL; + return -1; + } +} + +//----------------------------------------------------------------------------- + +#ifdef L_tcdrain +/* Wait for pending output to be written on FD. */ +int +tcdrain(fd) +int fd; +{ + /* With an argument of 1, TCSBRK just waits for output to drain. */ + return ioctl(fd, TCSBRK, 1); +} +#endif + +#ifdef L_tcflow +int +tcflow(fd, action) +int fd; +int action; +{ + return ioctl(fd, TCXONC, action); +} +#endif + +/* Flush pending data on FD. */ +int +tcflush(fd, queue_selector) +int fd; +int queue_selector; +{ + return ioctl(fd, TCFLSH, queue_selector); +} + +/* Send zero bits on FD. */ +int +tcsendbreak(fd, duration) +int fd; +int duration; +{ + /* + * The break lasts 0.25 to 0.5 seconds if DURATION is zero, and an + * implementation-defined period if DURATION is nonzero. We define a + * positive DURATION to be number of milliseconds to break. + */ + if (duration <= 0) + return ioctl(fd, TCSBRK, 0); + + /* + * ioctl can't send a break of any other duration for us. This could be + * changed to use trickery (e.g. lower speed and send a '\0') to send + * the break, but for now just return an error. + */ + errno = EINVAL; + return -1; +} + +#ifdef L_tcsetpgrp +/* Set the foreground process group ID of FD set PGRP_ID. */ +int +tcsetpgrp(fd, pgrp_id) +int fd; +pid_t pgrp_id; +{ + return ioctl(fd, TIOCSPGRP, &pgrp_id); +} +#endif + +#ifdef L_tcgetpgrp +/* Return the foreground process group ID of FD. */ +pid_t +tcgetpgrp(fd) +int fd; +{ + int pgrp; + if (ioctl(fd, TIOCGPGRP, &pgrp) < 0) + return (pid_t) - 1; + return (pid_t) pgrp; +} +#endif + +speed_t cfgetospeed(tp) +struct termios *tp; +{ + return (tp->c_cflag & CBAUD); +} + +speed_t cfgetispeed(tp) +struct termios *tp; +{ + return (tp->c_cflag & CBAUD); +} + +int cfsetospeed(tp, speed) +struct termios *tp; speed_t speed; +{ +#ifdef CBAUDEX + if ((speed & ~CBAUD) || + ((speed & CBAUDEX) && (speed < B57600 || speed > B115200))) + return 0; +#else + if (speed & ~CBAUD) + return 0; +#endif + tp->c_cflag &= ~CBAUD; + tp->c_cflag |= speed; + + return 0; +} + +int cfsetispeed(tp, speed) +struct termios *tp; speed_t speed; +{ + return cfsetospeed(tp, speed); +} + +/* From linux libc-4.6.27 again */ +#ifdef L_cfmakeraw +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library.*/ + +void +cfmakeraw(t) +struct termios *t; +{ +/* I changed it to the current form according to the suggestions + * from Bruce Evans. Thanks Bruce. Please report the problems to + * H.J. Lu (hlu@eecs.wsu.edu). + */ + +/* + * I took out the bits commented out by #if 1...#else - RHP + */ + + /* VMIN = 0 means non-blocking for Linux */ + t->c_cc[VMIN] = 1; t->c_cc[VTIME] = 1; + /* clear some bits with &= ~(bits), set others with |= */ + t->c_cflag &= ~(CSIZE|PARENB|CSTOPB); + t->c_cflag |= (CS8|HUPCL|CREAD); + t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|INPCK|ISTRIP); + t->c_iflag &= ~(INLCR|IGNCR|ICRNL|IXON|IXOFF); + t->c_iflag |= (BRKINT|IGNPAR); + t->c_oflag &= ~(OPOST|OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL); + t->c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY); + t->c_oflag |= (ONLCR|NL0|CR0|TAB3|BS0|VT0|FF0); + t->c_lflag &= ~(ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK|ECHONL); + t->c_lflag &= ~(NOFLSH|XCASE); + t->c_lflag &= ~(ECHOPRT|ECHOCTL|ECHOKE); +} +#endif diff --git a/libc/termios/ttyname.c b/libc/termios/ttyname.c new file mode 100644 index 000000000..8b19df0e4 --- /dev/null +++ b/libc/termios/ttyname.c @@ -0,0 +1,47 @@ + +#include +#include +#include +#include +#include + +char * ttyname (int fd) +{ + static char dev[] = "/dev"; + struct stat st, dst; + DIR *fp; + struct dirent *d; + static char name[16]; /* should be MAXNAMLEN but that's overkill */ + int noerr = errno; + + if (fstat(fd, &st) < 0) + return 0; + if (!isatty(fd)) + { + errno = ENOTTY; + return 0; + } + + fp = opendir(dev); + if (fp == 0) + return 0; + strcpy(name, dev); + strcat(name, "/"); + + while ((d = readdir(fp)) != 0) + { + if( strlen(d->d_name) > sizeof(name) - sizeof(dev) - 1) + continue; + strcpy(name + sizeof(dev), d->d_name); + if (stat(name, &dst) == 0 + && st.st_dev == dst.st_dev && st.st_ino == dst.st_ino) + { + closedir(fp); + errno = noerr; + return name; + } + } + closedir(fp); + errno = noerr; + return 0; +} diff --git a/libc/time/Makefile b/libc/time/Makefile new file mode 100644 index 000000000..fa99be6b6 --- /dev/null +++ b/libc/time/Makefile @@ -0,0 +1,16 @@ +# Makefile of /libc/termios module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS= localtime.c ctime.c tm_conv.c asctime.c asc_conv.c +OBJS= $(SRCS:.c=.o) + +all: $(LIBC) + +$(OBJS): $(SRCS) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +clean: + rm -f *.o diff --git a/libc/time/asc_conv.c b/libc/time/asc_conv.c new file mode 100644 index 000000000..78cbcdd8d --- /dev/null +++ b/libc/time/asc_conv.c @@ -0,0 +1,49 @@ + +#include +#include +/* + * Internal ascii conversion routine, avoid use of printf, it's a bit big! + */ + + +static void +hit(buf, val) +char * buf; +int val; +{ + *buf = '0' + val%10; +} + +void +__asctime(buffer, ptm) +register char * buffer; +struct tm * ptm; +{ +static char days[] = "SunMonTueWedThuFriSat"; +static char mons[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + int year; + + /* 012345678901234567890123456 */ + strcpy(buffer, "Err Err .. ..:..:.. ....\n"); + if( (ptm->tm_wday >= 0) && (ptm->tm_wday <= 6) ) + memcpy(buffer, days+3*(ptm->tm_wday), 3); + + if( (ptm->tm_mon >= 0) && (ptm->tm_mon <= 11) ) + memcpy(buffer+4, mons+3*(ptm->tm_mon), 3); + + + hit(buffer+ 8, ptm->tm_mday/10); + hit(buffer+ 9, ptm->tm_mday ); + hit(buffer+11, ptm->tm_hour/10); + hit(buffer+12, ptm->tm_hour ); + hit(buffer+14, ptm->tm_min/10); + hit(buffer+15, ptm->tm_min ); + hit(buffer+17, ptm->tm_sec/10); + hit(buffer+18, ptm->tm_sec ); + + year = ptm->tm_year + 1900; + hit(buffer+20, year/1000); + hit(buffer+21, year/100); + hit(buffer+22, year/10); + hit(buffer+23, year); +} diff --git a/libc/time/asctime.c b/libc/time/asctime.c new file mode 100644 index 000000000..ea13bf8e9 --- /dev/null +++ b/libc/time/asctime.c @@ -0,0 +1,15 @@ + +#include + +extern void __asctime(); + +char * +asctime(timeptr) +__const struct tm * timeptr; +{ +static char timebuf[26]; + + if( timeptr == 0 ) return 0; + __asctime(timebuf, timeptr); + return timebuf; +} diff --git a/libc/time/ctime.c b/libc/time/ctime.c new file mode 100644 index 000000000..37d1f2919 --- /dev/null +++ b/libc/time/ctime.c @@ -0,0 +1,27 @@ + +#include +#include + +extern void __tm_conv(); +extern void __asctime(); + +char * +ctime(timep) +__const time_t * timep; +{ + static char cbuf[26]; + struct tm tmb; + struct timezone tz; + time_t offt; + + gettimeofday((void*)0, &tz); + + offt = -tz.tz_minuteswest*60L; + + /* tmb.tm_isdst = ? */ + __tm_conv(&tmb, timep, offt); + + __asctime(cbuf, &tmb); + + return cbuf; +} diff --git a/libc/time/localtime.c b/libc/time/localtime.c new file mode 100644 index 000000000..527f87d8c --- /dev/null +++ b/libc/time/localtime.c @@ -0,0 +1,22 @@ + +#include + +#include + +extern void __tm_conv(); + +struct tm * localtime (const time_t * timep) +{ + static struct tm tmb; + struct timezone tz; + time_t offt; + + gettimeofday((void*)0, &tz); + + offt = -tz.tz_minuteswest*60L; + + /* tmb.tm_isdst = ? */ + __tm_conv(&tmb, timep, offt); + + return &tmb; +} diff --git a/libc/time/tm_conv.c b/libc/time/tm_conv.c new file mode 100644 index 000000000..ffd524c4b --- /dev/null +++ b/libc/time/tm_conv.c @@ -0,0 +1,138 @@ + +#if 0 +#include + +/* This is a translation from ALGOL in Collected Algorithms of CACM. */ +/* Copied from Algorithm 199, Author: Robert G. Tantzen */ + +void +__tm_conv(tmbuf, timep, offset) +struct tm *tmbuf; +time_t *timep; +time_t offset; +{ +static int moffset[] = + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + + long s; + long j, d, m, y; + + offset += *timep; + + tmbuf->tm_isdst = 0; /* Someone else can set this */ + + j = offset / 86400L + 719469; + s = offset % 86400L; + + if( s < 0 ) { s += 86400L; j--; } + + tmbuf->tm_sec = s % 60; + tmbuf->tm_min = (s / 60) % 60; + tmbuf->tm_hour = s / 3600; + + tmbuf->tm_wday = (j+2) % 7; + + /* + * Julian date converter. Takes a julian date (the number of days since + * some distant epoch or other), and fills tmbuf. + */ + + y = (4L * j - 1L) / 146097L; + j = 4L * j - 1L - 146097L * y; + d = j / 4L; + j = (4L * d + 3L) / 1461L; + d = 4L * d + 3L - 1461L * j; + d = (d + 4L) / 4L; + m = (5L * d - 3L) / 153L; + d = 5L * d - 3 - 153L * m; + d = (d + 5L) / 5L; + y = 100L * y + j; + if (m < 10) + m += 2; + else + { + m -= 10; + ++y; + } + + tmbuf->tm_year = y - 1900; + tmbuf->tm_mon = m; + tmbuf->tm_mday = d; + + tmbuf->tm_yday = d + moffset[m]; + if (m > 1 && ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))) + tmbuf->tm_yday++; +} + +#else + +/* This is adapted from glibc */ +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc */ + +#define SECS_PER_HOUR 3600L +#define SECS_PER_DAY 86400L + +#include + +static const unsigned short int __mon_lengths[2][12] = + { + /* Normal years. */ + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + /* Leap years. */ + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + + +void +__tm_conv(tmbuf, t, offset) +struct tm *tmbuf; +time_t *t; +time_t offset; +{ + long days, rem; + register int y; + register unsigned short int *ip; + + days = *t / SECS_PER_DAY; + rem = *t % SECS_PER_DAY; + rem += offset; + while (rem < 0) + { + rem += SECS_PER_DAY; + --days; + } + while (rem >= SECS_PER_DAY) + { + rem -= SECS_PER_DAY; + ++days; + } + tmbuf->tm_hour = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + tmbuf->tm_min = rem / 60; + tmbuf->tm_sec = rem % 60; + /* January 1, 1970 was a Thursday. */ + tmbuf->tm_wday = (4 + days) % 7; + if (tmbuf->tm_wday < 0) + tmbuf->tm_wday += 7; + y = 1970; + while (days >= (rem = __isleap(y) ? 366 : 365)) + { + ++y; + days -= rem; + } + while (days < 0) + { + --y; + days += __isleap(y) ? 366 : 365; + } + tmbuf->tm_year = y - 1900; + tmbuf->tm_yday = days; + ip = __mon_lengths[__isleap(y)]; + for (y = 0; days >= ip[y]; ++y) + days -= ip[y]; + tmbuf->tm_mon = y; + tmbuf->tm_mday = days + 1; + tmbuf->tm_isdst = -1; +} + +#endif From 563b656804df81f5d684e4289286220e6b9a3ff2 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Sun, 24 Jun 2018 14:40:26 +0200 Subject: [PATCH 02/20] [libc] Test round 1 with sash - Fix process entry point - Tune memory allocation - Unify table of system calls --- elks/arch/i86/kernel/process.c | 5 +- elks/arch/i86/kernel/syscall.dat | 16 +- elks/arch/i86/mm/malloc.c | 17 +- elks/fs/exec.c | 27 +- elks/include/linuxmt/init.h | 2 +- elks/include/linuxmt/minix.h | 4 +- elkscmd/Make.defs | 4 +- elkscmd/sash/Makefile | 2 +- elkscmd/sys_utils/Makefile | 2 + elkscmd/sys_utils/init.c | 4 +- libc/crt0.S | 7 +- libc/include/unistd.h | 3 +- libc/malloc/heap.c | 146 +-------- libc/misc/getcwd.c | 19 +- libc/stdio/printf.c | 2 +- libc/system/call_tab.v | 75 ----- libc/system/syscall.dat | 170 ----------- libc/system/syscall1.s | 510 ------------------------------- 18 files changed, 87 insertions(+), 928 deletions(-) delete mode 100644 libc/system/call_tab.v delete mode 100644 libc/system/syscall.dat delete mode 100644 libc/system/syscall1.s diff --git a/elks/arch/i86/kernel/process.c b/elks/arch/i86/kernel/process.c index 2e6e2b4d0..85c31b628 100644 --- a/elks/arch/i86/kernel/process.c +++ b/elks/arch/i86/kernel/process.c @@ -92,13 +92,12 @@ unsigned get_ustack(register struct task_struct *t,int off) /* * Called by sys_execve() - * Despite its name, this function sets up the user stack */ -void arch_setup_kernel_stack(register struct task_struct *t) +void arch_setup_user_stack (register struct task_struct * t, word_t entry) { put_ustack(t, -2, USER_FLAGS); /* Flags */ put_ustack(t, -4, (int) t->t_xregs.cs); /* user CS */ - put_ustack(t, -6, 0); /* addr 0 */ + put_ustack(t, -6, entry); /* user entry point */ put_ustack(t, -8, 0); /* user BP */ t->t_regs.sp -= 8; } diff --git a/elks/arch/i86/kernel/syscall.dat b/elks/arch/i86/kernel/syscall.dat index f34d03016..123a1a358 100644 --- a/elks/arch/i86/kernel/syscall.dat +++ b/elks/arch/i86/kernel/syscall.dat @@ -5,7 +5,7 @@ # all three of those packages. # # '.' = Ok, with comment -# '*' = Needs libc code (Prefix __) +# '*' = Needs libc code (Prefix _) # '-' = Obsolete/not required # '@' = May be required later # '=' = Depends on stated config variable @@ -87,13 +87,17 @@ insmod 65 1 - Removed support for modules fchown +66 3 dlload +67 2 - Removed support for dynamic libraries setsid +68 0 -socket +69 3 = CONFIG_SOCKET -bind +70 3 = CONFIG_SOCKET -listen +71 2 = CONFIG_SOCKET -accept +72 3 = CONFIG_SOCKET -connect +73 3 = CONFIG_SOCKET +sbrk +69 2 * Legacy number from Linux knlvsn +74 1 = CONFIG_SYS_VERSION # +# From /usr/include/asm-generic/unistd.h +# +socket +198 3 = CONFIG_SOCKET +bind +200 3 = CONFIG_SOCKET +listen +201 2 = CONFIG_SOCKET +accept +202 3 = CONFIG_SOCKET +connect +203 3 = CONFIG_SOCKET +# # Name No Args Flag&comment # # ( awk '{$2=NR+500;OFS="\t";print ;}'| expand -24,32,40 | unexpand ) <t_enddata, currentp->t_begstack, currentp->t_endbrk, currentp->t_endseg, mm_get_usage(MM_MEM, 1), @@ -771,6 +771,21 @@ int sys_brk(__pptr len) return 0; } + +int sys_sbrk (int increment, u16_t * pbrk) +{ + __pptr brk = current->t_endbrk; + if (increment) { + brk += increment; + int err = sys_brk (brk); + if (err) return err; + } + + put_user (brk, pbrk); + return 0; +} + + /* * Initialise the memory manager. */ diff --git a/elks/fs/exec.c b/elks/fs/exec.c index 9b04d30ac..f2509eb5e 100644 --- a/elks/fs/exec.c +++ b/elks/fs/exec.c @@ -51,7 +51,11 @@ static struct minix_exec_hdr mh; static struct minix_supl_hdr msuph; #endif -#define INIT_HEAP 0x0 +// Default data sizes + +#define INIT_HEAP 0x1000 // 4 K +#define INIT_STACK 0x1000 // 4 K + int sys_execve(char *filename, char *sptr, size_t slen) { @@ -100,17 +104,23 @@ int sys_execve(char *filename, char *sptr, size_t slen) /* Sanity check it. */ if (retval != (int)sizeof(mh) || - (mh.type != MINIX_SPLITID) || mh.chmem < 1024 || mh.tseg == 0) { + (mh.type != MINIX_SPLITID) || mh.tseg == 0) { debug1("EXEC: bad header, result %u\n", retval); goto error_exec3; } /* * Size for data segment - * mh.chmem is "total size" requested by ld. Note that ld used to ask - * for (at least) 64K + * mh.chmem was used by old ld86 + * New LD script sets this to zero (default) */ len = mh.chmem; + if (!len) len = mh.dseg + mh.bseg + INIT_HEAP + INIT_STACK; + + // TODO: revise the ELKS specific executable format + // as we now master the executable header content + // with the new GNU build tool chain (custom LD script) + #ifdef CONFIG_EXEC_ELKS if ((unsigned int) mh.hlen == 0x30) { /* BIG HEADER */ @@ -129,7 +139,7 @@ int sys_execve(char *filename, char *sptr, size_t slen) if ((unsigned int) mh.hlen != 0x20) goto error_exec3; len = (len + 15) & ~15L; - if (len > (lsize_t) 0x10000L) goto error_exec3; + if (len > (lsize_t) 0xFFFFL) goto error_exec3; // 64K - 1 to avoid 16 bits rounding debug("EXEC: Malloc time\n"); @@ -234,13 +244,12 @@ int sys_execve(char *filename, char *sptr, size_t slen) } currentp->t_enddata = (__pptr) ((__u16)mh.dseg + (__u16)mh.bseg + base_data); - currentp->t_endbrk = currentp->t_enddata + INIT_HEAP; + currentp->t_endbrk = currentp->t_enddata; /* - * Arrange our return to be to CS:0 - * (better to use the entry offset in the header) + * Arrange our return to be to CS:entry */ - arch_setup_kernel_stack(currentp); + arch_setup_user_stack(currentp, (word_t) mh.entry); wake_up(¤tp->p_parent->child_wait); diff --git a/elks/include/linuxmt/init.h b/elks/include/linuxmt/init.h index 7fe184a6a..a8cc87173 100644 --- a/elks/include/linuxmt/init.h +++ b/elks/include/linuxmt/init.h @@ -36,7 +36,7 @@ extern void init_console(void); extern void device_setup(void); extern void kfork_proc(void ()); -extern void arch_setup_kernel_stack(struct task_struct *); +extern void arch_setup_user_stack(struct task_struct *, word_t entry); extern void setup_dev(register struct gendisk *); extern void mem_dev_init(void); extern void init_bioshd(void); diff --git a/elks/include/linuxmt/minix.h b/elks/include/linuxmt/minix.h index 98ea9dd20..88382c253 100644 --- a/elks/include/linuxmt/minix.h +++ b/elks/include/linuxmt/minix.h @@ -10,7 +10,7 @@ /* Values for the type field of minix_exec_header */ #define MINIX_COMBID 0x04100301UL -#define MINIX_SPLITID 0x04200301UL +#define MINIX_SPLITID 0x04300301UL // Executable (0x10) with separate I/D (0x20) #define MINIX_S_SPLITID 0x04600301UL #define MINIX_DLLID 0x04A00301UL @@ -20,7 +20,7 @@ struct minix_exec_hdr { unsigned long tseg; unsigned long dseg; unsigned long bseg; - unsigned long unused; + unsigned long entry; unsigned long chmem; unsigned long unused2; }; diff --git a/elkscmd/Make.defs b/elkscmd/Make.defs index ca0932744..8bf41bdc4 100644 --- a/elkscmd/Make.defs +++ b/elkscmd/Make.defs @@ -80,9 +80,11 @@ ifeq ($(PLATFORM),i86-ELKS) LD=ia16-elf-ld # LDFLAGS=-s -ansi LDFLAGS= -T $(TOPDIR)/elks/elks-small.ld +# TODO: move crt0 to begin of object files LDLIBS='-(' $(TOPDIR)/libc/crt0.o $(TOPDIR)/libc/libc.a '-)' CHECK=gcc -c -o .null.o -Wall -pedantic - AS=as86 + AS=ia16-elf-as + ASFLAGS=-mtune=i8086 endif ifeq ($(PLATFORM),DEFAULT) diff --git a/elkscmd/sash/Makefile b/elkscmd/sash/Makefile index a6d91bd14..f620ad3f2 100644 --- a/elkscmd/sash/Makefile +++ b/elkscmd/sash/Makefile @@ -17,7 +17,7 @@ OBJS = sash.o cmds.o cmd_dd.o cmd_ed.o cmd_grep.o cmd_ls.o cmd_tar.o utils.o all: sash sash: $(OBJS) - $(CC) $(LDFLAGS) -o sash $(OBJS) + $(LD) $(LDFLAGS) -o sash $(OBJS) $(LDLIBS) clean: rm -f core sash $(OBJS) diff --git a/elkscmd/sys_utils/Makefile b/elkscmd/sys_utils/Makefile index 91105f3bc..0f5a84dac 100644 --- a/elkscmd/sys_utils/Makefile +++ b/elkscmd/sys_utils/Makefile @@ -13,6 +13,8 @@ include $(BASEDIR)/Make.rules PRGS = init getty login kill mount umount passwd reboot shutdown ps \ swapon meminfo who knl man poweroff +CFLAGS += -DDEBUG + # clock disabled because direct I/O port access # exitemu disabled because it calls INT directly to DOSEMU diff --git a/elkscmd/sys_utils/init.c b/elkscmd/sys_utils/init.c index af2af947a..6573fa0be 100644 --- a/elkscmd/sys_utils/init.c +++ b/elkscmd/sys_utils/init.c @@ -463,7 +463,7 @@ int main(int argc, char **argv) argv[0] = "init"; #ifdef DEBUG - fd = open(DEVTTY, O_RDWR); + int fd = open(DEVTTY, O_RDWR); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); @@ -516,7 +516,7 @@ int main(int argc, char **argv) pid = wait(NULL); FPUTS("and "); - FPUTD(pid) + FPUTD(pid); FPUTS(" came out\n"); if (-1 == pid) continue; diff --git a/libc/crt0.S b/libc/crt0.S index 0f14f1d4b..dbcd408c4 100644 --- a/libc/crt0.S +++ b/libc/crt0.S @@ -17,12 +17,13 @@ entry: .global exit // C runtime startup +// Stack is empty and immediately followed by argc, argv and envp _startup: push %bp mov %sp,%bp - lea 6(%bp),%bx // argv [0] - mov 4(%bp),%cx // argc + lea 4(%bp),%bx // argv [0] + mov 2(%bp),%cx // argc mov %cx,%ax shl $1,%ax add %bx,%ax // envp [0] @@ -31,7 +32,7 @@ _startup: push %bx push %cx call main - add $4,%sp + add $6,%sp push %ax // main return value call exit // no return int $3 diff --git a/libc/include/unistd.h b/libc/include/unistd.h index c4988043d..7c6db6faf 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -38,7 +38,7 @@ typedef int intptr_t; // Functions int brk (void * addr); -void *sbrk (intptr_t increment); +void * sbrk (intptr_t increment); int close (int fildes); int dup2 (int oldfd, int newfd); @@ -51,3 +51,4 @@ pid_t setsid (); uid_t getuid (void); +char * getcwd (char * buf, size_t size); diff --git a/libc/malloc/heap.c b/libc/malloc/heap.c index 4c5a355fd..83726b43b 100644 --- a/libc/malloc/heap.c +++ b/libc/malloc/heap.c @@ -6,156 +6,24 @@ #include #include -/****************************************************************************/ - -#ifdef L_errno -int errno = 0; /* libc error value */ -#endif - -/****************************************************************************/ - -#ifdef __AS386_16__ - -#ifdef L___brk_addr -#asm -.data -export brk_addr -brk_addr: .word __end ! This holds the current return for sbrk(0) -.text -#endasm -#endif - -/****************************************************************************/ - -#ifdef L_sbrk -int sbrk(brk_off) -int brk_off; -{ -#asm - mov bx,sp -#if !__FIRST_ARG_IN_AX__ - mov ax,[bx+2] ! Fetch the requested value -#endif - test ax,ax - jnz has_change - mov ax,[brk_addr] ! Simple one, read current - can`t fail. - jmp eof - -has_change: - js go_down - add ax,[brk_addr] ! Goin up! - jc Enomem - sub bx,#511 ! Safety space 512 bytes - cmp bx,ax ! Too close ? - jb Enomem - -sbrk_ok: -#if !defined(__MSDOS__) && !defined(__STANDALONE__) - push ax ! MSDOS `kernel` doesn`t care - call ___brk ! Tell the kernel - test ax,ax - pop ax ! ASSUME ___brk doesn`t alter stack! - jnz Enomem ! Ugh! kernel didn`t like the idea! -#endif - xchg [brk_addr],ax ! Save away new val - jmp eof ! Return it -go_down: - add ax,[brk_addr] - jnc Enomem - cmp ax,#__end - jae sbrk_ok - -Enomem: - mov ax,#12 ! This should be ENOMEM not a magic. - mov [_errno],ax - mov ax,#-1 -eof: -#endasm -} -#endif - -/****************************************************************************/ - -#ifdef L_brk -int -brk(new_brk) -char * new_brk; -{ -#asm - mov bx,sp -#if !__FIRST_ARG_IN_AX__ - mov ax,[bx+2] ! Fetch the requested value -#endif - sub bx,#512 ! Safety space 512 bytes - cmp bx,ax ! Too close ? - jb Enomem - cmp ax,#__end - jae brk_ok -Enomem: - mov ax,#12 ! This should be ENOMEM not a magic. - mov [_errno],ax - mov ax,#-1 - ret -brk_ok: -#if !defined(__MSDOS__) && !defined(__STANDALONE__) - push ax - call ___brk ! Tell the kernel - test ax,ax - pop bx ! ASSUME ___brk doesn`t alter stack! - jnz Enomem ! Ugh! kernel didn`t like the idea! - mov [brk_addr],bx ! Save away new val -#else - mov [brk_addr],ax ! MSDOS `kernel` doesn`t care - mov ax,#0 -#endif -#endasm -} -#endif - -#endif - -//----------------------------------------------------------------------------- - -char * __brk_addr = 0; /* This holds the current return for sbrk(0) */ - -__brk_addr_init() -{ - if( __brk_addr == 0 && (__brk_addr = _brk(0)) == 0 ) - { - errno = ENOMEM; - return -1; - } - return 0; -} - //----------------------------------------------------------------------------- void * sbrk (intptr_t increment) { - char * new_brk; - if( __brk_addr_init() ) return (char*)-1; - if( increment == 0 ) return __brk_addr; + void * new_brk; + if (_sbrk (increment, &new_brk)) + return (void *) -1; - new_brk = __brk_addr + increment; - __brk_addr = _brk(new_brk); - if( __brk_addr != new_brk ) - { - errno = ENOMEM; - return (char*)-1; - } - return __brk_addr - increment; + return new_brk; } //----------------------------------------------------------------------------- +// TODO: simplify + int brk (void * addr) { - if( __brk_addr_init() ) return -1; - - __brk_addr = _brk(addr); - if( __brk_addr == addr ) return 0; - errno = ENOMEM; - return -1; + return _brk (addr); } //----------------------------------------------------------------------------- diff --git a/libc/misc/getcwd.c b/libc/misc/getcwd.c index 351214cf4..f3a792a02 100644 --- a/libc/misc/getcwd.c +++ b/libc/misc/getcwd.c @@ -30,7 +30,11 @@ int size; if( size < 3 ) { errno = ERANGE; return 0; } strcpy(path_buf, "."); - if( stat("/", &st) < 0 ) return 0; + if( stat("/", &st) < 0 ) + { + perror ("stat"); + return 0; + } root_dev = st.st_dev; root_ino = st.st_ino; @@ -43,7 +47,12 @@ recurser() { dev_t this_dev; ino_t this_ino; - if( stat(path_buf, &st) < 0 ) return 0; + if( stat(path_buf, &st) < 0 ) + { + perror ("stat"); + return 0; + } + this_dev = st.st_dev; this_ino = st.st_ino; if( this_dev == root_dev && this_ino == root_ino ) @@ -84,7 +93,11 @@ ino_t this_ino; slen++; dp = opendir(path_buf); - if( dp == 0 ) return 0; + if( dp == 0 ) + { + perror ("opendir"); + return 0; + } while( (d=readdir(dp)) != 0 ) { diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index 29509ba96..106dda974 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -145,7 +145,7 @@ int vfprintf(FILE *op, const char *fmt, va_list ap) int preci, dpoint, width; char pad, sign, radix, hash; register char *ptmp; - char tmp[64], *ltostr(), *ultostr(); + char tmp[64]; int buffer_mode; /* This speeds things up a bit for unbuffered */ diff --git a/libc/system/call_tab.v b/libc/system/call_tab.v deleted file mode 100644 index 0cb6ffa0b..000000000 --- a/libc/system/call_tab.v +++ /dev/null @@ -1,75 +0,0 @@ -/* 0 */ sys_enosys, /* */ -/* 1 */ sys_enosys, /* */ -/* 2 */ sys_enosys, /* */ -/* 3 */ sys_enosys, /* */ -/* 4 */ sys_enosys, /* */ -/* 5 */ sys_enosys, /* */ -/* 6 */ sys_enosys, /* */ -/* 7 */ sys_enosys, /* */ -/* 8 */ sys_enosys, /* creat */ -/* 9 */ sys_enosys, /* */ -/* 10 */ sys_enosys, /* */ -/* 11 */ sys_enosys, /* */ -/* 12 */ sys_enosys, /* */ -/* 13 */ sys_enosys, /* time */ -/* 14 */ sys_enosys, /* */ -/* 15 */ sys_enosys, /* */ -/* 16 */ sys_enosys, /* */ -/* 17 */ sys_enosys, /* */ -/* 18 */ sys_enosys, /* */ -/* 19 */ sys_enosys, /* */ -/* 20 */ sys_enosys, /* */ -/* 21 */ sys_enosys, /* */ -/* 22 */ sys_enosys, /* */ -/* 23 */ sys_enosys, /* */ -/* 24 */ sys_enosys, /* */ -/* 25 */ sys_enosys, /* stime */ -/* 26 */ sys_enosys, /* ptrace */ -/* 27 */ sys_alarm, -/* 28 */ sys_enosys, /* */ -/* 29 */ sys_pause, -/* 30 */ sys_enosys, /* */ -/* 31 */ sys_enosys, /* */ -/* 32 */ sys_enosys, /* */ -/* 33 */ sys_enosys, /* */ -/* 34 */ sys_nice, -/* 35 */ sys_sleep, -/* 36 */ sys_enosys, /* */ -/* 37 */ sys_enosys, /* */ -/* 38 */ sys_enosys, /* */ -/* 39 */ sys_enosys, /* */ -/* 40 */ sys_enosys, /* */ -/* 41 */ sys_enosys, /* */ -/* 42 */ sys_enosys, /* */ -/* 43 */ sys_times, -/* 44 */ sys_enosys, /* profil */ -/* 45 */ sys_enosys, /* */ -/* 46 */ sys_enosys, /* */ -/* 47 */ sys_getgid, -/* 48 */ sys_enosys, /* */ -/* 49 */ sys_enosys, /* getinfo */ -/* 50 */ sys_enosys, /* */ -/* 51 */ sys_enosys, /* acct */ -/* 52 */ sys_enosys, /* phys */ -/* 53 */ sys_enosys, /* lock */ -/* 54 */ sys_enosys, /* */ -/* 55 */ sys_enosys, /* */ -/* 56 */ sys_enosys, /* mpx */ -/* 57 */ sys_enosys, /* */ -/* 58 */ sys_enosys, /* */ -/* 59 */ sys_enosys, /* */ -/* 60 */ sys_enosys, /* */ -/* 61 */ sys_enosys, /* */ -/* 62 */ sys_enosys, /* */ -/* 63 */ sys_enosys, /* */ -/* 64 */ sys_enosys, /* */ -/* 65 */ sys_enosys, /* insmod */ -/* 66 */ sys_enosys, /* */ -/* 67 */ sys_enosys, /* */ -/* 68 */ sys_enosys, /* */ -/* 69 */ sys_enosys, /* */ -/* 70 */ sys_enosys, /* */ -/* 71 */ sys_enosys, /* */ -/* 72 */ sys_enosys, /* */ -/* 73 */ sys_enosys, /* */ -/* 74 */ sys_enosys, /* */ diff --git a/libc/system/syscall.dat b/libc/system/syscall.dat deleted file mode 100644 index 3aa1ef7ae..000000000 --- a/libc/system/syscall.dat +++ /dev/null @@ -1,170 +0,0 @@ -# -# warning! -# this file is used to generate the system call lists for dev86(elks) -# elksemu and elks itself. changes to this may require changes in -# all three of those packages. -# -# '.' = ok, with comment -# '*' = needs libc code (prefix __) -# '-' = obsolete/not required -# '@' = may be required later -# '=' = depends on stated config variable -# -# an initial plus on the call number specifies that this call is -# implemented in the kernel. -# -# package versions are matched. -# dev86/elksemu version - 0.13.1 -# elks version - 0.0.66 -# -# name no args flag, comment -# -exit +1 1 * c exit does stdio, _exit in crt0 -fork +2 0 -read +3 3 -write +4 3 -open +5 3 -close +6 1 -wait4 +7 4 -creat 8 0 - not needed alias for open -link +9 2 -unlink +10 1 -execve +11 3 * execve minix style -chdir +12 1 -time 13 1 - use settimeofday -mknod +14 3 -chmod +15 2 -chown +16 3 -brk +17 1 * this is only to tell the system -stat +18 2 -lseek +19 3 * nb 2nd arg is an io ptr to long not a long. -getpid +20 1 * this gets both pid & ppid -mount +21 5 -umount +22 1 -setuid +23 1 -getuid +24 1 * this gets both uid and euid -stime 25 2 - this must not exist - even as a libc. -ptrace 26 4 @ adb/sdb/dbx need this. -alarm 27 2 -fstat +28 2 -pause 29 0 -utime +30 2 -chroot +31 1 -vfork +32 0 -access +33 2 -nice 34 1 -sleep 35 1 -sync +36 0 -kill +37 2 -rename +38 2 -mkdir +39 2 -rmdir +40 1 -dup +41 1 . there is a fcntl lib function too. -pipe +42 1 = config_pipe -times 43 2 * 2nd arg is pointer for long ret val. -profil 44 4 @ -dup2 +45 2 -setgid +46 1 -getgid 47 1 * this gets both gid and egid -signal +48 2 * have put the despatch table in user space. -getinfo 49 1 @ possible? gets pid,ppid,uid,euid etc -fcntl +50 3 -acct 51 1 @ accounting to named file (off if null) -phys 52 3 - replaced by mmap() -lock 53 1 @ prevent swapping for this proc if flg!=0 -ioctl +54 3 . make this and fcntl the same ? -reboot +55 3 . the magic number is 0xfee1,0xdead,... -mpx 56 2 - replaced by fifos and select. -lstat +57 2 -symlink +58 2 -readlink +59 3 -umask +60 1 -settimeofday +61 2 -gettimeofday +62 2 -select +63 5 . 5 paramaters is possible -readdir +64 3 * -insmod 65 1 - removed support for modules -fchown +66 3 -dlload +67 2 - removed support for dynamic libraries -setsid +68 0 -socket +69 3 = config_socket -bind +70 3 = config_socket -listen +71 2 = config_socket -accept +72 3 = config_socket -connect +73 3 = config_socket -knlvsn +74 1 = config_sys_version -# -# name no args flag&comment -# -# ( awk '{$2=nr+500;ofs="\t";print ;}'| expand -24,32,40 | unexpand ) < Date: Sun, 24 Jun 2018 21:09:21 +0200 Subject: [PATCH 03/20] Update README and cleanup in libc/system --- README | 39 ++++++++++++++++++++++++++------------- libc/system/.gitignore | 4 ++++ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/README b/README index f4f71e87d..09f89085e 100644 --- a/README +++ b/README @@ -1,21 +1,31 @@ ELKS, the Embeddable Linux Kernel Subset ---------------------------------------- -This is a project to write a Linux-like operating system for systems based on -the Intel IA16 architecture (16 bits processors: i8088, i8086, i80188, i80186, -i80286, V20, V30 and compatibles). -Such systems are ancient computers (IBM-PC XT/AT and clones) or more recent -embedded ones that reuse their huge hardware & software legacy. +What is this ? +-------------- -To build ELKS, you need a cross build chain, mainly based on DEV86 (still used -for the user land) and GCC-IA16 (now used for the kernel). +This is a project to write a Linux-like OS for systems based on the Intel +IA16 architecture (16 bits processors: 8088, 8086, 80188, 80186, 80286, +Nec V20, V30 and compatibles). -A script is provided to automatically download and build that cross chain: +Such systems are ancient computers (IBM-PC XT / AT and clones), or more +recent SBC / SoC / FPGA that reuse the huge hardware & software legacy +from that popular platform. + + +How to build ? +-------------- + +To build ELKS, you need a cross build tool chain, mainly based on the latest +GCC-IA16 (DEV86 including BCC was used for previous versions, but has been +dropped because it was obsolete and no more actively maintained). + +A script is provided to automatically download and build that tool chain: 'tools/build.sh' -Note: all the scripts must be executed with the top folder 'elks/' as the +Note: all the scripts must be executed within the top folder 'elks/' as the current one. A script is provided to automate the whole build process (configuration, @@ -34,8 +44,7 @@ The general build procedure for ELKS is as follows: '. tools/env.sh' (note the '.' before the script) -* Configure the build chain, the kernel, the user land and the target image - format: +* Configure the kernel, the user land and the target image: 'make menuconfig' @@ -46,10 +55,14 @@ The general build procedure for ELKS is as follows: The target root folder is built in 'target/', and depending on your configuration, that folder is packed as either a floppy disk image (fd1440, fd1680, fd1200, fd720, fd360, without MBR), a hard-disk image (hd, with MBR), -or a file image (rom, tar), into the '/image' folder. +or a file image (ROM, TAR), into the '/image' folder. Before writting the image on the real device, you can test it first on QEMU -with './qemu.sh' (will configure QEMU for an ISA system). +with './qemu.sh' (will configure QEMU as an ISA system). + + +More information +---------------- Questions? Problems? Patches? Open an issue in this project! You can also join and email the 'Linux-8086' list at linux-8086@vger.kernel.org. diff --git a/libc/system/.gitignore b/libc/system/.gitignore index b7ad22105..f6e0a7f01 100644 --- a/libc/system/.gitignore +++ b/libc/system/.gitignore @@ -1 +1,5 @@ setjmp.s +syscall.dat +syscall1.s +call_tab.v +defn_tab.v From a0e33cf436f4bb0a1aedc76f4d6e66dcaa5c6cab Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Sun, 24 Jun 2018 21:40:03 +0200 Subject: [PATCH 04/20] [e3] Remove not portable applet The E3 editor is written in assembly and thus is not portable. Moreover it requires specifically NASM to compile. In ELKS approach, the user land shall use as less as possible architecture specific code. This is kernel's job. --- elkscmd/CHANGELOG | 4 - elkscmd/config.in | 1 - elkscmd/e3/Makefile | 13 - elkscmd/e3/e3-16.asm | 2603 ------------------------------------------ 4 files changed, 2621 deletions(-) delete mode 100644 elkscmd/e3/Makefile delete mode 100644 elkscmd/e3/e3-16.asm diff --git a/elkscmd/CHANGELOG b/elkscmd/CHANGELOG index 9d1c92c37..e185df75b 100644 --- a/elkscmd/CHANGELOG +++ b/elkscmd/CHANGELOG @@ -83,10 +83,6 @@ Wed Jun 09 03:47:56 CST 2004 Tommy McCabe * Included ktcp in full5 -Wed Jun 09 03:45:34 CST 2004 Miguel Bolanos - - * Added e3 - Sat Jun 5 17:44:06 BRT 2004 Eduardo Habkost * rootfs_template/etc/passwd doesn't depend on rootfs_template.tar diff --git a/elkscmd/config.in b/elkscmd/config.in index 1745c5301..58f53a20c 100644 --- a/elkscmd/config.in +++ b/elkscmd/config.in @@ -22,7 +22,6 @@ mainmenu_option next_comment bool 'bc' CONFIG_APP_BC y bool 'dbgutils' CONFIG_APP_DBG_UTILS y bool 'diskutils' CONFIG_APP_DISK_UTILS y - bool 'e3' CONFIG_APP_E3 y bool 'elvis' CONFIG_APP_ELVIS y bool 'fileutils' CONFIG_APP_FILE_UTILS y bool 'levee' CONFIG_APP_LEVEE y diff --git a/elkscmd/e3/Makefile b/elkscmd/e3/Makefile deleted file mode 100644 index e564494c2..000000000 --- a/elkscmd/e3/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -PREFIX = /usr -ASOURCES=e3-16.asm -AFLAGS = -w+orphan-labels -f as86 - -all: $(ASOURCES) Makefile - nasm $(AFLAGS) -o e3-16.o $(ASOURCES) -l e3-16.lst -D AS86 -D ELKS - ld86 -0 -s -i -H 0xF800 -o e3 e3-16.o - -install: e3 - sudo install e3 $(TARGET_MNT)/bin - -clean: - rm -f e3*.o e3*.lst e3 diff --git a/elkscmd/e3/e3-16.asm b/elkscmd/e3/e3-16.asm deleted file mode 100644 index e16763206..000000000 --- a/elkscmd/e3/e3-16.asm +++ /dev/null @@ -1,2603 +0,0 @@ -;------------------------------------------------------------------------- -; -; Copyright (C) 2002,03 Albrecht Kleine -; -; This program is free software; you can redistribute it and/or -; modify it under the terms of the GNU General Public License -; as published by the Free Software Foundation; either -; version 2 of the License, or (at your option) any later version. -; -; This library is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -; Library General Public License for more details. -; -; You should have received a copy of the GNU Library General Public -; License along with this library; if not, write to the Free Software -; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -; -;-------------------------------------------------------------------------- -; -; This is e3-16, a 16 bit derived work of 32 bit micro editor e3, ... -; ...running on ELKS (==Embeddable Linux Kernel Subset) and DOS. -; Unlike e3 we are supporting WStar key bindings only. -; Unlike e3 "BAK-files" (*~) are not yet created. -; -TAB equ 8 -TABCHAR equ 09h ; ^I -SPACECHAR equ ' ' -CHANGED equ '*' -UNCHANGED equ SPACECHAR -NEWLINE equ 0ah -errlen equ 100 -MAXERRNO equ 30 -ERRNOMEM equ 12 -ERRNOIO equ 5 -sBREITE equ 80 ;cols -sHOEHE equ 24 ;rows -MAXLEN equ 0x7FFF -maxfilenamelen equ 255 -%ifdef ELKS - %define LESSWRITEOPS - stdin equ 0 - stdout equ 1 - O_WRONLY_CREAT_TRUNC equ 1101q - O_RDONLY equ 0 - PERMS equ 644q -%else ;-------------- - normfarbe equ 07h - kursorfarbe equ 70h - slinefarbe equ 1eh ;yellow on blue - blockfarbe equ 15 - O_WRONLY_CREAT_TRUNC equ 0 -%endif - -section .text -bits 16 - -global _start -global _main ; for ELKS and the ld86 linker -_start: -_main: -EXE_startcode: -%ifdef EXESTUB -..start: -%endif -;------- -%ifdef ELKS - call InitBSS - pop ax - pop bx - pop si ;si points to first arg -%else -%ifdef COM - org 100h -%else -%ifdef EXESTUB - mov ax,data - mov es,ax - push ax -%else -%ifdef EXE - EXE_realstacksize equ 0x800 - org 0e0h -header_start: -;EXE header adapted from a NASM contribution by Yann Guidon - db 'M','Z' ; EXE file signature - dw EXE_allocsize % 512 - dw (EXE_allocsize + 511) / 512 - dw 0 ; relocation information: none - dw (header_end-header_start)/16 ; header size in paragraphs - dw (EXE_absssize + EXE_realstacksize) / 16 ; min extra mem - dw (EXE_absssize + EXE_realstacksize) / 16 ; max extra mem - dw -10h ; Initial SS (before fixup) - dw EXE_endbss + EXE_realstacksize ; 2k - dw 0 ; (no) Checksum - dw 100h ; Initial IP - start just after the header - dw -10h ; Initial CS (before fixup) - dw 0 ; file offset to relocation table: none - dw 0,0,0 ; (no overlay) -header_end: ; here we go... (@ org 100h) -%endif -%endif -%endif - call InitBSS - call GetArg -%ifdef EXESTUB - pop ds -%endif -%endif -;----------------------------------------------------------------------- -; -; start with OUTER editor loop -; -ReStart:call NewFile - jc E3exit -MainCharLoop:call DispNewScreen - call RestoreStatusLine - call HandleChar - cmp byte [endedit],0 - je MainCharLoop - xor si,si ;just like if no arg is present - cmp byte [endedit],2 - je ReStart ;^KD repeat edit using another file -E3exit: call KursorStatusLine -;------- -%ifdef ELKS - mov bx,stdout ;file handle - mov cx,newline ;enter next line on terminal - xor dx,dx - inc dx ;mov dx,1 - push dx - call WriteFile - pop ax ;mov ax,1 - xor bx,bx ;return 0 - int 80h -%else - mov ah,4ch - int 21h -%endif -;---------------------------------------------------------------------- -; -; MAIN function for processing keys -; -HandleChar:call ReadChar - jz ExtAscii ;DOS version got ah=0 by int 16 for F-keys and cursor keys - cmp al,19h ;^Y is the last - ja NormChar - mov bl,al - add bl,jumps1 - jmp short CompJump2 -NormChar:call CheckMode - jnz OverWriteChar - push ax - xor ax,ax - inc ax - call InsertByte - pop ax - jc InsWriteEnd ;error: text buffer full -OverWriteChar:cld - stosb - mov byte [changed],CHANGED -InsWriteEnd:ret -;------- -; -; helper for HandleChar -; -CtrlKMenu:mov bx,Ktable - mov cx,4b5eh ;^K - jmp short Menu -CtrlQMenu:mov bx,Qtable - mov cx,515eh ;^Q -Menu: call MakeScanCode - jc EndeRet ;if no valid scancode -ExtAscii:mov bl,ah ;don't use al (carries char e.g. TAB) - sub bl,lowest ;= scan code first key in jumptab1 - jb EndeRet - cmp bl,jumps1 - jae EndeRet -CompJump2:and bx,0ffh - shl bx,1 ;2*bx is due 2 byte per entry -;------- - call [bx+jumptab1] -;------- - cmp byte [numeriere],1 ;after return from functions... - jnz BZNret ;...decide whether count current line number - mov word [linenr],0 - push di - mov si,sot - xchg si,di -BZNLoop:inc word [linenr] - call LookForward - inc di ;point to start of next line -%ifndef ELKS - inc di ;for DOS one extra -%endif - cmp di,si - jbe BZNLoop - pop di - mov byte [numeriere],0 -BZNret: ret -;------- -MakeScanCode:call WriteTwo ;bx expects xlat-table - push bx - call GetChar - pop bx - and al,01fh - cmp al,26 - jnb exit - xlatb - mov ah,al ;returns pseudo "scancode" - stc -exit: cmc ;ok=nc -EndeRet:ret -;---------------------------------------------------------------------- -; -; processing special keys: cursor, ins, del -; -KeyRet: call CheckMode - jnz OvrRet - call CountToLineBegin ;set si / returns ax - inc si - inc si - xor bx,bx - or ax,ax - jz KeyRetNoIndent - dec bx -KeyRetSrch:inc bx ;search non (SPACE or TABCHAR) - cmp byte [si+bx],SPACECHAR - je KeyRetSrch - cmp byte [si+bx],TABCHAR - je KeyRetSrch -KeyRetNoIndent: - push si - push bx ;ax is 0 or =indented chars - call GoDown - pop ax - - push ax - inc ax ;1 extra for 0ah -%ifndef ELKS - inc ax -%endif - call InsertByte - pop cx ;# blanks - pop si ;where to copy - jc SimpleRet - inc word [linenr] - cld -%ifdef ELKS - mov al,NEWLINE - stosb -%else - mov ax,0a0dh - stosw -%endif - jcxz SimpleRet - rep movsb ;copy upper line i.e. SPACES,TABS into next -SimpleRet:ret -OvrRet: mov word [ch2linebeg],0 - jmp short DownRet -;------- -KeyDown:call CountColToLineBeginVis -DownRet:call GoDown - call LookLineDown - jmp short SetColumn -;------- -KeyUp: call GoUp - call CountColToLineBeginVis - call LookLineUp - jmp short SetColumn -;------- -KeyPgUp:call CountColToLineBeginVis - call LookPageUp - jmp short SetColumn -;------- -KeyPgDn:call CountColToLineBeginVis - call LookPgDown ;1st char last line -;------- -SetColumn:mov cx,[ch2linebeg] ;maximal columns - xor dx,dx ;counts visible columns i.e. expand TABs - dec di -lod: inc di - cmp dx,cx ;from CountColToLineBeginVis - jae fert -%ifdef ELKS - cmp byte [di],NEWLINE ;don't go beyond line earlier line end -%else - cmp byte [di],0dh -%endif - jz fert - cmp byte [di],TABCHAR - jz isTab - inc dx ;count columns - jmp short lod -isTab: call SpacesForTab - add dl,ah - cmp dx,cx ;this tab to far away right? - jna lod ;no -fert: ret -;------- -KeyHome:call CountToLineBegin - sub di,ax - ret -;------- -KeyEnd: call CountToLineEnd - add di,ax ;points to a 0ah char - ret -;------- -KeyIns: not byte [insstat] - ret -;------- -KeyDell:call KeyLeft - jz KeyDell2 -KeyDel: cmp di,bp - jnb KeyLeftEnd - mov ax,1 ;delete one @ cursor -%ifndef ELKS - cmp byte [di],0dh - jnz KeyDell3 - inc ax -%endif -KeyDell3:jmp DeleteByte -KeyDell2:call CheckBOF ;cmp di,sot delete newline char - jbe KeyLeftEnd - dec word [linenr] - dec di -%ifndef ELKS - dec di -%endif - jmp BisNeueZeile -;------- -KeyLeft:cmp byte [di-1],NEWLINE ;FIXME another check of BOF - jz KeyLeftEnd ;jmp if at BOL - dec di -KeyLeftEnd:ret -;------- -KeyRight: -%ifdef ELKS - cmp byte [di],NEWLINE -%else - cmp byte [di],0dh -%endif - jz KeyRightEnd ;at right margin - inc di -KeyRightEnd:ret -;------- -KeyCLeft3:call CheckBOF ;cmp di,sot bzw sot-1 - jbe KeyCLEnd - dec di -%ifndef ELKS - dec di -%endif -KeyCtrlLeft:call KeyLeft - jz KeyCLeft3 - cmp byte [di],2fh - jbe KeyCtrlLeft - cmp byte [di-1],2fh - ja KeyCtrlLeft -KeyCLEnd:ret -;------- -KeyCRight3:call CheckEOF - jae KeyCREnd - inc di -KeyCtrlRight:call KeyRight - jz KeyCRight3 - cmp byte [di],2fh - jbe KeyCtrlRight - cmp byte [di-1],2fh - ja KeyCtrlRight -KeyCREnd:ret -; -; processing special keys from the Ctrl-Q menu -; -;------- -KeyCtrlQA:call AskForReplace - jc CtrlQFEnd - mov byte [bereitsges],2 -CQACtrlL:push di - call FindText - jc CtrlQFNotFound - mov ax,[suchlaenge] - call DeleteByte - mov ax,[repllaenge] - call InsertByte - mov si, replacetext - call MoveBlock - jmp short CQFFound -;------- -KeyCtrlQF:call AskForFind - jc CtrlQFEnd - mov byte [bereitsges],1 -CQFCtrlL:push di - call FindText - jc CtrlQFNotFound -CQFFound:pop si ;dummy -CQFNum: mov byte [numeriere],1 - ret -CtrlQFNotFound:pop di -CtrlQFEnd:ret -;------- -KeyCtrlQC:mov di,bp - jmp short CQFNum -;------- -KeyCtrlQR:mov di,sot - jmp short CQFNum -;------- -KeyCtrlQP:mov di,[veryold] - jmp short CQFNum -;------- -KeyCtrlL:mov al,[bereitsges] ;2^QA 1^QF 0else - dec al - jz CQFCtrlL - dec al - jz CQACtrlL -SimpleRet4:ret -;------- -KeyCtrlQB:mov ax,di - mov di,[blockbegin] -CtrlQB2:or di,di ;exit of no marker set - jnz CQFNum - xchg di,ax ;old mov di,ax - ret -;------- -KeyCtrlQK:xchg ax,di ;old mov ax,di - mov di,[blockende] - jmp short CtrlQB2 -;------- -KeyCtrlQY:call CountToLineEnd - jmp short CtrlTEnd1 -;------- -KeyCtrlY:call CountToLineBegin - sub di,ax ;di at begin - call CountToLineEnd - call DeleteByteCheckMarker - jmp short BisNeueZeile -;------- -KeyCtrlT:call CountToWordBegin -%ifdef ELKS - cmp byte [di],NEWLINE -%else - cmp byte [di],0dh -%endif - jnz CtrlTEnd1 -BisNeueZeile:call CheckEOF - jz SimpleRet4 -%ifdef ELKS - mov ax,1 ;0ah -%else - mov ax,2 ;0dh,0ah -%endif -CtrlTEnd1:jmp DeleteByteCheckMarker -;------- -KeyCtrlQI:mov dx,asklineno - call GetAsciiToInteger - jbe CtrlQFEnd ;CY or ZR set - mov di,sot - call LookPD2 - jmp CheckENum -;---------------------------------------------------------------------- -; -; processing special Keys from Ctrl-K menu -; -KeyCtrlKY:call CheckBlock - jc SimpleRet3 ;no block: no action - mov ax,[blockende] - mov di,[blockbegin] - sub ax,si ;block length - mov di,si ;begin - call DeleteByte ;out cx:=0 - mov [blockende],cx - mov [blockbegin],cx - jmp CQFNum -;------- -KeyCtrlKH:xor byte [showblock],1 ;flip flop -SimpleRet3:ret -;------- -KeyCtrlKK:mov [blockende],di - jmp short KCKB -;------- -KeyCtrlKW:call CheckBlock - jc SimpleRet2 ;no action - call SaveBlock - jmp short CtrlKREnd -;------- -KeyCtrlKC:call CopyBlock - jc SimpleRet2 -CtrlKC2:mov [blockbegin],di - add ax,di - mov [blockende],ax - ret -;------- -KeyCtrlKV:call CopyBlock - jc SimpleRet2 - push di - cmp di,[blockbegin] - pushf - mov di,[blockbegin] - call DeleteByte - popf - pop di - jb CtrlKC2 - mov [blockende],di - sub di,ax -KeyCtrlKB:mov [blockbegin],di -KCKB: mov byte [showblock],1 -SimpleRet2:ret -;------- -KeyCtrlKR:call ReadBlock - jc CtrlKREnd - call KeyCtrlKB - add cx,di - mov [blockende],cx -CtrlKREnd:jmp RestKursPos -;------- -KeyCtrlKS:call SaveFile - pushf ;(called by ^kd) - call RestKursPos - popf - jc CtrlKSEnd - mov byte [changed],UNCHANGED -CtrlKSEnd:ret -;------- -KeyCtrlKQ:cmp byte [changed],UNCHANGED - jz CtrlKQ2 - mov dx, asksave - call DE1 - call RestKursPos - and al,0dfh - cmp al,'N' ;confirm - jnz KeyCtrlKX -CtrlKQ2:mov byte [endedit],1 - ret -KeyCtrlKD:call KeyCtrlKS - jc CtrlKSEnd - mov byte [endedit],2 - ret -KeyCtrlKX:call KeyCtrlKS - jc CtrlKSEnd - inc byte [endedit] -KeyKXend:ret -;--------------------------------------------------------------------- -; -; the general PAGE DISPLAY function: called after any pressed key -; -; side effect: sets 'columne' for RestoreStatusLine function (displays columne) -; variable kurspos: for placing the cursor at new position -; register bh counts lines -; register bl counts columns visible on screen (w/o left scrolled) -; register dx counts columns in text lines -; register cx screen line counter and helper for rep stos -; register si text index -; register di screen line buffer index -; -DispNewScreen:call GetEditScreenSize ;check changed tty size - xor ax,ax -%ifdef ELKS - mov byte[isbold],al - mov byte[inverse],al -%endif - mov [zloffset],ax - mov [columne],ax - mov [fileptr],di ;for seeking current cursor pos - call CountColToLineBeginVis ;i.e. expanding TABs - cmp ax,[columns] - jb DispShortLine - sub ax,[columns] - inc ax - mov [zloffset],ax -DispShortLine:call LookPgBegin ;go on 1st char upper left on screen - mov si,di ;si for reading chars from text - mov cx,[lines] - jcxz KeyKXend ;window appears too small - cld -%ifndef ELKS - dec si -%endif - mov bh,0 - dec bh -DispNewLine: -%ifndef ELKS - inc si -%endif - inc bh ;new line - mov di,screenline ;line display buffer - xor dx,dx ;reset char counter - mov bl,0 ;reset screen column -%ifdef LESSWRITEOPS - cmp cx,1 ;not in status line - jz DCL0 - call SetColor2 ;set initial character color per each line -DCL0: -%endif -DispCharLoop: - cmp si,[fileptr] ;display char @ cursor postion ? - jnz DispCharL1 - cmp byte[tabcnt],0 - jnz DispCharL1 - mov [kurspos],bx - mov byte [columne],bl - mov ax,[zloffset] ;chars scrolled left hidden - add [columne],ax -%ifdef ELKS - stc - call SetInverseStatus - jnc DispEndLine -%else - mov ah,kursorfarbe - cmp byte [insstat],1 - jz DispEndLine -%endif -DispCharL1:call SetColor -;------- -DispEndLine:cmp si,bp - ja FillLine ;we have passed EOF, so now fill rest of screen - cmp byte[tabcnt],0 - jz ELZ - dec byte[tabcnt] - jmp short ELZ2 -ELZ: cmp si,bp - jnz ELZ6 - inc si ;set si>bp will later trigger "ja FillLine" - jmp short ELZ2 -ELZ6: lodsb - cmp al,TABCHAR - jnz ELZ3 - push ax ;preserve color attribute - call SpacesForTab ;ah = space_up_to_next_tab location - dec ah ;count out the tab char itself - mov byte[tabcnt],ah - pop ax -ELZ2: mov al,SPACECHAR -ELZ3: -%ifdef ELKS - cmp al,NEWLINE -%else - cmp al,0dh -%endif - jz FillLine - cmp al,SPACECHAR - jae ELZ9 ;simply ignore chars like carriage_return etc. - mov al,'.' -ELZ9: cmp al,7fh - jne ELZ8 - mov al,'.' -ELZ8: cmp bl,byte [columns] ;screen width - jae DispEndLine ;continue reading line until end - inc dx ;also count hidden chars (left margin) -KZA6: cmp dx,[zloffset] - jbe DispCharLoop ;load new char (but no display) -%ifdef ELKS - stosB - clc - call SetInverseStatus -%else - stosw -%endif - inc bl ;counts displayed chars only - jmp DispCharLoop -;------- -FillLine:push cx ;continue rest of line - mov cx,[columns] ;width - sub cl,bl - mov al,SPACECHAR ;fill with blanks - jcxz FillLine2 -%ifdef ELKS - cmp byte[inverse],1 ;special cursor attribute? -%else - cmp ah,kursorfarbe -%endif - jnz FillLine1 -%ifdef ELKS - mov al,SPACECHAR - stosB ;only 1st char with special attribute - clc - call SetInverseStatus - dec cx ;one char less - jz FillLine2 -FillLine1:rep stosB ;store the rest blanks -%else - stosw - dec cx - jz FillLine2 - mov ah,normfarbe -FillLine1:rep stosw -%endif -FillLine2:pop cx -%ifdef ELKS - mov byte[di],0 -%endif - call ScreenLineShow - dec cx - jz XX1 - jmp DispNewLine -XX1: call RestKursPos - mov di,[fileptr] ;restore old value - ret -;---------------------------------------------------------------------- -InitVars:mov word [textX],0a0ah ;don't touch si! - mov byte [changed],UNCHANGED - xor ax,ax - mov byte[bereitsges],al - mov [blockbegin],ax - mov [blockende],ax - mov [endedit],al - mov word[old], sot - inc ax - mov word [linenr],ax - mov byte [showblock],al - mov byte [insstat],al - mov word [error],'ER' - mov word [error+2],'RO' - mov word [error+4],'R ' - mov word [error+6],' ' -%ifdef ELKS - mov word [perms],PERMS -%endif - cld - ret -;---------------------------------------------------------------------- -; -; STATUS LINE maintaining subroutines -; at first the writer of a complete line -; -RestoreStatusLine: ;important e.g. for asksave - push ax - push bx - push cx - push dx - push si - push di - push bp -%ifdef ELKS - mov cx,[columns] ;width - push cx - mov al,SPACECHAR ;first prepare the line buffer.... - mov di,screenline - cld - rep stosb - mov al,0 ;prepare ASCIIZ string - stosb - pop cx - cmp cl,stdtxtlen+15+5+2 ;this window is too small - jb no_lineNr - mov bl, byte [changed] - mov byte[screenline+1],bl ;changed status - mov bx,'IN' ;Insert - cmp byte [insstat],1 - jz rrr1 - mov bx,'OV' ;Overwrite -rrr1: mov [screenline+4],bx ;mode status - mov di,screenline+stdtxtlen - mov cx,[columns] - sub cx,stdtxtlen+15+5 ;space for other than filename - mov si,filepath -rrr2: lodsb - or al,al - jz raus -okay: stosb - loop rrr2 - jmp short wett -raus: mov al,SPACECHAR - stosb - loop raus -wett: mov di,screenline-15 - add di,[columns] - js no_lineNr - mov ax,[columne] - inc ax ;start with 1 - call IntegerToAscii - mov byte [di],':' ;delimiter ROW:COL - dec di - mov ax,[linenr] - call IntegerToAscii -%else ;---------------------------------------------- - mov di,zeilenangabe ;make string - mov cx,12 - mov al,SPACECHAR - cld - rep stosb - mov di,zeilenangabe+8 - mov ax,[columne] - inc ax ;start with 1 - call IntegerToAscii - mov byte [di],':' ;delimiter ROW:COL - dec di - mov ax,[linenr] - call IntegerToAscii - cld -;------- - mov cx,[columns] - mov ah,slinefarbe - mov al,SPACECHAR - mov di,screenline - cld - rep stosw - mov bl, byte [changed] - mov byte[screenline+2],bl - mov di,screenline+20 - mov cx,55 - mov si,filepath -rrr2: lodsb - stosw - loop rrr2 - mov cx,10 - mov si,zeilenangabe -rrr3: lodsb - stosw - loop rrr3 -%endif -no_lineNr:call StatusLineShow ;now write all at once - pop bp - pop di - pop si - pop dx - pop cx - pop bx - pop ax - ret -;------------------------------------------------------------------------- -; this function does write the line buffer to screen i.e. terminal -; at begin a special entry point for writing the STATUS line below -; -StatusLineShow:xor cx,cx ;0 for last line -ScreenLineShow: ;expecting in cx screen line counted from 0 - push ax - push bx - push cx - push dx - push si - push di - push bp -%ifdef ELKS - -%ifdef LESSWRITEOPS - xor bx,bx ;flag - mov ax,[columns] - add ax,32 ;estimated max ESC sequences extra bytes (i.e. boldlen*X) - mul cl - mov di,screenbuffer - add di,ax - cld -; xor dx,dx ;counter - mov si,screenline -sl_3: lodsb -; inc dx ;count message length to write - cmp di,screenbuffer_end ;never read/write beyond buffer - jnb sl5 - cmp al,[di] - jz sl4 - mov [di],al -sl5: inc bx ;set flag whether line need redrawing -sl4: inc di - or al,al - jnz sl_3 - or bx,bx ;redraw ? - jz NoWrite -%endif - mov dh,byte [lines] - sub dh,cl - mov dl,0 - call sys_writeKP - call sys_writeSL - mov dx,[kurspos2] - call sys_writeKP ;restore cursor pos -%else -%ifdef DO_NOT_USE_AX_1302 ;very slow (but running on some very old 1980's PC) - mov si,screenline - cld - mov dh,[lines] - sub dh,cl - mov dl,0 -no1302: call sys_writeKP - lodsw - mov bl,ah - mov bh,0 - mov ah,09h - mov cx,1 - int 10h - mov al,[columns] - dec al - cmp dl,al - inc dl - jb no1302 - mov dx,[kurspos2] - call sys_writeKP ;restore cursor pos -%else - mov ax,1302h - mov bx,0 - mov dh,[lines] - sub dh,cl - mov dl,0 - mov cx,[columns] - mov bp,screenline - int 10h -%endif -%endif -NoWrite: - pop bp - pop di - pop si - pop dx - pop cx - pop bx - pop ax - ret -;----------------------------------------------------------------------- -; write an answer prompt into status line -; (with and without re-initialisation) -; expecting dx points to ASCIIZ-string -; -WriteMess9MachRand: - call InitStatusLine -WriteMess9: -%ifdef ELKS - push ax - push bx - push cx - push dx - push si - push di - push bp - mov di,screenline - mov si,dx - cld -WriteMLoop:lodsb - or al,al - jz WriteMEnd - cmp al,0ah ;for error messages - jz WriteMEnd - stosb - jmp short WriteMLoop -WriteMEnd:call StatusLineShow - pop bp - pop di - pop si - pop dx - pop cx - pop bx - pop ax -%else ;--------------------- - push si - push di - mov si,dx - cld - mov di,screenline - mov ah,slinefarbe -WriteMLoop:lodsb - or al,al - jz WriteMEnd - cmp al,0dh - jz WriteMEnd - stosw - jmp short WriteMLoop -WriteMEnd:call StatusLineShow - pop di - pop si -%endif - call KursorStatusLine - ret -;------- -; another way: write 2 letters in ch/cl to status line -; called by MakeScanCode for showing ^K and ^Q status (lower left) -; -WriteTwo:push di -%ifdef ELKS - mov word[screenline],cx -%else - mov di,screenline - mov al,cl - mov ah,slinefarbe - cld - stosw - mov al,ch - stosw -%endif - call StatusLineShow ;write the line on last screen line - pop di - ret -;-------------------------------------------------------------------- -; a helper for other status line functions: -; simply init an empty line -; -InitStatusLine:push di - push ax - push cx - mov di,screenline - cld - mov al,SPACECHAR - mov cx,[columns] -%ifdef ELKS - cld - rep stosb -%else - mov ah,slinefarbe - rep stosw -%endif - pop cx - pop ax - pop di - ret -;----------------------------------------------------------------------- -; -; getting INPUT from terminal -; at first read a whole string until pressed, -; follwed by handling reading one char alone -; -%ifdef ELKS -; expecting buffer in cx -; expecting count byte in dx -InputString:call sys_writeSLColors1 - push cx - mov bx,stdin ;file desc - call ReadFile - pop cx - stc - js ISRet - dec ax ;0ah - push bx - mov bx,ax - add bx,cx - mov byte[bx],0 ;make asciz string - pop bx - cmp ax,1 ;set cy flag if empty string -ISRet: pushf - call sys_writeSLColors0 ;FIXME should flush stdin: read until empty buffer - popf - ret -%else ;---------------------------------- -InputString:mov dx,cx ;ELKS register style - xor cx,cx ;char counter - push di - mov di,dx - cld -GetNameLoop:call GetChar - cmp ah,4bh ;left - jz GetNameDelete - cmp ah,4dh - jz GetNameOldChar - or al,al - jz GetNameLoop - cmp al,7 - jz GetNameLoop ;no beep - cmp al,0dh - jz GetNameEnd - cmp al,1bh - stc - jz GetNameErr - cmp al,8 - jnz GetNameChar -GetNameDelete:mov al,8 - dec cx - jS GetNameNoToDel - call xDispChar - dec di - mov al,0 - call xDispChar - mov al,8 - call xDispChar - jmp short GetNameLoop -GetNameOldChar:mov al,[di] - or al,al - jz GetNameLoop -GetNameChar:stosb - call xDispChar -GetNameNoToDel:inc cx - cmp cl,maxfilenamelen - jnc GetNameEnd - jmp short GetNameLoop -GetNameEnd:mov byte [di],0 - mov ax,di - sub ax,dx ;ret ax=lge - cmp ax,1 ;clc -GetNameErr:pop di - ret -;------- -xDispChar:push bx ;char in al - mov ah,0eh - mov bx,0111b ;page bh,0 - int 10h - pop bx - ret -%endif -;----------------------------------------------------------------------- -%ifdef ELKS -; -; GetChar returns ZERO flag for non ASCII (checked in HandleChar) -; FIXME: e3-32 bit does the IOctlTerminal only at start/end of editor... -; ...but here we are calling IOctlTerminal each time (==useless overhead) -; (see diff e3 release 0.1 -> 0.2) -; -ReadChar:mov ax,di - xchg ax,[old] ;fuer ^QP - mov [veryold],ax -GetChar:mov cx, 0x5401 ;TCGETS asm/ioctls.h - mov dx,termios - call IOctlTerminal - call SaveTermStruc - push bx - mov bx,dx - and byte [bx+12],(~2 & ~1 & ~8) ;icanon off, isig (^C) off, echo off - and byte [bx+ 1],(~4) ;ixon off was:and word [bx+ 0],(~400h) - pop bx - mov cx, 0x5402 ;TCSETS asm/ioctls.h - call IOctlTerminal ;dx is termios pointer -readloop:call ReadOneChar - cmp al,7FH - jne No7F ; special case: remap DEL to Ctrl-H - mov al,8 -No7F: cmp al,27 ; ESC ? - jnz ready_2 - call ReadOneChar ;e.g. [ for ELKS vt100 - mov bl,48h ;48h up - the lowest - cmp al,'A' - jz ready - add bl,3 ;4Bh left - cmp al,'D' - jz ready - add bl,2 ;4Dh right - cmp al,'C' - jz ready - add bl,3 ;50h down - cmp al,'B' - jz ready - jmp short ready_2 -;------- -ready: xor ax,ax - mov ah,bl -ready_2:push ax - mov cx,0x5402 ;TCSETS asm/ioctls.h - mov dx,orig - call IOctlTerminal ; restore termios settings - pop ax - or al,al ; was similar DOS version (via BIOS int 16h) - ret -;------- -SaveTermStruc:push di - mov si,termios - mov di,orig - mov cx,termios_size - cld - rep movsb - pop di - ret -;------- -; called by ReadChar/GetChar -; -ReadOneChar:mov bx,stdin ;file desc - mov cx,read_b ;pointer to buf - xor dx,dx - inc dx ;mov dx,1 (length) - call ReadFile - mov ax,[read_b] - ret -%else ;------- -ReadChar:mov ax,di - xchg ax,[old] ;for ^QP - mov [veryold],ax - call GetChar - or al,al - ret -;------- -GetChar:mov ah,0 - int 16h - ret -%endif -;---------------------------------------------------------------------- -%ifdef ELKS -; -; helper subroutine called by DispNewScreen -; -SetInverseStatus: - push si ; returns zero flag - push cx - mov cx,boldlen - jnc SIS1 - cmp byte [insstat],1 - stc - jnz SIS4 - mov byte[inverse],1 - mov si,reversevideoX - rep movsb - jmp short SIS3 -SIS1: cmp byte[inverse],1 - jnz SIS3 - mov byte[inverse],0 - mov byte[isbold],0 -SIS_5: mov si,bold0 - rep movsb -SIS3: clc -SIS4: pop cx - pop si - ret -%endif -;------- -; another helper subroutine called by DispNewScreen -; -SetColor: -%ifdef ELKS - call IsShowBlock - push si ;expects cy flag:bold / nc:normal - push cx - mov cx,boldlen - jnc SFEsc1 - cmp byte [isbold],1 ;never set bold if it is already bold - jz SFEsc2 -SCEsc_2:mov si,bold1 - rep movsb - mov byte [isbold],1 - jmp short SFEsc2 -SFEsc1: cmp byte [isbold],0 ;ditto - jz SFEsc2 - mov si,bold0 - rep movsb - mov byte [isbold],0 -SFEsc2: pop cx - pop si - ret -%ifdef LESSWRITEOPS -SetColor2:push si - push cx - call IsShowBlock - mov cx,boldlen - jnc SIS_5 - jmp short SCEsc_2 -%endif -%else ;--------------------------------- - mov ah,normfarbe - cmp byte[showblock],0 - je SetColorEnde - cmp word [blockbegin],0 - je SetColorEnde - cmp [blockbegin],si - ja SetColorEnde - cmp si,[blockende] - jnb SetColorEnde - mov ah,blockfarbe -SetColorEnde:ret -%endif -;----------------------------------------------------------------------- -; -; LOWER LEVEL screen acces function (main +2 helpers) (ELKS only) -; -%ifdef ELKS -sys_writeSL:push cx - or cx,cx - jnz sl1 - call sys_writeSLColors1 ;special for status line (cx==0) -sl1: push si - cld - xor dx,dx - mov si,screenline -sl3: lodsb - inc dx ;count message length to write - or al,al - jnz sl3 - dec dx ;one too much - pop si - mov bx,stdout ;first argument: file desc (stdout) - mov cx,screenline ;second argument: pointer to message to write - call WriteFile - pop cx - or cx,cx - jnz sl2 - call sys_writeSLColors0 -sl2: ret -;------- -sys_writeSLColors1: - push ax - push bx - push cx - push dx - push si - push di - push bp - mov cx,screencolors1 ;set bold yellow on blue - jmp short SwSL -;------- -sys_writeSLColors0: - push ax - push bx - push cx - push dx - push si - push di - push bp - mov cx,screencolors0 ;reset to b/w -SwSL: mov bx,stdout - mov dx,scolorslen - call WriteFile - pop bp - pop di - pop si - pop dx - pop cx - pop bx - pop ax - ret -%endif -;---------------------------------------------------------------------- -; -; L O O K functions -; search special text locations and set register di -; -%ifdef ELKS -LookBackward: ;set di to 1 before EOL (0Ah) i.e., 2 before start of next line - push cx - push bx - xor bx,bx - cmp byte[di-1],NEWLINE ;at BOL ? - jz LBa3 - cmp byte[di],NEWLINE ;at EOL ? - jnz LBa1 - dec di ;at EOL ? start search 1 char earlier - inc bx ;increase counter -LBa1: mov cx,9999 - mov al,NEWLINE - std - repne scasb - mov ax,9997 - sub ax,cx - add ax,bx - pop bx - pop cx - jmp short CheckBOF -;------- -LBa3: xor ax,ax - pop bx - pop cx - dec di - dec di - jmp short CheckBOF -%else -LookBackward:push cx - mov cx,9999 - mov al,0ah - std - repne scasb - mov ax,9997 - sub ax,cx - pop cx - jmp short CheckBOF -%endif -LookForward:push cx - mov cx,9999 -%ifdef ELKS - mov al,NEWLINE -%else - mov al,0dh -%endif - cld - repne scasb - mov ax,9998 - sub ax,cx - pop cx - dec di -CheckEOF:cmp di,bp ;ptr is eof-ptr? - jnz CheckEnd ;Z flag if eof - jmp short CheckENum -CheckBOF:cmp di,sot - ja CheckEnd -CheckENum:mov byte [numeriere],1 ;if bof -CheckEnd:ret -;------- -LookPgBegin:mov dx,[kurspos2] ;called by DispNewScreen to get sync with 1st char on screen - mov cl,dh ;called by KeyCtrlQE (go upper left) - mov ch,0 - inc cl - jmp short LookPU2 -;------- -LookLineUp:mov cx,2 ;2 lines: THIS line and line BEFORE - dec word [linenr] - jmp short LookPU2 -;------- -LookLineDown:mov cx,2 ;2 lines: THIS and NEXT line - inc word [linenr] - jmp short LookPD2 -;------- -LookPageUp:mov cx,[lines] - sub [linenr],cx - inc word [linenr] ;PgUp,PgDown one line less -LookPU2:call LookBackward - jb LookPUEnd ;if BOF -%ifdef ELKS - inc di -%endif - loop LookPU2 ;after loop di points to char left of 0ah -%ifdef ELKS - dec di -%endif -LookPUEnd:inc di - inc di ;now points to 1st char on screen or line - ret -;------- -LookPgDown:mov cx,[lines] - add [linenr],cx - dec word [linenr] -LookPD2:call LookForward - jz LookPDEnd ;(jmp if EOF) -%ifndef ELKS - inc di -%endif - inc di ;1st char next line - loop LookPD2 -%ifndef ELKS - dec di -%endif - dec di ;last char last line -LookPDEnd:sub di,ax ;1st char last line - ret -;---------------------------------------------------------------------- -; -; some more CHECK functions -; -CheckBlock:cmp byte [showblock],1 ;returns CY if error else ok: NC - jc CheckBlockEnd - mov si,[blockende] - cmp si, sot - jb CheckBlockEnd - mov si,[blockbegin] ;side effect si points to block begin - cmp si, sot - jb CheckBlockEnd - cmp [blockende],si ;^KK > ^KB ..OK if above! -CheckBlockEnd:ret -;------- -CheckImBlock:cmp [blockbegin],di ;^KB mark > di ? - ja CImBlockEnd ;OK - cmp di,[blockende] ;di > ^KK -CImBlockEnd:ret ;output:cy fehler / nc ok inside block -;------- -CheckMode: -%ifdef ELKS - cmp byte [di],NEWLINE ;checks for INSERT status -%else - cmp byte [di],0dh -%endif - jz ChModeEnd - cmp byte [insstat],1 -ChModeEnd:ret ;Z flag for ins-mode -;------- -; a special case called by DeleteByteCheckMarker -; -CheckMarker: ;dx is blockbegin (^KB) - ;bx is deleate area end --- di delete area start - cmp di,dx ;delete area start < ^KB marker ? - ja CMEnd ;no - cmp bx,dx ;yes, but delete area end > ^KB ? - jl CMEnd ;no - mov dx,di ;yes so block start (^KB) to delete area start -CMEnd: ret -;---------------------------------------------------------------------- -; -; C O U N T functions -; to return number of chars up to some place -; (all of them are wrappers of Look....functions anyway) -; -CountToLineEnd:push di - call LookForward - pop di - ret ;ax=chars up to line end -;------- -CountColToLineBeginVis: ;counts columns represented by chars in ax - call CountToLineBegin ;i.e. EXPAND any TAB chars found - push si - xor dx,dx - mov si,di ;startpoint - sub si,ax ;to bol - dec si -CCV1: inc si - cmp si,di - jae CCVend - cmp byte [si],TABCHAR - jz CCVTab - inc dx ;count visible chars - jmp short CCV1 -CCVTab: call SpacesForTab ;return space_up_to_next_tab in ah - add dl,ah ;FIXME: now using 8 bits only - jmp short CCV1 -CCVend: mov [ch2linebeg],dx ;ch2linebeg: interface to Key... functions - mov ax,dx ;ax: interface to DispNewScreen - pop si - ret -;------- -CountToLineBegin:push di ;output ax=chars up there - call LookBackward - mov si,di ;side effect: set di to 1st char in line - pop di - ret -;------- -CountToWordBegin: ;output ax=chars up there - mov si,di -CountNLoop:inc si -%ifdef ELKS - cmp byte [si],NEWLINE -%else - cmp byte [si],0dh -%endif - jz fertig2 - cmp byte [si],SPACECHAR ;below SPACE includes tab chars - jbe CountNLoop - cmp byte [si-1],2fh - ja CountNLoop -fertig2:mov ax,si - sub ax,di ;maybe =0 - ret -;--------------------------------------------------------------------- -; -; some CURSOR control functions -; -GoUp: mov al,0 - mov ah,-1 - jmp short UpDown -GoDown: mov al,byte [lines] - dec al - mov ah,1 -UpDown: mov dx,[kurspos2] ;former was call getkurspos - cmp dh,al - jz Goret - add dh,ah ;ONLY here we change curent line of cursor - jmp short SetKursPos -Goret: ret -;------- -; set cursor to some desired places -; -KursorStatusLine:mov dh,[lines] - mov dl,stdtxtlen - jmp short SetKursPos -RestKursPos:mov dx,[kurspos] -SetKursPos:mov [kurspos2],dx ;saves reading cursor pos (0,0) -%ifndef ELKS -sys_writeKP: - push ax - mov ah,2 - mov bh,0 - int 10h - pop ax - ret -%else ;--------------------------------------------------------------- -sys_writeKP: - push ax - push bx - push cx - push dx - push si - push di - push bp - call make_KPstr - mov bx,stdout ;file handle (stdout) - mov cx,setkp ;second argument: pointer to message to write - mov dx,setkplen ;third argument: message length - call WriteFile - pop bp - pop di - pop si - pop dx - pop cx - pop bx - pop ax - ret -;------- -; make ESC sequence appropriate to most important terminals -; -make_KPstr: - inc dl ;expecting cursor pos in dh/dl (0,0) - inc dh ;both line (dh) col (dl) are counted now from 1 - cld - mov di,setkp ;build cursor control esc string db 27,'[000;000H' - mov ax,0x5B1B ;line starts at setkp+2, col starts at setkp+6 - stosw - mov ax,'00' - stosw - mov ax,'0;' ;init memory - stosw - mov ax,'00' - stosw - mov ax,'0H' ;init memory - stosw - mov di,setkp+1+3 ;line end - xor ax,ax - mov al,dh ;DH=line - push dx - call IntegerToAscii ;make number string - pop dx - cld - mov di,setkp+1+3+4 ;column end - xor ax,ax - mov al,dl ;DL=col - jmp IntegerToAscii -%endif -;----------------------------------------------------------------------- -; -; functions for INSERTING, COPYING and DELETING chars in text -; -InsertByte:or ax,ax ;input: ax = #bytes , di = ptr - jz Ins3 - mov byte [changed],CHANGED - mov cx,MAXLEN ;max_len+offset-eofptr=freespace(cx) - add cx,sot - sub cx,bp - cmp cx,ax ;cmp freespace - newbytes ;>= 0 ok/ NC <0 bad / CY - jnc SpaceAva - mov word[errno],ERRNOMEM - call DosError - call RestKursPos - stc - ret -SpaceAva:push di - mov si,bp ;end of text - mov cx,bp - add cx,ax - sub cx,di ;space count - mov di,bp - add di,ax - std - rep movsB - pop di -;------- - add bp,ax - cmp di,[blockende] - ja Ins1 - add [blockende],ax -Ins1: cmp di,[blockbegin] - ja Ins2 - add [blockbegin],ax -Ins2: clc -Ins3: ret ;output:nc=ok / cy=bad -;------- -CopyBlock:call CheckBlock ;copy block, called by ^KC, ^KV - jc MoveBlEnd - call CheckImBlock - jc MoveBlEnd - mov ax,[blockende] - sub ax,si ;block len - call InsertByte - jc MoveBlEnd - mov si,[blockbegin] -MoveBlock:push di ;input : si=^KB di=current - mov cx,ax - cld - rep movsb - pop di - clc ;nocarry->ok -MoveBlEnd:ret -;------- -DeleteByteCheckMarker: ;di points to begin - mov bx,di - add bx,ax - mov dx,[blockbegin] - call CheckMarker - mov [blockbegin],dx - mov dx,[blockende] - call CheckMarker - mov [blockende],dx -DeleteByte:or ax,ax ;input in ax - jz DeleteByteEnd - mov byte [changed],CHANGED - push di - push si - mov cx,bp ;end - sub cx,di - mov si,di - add si,ax - sub cx,ax - add cx,3 - shr cx,1 - cld - rep movsW - pop si - pop di - sub bp,ax - cmp di,[blockende] - jae Del1 - sub [blockende],ax -Del1: cmp di,[blockbegin] - jae DeleteByteEnd - sub [blockbegin],ax -DeleteByteEnd:ret -;--------------------------------------------------------------------- -; read a file name for block operations -; expecting message text ptr in dx -; -getBlockName: - push ax - push bx - push cx - push dx - push si - push di - push bp - call WriteMess9MachRand - mov cx,blockpath - mov dx,maxfilenamelen - call InputString ;cy if empty string - pushf - call RestKursPos - popf - pop bp - pop di - pop si - pop dx - pop cx - pop bx - pop ax - ret -;---------------------------------------------------------------------- -; -; functions reading/writing text or blocks from/into files -; -NewFile:call InitVars - call DelEditScreen - or si,si - jz noarg - cld - mov di,filepath -ccc: lodsb - stosb - or al,al - jnz ccc - jmp short GetFile -;------- -noarg: mov dx, filename - call WriteMess9MachRand - mov cx,filepath - mov dx,maxfilenamelen - call InputString - jc NFEnd2 ;empty string not allowed here -;------- -GetFile:mov bx,filepath - xor cx,cx ;i.e O_RDONLY - call OpenFile - mov di,sot - mov bp,di - mov bx,ax ;file descriptor - js NewFileEnd -OldFile: -%ifdef SYS_FSTAT - call Fstat ;kernel returns error 38 - js DosEjmp0 - mov ax,[fstatbuf+8] ;better define some structure - and ax,777q - mov [perms],ax -%endif -;------- - mov dx,MAXLEN - mov cx,di ;sot - call ReadFile - mov dx,ax ;bytes read - js DosEjmp0 ;DosError - call CloseFile - js DosEjmp0 ;DosError -;------- - mov word [errno],ERRNOMEM - cmp dx,MAXLEN ;MAXLEN read amount is too much - jnz XX2 - jmp DosError -XX2: -;------- - mov bp,sot ;eof_ptr=filesize+start_of_text - add bp,dx -NewFileEnd: -%ifdef ELKS - mov byte [ds:bp],NEWLINE ;eof-marker -%else - mov word [ds:bp],0a0dh -%endif - clc -NFEnd2: ret -;------- -; save file (called by ^KS,^KX) -; -SaveFile:cmp byte [changed],UNCHANGED - jz SaveFile3 ;no changes: nothing to save - mov dx,filesave - call WriteMess9 - mov cx,O_WRONLY_CREAT_TRUNC - mov bx,filepath -%ifdef ELKS - mov dx,[perms] - call OpenFile -%else - call CreateFile -%endif -DosEjmp0:js DosEjmp ;DosError - mov cx,sot ;cx=bof - mov dx,bp ;eof -SaveFile2:sub dx,cx ;dx=filesize= eof-bof - mov bx,ax ;file descriptor - call WriteFile - js DosEjmp ;DosError - mov word[errno],ERRNOIO ;just in case of.... - cmp ax,dx ;all written? - jz XX4 - jmp DosError -XX4: call CloseFile - js DosEjmp ;DosError -SaveFile3:ret -;------------------------------ -; save block (called by ^KW) -; -SaveBlock:mov dx,blocksave - call getBlockName - jnc XX3 - jmp DE2 -XX3: mov cx,O_WRONLY_CREAT_TRUNC - mov bx,blockpath -%ifdef ELKS - mov dx,[perms] - call OpenFile -%else - call CreateFile -%endif - js DosEjmp ;DosError - mov cx,si ;= block begin - mov dx,[blockende] - jmp short SaveFile2 -;------- -; read a block into buffer (by ^KR) -; -ReadBlock:mov dx,blockread - call getBlockName - jnc XX5 - jmp DE2 -XX5: xor cx,cx ;i.e O_RDONLY - mov bx,blockpath - call OpenFile -DosEjmp:js DosError - mov bx,ax ;file desc - mov dx,2 - call SeekFile ;end - js DosError - push dx - push ax - xor dx,dx - call SeekFile ;home - pop ax - pop dx - js DosError - or dx,dx - mov word [errno],ERRNOMEM - jnz DosError - push ax - call InsertByte - pop dx ;file size - jc DosError - mov cx,di ;^offset akt ptr - call ReadFile - js preDosError ;to delete inserted bytes (# in dx) - mov cx,ax ;bytes read - call CloseFile - js DosError - mov word[errno],ERRNOIO ;just in case of.... - cmp dx,cx ;all read? - jnz DosError -ReadBlock2:jmp NewFileEnd -;------------------------------------------------------------ -; -; Error handler -; -preDosError:mov ax,dx ;count bytes - call DeleteByte ;delete space reserved for insertation -DosError:push di - mov di,error+8 ;where to store ASCII value of errno - mov ax,[errno] - push ax - call IntegerToAscii ;TODO: print a string instead of errno value - pop cx - cmp cx,MAXERRNO - ja DE0 - mov di,errmsgs - call LookPD2 ;look message x in line number x - mov si,di - mov di,error+9 - mov ax,' :' - stosw - mov cx,80 ;max strlen / compare errlen equ 100 - rep movsb -DE0: mov dx,error - pop di -DE1: call WriteMess9 - call GetChar -DE2: call RestoreStatusLine - stc ;error status - ret -;---------------------------------------------------------------------- -; -; some GENERAL helper functions -; -IntegerToAscii: - mov cx,10 - std - mov bx,ax ;bx=quotient -Connum1:mov ax,bx - sub dx,dx - div cx - mov bx,ax ;save quotient (new low word) - mov al,dl - call Hexnibble - or bx,bx - jne Connum1 - cld - ret -Hexnibble:and al,0fh - add al,'0' - cmp al,':' - jb noHex - add al,7 ;(should never be due cx==10) -noHex: stosb - ret -;------- -; -; GetAsciiToInteger reads integer value from keyboard (only > 0) -; -GetAsciiToInteger:call WriteMess9MachRand - mov cx,blockpath - mov dx,maxfilenamelen - call InputString - call AskFor_Ex ;repair status line & set cursor pos / preserve flags - mov ax,0 ;preserve flags - mov cx,ax - mov bl,9 ;bl == base-1 - jc AIexit2 - mov si,blockpath - cld -AIload: lodsb - sub al,'0' - js AIexit - cmp al,bl - ja AIexit - mov dx,cx - shl cx,3 ;* 8 - add cx,dx ;+ 1 - add cx,dx ;+ 1 - add cx,ax ;+digit - jmp short AIload -AIexit: or cx,cx ;ret ecx -AIexit2:ret ;CY or ZR if error -;------- -; -; expects curent column in dx -; returns # spaces up to next tabulated location in AH -; -SpacesForTab:push cx - mov ax,dx - mov cl,TAB - div cl - neg ah ;ah = modulo division - add ah,TAB ;TAB - pos % TAB - pop cx - ret -;------- -; a little helper for SetColor* functions -; -IsShowBlock:cmp byte [showblock],0 - je SBlock - cmp word [blockbegin],0 - je SBlock - cmp [blockbegin],si - ja SBlock - cmp si,[blockende] - jb SB_ret -SBlock: clc -SB_ret: ret -;------- -GetEditScreenSize: - mov al,sHOEHE-1 - mov byte [lines],al - mov al,sBREITE - mov byte [columns],al ;columns > 255 are ignored... - ret -;------- -DelEditScreen:push si - push bp - mov di,help - mov bp,di ;end - add bp,help_ws_size - call DispNewScreen - pop bp - pop si - ret -;------- -InitBSS:mov cx,EXE_absssize ;init bss - mov di,EXE_startbss - cld - xor ax,ax - rep stosb - mov word [es:textX],0a0ah ;es: due EXESTUB version - ret -;------- -%ifndef ELKS -GetArg: mov si,80h ;point to params - mov cl,[si] ;get number of chars - xor ch,ch ;make it a word - inc si ;point to first char - add si,cx ;point to just after last char - mov byte [si],0 ;make into an ASCIIZ string - sub si,cx ;get back ptr to first char - cld - jcxz no_filename ;if no file name, then get one - mov dx,cx -del_spaces:lodsb - cmp al,SPACECHAR - jne found_letter ;exit loop if al not space - loop del_spaces -found_letter:dec si ;backup to first ascii char - cmp byte [si],SPACECHAR - jz no_filename - ret -no_filename:xor si,si - ret -%endif -;---------------------------------------------------------------------- -; -; FIND/REPLACE related stuff -; -AskForReplace:mov dx, askreplace1 - call WriteMess9MachRand - mov cx,suchtext - mov dx,maxfilenamelen - call InputString - jc AskFor_Ex - mov [suchlaenge],ax - mov dx,askreplace2 - call WriteMess9MachRand - mov cx,replacetext - mov dx,maxfilenamelen - call InputString - mov [repllaenge],ax - jc AskFor_Ex - jmp short GetOptions -AskForFind:mov dx,askfind - call WriteMess9MachRand - mov cx,suchtext - mov dx,maxfilenamelen - call InputString - mov [repllaenge],ax - jc AskFor_Ex -GetOptions:mov dx,optiontext - call WriteMess9MachRand - mov cx,optbuffer - mov dx,optslen - call InputString ; empty string is allowd for std options... - call ParseOptions ; ...(set in ParseOptions) - clc -AskFor_Ex:pushf - call RestoreStatusLine - call RestKursPos - popf - ret -;------- -; check string for 2 possible options -; -ParseOptions:push si - cld - mov si,optbuffer - mov word[vorwarts],1 - mov byte[grossklein],0dfh -Scan1: lodsb - and al,5fh - cmp al,'C' - jnz notCopt - xor byte[grossklein],20h ;result 0dfh, 2*C is 20h again -->not U option -notCopt:cmp al,'B' - jnz notBopt - neg word[vorwarts] ;similar 2*B is backward twice i.e. forward -notBopt:or al,al - jnz Scan1 - pop si - ret -;------- -; the find subroutine itself -; -find2: mov bx,di -find3: lodsb - or al,al ;=end? - jz found - cmp al,41h - jb find7 - and al,ch -find7: inc di - mov cl,byte [di] - cmp cl,41h - jb find10 - and cl,ch -find10: cmp al,cl - jz find3 - mov di,bx -FindText:mov dx,[vorwarts] ;+1 or -1 - mov ch,[grossklein] ;ff or df - mov si,suchtext - cld - lodsb - cmp al,41h - jb find1 - and al,ch -find1: add di,dx ;+1/-1 - mov cl,byte [di] - cmp cl,41h - jb find6 - and cl,ch -find6: cmp al,cl - je find2 - cmp di,bp - ja notfound - cmp di,sot - jnb find1 -notfound:stc - ret -found: mov di,bx - clc ;di points after location - ret -;---------------------------------------------------------------------- -; -; INTERFACE to OS kernel -; -%ifdef ELKS -ReadFile:mov ax,3 ;(3==sys_read) ;return read byte ax - jmp short IntCall ;bx file / cx buffer / dx count byte -;------- -WriteFile:mov ax,4 ;(4==sys_write) - jmp short IntCall -;------- -OpenFile:mov ax,5 - jmp short IntCall ;cx mode / bx path / dx permissions (if create) -;------- -CloseFile: - push bx - push cx - push dx - push si - push di - push bp - mov ax,6 ;bx is file desc - int 80h - pop bp - pop di - pop si - pop dx - pop cx - pop bx - xor ax,ax ;always return "NO_ERROR" - ret -;------- -SeekFile:xor cx,cx ;offset - mov word [seekhelp],cx ;due special ELKS kernel interface - mov word [seekhelp+2],cx ;due special ELKS kernel interface - mov cx,seekhelp ;2nd arg is a ptr to long, not a long - mov ax,19 ;system call number (lseek) - push bx - int 0x80 ;bx file / dx method - pop bx - or ax,ax - js IC2 - mov ax,word [seekhelp] ;seek result: file size. 32 bit Linux is different here! - mov dx,word [seekhelp+2] - ret -;------- -IntCall:int 0x80 ;bx file / dx method -IC2: neg ax - mov [errno],ax - neg ax ;set flags also - ret -;------- -IOctlTerminal:mov bx,stdin ;expects dx termios or winsize structure ptr - mov ax,54 ;54 == the ioctl syscall no. - int 80h ;cx TCSETS,TCGETS,TIOCGWINSZ - ret -;------- -%ifdef SYS_FSTAT -Fstat: mov cx,fstatbuf - mov al,108 ;currently (April 2002) one gets - jmp short IntCall ;error code 38: Function not implemented -%endif -%else ;--------------- -; -; ******beside int 21h we have also BIOS calls: -; **** mov ax,1302h int 10h -; **** mov ah,0eh int 10h -; **** mov ah,2 int 10h -; **** mov ah,0 int 16h -; ***************************** -; -OpenFile:xchg bx,dx ;elks register style - mov ax,3d02h ;r/w input bx=^path -Intcall:int 21h ;=ax file - jnc NoErr - mov [errno],ax - mov ax,-1 -NoErr: test ax,ax ;set sign flag - ret -CreateFile:xor dx,dx - xchg bx,dx ;elks style - xor cx,cx ;input bx=^path - mov ah,3ch - jmp short Intcall -ReadFile:mov ah,3fh - jmp short WFile -WriteFile:mov ah,40h -WFile: push dx - xchg dx,cx - int 21h - jnc NoErr2 - mov [errno],ax - mov ax,-1 -NoErr2: test ax,ax ;set sign flag - pop dx - ret -CloseFile:mov ah,3eh ;path in bx - jmp short Intcall -SeekFile:mov al,dl ;ELKS register style - mov ah,42h - xor dx,dx - xor cx,cx - jmp short Intcall -%endif -EXE_endcode: -; -;---------------------------------------------------------------------- -; -section .data -bits 16 -EXE_startdata: -; -; CONSTANT DATA AREA -; -Ktable db 45h ;^K@ xlatb table for making pseudo-scancode - db 45h ;^ka 45h points to an an offset in jumptab1 - db 41h ;^kb 41h for example points to KeyCtrlKB function offset - db 43h ;^kc - db 5dh ;^kd - db 45h ;^ke 45h means SimpleRet i.e. 'do nothing' - db 45h ;^kf - db 45h ;^kg - db 57h ;^kh - db 45h ;^ki - db 45h ;^kj - db 42h ;^kk - db 45h ;^kl - db 45h ;^km - db 45h ;^kn - db 45h ;^ko - db 45h ;^kp - db 46h ;^kq - db 3dh ;^kr ;not yet for ELKS - db 5ch ;^ks - db 45h ;^kt - db 45h ;^ku - db 56h ;^kv - db 3eh ;^kw - db 44h ;^kx - db 4eh ;^ky -Qtable db 45h ;^q@ ditto for ^Q menu - db 54h ;^qa - db 5ah ;^qb - db 58h ;^qc - db 4fh ;^qd - db 45h ;^qe - db 55h ;^qf - db 45h ;^qg - db 45h ;^qh - db 4Ah ;^qi - db 45h ;^qj - db 5bh ;^qk - db 45h ;^ql - db 45h ;^qm - db 45h ;^qn - db 45h ;^qo - db 4ch ;^qp - db 45h ;^qq - db 59h ;^qr - db 47h ;^qs - db 45h ;^qt - db 45h ;^qu - db 45h ;^qv - db 45h ;^qw - db 45h ;^qx - db 40h ;^qy -size equ 2 ;(byte per entry) -jumptab1: ; The associated key values originaly were BIOS scan codes... - ; ... now using terminal device this does have less sense, so I altered some - ; ... special cases, like ^PageUp (was 84h, but extends the table too much) - ; ... to some places shortly after 5dh (i.e. shift F10). - ; Using terminals the F-keys are not supported on ELKS (but DOS only). -lowest equ 3bh - dw SimpleRet ;3bh - dw KeyCtrlL ;3ch ^L F2 (ditto) - dw KeyCtrlKR ;3dh ^KR F3 (etc) - dw KeyCtrlKW ;3eh ^KW - dw KeyCtrlT ;3fh ^T - dw KeyCtrlQY ;40h ^QY - dw KeyCtrlKB ;41h ^KB - dw KeyCtrlKK ;42h ^KK - dw KeyCtrlKC ;43h ^KC - dw KeyCtrlKX ;44h ^KX F10 - dw SimpleRet ;45h F11 - dw KeyCtrlKQ ;46h F12 - dw KeyHome ;47h - dw KeyUp ;48h - dw KeyPgUp ;49h - dw KeyCtrlQI ;4Ah - dw KeyLeft ;4bh - dw KeyCtrlQP ;(5 no num lock) - dw KeyRight ;4dh - dw KeyCtrlKY ;(+) ^KY - dw KeyEnd ;4fh - dw KeyDown ;50H - dw KeyPgDn ;51h - dw KeyIns ;52H - dw KeyDel ;53H - dw KeyCtrlQA ;54h ^QA sF1 - dw KeyCtrlQF ;55h ^QF sF2 - dw KeyCtrlKV ;56h ^KV - dw KeyCtrlKH ;57h - dw KeyCtrlQC ;58h - dw KeyCtrlQR ;59h - dw KeyCtrlQB ;5Ah ^QB - dw KeyCtrlQK ;5Bh ^QK sF8 - dw KeyCtrlKS ;5ch ^KS sF9 - dw KeyCtrlKD ;5dh ^KD sF10 -jumps1 equ ($-jumptab1) / size -jumptab3 dw SimpleRet ;^@ - dw KeyCtrlLeft ;^a - dw SimpleRet ;^b - dw KeyPgDn ;^c - dw KeyRight ;^d - dw KeyUp ;^e - dw KeyCtrlRight ;^f - dw KeyDel ;^g 7 - dw KeyDell ;^h 8 DEL (7fh is translated to this) - dw NormChar ;^i 9 - dw KeyRet ;^j = 0ah - dw CtrlKMenu ;^k b - dw KeyCtrlL ;^l c - dw KeyRet ;^m 0dh - dw SimpleRet ;^n e - dw SimpleRet ;^o f - dw CtrlQMenu ;^p 10 ;^P like ^Q - dw CtrlQMenu ;^q 11 - dw KeyPgUp ;^r 12 - dw KeyLeft ;^s 13 - dw KeyCtrlT ;^t 14 - dw SimpleRet ;^u 15 - dw KeyIns ;^v 16 - dw SimpleRet ;^w 17 - dw KeyDown ;^x 18 - dw KeyCtrlY ;^y 19 -;------- -optiontext db 'OPT? C/B ',0 -filename db 'FILENAME:',0 -filesave db ' SAVE: ',0 -asksave db 'SAVE? Y/n',0 -blockread db '^KR NAME:',0 -blocksave db '^KW NAME:',0 -asklineno db 'GO LINE :',0 -askfind db '^QF FIND:',0 -askreplace1 db '^QA REPL:',0 -askreplace2 db '^QA WITH:',0 -stdtxtlen equ filesave-filename - -%ifdef ELKS - screencolors0 db 27,'[40m',27,'[37m' - bold0 db 27,'[0m' ;reset to b/w - screencolors1 db 27,'[41m',27,'[36m' ;yellow on blue - reversevideoX: - bold1: db 27,'[1m' ;bold - scolorslen equ $-screencolors1 - boldlen equ $-bold1 ;take care length of bold0 == length of bold1 -%endif - -;------- -%macro LD 0 - %ifdef ELKS - db 10 - %else - db 13,10 - %endif -%endmacro -;------- -errmsgs: -%ifdef ELKS -db "Op not permitted" ;1 -LD -db "No such file|directory" ;2 -LD -LD ;3 -LD ;4 -db "Input/output" ;5 -LD -db "No such device" ;6 -LD -LD ;7 -LD ;8 -db "Bad file descriptor" ;9 -LD -LD ;10 -LD ;11 -db "Cannot allocate memory" ;12 -LD -db "Permission denied" ;13 -LD -LD ;14 -LD ;15 -db "Device or resource busy" ;16 -LD -LD ;17 -LD ;18 -db "No such device" ;19 -LD -LD ;20 -db "Is a directory" ;21 -LD -db "Invalid argument" ;22 -LD -db "Too many open files" ;23 -LD -db "Too many open files" ;24 -LD -db "Inappropriate ioctl" ;25 -LD -db "Text file busy" ;26 -LD -db "File too large" ;27 -LD -db "No space left on device" ;28 -LD -db "Illegal seek" ;29 -LD -db "R/O file system" ;30 -LD -%else -db "Op not permitted" ;1 -LD -db "No such file|directory" ;2 -LD -db "Path not found" ;3 -LD -db "Too much open files" ;4 -LD -db "Access denied" ;5 -LD -LD ;6 -LD ;7 -LD ;8 -LD ;9 -LD ;10 -LD ;11 -db "Cannot allocate memory" ;12 -LD -LD ;13 -LD ;14 -db "Invalid drive" -LD ;15 -LD ;16 -LD ;17 -LD ;18 -db "R/O file system" ;19 -LD -LD ;20 -db "Drive not ready" ;21 -LD -db "Invalid argument" ;22 -LD -LD ;23 -LD ;24 -db "Illegal seek" ;25 -LD -LD ;26 -LD ;27 -LD ;28 -db "Write" ;29 -LD -db "Read" ;30 -LD -%endif -;----------------------------------------------------------------------- -newline: -db 10 -help: -db "MicroEditor e3/16bit v0.3 GPL (C) 2002,03 A.Kleine " -LD -db "Enter filename or leave with RETURN" -LD -LD -db "Files: ^KR Insert ^KS Save ^KX Save&Exit ^KQ Abort&Exit" -LD -db " ^KD Save&Load" -; ^KR not yet ready on ELKS -LD -LD -db "Blocks: ^KB Start ^KK End ^KC Copy ^KY Del" -LD -db " ^KV Move ^KW Write" -LD -LD -db "Search: ^QF Find ^L Repeat ^QA Srch&Repl" -LD -LD -db "Move: ^E Up ^X Down ^S Left ^D Right" -LD -db " ^R Page Up ^C Page Dn ^F Next Word ^A Prev Word" -LD -LD -db "Quick- ^QS Home ^QD End ^QR BOF ^QC EOF" -LD -db "-Move: ^QB Blk Begin ^QK Blk End ^F Next Word ^A Prev Word" -LD -db " ^QI Go Line#" -LD -LD -db "Delete: ^T Word ^Y Line ^H Left ^G Chr" -LD -db " ^QY Line End" -LD -help_ws_size equ $-help -LD -%ifndef EXESTUB -EXE_enddata: -;----------------------------------------------------------------------- -; -section .bss -bits 16 -%endif -EXE_startbss: -; -%ifdef ELKS - screenline_len equ 256+4*scolorslen ;max possible columns + 4 color ESC seq per line -%else ;-------------- - screenline_len equ sBREITE * 2 ;2 byte per char -%endif - -%ifdef ELKS - termios_size equ 60 - termios resb termios_size - orig resb termios_size - setkplen equ 10 - setkp resb setkplen ;to store cursor ESC seq like db 27,'[000;000H' - read_b resw 1 ;buffer for GetChar - isbold resw 1 ;control of bold display of ws-blocks - inverse resw 1 - seekhelp resd 1 ;syscall helper (for seeking more than 16 bit range) - perms resw 1 -%ifdef SYS_FSTAT - fstatbuf resb 64 ;prepared for later -%endif -%else ;----- - zeilenangabe resb 12 ;buffer for showlinenum -%endif -%ifdef LESSWRITEOPS - screenbuffer_size equ 62*(160+32) ;estimated 62 lines 160 columns, 32 byte ESC seq (ca.12k) - screenbuffer_dwords equ screenbuffer_size/4 - screenbuffer resb screenbuffer_size - screenbuffer_end equ $ ;If you really have higher screen resolution, -%endif -errno resw 1 ;used similar libc, but not excactly equal -error resb errlen ;reserved space for string: 'ERROR xxx:tttteeeexxxxtttt',0 -columne resw 1 ;helper for display of current column -zloffset resw 1 ;helper: chars scrolled out at left border -fileptr resw 1 ;helper for temp storage of current pos in file -tabcnt resw 1 ;internal helper byte in DispNewScreen() only -kurspos resw 1 ;cursor position set by DispNewScreen() -kurspos2 resw 1 ;cursor position set by other functions -insstat resw 1 -endedit resw 1 ;byte controls program exit -changed resw 1 ;status byte: (UN)CHANGED -linenr resw 1 ;current line -showblock resw 1 ;helper for ^KH -blockbegin resw 1 -blockende resw 1 -bereitsges resw 1 ;byte used for ^L -suchlaenge resw 1 ;helper for ^QA,^QF -repllaenge resw 1 -vorwarts resw 1 -grossklein resw 1 ;helper byte for ^QF,^QA -old resw 1 ;helper for ^QP -veryold resw 1 ;ditto -ch2linebeg resw 1 ;helper keeping cursor pos max at EOL (up/dn keys) -numeriere resw 1 ;byte controls re-numeration -lines resw 1 ;equ 23 or similar i.e. screen lines-2 (status-,unused line) -columns resw 1 ;equ 80 or similar word (using only LSB) -filepath resb maxfilenamelen+1 -blockpath resb maxfilenamelen+1 -replacetext resb maxfilenamelen+1 -suchtext resb maxfilenamelen+1 -optbuffer resb maxfilenamelen+1 ;buffer for search/replace options and for ^QI -optslen equ $-optbuffer -screenline resb screenline_len ;buffer for displaying a text line -textX resb MAXLEN -sot equ (textX+1) ;start-of-text - -alignb 4 -EXE_endbss: - EXE_absssize equ (EXE_endbss-EXE_startbss+3) & (~3) -%ifdef EXE - EXE_acodesize equ (EXE_endcode-EXE_startcode+3) & (~3) - EXE_datasize equ EXE_enddata-EXE_startdata - EXE_allocsize equ EXE_acodesize + EXE_datasize +100h -%endif - -%ifndef ELKS -%ifdef EXESTUB -bits 16 -section .stack stack - resb 0x800 -%endif -%endif From 30609c1c4aa04b04194f2409947c1e26b05d5880 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Thu, 28 Jun 2018 21:57:08 +0200 Subject: [PATCH 05/20] [libc] Test round 2 with sash and ash - Fix va_arg() hang in vfprintf() - Disable debug in init process - Fix some warnings --- elks/fs/exec.c | 4 ++-- elkscmd/sys_utils/Makefile | 2 -- libc/include/stdio.h | 3 +++ libc/misc/ltostr.c | 27 ++++++++++----------------- libc/stdio/printf.c | 10 +++++++--- 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/elks/fs/exec.c b/elks/fs/exec.c index f2509eb5e..a3b30c9f5 100644 --- a/elks/fs/exec.c +++ b/elks/fs/exec.c @@ -53,8 +53,8 @@ static struct minix_supl_hdr msuph; // Default data sizes -#define INIT_HEAP 0x1000 // 4 K -#define INIT_STACK 0x1000 // 4 K +#define INIT_HEAP 0x0 // For future use (inverted heap and stack) +#define INIT_STACK 0x4000 // 16 K (space for both stack and heap) int sys_execve(char *filename, char *sptr, size_t slen) diff --git a/elkscmd/sys_utils/Makefile b/elkscmd/sys_utils/Makefile index 0f5a84dac..91105f3bc 100644 --- a/elkscmd/sys_utils/Makefile +++ b/elkscmd/sys_utils/Makefile @@ -13,8 +13,6 @@ include $(BASEDIR)/Make.rules PRGS = init getty login kill mount umount passwd reboot shutdown ps \ swapon meminfo who knl man poweroff -CFLAGS += -DDEBUG - # clock disabled because direct I/O port access # exitemu disabled because it calls INT directly to DOSEMU diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 39d2e6b40..0749abf55 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -4,6 +4,7 @@ #include #include +#include #ifndef SEEK_SET #define SEEK_SET 0 @@ -127,6 +128,8 @@ extern int printf __P ((__const char*, ...)); extern int fprintf __P ((FILE*, __const char*, ...)); extern int sprintf __P ((char*, __const char*, ...)); +int vfprintf (FILE * stream, const char * format, va_list ap); + #define stdio_pending(fp) ((fp)->bufread>(fp)->bufpos) void perror (const char * s); diff --git a/libc/misc/ltostr.c b/libc/misc/ltostr.c index c8966d9ef..742b77e63 100644 --- a/libc/misc/ltostr.c +++ b/libc/misc/ltostr.c @@ -5,23 +5,7 @@ static char buf[34]; -extern char * ultostr(); - -char * ltostr(val, radix) -long val; -int radix; -{ - char *p; - int flg = 0; - if( val < 0 ) { flg++; val= -val; } - p = ultostr(val, radix); - if(p && flg) *--p = '-'; - return p; -} - -char * ultostr(val, radix) -unsigned long val; -int radix; +char * ultostr (unsigned long val, int radix) { register char *p; register int c; @@ -41,3 +25,12 @@ int radix; return p; } +char * ltostr (long val, int radix) +{ + char *p; + int flg = 0; + if( val < 0 ) { flg++; val= -val; } + p = ultostr(val, radix); + if(p && flg) *--p = '-'; + return p; +} diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index 106dda974..28390db3c 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -24,10 +24,14 @@ #include #include -#include #include #include + +extern char * ltostr (long val, int radix); +extern char * ultostr (unsigned long val, int radix); + + int sprintf (char * sp, const char * fmt, ...) { static FILE string[1] = @@ -224,7 +228,7 @@ int vfprintf(FILE *op, const char *fmt, va_list ap) case 'i': ptmp = ltostr((long) ((lval) ? va_arg(ap, long) - : va_arg(ap, short)), + : va_arg(ap, int)), 10); goto printit; @@ -252,7 +256,7 @@ int vfprintf(FILE *op, const char *fmt, va_list ap) usproc: ptmp = ultostr((unsigned long) ((lval) ? va_arg(ap, unsigned long) - : va_arg(ap, unsigned short)), + : va_arg(ap, unsigned int)), radix); if( hash && radix == 8 ) { width = strlen(ptmp)+1; pad='0'; } goto printit; From 1b21e92e5615e563514cf7f7d4c118334c29a834 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Fri, 29 Jun 2018 00:31:54 +0200 Subject: [PATCH 06/20] [libc] Optimize memcpy() --- libc/Makefile | 3 ++- libc/asm/Makefile | 17 +++++++++++++ libc/asm/memcpy-a.s | 39 ++++++++++++++++++++++++++++ libc/include/asm/config.h | 6 +++++ libc/string/Makefile | 1 + libc/string/memcpy-c.c | 18 +++++++++++++ libc/string/string.c | 53 --------------------------------------- 7 files changed, 83 insertions(+), 54 deletions(-) create mode 100644 libc/asm/Makefile create mode 100644 libc/asm/memcpy-a.s create mode 100644 libc/include/asm/config.h create mode 100644 libc/string/memcpy-c.c diff --git a/libc/Makefile b/libc/Makefile index c81bdb4e2..8f7b2abaa 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -11,7 +11,8 @@ include Makefile.inc # Defines SUBDIRS = \ - error \ + asm \ + error \ gcc \ getent \ malloc \ diff --git a/libc/asm/Makefile b/libc/asm/Makefile new file mode 100644 index 000000000..d6dcbbd09 --- /dev/null +++ b/libc/asm/Makefile @@ -0,0 +1,17 @@ +# Makefile of /libc/asm module + +include $(TOPDIR)/libc/Makefile.inc + +SRCS = \ + memcpy-a.s \ + # end of list + +OBJS = $(SRCS:.s=.o) + +all: $(LIBC) + +$(LIBC): $(OBJS) + $(AR) $(ARFLAGS) $@ $? + +clean: + rm -f *.o diff --git a/libc/asm/memcpy-a.s b/libc/asm/memcpy-a.s new file mode 100644 index 000000000..bcf82d1ad --- /dev/null +++ b/libc/asm/memcpy-a.s @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// #include +// void * memcpy (void * dest, const void * src, size_t n); +//------------------------------------------------------------------------------ + + .code16 + + .text + + .global memcpy + +memcpy: + mov %sp,%bx + + push %si + push %di + + mov %es,%dx + + mov %ds,%ax + mov %ax,%es + + mov 2(%bx),%di // dest + mov 4(%bx),%si // src + mov 6(%bx),%cx // n + + mov %di,%ax // retval + + cld + rep + movsb + + mov %dx,%es + + pop %di + pop %si + ret + +//------------------------------------------------------------------------------ diff --git a/libc/include/asm/config.h b/libc/include/asm/config.h new file mode 100644 index 000000000..eb777d7aa --- /dev/null +++ b/libc/include/asm/config.h @@ -0,0 +1,6 @@ +// LIBC assembly configuration +// List of functions implemented in assembly + +#pragma once + +#define LIBC_ASM_MEMCPY diff --git a/libc/string/Makefile b/libc/string/Makefile index 7d648870f..d80963675 100644 --- a/libc/string/Makefile +++ b/libc/string/Makefile @@ -4,6 +4,7 @@ include $(TOPDIR)/libc/Makefile.inc SRCS = \ bzero.c \ + memcpy-c.c \ strcasecmp.c \ strcspn.c \ string.c \ diff --git a/libc/string/memcpy-c.c b/libc/string/memcpy-c.c new file mode 100644 index 000000000..7ad37fc10 --- /dev/null +++ b/libc/string/memcpy-c.c @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------- + +#include + +#include + +#ifndef LIBC_ASM_MEMCPY + +void * memcpy (void * d, const void * s, size_t l) +{ + register char *s1=d, *s2=(char *)s; + for( ; l>0; l--) *((unsigned char*)s1++) = *((unsigned char*)s2++); + return d; +} + +#endif + +//------------------------------------------------------------------------------- diff --git a/libc/string/string.c b/libc/string/string.c index 1b4f77092..0986ad4b1 100644 --- a/libc/string/string.c +++ b/libc/string/string.c @@ -315,59 +315,6 @@ char * s; return p; } -/********************** Function memcpy ************************************/ - -void *memcpy(void *d, const void *s, size_t l) -{ -#ifdef BCC_AX_ASM -#asm - mov bx,sp - push di - push si - -#ifdef PARANOID - push es - push ds ; Im not sure if this is needed, so just in case. - pop es - cld -#endif - -#if __FIRST_ARG_IN_AX__ - mov di,ax ; dest - mov si,[bx+2] ; source - mov cx,[bx+4] ; count -#else - mov di,[bx+2] ; dest - mov si,[bx+4] ; source - mov cx,[bx+6] ; count - - mov ax,di -#endif - ; If di is odd we could mov 1 byte before doing word move - ; as this would speed the copy slightly but its probably - ; too rare to be worthwhile. - ; NB 8086 has no problem with mis-aligned access. - - shr cx,#1 ; Do this faster by doing a mov word - rep - movsw - adc cx,cx ; Retrieve the leftover 1 bit from cflag. - rep - movsb - -#ifdef PARANOID - pop es -#endif - pop si - pop di -#endasm -#else /* ifdef BCC_AX_ASM */ - register char *s1=d, *s2=(char *)s; - for( ; l>0; l--) *((unsigned char*)s1++) = *((unsigned char*)s2++); - return d; -#endif /* ifdef BCC_AX_ASM */ -} - /********************** Function memccpy ************************************/ #ifdef L_memccpy From 63317f5f8940cb60e167a65b7904f555ab6ff5c4 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Tue, 3 Jul 2018 20:24:46 +0200 Subject: [PATCH 07/20] [libc] Optimize strcpy() --- libc/asm/Makefile | 3 +- libc/asm/{memcpy-a.s => memcpy-s.s} | 29 +++++++++++----- libc/asm/strcpy-s.s | 53 +++++++++++++++++++++++++++++ libc/include/asm/config.h | 1 + libc/string/Makefile | 1 + libc/string/strcpy-c.c | 18 ++++++++++ libc/string/string.c | 13 +------ 7 files changed, 96 insertions(+), 22 deletions(-) rename libc/asm/{memcpy-a.s => memcpy-s.s} (63%) create mode 100644 libc/asm/strcpy-s.s create mode 100644 libc/string/strcpy-c.c diff --git a/libc/asm/Makefile b/libc/asm/Makefile index d6dcbbd09..8fe64108e 100644 --- a/libc/asm/Makefile +++ b/libc/asm/Makefile @@ -3,7 +3,8 @@ include $(TOPDIR)/libc/Makefile.inc SRCS = \ - memcpy-a.s \ + memcpy-s.s \ + strcpy-s.s \ # end of list OBJS = $(SRCS:.s=.o) diff --git a/libc/asm/memcpy-a.s b/libc/asm/memcpy-s.s similarity index 63% rename from libc/asm/memcpy-a.s rename to libc/asm/memcpy-s.s index bcf82d1ad..d50bd56ce 100644 --- a/libc/asm/memcpy-a.s +++ b/libc/asm/memcpy-s.s @@ -10,30 +10,41 @@ .global memcpy memcpy: - mov %sp,%bx + push %bp + mov %sp,%bp - push %si - push %di + // Save SI DI ES mov %es,%dx mov %ds,%ax mov %ax,%es - mov 2(%bx),%di // dest - mov 4(%bx),%si // src - mov 6(%bx),%cx // n + mov %si,%ax + mov %di,%bx - mov %di,%ax // retval + // Do the copy + + mov 4(%bp),%di // dest + mov 6(%bp),%si // src + mov 8(%bp),%cx // n cld rep movsb + // Restore SI DI ES + + mov %ax,%si + mov %bx,%di + mov %dx,%es - pop %di - pop %si + // Return value is destination + + mov 4(%bp),%ax + + pop %bp ret //------------------------------------------------------------------------------ diff --git a/libc/asm/strcpy-s.s b/libc/asm/strcpy-s.s new file mode 100644 index 000000000..ae444a5f8 --- /dev/null +++ b/libc/asm/strcpy-s.s @@ -0,0 +1,53 @@ +//------------------------------------------------------------------------------ +// #include +// char * strcpy (char * dest, const char * src); +//------------------------------------------------------------------------------ + + .code16 + + .text + + .global strcpy + +strcpy: + push %bp + mov %sp,%bp + + // Save SI DI ES + + mov %es,%dx + + mov %ds,%ax + mov %ax,%es + + mov %si,%bx + mov %di,%cx + + // Do the copy + + mov 4(%bp),%di // dest + mov 6(%bp),%si // src + cld + +_loop: + lodsb + stosb + test %al,%al + jnz _loop + + // Restore SI DI ES + + mov %bx,%si + mov %cx,%di + + mov %dx,%es + + // Return value is destination + + mov 4(%bp),%ax + + pop %bp + ret + +//------------------------------------------------------------------------------ + diff --git a/libc/include/asm/config.h b/libc/include/asm/config.h index eb777d7aa..8e9501e85 100644 --- a/libc/include/asm/config.h +++ b/libc/include/asm/config.h @@ -4,3 +4,4 @@ #pragma once #define LIBC_ASM_MEMCPY +#define LIBC_ASM_STRCPY diff --git a/libc/string/Makefile b/libc/string/Makefile index d80963675..4a3078952 100644 --- a/libc/string/Makefile +++ b/libc/string/Makefile @@ -8,6 +8,7 @@ SRCS = \ strcasecmp.c \ strcspn.c \ string.c \ + strcpy-c.c \ strncasecmp.c \ strpbrk.c \ strspn.c \ diff --git a/libc/string/strcpy-c.c b/libc/string/strcpy-c.c new file mode 100644 index 000000000..401fa62e0 --- /dev/null +++ b/libc/string/strcpy-c.c @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------- + +#include + +#include + +#ifndef LIBC_ASM_STRCPY + +char * strcpy (char * dest, const char * src) +{ + /* This is probably the quickest on an 8086 but a CPU with a cache will + * prefer to do this in one pass */ + return memcpy(d, s, strlen(s)+1); +} + +#endif + +//------------------------------------------------------------------------------- diff --git a/libc/string/string.c b/libc/string/string.c index 0986ad4b1..918cfc463 100644 --- a/libc/string/string.c +++ b/libc/string/string.c @@ -80,17 +80,6 @@ char * strcat(char *d, const char * s) return d; } -/********************** Function strcpy ************************************/ - -char * strcpy(d, s) -char *d; -const char * s; -{ - /* This is probably the quickest on an 8086 but a CPU with a cache will - * prefer to do this in one pass */ - return memcpy(d, s, strlen(s)+1); -} - /********************** Function strcmp ************************************/ int strcmp(const char *d, const char * s) @@ -277,7 +266,7 @@ char * strchr (const char * s, int c) register char ch; for(;;) { - if( (ch= *s) == c ) return s; + if( (ch= *s) == c ) return (char *) s; if( ch == 0 ) return 0; s++; } From 453f4438d9d6c6c219b9339c21351864d8115274 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Tue, 3 Jul 2018 21:38:13 +0200 Subject: [PATCH 08/20] [libc] Optimize memset() --- libc/asm/Makefile | 1 + libc/asm/memset-s.s | 47 +++++++++++++++++++++++++++++ libc/include/asm/config.h | 1 + libc/string/Makefile | 1 + libc/string/memset-c.c | 18 +++++++++++ libc/string/string.c | 63 +-------------------------------------- 6 files changed, 69 insertions(+), 62 deletions(-) create mode 100644 libc/asm/memset-s.s create mode 100644 libc/string/memset-c.c diff --git a/libc/asm/Makefile b/libc/asm/Makefile index 8fe64108e..3f4b60cc5 100644 --- a/libc/asm/Makefile +++ b/libc/asm/Makefile @@ -4,6 +4,7 @@ include $(TOPDIR)/libc/Makefile.inc SRCS = \ memcpy-s.s \ + memset-s.s \ strcpy-s.s \ # end of list diff --git a/libc/asm/memset-s.s b/libc/asm/memset-s.s new file mode 100644 index 000000000..f7853e0ff --- /dev/null +++ b/libc/asm/memset-s.s @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// #include +// void * memset (void * s, int c, size_t n); +//------------------------------------------------------------------------------ + + .code16 + + .text + + .global memset + +memset: + push %bp + mov %sp,%bp + + // Save DI ES + + mov %es,%dx + + mov %ds,%ax + mov %ax,%es + + mov %di,%bx + + // Do the setup + + mov 4(%bp),%di // s + mov 6(%bp),%ax // c + mov 8(%bp),%cx // n + + cld + rep + stosb + + // Restore DI ES + + mov %bx,%di + mov %dx,%es + + // Return value is destination + + mov 4(%bp),%ax + + pop %bp + ret + +//------------------------------------------------------------------------------ diff --git a/libc/include/asm/config.h b/libc/include/asm/config.h index 8e9501e85..5b84defa6 100644 --- a/libc/include/asm/config.h +++ b/libc/include/asm/config.h @@ -4,4 +4,5 @@ #pragma once #define LIBC_ASM_MEMCPY +#define LIBC_ASM_MEMSET #define LIBC_ASM_STRCPY diff --git a/libc/string/Makefile b/libc/string/Makefile index 4a3078952..11a2a1aec 100644 --- a/libc/string/Makefile +++ b/libc/string/Makefile @@ -5,6 +5,7 @@ include $(TOPDIR)/libc/Makefile.inc SRCS = \ bzero.c \ memcpy-c.c \ + memset-c.c \ strcasecmp.c \ strcspn.c \ string.c \ diff --git a/libc/string/memset-c.c b/libc/string/memset-c.c new file mode 100644 index 000000000..93f23eca2 --- /dev/null +++ b/libc/string/memset-c.c @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------- + +#include + +#include + +#ifndef LIBC_ASM_MEMSET + +void * memset (void * str, int c, size_t l) +{ + register char *s1=str; + while(l-->0) *s1++ = c; + return str; +} + +#endif + +//------------------------------------------------------------------------------- diff --git a/libc/string/string.c b/libc/string/string.c index 918cfc463..75bffb2a2 100644 --- a/libc/string/string.c +++ b/libc/string/string.c @@ -368,68 +368,7 @@ void * memchr(const void * str, int c, size_t l) #endif /* ifdef BCC_ASM */ } -//----------------------------------------------------------------------------- - -void * memset (void * str, int c, size_t l) -{ -#ifdef BCC_AX_ASM -#asm - mov bx,sp - push di - -#ifdef PARANOID - push es - push ds ; Im not sure if this is needed, so just in case. - pop es - cld -#endif - -#if __FIRST_ARG_IN_AX__ - mov di,ax ; Fetch - mov ax,[bx+2] - mov cx,[bx+4] -#else - mov di,[bx+2] ; Fetch - mov ax,[bx+4] - mov cx,[bx+6] -#endif - -; How much difference does this alignment make ? -; I don`t think it`s significant cause most will already be aligned. - -; test cx,cx ; Zero size - skip -; je xit -; -; test di,#1 ; Line it up -; je s_1 -; stosb -; dec cx -;s_1: - - mov ah,al ; Replicate byte - shr cx,#1 ; Do this faster by doing a sto word - rep ; Bzzzzz ... - stosw - adc cx,cx ; Retrieve the leftover 1 bit from cflag. - - rep ; ... z - stosb - -xit: - mov ax,[bx+2] -#ifdef PARANOID - pop es -#endif - pop di -#endasm -#else /* ifdef BCC_AX_ASM */ - register char *s1=str; - while(l-->0) *s1++ = c; - return str; -#endif /* ifdef BCC_AX_ASM */ -} - -/********************** Function memcmp ************************************/ +//------------------------------------------------------------------------------ int memcmp(const void *s, const void *d, size_t l) { From de86ec1d0b443f660fe009a04f0781a9795da0bf Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Tue, 3 Jul 2018 22:19:59 +0200 Subject: [PATCH 09/20] [libc] Optimize strlen() --- libc/asm/Makefile | 1 + libc/asm/strlen-s.s | 48 +++++++++++++++++++++++++++ libc/include/asm/config.h | 1 + libc/string/Makefile | 1 + libc/string/string.c | 70 +++++---------------------------------- libc/string/strlen-c.c | 18 ++++++++++ libc/system/defn_tab.v | 24 -------------- 7 files changed, 77 insertions(+), 86 deletions(-) create mode 100644 libc/asm/strlen-s.s create mode 100644 libc/string/strlen-c.c delete mode 100644 libc/system/defn_tab.v diff --git a/libc/asm/Makefile b/libc/asm/Makefile index 3f4b60cc5..9874973a4 100644 --- a/libc/asm/Makefile +++ b/libc/asm/Makefile @@ -6,6 +6,7 @@ SRCS = \ memcpy-s.s \ memset-s.s \ strcpy-s.s \ + strlen-s.s \ # end of list OBJS = $(SRCS:.s=.o) diff --git a/libc/asm/strlen-s.s b/libc/asm/strlen-s.s new file mode 100644 index 000000000..d88e33d83 --- /dev/null +++ b/libc/asm/strlen-s.s @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// #include +// size_t strlen (const char * s); +//------------------------------------------------------------------------------ + + .code16 + + .text + + .global strlen + +strlen: + push %bp + mov %sp,%bp + + // Save DI ES + + mov %es,%dx + + mov %ds,%ax + mov %ax,%es + + mov %di,%bx + + // Do the scan + + mov 4(%bp),%di // s + mov $-1,%cx + xor %ax,%ax + + cld + repne + scasb + + mov %cx,%ax + not %ax + dec %ax + + // Restore DI ES + + mov %bx,%di + mov %dx,%es + + pop %bp + ret + +//------------------------------------------------------------------------------ + diff --git a/libc/include/asm/config.h b/libc/include/asm/config.h index 5b84defa6..b789e50cd 100644 --- a/libc/include/asm/config.h +++ b/libc/include/asm/config.h @@ -6,3 +6,4 @@ #define LIBC_ASM_MEMCPY #define LIBC_ASM_MEMSET #define LIBC_ASM_STRCPY +#define LIBC_ASM_STRLEN diff --git a/libc/string/Makefile b/libc/string/Makefile index 11a2a1aec..9104a295e 100644 --- a/libc/string/Makefile +++ b/libc/string/Makefile @@ -10,6 +10,7 @@ SRCS = \ strcspn.c \ string.c \ strcpy-c.c \ + strlen-c.c \ strncasecmp.c \ strpbrk.c \ strspn.c \ diff --git a/libc/string/string.c b/libc/string/string.c index 75bffb2a2..597d04799 100644 --- a/libc/string/string.c +++ b/libc/string/string.c @@ -6,72 +6,18 @@ #include #include -#ifdef __AS386_16__ -#if __FIRST_ARG_IN_AX__ -#define BCC_AX_ASM /* BCC Assembler that can cope with arg in AX */ -#else -#define BCC_AX_ASM -#define BCC_ASM /* Use 16 bit BCC assembler */ -#endif - -#define PARANOID /* Include extra code for cld and ES register */ -#endif +/* This is a basic string package; it includes the most used functions: -/* This is a basic string package; it includes the most used functions + strcat strcmp strncat strncpy strncmp strchr strrchr strdup + memccpy memchr memcmp memmove - strlen strcat strcpy strcmp strncat strncpy strncmp strchr strrchr strdup - memcpy memccpy memchr memset memcmp memmove - - These functions are in seperate files. - strpbrk.o strsep.o strstr.o strtok.o strcspn.o - strspn.o strcasecmp.o strncasecmp.o + These functions are in separate files: + memcpy memset + strcpy strlen + strpbrk strcpy strsep strstr strtok strcspn + strspn strcasecmp strncasecmp */ -/********************** Function strlen ************************************/ - -size_t strlen(const char * str) -{ -#ifdef BCC_AX_ASM -#asm -#if !__FIRST_ARG_IN_AX__ - mov bx,sp -#endif - push di - -#ifdef PARANOID - push es - push ds ! Im not sure if this is needed, so just in case. - pop es - cld -#endif - ! This is almost the same as memchr, but it can - ! stay as a special. - -#if __FIRST_ARG_IN_AX__ - mov di,ax -#else - mov di,[bx+2] -#endif - mov cx,#-1 - xor ax,ax - repne - scasb - not cx - dec cx - mov ax,cx - -#ifdef PARANOID - pop es -#endif - pop di -#endasm -#else - register char * p =(char *) str; - while(*p) p++; - return p-str; -#endif /* ifdef BCC_AX_ASM */ -} - /********************** Function strcat ************************************/ char * strcat(char *d, const char * s) diff --git a/libc/string/strlen-c.c b/libc/string/strlen-c.c new file mode 100644 index 000000000..50d59d173 --- /dev/null +++ b/libc/string/strlen-c.c @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------- + +#include + +#include + +#ifndef LIBC_ASM_STRLEN + +size_t strlen (const char * str) +{ + register char * p = (char *) str; + while (*p) p++; + return p - str; +} + +#endif + +//------------------------------------------------------------------------------- diff --git a/libc/system/defn_tab.v b/libc/system/defn_tab.v deleted file mode 100644 index c26096d0f..000000000 --- a/libc/system/defn_tab.v +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef sys_alarm -#define sys_alarm sys_enosys -#endif - -#ifndef sys_pause -#define sys_pause sys_enosys -#endif - -#ifndef sys_nice -#define sys_nice sys_enosys -#endif - -#ifndef sys_sleep -#define sys_sleep sys_enosys -#endif - -#ifndef sys_times -#define sys_times sys_enosys -#endif - -#ifndef sys_getgid -#define sys_getgid sys_enosys -#endif - From 9e038b816014f83c0808df1ee5697380cd6be499 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Sun, 3 Mar 2019 21:42:33 +0100 Subject: [PATCH 10/20] Revise bootblocks for GCC-IA16 Port the residual part that was stuck on BCC and simplify the boot process from MINIX FS. Issue #225 --- elks/elks-raw.ld | 7 + elks/elks-small.ld | 2 +- elks/elks-tiny.ld | 3 +- elkscmd/bootblocks/.gitignore | 6 +- elkscmd/bootblocks/Makefile | 44 +- elkscmd/bootblocks/as86_encap | 124 ---- elkscmd/bootblocks/minix.c | 943 ----------------------------- elkscmd/bootblocks/minix.h | 86 ++- elkscmd/bootblocks/minix_elks.c | 152 ----- elkscmd/bootblocks/minix_first.S | 602 ++++++++++++++++++ elkscmd/bootblocks/minix_second.c | 242 ++++++++ elkscmd/bootblocks/sysboot16.s | 82 --- elkscmd/rootfs_template/boot/.keep | 0 image/Make.defs | 1 - image/Makefile | 6 +- 15 files changed, 932 insertions(+), 1368 deletions(-) create mode 100644 elks/elks-raw.ld delete mode 100755 elkscmd/bootblocks/as86_encap delete mode 100644 elkscmd/bootblocks/minix.c delete mode 100644 elkscmd/bootblocks/minix_elks.c create mode 100644 elkscmd/bootblocks/minix_first.S create mode 100644 elkscmd/bootblocks/minix_second.c delete mode 100644 elkscmd/bootblocks/sysboot16.s delete mode 100644 elkscmd/rootfs_template/boot/.keep diff --git a/elks/elks-raw.ld b/elks/elks-raw.ld new file mode 100644 index 000000000..532a6256e --- /dev/null +++ b/elks/elks-raw.ld @@ -0,0 +1,7 @@ +OUTPUT_FORMAT(binary) + +SECTIONS { + .text : { *(.text*) *(.rodata*) *(.data*) } + .bss : { *(.bss) *(COMMON) } + /DISCARD/ : { *(.comment) } +} diff --git a/elks/elks-small.ld b/elks/elks-small.ld index d5afcc330..72899e0db 100644 --- a/elks/elks-small.ld +++ b/elks/elks-small.ld @@ -18,7 +18,7 @@ SECTIONS { _begintext = ALIGN(0x20); .text 0 : AT(_begintext) { *(.text*); . = ALIGN(0x10); } _begindata = _begintext + .; - .data 0 : AT(_begindata) { *(.data*) *(.rodata*) } + .data 0 : AT(_begindata) { *(.rodata*) *(.data*) } .bss : { *(.bss) *(COMMON) } /DISCARD/ : { *(.comment) } } diff --git a/elks/elks-tiny.ld b/elks/elks-tiny.ld index 70969ad0d..e3a3bc870 100644 --- a/elks/elks-tiny.ld +++ b/elks/elks-tiny.ld @@ -16,6 +16,7 @@ SECTIONS { LONG (0); /* symbol table size */ } _begintext = ALIGN(0x20); - .text 0 : AT(_begintext) { *(.text*) *(.data*) *(.rodata*) *(.bss) *(COMMON) } + .text 0 : AT(_begintext) { *(.text*) *(.rodata*) *(.data*) } + .bss : { *(.bss) *(COMMON) } /DISCARD/ : { *(.comment) } } diff --git a/elkscmd/bootblocks/.gitignore b/elkscmd/bootblocks/.gitignore index 6ce28de95..731e68648 100644 --- a/elkscmd/bootblocks/.gitignore +++ b/elkscmd/bootblocks/.gitignore @@ -1,6 +1,2 @@ *.bin -*.v -*.lst -*.sym -minix.s -minix_elks.s +minix_first.s diff --git a/elkscmd/bootblocks/Makefile b/elkscmd/bootblocks/Makefile index b8e611994..e360b273a 100644 --- a/elkscmd/bootblocks/Makefile +++ b/elkscmd/bootblocks/Makefile @@ -1,37 +1,33 @@ -CC=bcc -CFLAGS=-ansi -Ms -Oi -O -AS=as86 -ASFLAGS=-0 -w -LDFLAGS=-s -i -H0x10000 +CC = ia16-elf-gcc +CROSS_CFLAGS = -fno-inline -mcmodel=tiny -mno-segment-relocation-stuff -ffreestanding +INCLUDES = -I $(TOPDIR)/include +CFLAGS = -Os $(CROSS_CFLAGS) $(INCLUDES) -MINIXDEFS=-DDOTS -LST=-l $*.lst +AS = ia16-elf-as +ASFLAGS = -.PHONY: all +LD = ia16-elf-ld +LDFLAGS = -T $(TOPDIR)/elks/elks-raw.ld -all: minix.bin minix_elks.bin +.PHONY: all -minix.bin: minix.s -minix_elks.bin: minix_elks.v +all: minix.bin -minix.s: minix.c Makefile - $(CC) -Mf -O -DTRY_FLOPPY $(MINIXDEFS) -S minix.c +minix.bin: minix_first.o minix_second.o + $(LD) $(LDFLAGS) -o minix.bin minix_first.o minix_second.o -minix_elks.s: minix_elks.c Makefile minix.v - $(CC) -Mf -O $(MINIXDEFS) -S minix_elks.c +minix_first.o: minix_first.s + $(AS) -o minix_first.o minix_first.s -clean realclean: - rm -f minix.s minix_elks.s - rm -f *.bin *.lst *.sym *.v +minix_first.s: minix_first.S + $(CC) $(INCLUDES) -E -o minix_first.s minix_first.S -.SUFFIXES: .bin .v +minix_second.o: minix_second.c -.s.bin: - $(AS) -w- -0 -b $*.bin -s $*.sym $*.s $(LST) - -.s.v: - ./as86_encap $*.s $*.v $*_ $(ASFLAGS) $(LST) +clean realclean: + rm -f minix_first.s + rm -f *.o *.bin # Boot blocks are not part of the target filesystem # but embedded in the target disk image diff --git a/elkscmd/bootblocks/as86_encap b/elkscmd/bootblocks/as86_encap deleted file mode 100755 index 44e0b3ec1..000000000 --- a/elkscmd/bootblocks/as86_encap +++ /dev/null @@ -1,124 +0,0 @@ -#!/bin/sh - -# -# This file is simply an example of what can be done using the new binary -# and symbol table output functions. As shown it can be used to produce -# a C file containing the encapsulated binary of the assembly, plus any -# public symbols in the source are accessable to the C program. -# -# Use it in a makefile: -# -# .s.v: -# as86_encap $*.s $*.v $*_ $(AS86FLAGS) -# - -[ $# -lt 2 ] && { - echo "Usage: `basename $0` infile outfile prefix [as86 opts]" 1>&2 - exit 1 -} - -trap "rm -f _$$.* ; exit 99" 1 2 3 15 - -LIBDIR=/usr/lib/bcc -BINDIR=/usr/bin - -# If the one set by install fails then try a couple of others. -[ -x "$LIBDIR/as86" ] || LIBDIR="`dirname $0`" -[ -x "$LIBDIR/as86" ] || LIBDIR="$BINDIR" -[ -x "$LIBDIR/as86" ] || LIBDIR="`dirname $0`/../lib" -[ -x "$LIBDIR/as86" ] || LIBDIR=/usr/bin - -IFILE="$1" -OFILE="$2" -PREFIX="`basename $IFILE .s`_" - -shift ; shift -if [ $# -ge 1 ] -then case "$1" in - -* ) ;; - [A-Za-z_]* ) PREFIX="$1" - shift - ;; - esac -fi -RV=0 - -as86 "$@" "$IFILE" -b _$$.bin -s _$$.sym || RV=$? - -echo '#ifndef __ASSEMBLY__' > _$$.0 -echo >> _$$.0 -echo '#else' > _$$.3 -echo >> _$$.3 -echo '#endif' > _$$.5 - -[ "$RV" = 0 ] && { - ( - sort _$$.sym - echo %%%% - od -v -t uC _$$.bin - ) | \ - awk -v prefix=$PREFIX -v ofile=_$$ ' BEGIN{ - sname = prefix "start"; - sn_file= ofile ".1"; - bn_file= ofile ".2"; - as_file= ofile ".4"; - } - /^%%%%$/ { flg++; - if( flg == 1 ) - { - if( !started ) - { - printf "#define %s 0\n", sname > sn_file; - printf "%s = 0\n", sname > as_file; - } - - printf "static char %sdata[] = {\n", prefix >bn_file; - bincount=0; - } - next; - } - flg==0 { - if(NF == 0) next; - if( substr($2,1,4) == "0000" ) $2=substr($2,5); - if( $1 == "+" && $4 == "$start" ) - { - printf "#define %s 0x%s\n", sname, $2 > sn_file; - printf "%s = $%s\n", sname, $2 > as_file; - started = 1; - } - else if( substr($3, 1, 1) == "E" && $4 != "start" && $4 != "size" && $4 != "data" ) - { - printf "#define %s%s 0x%s\n", prefix, $4, $2 > sn_file; - printf "%s%s = $%s\n", prefix, $4, $2 > as_file; - } - next; - } - flg==1 { - if(NF == 0) next; - printf " " > bn_file; - for(i=2;i<=NF;i++) { - if( $i >= 32 && $i < 127 && $i != 39 && $i != 92 ) - printf("\047%c\047,", $i) > bn_file; - else - printf("%3d,", $i) > bn_file; - bincount++; - } - printf "\n" > bn_file; - } - END { - printf "};\n\n" > bn_file; - printf "#define %ssize %d\n\n", prefix, bincount > sn_file; - printf "%ssize = $%04x\n\n", prefix, bincount > as_file; - } - ' - RV=$? -} - -[ "$RV" = 0 ] && { - if [ "X$OFILE" = "X-" ] - then cat _$$.[0-9] - else cat _$$.[0-9] > "$OFILE" || RV=$? - fi -} - -rm -f _$$.* -exit $RV diff --git a/elkscmd/bootblocks/minix.c b/elkscmd/bootblocks/minix.c deleted file mode 100644 index fb482c3a7..000000000 --- a/elkscmd/bootblocks/minix.c +++ /dev/null @@ -1,943 +0,0 @@ -/* - * This bootblock loads the linux-8086 executable in the file 'boot' - * from the root directory of a minix filesystem. - * - * Copyright (C) 1990-1998 Robert de Bath, distributed under the GPL Version 2 - * Based on minix filesystem definitions. - * - * TODO: - * Alter nogood() to do a mov sp,... so the helper program can override - * the panic message. - */ - -#include -#include "minix.h" - -/* #define DOTS /* define to have dots printed */ -/* #define HARDDISK /* Define for hard disk version */ -/* #define TRY_FLOPPY /* To do trial reads to find floppy size */ - -/* #define MIN_SPACE */ - -#define zone_shift 0 /* for any < 32M (!= 0 not supported yet, if ever) */ -#define seg_at(k) ((k)*64) -#define seg_of(p) ((unsigned int)p >>4) -#define BOOTSEG (0x07c0) -#define LOADSEG (0x1000) -#define ORGADDR (0x0500) - -#ifdef HARDDISK -#define get_now() -#endif - -#ifdef zone_shift -#if zone_shift == 0 -#define load_zone load_block -#endif -#else -static short zone_shift; -#endif - -#asm -BOOTADDR = 0x7c00 - -.text -! Apparently on startup the only things we can assume are that we start at -! `start` (ABS addr $07C00) and the boot sector is in the segment. - -! So first set CS=DS=ES=SS=0 -! The we move this to $0500 and put the stack at the top of the first 64k. -! The directory 'file' is loaded $1500 and scanned there. -! The final executable will be loaded in the 2nd 64k chunk. -! -org ORGADDR ! The lowest available address. -start: -#ifndef MIN_SPACE - include sysboot16.s - -org start ! The lowest available address, again. - j skip_vars - -org dos_sysid - .ascii "MINIXFS BOOT (C) 1990-1999, Robert de Bath" - - org codestart -#endif - -! A few variables we need to know the positions of for patching, so export -! them and as86_encaps will make some variables. Put them here at the start -! so they're in the same place for both Floppy and harddisk versions as they -! will be used by helper programs. - -export inode ! Inode to search -inode: -_inode: .word 1 ! ROOT_INODE - -#ifndef MIN_SPACE -export dinode ! Inode of directory file was found in. -dinode: -_dinode: .word 1 ! ROOT_INODE -#endif - -export bootfile ! File to boot, make this whatever you like, -bootfile: ! 'boot' is good, 'linux' too. -_bootfile: - .ascii "boot" - .byte 0,0,0,0,0,0,0,0,0,0 - -skip_vars: -#ifdef HARDDISK - mov bx,[si+8] ! Fetch the linear address of part from DS:SI - mov dh,[si+10] ! DL is drive number -#endif - - xor ax,ax ! All segments are zero, first 64k of mem. - mov ds,ax - mov es,ax - mov ss,ax - mov sp,ax - -#ifndef HARDDISK -loopy: - mov ax,#$0203 ! Read 3 sectors, code + superblock. - mov bx,#start ! Where this _should_ be - mov cx,#$0001 ! From sector 1 - xor dx,dx ! Of the floppy drive head zero - int $13 - jc loopy -#else - - mov cx,#$100 ! Move 256 words - mov si,#BOOTADDR ! From default BB - mov di,#ORGADDR ! To the correct address. - rep - movsw - - xchg dl,dh - mov [bootpart],bx ! Save the partition sector offset (and drive) - mov [bootpart+2],dx - - ! Read next 2 sectors of hd. - xor dx,dx - mov cx,#1 - mov bx,#ORGADDR+$200 - mov al,#2 - - call load_sect -#endif - - jmpi code,#0 - -#endasm - -/* /* */ -/****************************************************************************/ -/* Section cdef */ -/****************************************************************************/ - -/* The name of the file and inode to start */ -extern char bootfile[]; -extern inode_nr inode; -extern inode_nr dinode; - -/* For multi-sector reads */ -extern sect_nr lastsect; -extern sect_nr firstsect; -extern unsigned loadaddr; -extern unsigned loadcount; - -/* Keep track of zones to load */ -extern zone_nr * next_zone; -extern zone_nr * end_zone; -extern zone_nr indirect; - -/* Where to load zones */ -extern unsigned ldaddr; - -/* Directory reading */ -extern dir_struct * dirptr; -extern unsigned flength; -extern unsigned dir_32; - -#ifndef HARDDISK -/* The 'shape' of the floppy - intuit from superblock or try to read max */ -extern unsigned n_sectors; -#endif - -extern struct super_block b_super; -extern d_inode b_inode[INODES_PER_BLOCK]; -extern zone_nr b_zone[NR_INDIRECTS]; -extern dir_struct directory[]; - -/* /* */ -/****************************************************************************/ -/* Section adef */ -/****************************************************************************/ - -#asm -.text - -#ifdef HARDDISK -bootpart: .long 0 -#else -_loadcount: .word 0 -_firstsect: .word 0 -_loadaddr: .word 0 -_lastsect: .word 0 -#endif - - block start+0x400 -_b_super: .blkb 512 - -#ifndef MIN_SPACE -export helper -helper: .blkb 1024 -export helper_end -helper_end: -#endif - -_b_inode: .blkb 1024 -_b_zone: .blkb 1024 - -#ifdef MIN_SPACE -temp_space: .blkb 512 -#endif -probe_buf: -_directory: .blkb 32768 - endb - -#endasm - -/* /* */ -/****************************************************************************/ -/* Section nogood */ -/****************************************************************************/ -/* #if defined(HARDDISK) && !defined(SKIPBOOT) */ -#ifndef SKIPBOOT -static -nogood() -{ -#asm - mov si,#fail_fs -min_nextc: - lodsb - cmp al,#0 - jz min_eos - mov bx,#7 - mov ah,#$E ! Can't use $13 cause that's AT+ only! - int $10 - jmp min_nextc -min_eos: ! Wait for a key then reboot - xor ax,ax - int $16 - jmpi $0,$FFFF ! Reboot. - -fail_fs: - .byte 13,10 -#if defined(HARDDISK) - .asciz "Initial boot failed, press return to reboot\r\n" -#else - .asciz "Boot failed:" -#endif -#endasm -} - -#else - -static -nogood() -{ -/* This didn't work, chain the boot sector of the HD */ -#asm - push cs - pop es -hcode: - mov ax,#$0201 ! Read 1 sector - mov bx,#BOOTADDR ! In the boot area - mov cx,#$0001 ! From sector 1 - mov dx,#$0080 ! Of the hard drive head zero - int $13 - jc hcode ! Keep trying forever! - jmpi BOOTADDR,0 -#endasm -} -#endif - -/* /* */ -/****************************************************************************/ -/* Section hd_sect */ -/****************************************************************************/ -#ifdef HARDDISK -#asm -! -! Load AL sectors from linear sector DX:CX into location ES:BX -! Linear sector zero is at [bootpart] -! This loads one sector at a time, but that's OK cause even in the _very_ -! worst case it'll take no more that 5 seconds to load a 16 bit executable. -! -load_sect: - add cx,[bootpart] - adc dx,[bootpart+2] -moresect: - cmp al,#0 - jnz onesect - clc - ret - -! Load one sector... -onesect: - push ax ! Save lots - push di - push si - push cx ! Drive and sector. - push dx - - push es ! Load location - push bx - - push cx ! Drive and sector again. - push dx - - ! Fetch drive 'shape' - mov ah,#8 - mov dl,dh - int $13 ! DX:CX = drive specification - jc _nogood - - and cx,#$3F ! Get sector count => DI - mov di,cx - - xor dl,dl ! Get head count => SI - xchg dl,dh - inc dx - mov si,dx - - pop dx ! Get back drive and sector - pop ax - - mov bl,dh ! Save drive - xor dh,dh - - div di ! DX=sector, AX=track number - mov cx,dx - inc cl ! CL=sector number - - xor dx,dx - div si ! DX=head, AX=cylinder - - mov dh,dl - mov dl,bl ! DX for int 1302 - - xchg al,ah - ror al,#1 - ror al,#1 - or cx,ax ! CX for int 1302 - - pop bx ! ES:BX for int 1302 - pop es - - mov di,#5 ! Lots of retries for a hd -retry: - mov ax,#$0201 - int $13 - jnc got_hd_sect - - xor ax,ax ! Reset between each try. - int $13 - - dec di - jnz retry - br _nogood - -got_hd_sect: - pop dx - pop cx - pop si - pop di - pop ax - - dec al - add cx,#1 - adc dh,#0 - add bh,#2 - jmp moresect -#endasm -#endif - -/****************************************************************************/ -/* This is the end of the parts that MUST be in the first sector */ -/* From here down the functions can safely be in any order. */ -/****************************************************************************/ - -/* /* */ -/****************************************************************************/ -/* Section fd_block */ -/****************************************************************************/ -#ifndef HARDDISK -static -load_block(address, blkno) -unsigned address, blkno; -{ - register sect_nr sectno; - if(blkno == 0) { zero_block(address); return; } -#ifdef DOTS - prt_dot(); -#endif - - sectno = (sect_nr)blkno * 2; - load_sect(address, sectno); - load_sect(address+32, sectno+1); -} -#endif - -/****************************************************************************/ -/* Section fd_bpb */ -/****************************************************************************/ -#ifndef HARDDISK -#asm -_set_bpb: -#ifdef MIN_SPACE -bios_tabl=temp_space ! Temp space. -bios_disk=temp_space+4 ! -#else -bios_tabl=dosfs_stat ! Temp space. -bios_disk=dosfs_stat+4 ! -#endif - -#ifndef __CALLER_SAVES__ - push si - push di -#endif - - mov di,#bios_disk - mov bx,#0x78 -! 0:bx is parameter table address - - push ds - push di - - mov si,[bx] - mov ax,[bx+2] - mov [bios_tabl],si - mov [bios_tabl+2],ax - push ax - - pop ds -! ds:si is source - -! copy 12 bytes - mov cl,#6 - cld - rep - movsw - - pop di - pop ds - mov ax,[_n_sectors] - movb 4[di],al ! patch sector count - - mov [bx],di - mov 2[bx],es - -#ifndef __CALLER_SAVES__ - pop si - pop di -#endif - ret - -_unset_bpb: -! 0:0x78 is parameter table address - - mov ax,[bios_tabl] - mov [0x78],ax - mov ax,[bios_tabl+2] - mov [0x78+2],ax - ret - -#endasm -#endif - -/****************************************************************************/ -/* Section fd_get_now */ -/****************************************************************************/ -#ifndef HARDDISK -static -get_now() -{ -#asm - mov si,#5 -retry_get: - xor dx,dx - mov cx,[_firstsect] - shr ch,#1 - adc dh,#0 - mov es,[_loadaddr] - xor bx,bx - mov ax,[_loadcount] - test ax,ax - jz no_load - mov ah,#2 - int $13 ! Try fetch - jnc no_load - xor ax,ax ! Bad, retry. - int $13 - dec si - jnz retry_get - br _nogood -no_load: - xor ax,ax - mov [_loadcount],ax -#endasm -} -#endif - -/****************************************************************************/ -/* Section fd_probe */ -/****************************************************************************/ -#ifndef HARDDISK -#ifdef TRY_FLOPPY -#asm -!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -! -! These are the number of sectors per track that will be scanned for. -! For 3.5 inch floppies 36 is 2.88 Mb, 18 is 1.44Mb, 21 is 1.68Mb on -! a 1.44Mb floppy drive. 15 and 9 are for 5.25 inch floppies. - -disksizes: .byte 36,21,18,15,9 - -! It seems that there is no BIOS call to get the number of sectors. Guess -! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read, -! 15 if sector 15 can be read. Otherwise guess 9. - -_probe_sectors: - mov si,#disksizes ! table of sizes to try - -probe_loop: - lodsb - cbw ! extend to word - mov _n_sectors, ax - cmp al,#9 - je got_sectors ! if all else fails, try 9 - xchg ax, cx ! cx = track and sector - xor dx, dx ! drive 0, head 0 - mov bx,#probe_buf ! address after setup (es = cs) - mov ax,#0x0201 ! service 2, 1 sector - int 0x13 - jc probe_loop ! try next value -got_sectors: - - ret -#endasm -#else -probe_sectors() -{ - /* Guess the number of sectors based on the size of the file system */ - if( (n_sectors = b_super.s_nzones / 40) > 11 ) n_sectors /= 2; -} -#endif -#endif - -/****************************************************************************/ -/* Section fd_sect */ -/****************************************************************************/ -#ifndef HARDDISK -static -load_sect(address, sectno) -unsigned address; -sect_nr sectno; -{ - register sect_nr nsect; - - nsect = sectno%n_sectors +1; - sectno /= n_sectors; - nsect |= (sectno<<8); - - if( loadcount ) - { - lastsect++; - if( ( address & 4095 ) && nsect == lastsect ) - { - loadcount++; - return; - } - get_now(); - } - - lastsect = firstsect = nsect; - loadaddr = address; - loadcount = 1; -} -#endif - -/****************************************************************************/ -/* Section fd_zeroblk */ -/****************************************************************************/ -#ifndef HARDDISK -static -zero_block(address) -{ -#asm -#if __FIRST_ARG_IN_AX__ - mov es,ax -#else - mov bx,sp - mov es,[bx+2] -#endif - push di - mov cx,#512 - xor ax,ax - mov di,ax - rep - stosw - pop di -#endasm -} -#endif - -/****************************************************************************/ -/* Section hd_block */ -/****************************************************************************/ -#ifdef HARDDISK -/*----------------------------------*/ -/* Hard disk block driver */ -/*----------------------------------*/ - -#asm -_load_block: - push bp - mov bp,sp -#if __FIRST_ARG_IN_AX__ - ! Fetch load location - mov es,ax - - ! Test for block zero - mov ax,4[bp] -#else - ! Fetch load location - mov ax,[bp+4] - mov es,ax - - ! Test for block zero - mov ax,6[bp] -#endif - test ax,ax - jne real_block - - ! Iff block zero, zap memory - push di - mov cx,#512 - xor ax,ax - mov di,ax - rep - stosw - pop di - -func_exit: - mov sp,bp - pop bp - ret - -real_block: -#ifdef DOTS - push ax - call _prt_dot - pop ax -#endif - -! Load a real block. - mov cx,ax - xor dx,dx - shl cx,#1 - rcl dx,#1 - - xor bx,bx - mov al,#2 - call load_sect - - j func_exit -#endasm -#endif - -/****************************************************************************/ -/* Section main */ -/****************************************************************************/ -#asm -code: - call _loadprog - call _runprog - br _nogood - -#endasm - -/****************************************************************************/ -/* Section prt_dots */ -/****************************************************************************/ -#ifdef DOTS -#asm -_prt_crlf: - mov al,#13 - call outch - mov al,#10 - j outch -_prt_dot: - mov al,#'. -outch: - mov ah,#$0E - mov bx,#7 - int $10 - ret -#endasm -#endif - -/****************************************************************************/ -/* Section end_1 */ -/****************************************************************************/ -#if defined(HARDDISK) || !defined(MIN_SPACE) -#asm -end_of_part1: -#ifdef HARDDISK - if *>start+0x1FE ! Leave space for magic -#else - if *>start+0x200 -#endif - fail! Part 1 too large! - endif - .blkb 0x200+start-* -#endasm -#endif - -/****************************************************************************/ -/* Section prog_load */ -/****************************************************************************/ - -loadprog() -{ -#ifdef DOTS - prt_dot(); -#endif - if( b_super.s_magic == SUPER_MAGIC2 ) - dir_32 = 1; - else if( b_super.s_magic == SUPER_MAGIC ) - dir_32 = 0; - else - nogood(); - -#ifdef zone_shift - if( zone_shift != b_super.s_log_zone_size) nogood(); -#else - zone_shift = b_super.s_log_zone_size; -#endif - -#ifndef HARDDISK - probe_sectors(); - - /* if( (n_sectors = b_super.s_nzones / 40) > 11 ) n_sectors /= 2; */ - - set_bpb(); -#endif - -try_again:; - inode--; - load_block(seg_of(b_inode), inode/INODES_PER_BLOCK - + b_super.s_imap_blocks - + b_super.s_zmap_blocks - + 2); - get_now(); - - ldaddr = LOADSEG; /* Load at 64k mark */ - - { - register d_inode * i_ptr; - i_ptr = b_inode + inode%INODES_PER_BLOCK; - next_zone = i_ptr->i_zone; - flength = i_ptr->i_size; - if( (i_ptr->i_mode & I_TYPE) == I_DIRECTORY ) - { - ldaddr = seg_of(directory); -#ifndef MIN_SPACE - dinode = inode+1; /* Remember current directory */ -#endif - inode = 0; /* Mark - we've no _file_ inode yet */ - } - } - - end_zone = next_zone+NR_DZONE_NUM; - load_zone(seg_of(b_zone), (indirect = next_zone[NR_DZONE_NUM])); - get_now(); - - for(;;) - { - if( next_zone >= end_zone ) - { - if( indirect != 0 ) - { - next_zone = b_zone; - end_zone = next_zone + NR_INDIRECTS; - indirect = 0; - continue; - } - break; - } - load_zone(ldaddr, *next_zone); - next_zone++; - ldaddr += (seg_at(1) << zone_shift); - } - get_now(); - -#ifdef DOTS - prt_crlf(); -#endif - if(!inode) - { - dirptr = directory; - while(flength > 0) - { -register char * s = bootfile; -register char * p = dirptr->d_name; - - if( dirptr->d_inum ) - { - for(;;) - { - if( *s == '\0') - { - if(*p == '\0') - { - inode = dirptr->d_inum; - goto try_again; - } - break; - } - if( *s++ != *p++ ) break; - } - } - flength -= 16; - dirptr++; - if( dir_32 ) - { - flength -= 16; - dirptr++; - } - } - nogood(); - } -#ifndef HARDDISK - unset_bpb(); -#endif -} - -/****************************************************************************/ -/* Section prog_run */ -/****************************************************************************/ -static -runprog() -{ -/* It all worked, run the loaded executable */ -#asm -#ifdef HARDDISK - mov dx,[bootpart+2] - xchg dh,dl ! DX => hard drive - push [bootpart] ! CX => partition offset - xor si,si -#else - xor dx,dx ! DX=0 => floppy drive - push dx ! CX=0 => partition offset = 0 - mov si,[_n_sectors] ! Save for monitor.out -#endif - - mov bx,#LOADSEG - mov ds,bx ! DS = loadaddress - xor di,di ! Zero - mov ax,[di] - cmp ax,#0x0301 ! Right magic ? - jnz binfile ! Yuk ... assume .SYS - inc bx - inc bx ! bx = initial CS - mov ax,[di+2] - and ax,#$20 ! Is it split I/D ? - jz impure ! No ... - mov cl,#4 - mov ax,[di+8] - shr ax,cl -impure: - pop cx - add ax,bx - mov ss,ax - mov sp,[di+24] ! Chmem value - mov ds,ax -binfile: - - push bx - push di ! jmpi 0,#LOADSEG+2 - retf -#endasm -} - -/****************************************************************************/ -/* Section sys_libs */ -/****************************************************************************/ -#asm -! These functions are pulled from the C library. -libstuff: -imodu: - xor dx,dx - div bx - mov ax,dx ! instruction queue full so xchg slower - ret -idiv_u: - xor dx,dx - div bx - ret -#ifndef zone_shift -isl: -islu: - mov cl,bl - shl ax,cl - ret -#endif -libend: -#endasm - -/****************************************************************************/ -/* Section sys_vars */ -/****************************************************************************/ -#asm -#ifdef MIN_SPACE - block temp_space+64 -#endif -vars: -#ifndef HARDDISK -_n_sectors: .blkw 1 -#endif -_next_zone: .blkw 1 -_end_zone: .blkw 1 -_indirect: .blkw 1 -_ldaddr: .blkw 1 -_dirptr: .blkw 1 -_flength: .blkw 1 -_dir_32: .blkw 1 -varend: -#ifdef MIN_SPACE - endb -#endif -#endasm - -/****************************************************************************/ -/* Section end_2 */ -/****************************************************************************/ -#asm -end_of_prog: - if *>start+0x400 - fail! Part 2 too large! - endif - - if end_of_prog + +#define BOOTADDR 0x7C00 +#define LOADSEG 0x1000 + +// Must match ELKS +#define ELKS_INITSEG (0x0100) +#define ELKS_SYSSEG (0x1000) + + .code16 + + .text + +// Boot block is the first one in the MINIX filesystem +// First part of the boot block (1K) is the boot sector (512 B) +// Loaded by the BIOS at address 0x7C00 (32K - 1K) + +sector_1: + + // Get the memory size + + int $0x12 // in KB + mov $6,%cl // to paragraphs + shl %cl,%ax + + // Move to the latest rounded 64K + // To avoid unaligned buffer for BIOS INT 13h + + sub $0x1000,%ax + and $0xF000,%ax + mov %ax,%es + + xor %ax,%ax + mov %ax,%ds + mov $BOOTADDR,%si + xor %di,%di + mov $256,%cx // 256 words = 512 B + cld + rep + movsw + + // Rebase CS DS ES SS to work in the 64K segment + + mov %es,%ax + mov %ax,%ds + mov %ax,%ss // automatic CLI for next instruction + xor %sp,%sp + + push %ax + mov $_next1,%ax + push %ax + retf + +_next1: + + mov $msg_head,%bx + call _puts + + // Load the second sector of the boot block + + mov $0x0201,%ax // read 1 sector + mov $sector_2,%bx // destination + mov $2,%cx // track 0 - from sector 2 (base 1) + xor %dx,%dx // drive 0 - head 0 + int $0x13 // BIOS disk services + jnc _next2 + + mov $msg_load,%bx + call _puts + +// void reboot () + + .global reboot + +reboot: + + mov $msg_reboot,%bx + call _puts + xor %ax,%ax // wait for key + int $0x16 + int $0x19 + jmp reboot + +_next2: + + .extern main + + /* + // Not necessary as fixed format + err = drive_get (0); + if (err) { + puts ("drive_get:"); + word_hex (err); + puts ("\r\n"); + break; + } + */ + + + call main + jmp reboot + +//------------------------------------------------------------------------------ + +msg_head: + .asciz "\r\nMINIX boot\r\n" + +msg_load: + .asciz "Sector 2!\r\n" + +msg_reboot: + .asciz "Press key\r\n\r\n" + +//------------------------------------------------------------------------------ + +_putc: + + mov $7,%bx // page 0 - color 7 + mov $0xE,%ah // teletype write + int $0x10 // BIOS video services + ret + +_puts: + + mov (%bx),%al + or %al,%al + jz puts_exit + mov %bx,%dx + call _putc + mov %dx,%bx + inc %bx + jmp _puts + +puts_exit: + ret + +// void puts (const char * s) + + .global puts + +puts: + + mov %sp,%bx + mov 2(%bx),%bx + call _puts + ret + +//------------------------------------------------------------------------------ + +/* +hex_tab: + .asciz "0123456789ABCDEF" + +_quad_hex: + + and $0x0F,%al + xor %bh,%bh + mov %al,%bl + mov hex_tab(%bx),%al + call _putc + ret + +_byte_hex: + + mov %al,%dl + + mov $4,%cl + shr %cl,%al + call _quad_hex + + mov %dl,%al + call _quad_hex + + ret + +_word_hex: + + push %ax + mov %ah,%al + call _byte_hex + pop %ax + call _byte_hex + ret + +// void word_hex (word_t w) + + .global word_hex + +word_hex: + + mov %sp,%bx + mov 2(%bx),%ax + call _word_hex + ret +*/ + +//------------------------------------------------------------------------------ + +// int seg_data () + + .global seg_data + +seg_data: + + mov %ds,%ax + ret + +//------------------------------------------------------------------------------ + +// int drive_reset (int drive) +/* + .global drive_reset + +drive_reset: + mov %sp,%bx + mov 2(%bx),%dx // DL = drive (0 based) + xor %ah,%ah + int $0x13 + mov %ah,%al // AH = status + xor %ah,%ah + ret +*/ + +//------------------------------------------------------------------------------ + +// Disk geometry (CHS) + + .global sect_max + .global head_max + .global track_max + +// #undef CONFIG_IMG_FD1680 +// #undef CONFIG_IMG_FD1200 +// #undef CONFIG_IMG_FD720 +// #undef CONFIG_IMG_FD360 + +sect_max: +#ifdef CONFIG_IMG_FD1440 + .word 18 +#endif + +head_max: +#ifdef CONFIG_IMG_FD1440 + .word 2 +#endif + +track_max: +#ifdef CONFIG_IMG_FD1440 + .word 80 +#endif + +//------------------------------------------------------------------------------ + +// int drive_get (int drive) +/* + .global drive_get + +drive_get: + + mov %sp,%bx + mov 2(%bx),%dx // DL = drive ( base 0) + + push %es + push %si + + mov $8,%ah + int $0x13 + + pop %si + pop %es + + jc dg_error + + mov %ch,%al // maximum track (base 0) + mov $0,%ah + inc %al + mov %ax,track_max + + mov %cl,%al // maximum sector (base 1) + and $0x3F,%al + mov %ax,sect_max + + mov %dh,%al // maximum head (base 0) + inc %al + mov %ax,head_max + + xor %ax,%ax + jmp dg_exit + +dg_error: + + mov %ah,%al + mov $0,%ah + +dg_exit: + + ret +*/ + +//------------------------------------------------------------------------------ + +// int disk_read (int drive, int sect, int count, byte_t * buf, int seg) + + .global disk_read + +disk_read: + + push %bp + mov %sp,%bp + sub $8,%sp + +// -2(%bp) = relative sector +// -4(%bp) = relative head +// -6(%bp) = relative track +// -8(%bp) = relative count + + // Compute the CHS from absolute sector + + mov 6(%bp),%ax // absolute sector + xor %dx,%dx + divw sect_max + mov %dx,-2(%bp) + xor %dx,%dx + divw head_max + mov %dx,-4(%bp) + mov %ax,-6(%bp) + + // Read loop + +dr_loop: + + // Compute remaining sectors in current track + + mov -2(%bp),%ax + add 8(%bp),%ax // absolute count + cmp sect_max,%ax + ja dr_over + mov 8(%bp),%ax + jmp dr_next1 + +dr_over: + + mov sect_max,%ax + sub -2(%bp),%ax + +dr_next1: + + mov %ax,-8(%bp) // relative count + + mov 4(%bp),%dl // drive number + mov -4(%bp),%dh // head number + mov -2(%bp),%cl // first sector number + inc %cl // base 1 for sector number + mov -6(%bp),%ch // cylinder number + + push %es + mov 10(%bp),%bx + mov 12(%bp),%es + mov $0x02,%ah // BIOS read disk + int $0x13 + pop %es + + jc dr_error + + // Update absolute count + + mov -8(%bp),%ax + sub %ax,8(%bp) + jz dr_end + + // Move to next head + + movw $0,-2(%bp) + mov -4(%bp),%ax + inc %ax + mov %ax,-4(%bp) + + cmp head_max,%ax + jnz dr_next2 + + // Move to next track + + movw $0,-4(%bp) + mov -6(%bp),%ax + inc %ax + mov %ax,-6(%bp) + +dr_next2: + + // Advance in buffer + + mov -8(%bp),%ax + mov $5,%cl + shl %cl,%ax + add %ax,12(%bp) + + jmp dr_loop + +dr_error: + mov %ah,%al + mov $0,%ah + jmp dr_exit + +dr_end: + xor %ax,%ax + +dr_exit: + + mov %bp,%sp + pop %bp + ret + +//------------------------------------------------------------------------------ + +// int strcmp (const char *s, const char * d) + + .global strcmp + +strcmp: + + mov %sp,%bx + push %di + push %si + + mov 2(%bx),%di + mov 4(%bx),%si + +_sc_loop: + + lodsb + scasb + jne _sc_diff + test %al,%al + jne _sc_loop + xor %ax,%ax + jmp _sc_exit + +_sc_diff: + cmc + sbb %ax,%ax + or $1,%al + +_sc_exit: + pop %si + pop %di + ret + +//------------------------------------------------------------------------------ + +// void run_prog () + + .global run_prog + +run_prog: + +/* +static +run_prog() +{ +// It all worked, run the loaded executable +#asm +#ifdef HARDDISK + mov dx,[bootpart+2] + xchg dh,dl ! DX => hard drive + push [bootpart] ! CX => partition offset + xor si,si +#else + xor dx,dx ! DX=0 => floppy drive + push dx ! CX=0 => partition offset = 0 + mov si,[_n_sectors] ! Save for monitor.out +#endif + + mov bx,#LOADSEG + mov ds,bx ! DS = loadaddress + xor di,di ! Zero + mov ax,[di] + cmp ax,#0x0301 ! Right magic ? + jnz binfile ! Yuk ... assume .SYS + inc bx + inc bx ! bx = initial CS + mov ax,[di+2] + and ax,#$20 ! Is it split I/D ? + jz impure ! No ... + mov cl,#4 + mov ax,[di+8] + shr ax,cl +impure: + pop cx + add ax,bx + mov ss,ax + mov sp,[di+24] ! Chmem value + mov ds,ax +binfile: + + push bx + push di ! jmpi 0,#LOADSEG+2 + retf +#endasm +} +*/ + + push %ds + mov $LOADSEG,%ax + mov %ax,%ds + + mov 0x01E6,%ax // check for ELKS magic number + cmp $0x4C45,%ax + jnz not_elks + mov 0x01E8,%ax + cmp $0x534B,%ax + jz boot_it + +not_elks: + + pop %ds + mov $msg_elks,%bx + call _puts + jmp reboot + +boot_it: + + pop %ds + mov $LOADSEG,%ax + mov %ax,%ds + mov $ELKS_INITSEG,%ax + mov %ax,%es + + mov 497,%bl // fetch number of setup sectors + xor %bh,%bh + inc %bx + mov 500,%ax // fetch system executable size + mov $5,%cl + add $31,%ax + shr %cl,%ax + mov %ax,%dx + +// Put the setup where it belongs + +looping: + call copy_sect + dec %bx + jnz looping + + mov $ELKS_SYSSEG,%ax + mov %ax,%es + +// Put the system code at the right place + +looping2: + call copy_sect + dec %dx + jnz looping2 + +// Ok, everything should be where it belongs call it + + mov $ELKS_INITSEG,%ax + mov %ax,%ds + mov %ax,%es + mov %ax,%ss + mov $0x4000-12,%sp + ljmp $ELKS_INITSEG+0x20,$0 + +copy_sect: + mov $256,%cx + xor %si,%si + xor %di,%di + rep + movsw + + mov %ds,%ax + add $32,%ax + mov %ax,%ds + mov %es,%ax + add $32,%ax + mov %ax,%es + ret + +msg_elks: + .asciz "Not ELKS!\r\n" + +//------------------------------------------------------------------------------ + +// Magic at end of first sector +// to mark it as bootable for BIOS + + .org 0x1FE + .word 0xAA55 + +// Second sector of the boot block + + .org 0x200 + +sector_2: + +//------------------------------------------------------------------------------ diff --git a/elkscmd/bootblocks/minix_second.c b/elkscmd/bootblocks/minix_second.c new file mode 100644 index 000000000..f33c61391 --- /dev/null +++ b/elkscmd/bootblocks/minix_second.c @@ -0,0 +1,242 @@ +//------------------------------------------------------------------------------ +// MINIX Boot Block (first block of the filesystem) +// Sourced from DEV86 bootblocks +// Reworked for ELKS to load directly the kernel without any helper +// Sector 2 : boot loader +//------------------------------------------------------------------------------ + +//#include +#include "minix.h" + +// Global constants + +#define LOADSEG 0x1000 + +// Global variables + +//extern int sect_max; +//extern int head_max; +//extern int track_max; + +static unsigned char dir_32; + +static byte_t sb_block [BLOCK_SIZE]; // super block block buffer +static struct super_block *sb_data; // super block structure + +static int i_now = 0; +static int ib_first; // inode first block +static byte_t i_block [BLOCK_SIZE]; // inode block buffer +static struct inode_s * i_data; // current inode structure + +static byte_t z_block [LEVEL_MAX] [BLOCK_SIZE]; // zone block buffer + +static file_pos f_pos; + +static byte_t d_dir [BLOCK_SIZE]; // latest in program segment + + +//------------------------------------------------------------------------------ + +// Helpers from minix_first + +void reboot (); + +void puts (const char * s); + +void word_hex (const int w); +int seg_data (); + +int drive_reset (const int drive); +//int drive_get (const int drive); +int disk_read (const int drive, + const int sect, const int count, + const byte_t * buf, const int seg); + +int strcmp (const char * s, const char * d); + +void run_prog (); + +//------------------------------------------------------------------------------ + +/* +static void log_err (const char * s) +{ + puts ("ERROR: "); + puts (s); + puts (" !\r\n"); +} +*/ + +//------------------------------------------------------------------------------ + +static int load_super () +{ + int err; + + while (1) { + err = disk_read (0, 2, 2, sb_block, seg_data ()); + //if (err) break; + + sb_data = (struct super_block *) sb_block; + /* + if (sb_data->s_log_zone_size) { + //log_err ("zone size"); + err = -1; + break; + } + */ + + ib_first = 2 + sb_data->s_imap_blocks + sb_data->s_zmap_blocks; + + /* + if (sb_data->s_magic == SUPER_MAGIC) { + dir_32 = 0; + } else if (sb_data->s_magic == SUPER_MAGIC2) { + dir_32 = 1; + } else { + //log_err ("super magic"); + err = -1; + } + */ + + break; + } + + return err; +} + +//------------------------------------------------------------------------------ + +static int load_inode () +{ + int err; + + while (1) { + + // Compute inode block and load if not cached + + int ib = ib_first + i_now / INODES_PER_BLOCK; + err = disk_read (0, ib << 1, 2, i_block, seg_data ()); + //if (err) break; + + // Get inode data + + i_data = (struct inode_s *) i_block + i_now % INODES_PER_BLOCK; + break; + } + + return err; +} + +//------------------------------------------------------------------------------ + +static int load_zone (int level, zone_nr * z_start, zone_nr * z_end) +{ + int err; + + for (zone_nr * z = z_start; z < z_end; z++) { + if (level == 0) { + // FIXME: image can be > 64K + err = disk_read (0, (*z) << 1, 2, i_now ? f_pos : d_dir + f_pos, i_now ? LOADSEG : seg_data ()); + f_pos += BLOCK_SIZE; + if (f_pos >= i_data->i_size) break; + } else { + int next = level - 1; + err = disk_read (0, *z << 1, 2, z_block [next], seg_data ()); + load_zone (next, (zone_nr *) z_block [next], (zone_nr *) (z_block [next] + BLOCK_SIZE)); + } + } + + return err; +} + +//------------------------------------------------------------------------------ + +static int load_file () +{ + int err; + + while (1) { + err = load_inode (); + if (err) break; + + /* + puts ("size="); + word_hex (i_data->i_size); + puts ("\r\n"); + */ + + f_pos = 0; + + while (1) { + + // Direct zones + load_zone (0, &(i_data->i_zone [ZONE_IND_L0]), &(i_data->i_zone [ZONE_IND_L1])); + if (f_pos >= i_data->i_size) break; + + // Indirect zones + load_zone (1, &(i_data->i_zone [ZONE_IND_L1]), &(i_data->i_zone [ZONE_IND_L2])); + if (f_pos >= i_data->i_size) break; + + // Double-indirect zones + //load_zone (2, &(i_data->i_zone [ZONE_IND_L2]), &(i_data->i_zone [ZONE_IND_END])); + + break; + } + + break; + } + + return err; +} + +//------------------------------------------------------------------------------ + +void main () +{ + int err; + + while (1) { + /* + puts ("C="); + word_hex (track_max); + puts (" H="); + word_hex (head_max); + puts (" S="); + word_hex (sect_max); + puts ("\r\n"); + */ + + err = load_super (); + /* + if (err) { + //log_err ("load_super"); + break; + } + */ + + /* + puts ("inodes="); + word_hex (sb_data->s_ninodes); + puts (" zones="); + word_hex (sb_data->s_nzones); + puts ("\r\n"); + */ + + load_file (); + + for (int d = 0; d < i_data->i_size; d += DIRENT_SIZE) { + if (!strcmp (d_dir + 2 + d, "linux")) { + //puts ("Linux found\r\n"); + i_now = (*(int *)(d_dir + d)) - 1; + load_file (); + run_prog (); + break; + } + } + + break; + } +} + +//------------------------------------------------------------------------------ diff --git a/elkscmd/bootblocks/sysboot16.s b/elkscmd/bootblocks/sysboot16.s deleted file mode 100644 index baac80692..000000000 --- a/elkscmd/bootblocks/sysboot16.s +++ /dev/null @@ -1,82 +0,0 @@ - -! The master boot sector will have setup a stack, -! this is normally at 0:7c00 down. -! DS, SS, CS and ES will all have value 0 so the execution address is 0:7c00 -! On entry the register SI will be pointer to the partition entry that -! this sector was loaded from, DL is the drive. - -! Also if it's a standard Master boot DH will be the head, CX will be the -! sector and cylinder, BX=7C00, AX=1, DI=7DFE, BP=SI. There's a reasonable -! chance that this isn't true though. - -! The Master boot itself will have been loaded and run at $07c00 -! The BIOS must have setup a stack because interrupts are enabled -! Little else can be assumed because DOS doesn`t assume anything either - -sysboot_start: -j codestart -nop ! DOS appears to _require_ this to identify an MSDOS disk!! - -.blkb sysboot_start+3-* -public dosfs_stat -dos_sysid: .ascii "LINUX" ! System ID - .byte 0,0,0 -dosfs_stat: -dos_sect: .blkw 1 ! Sector size -dos_clust: .blkb 1 ! Cluster size -dos_resv: .blkw 1 ! Res-sector -dos_nfat: .blkb 1 ! FAT count -dos_nroot: .blkw 1 ! Root dir entries -dos_maxsect: .blkw 1 ! Sector count (=0 if large FS) -dos_media: .blkb 1 ! Media code -dos_fatlen: .blkw 1 ! FAT length -dos_spt: .blkw 1 ! Sect/Track -dos_heads: .blkw 1 ! Heads -dos_hidden: .blkw 2 ! Hidden sectors - -! Here down is DOS 4+ and probably not needed for floppy boots. - -dos4_maxsect: .blkw 2 ! Large FS sector count -dos4_phy_drive: .blkb 1 ! Phys drive -.blkb 1 ! Reserved -.blkb 1 ! DOS 4 - -floppy_temp: -dos4_serial: .blkw 2 ! Serial number -dos4_label: .blkb 11 ! Disk Label (DOS 4+) -dos4_fattype: .blkb 8 ! FAT type - -! -! This is where the code will be overlaid, the default is a hang -.blkb sysboot_start+0x3E-* -public codestart -codestart: - j codestart - -! Partition table -public bootblock_magic - -.blkb sysboot_start+0x1BE-* -partition_1: -.blkb 8 ! IN,SH,SS,ST,OS,EH,ES,ET -.blkw 2 ! Linear position (0 based) -.blkw 2 ! Linear length -.blkb sysboot_start+0x1CE-* -partition_2: -.blkb 8 ! IN,SH,SS,ST,OS,EH,ES,ET -.blkw 2 ! Linear position (0 based) -.blkw 2 ! Linear length -.blkb sysboot_start+0x1DE-* -partition_3: -.blkb 8 ! IN,SH,SS,ST,OS,EH,ES,ET -.blkw 2 ! Linear position (0 based) -.blkw 2 ! Linear length -.blkb sysboot_start+0x1EE-* -partition_4: -.blkb 8 ! IN,SH,SS,ST,OS,EH,ES,ET -.blkw 2 ! Linear position (0 based) -.blkw 2 ! Linear length - -.blkb sysboot_start+0x1FE-* -bootblock_magic: -.word 0xAA55 diff --git a/elkscmd/rootfs_template/boot/.keep b/elkscmd/rootfs_template/boot/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/image/Make.defs b/image/Make.defs index d7925ce86..22d77081a 100644 --- a/image/Make.defs +++ b/image/Make.defs @@ -13,7 +13,6 @@ ELKSCMD_DIR = $(TOPDIR)/elkscmd MINIX_BOOT = $(ELKSCMD_DIR)/bootblocks FD_BSECT = $(MINIX_BOOT)/minix.bin -KHELPER = $(MINIX_BOOT)/minix_elks.bin # Image file options diff --git a/image/Makefile b/image/Makefile index 7d12248af..3264786a6 100644 --- a/image/Makefile +++ b/image/Makefile @@ -6,7 +6,7 @@ include Make.rules # All target ifdef CONFIG_IMG_BOOT -all: $(FD_BSECT) $(KHELPER) $(ELKS_DIR)/arch/i86/boot/Image +all: $(FD_BSECT) $(ELKS_DIR)/arch/i86/boot/Image else all: endif @@ -32,9 +32,7 @@ endif $(MAKE) -C $(ELKSCMD_DIR) install sudo bash -c "$(ELKSCMD_DIR)/tools/ver.pl $(ELKS_DIR)/Makefile-rules > $(TARGET_MNT)/etc/issue" ifdef CONFIG_IMG_BOOT - sudo mkdir -p $(TARGET_MNT)/boot - sudo install $(ELKS_DIR)/arch/i86/boot/Image $(TARGET_MNT)/boot/linux - sudo install $(KHELPER) $(TARGET_MNT)/boot/boot + sudo install $(ELKS_DIR)/arch/i86/boot/Image $(TARGET_MNT)/linux endif ifdef CONFIG_IMG_DEV sudo umount -d $(TARGET_FILE) From 1f225918c3a075d66f7ed536ba6d9f4c7327048c Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Mon, 4 Mar 2019 08:20:03 +0100 Subject: [PATCH 11/20] [config] Remove compiler option --- .gitignore | 2 -- config-emu86 | 8 -------- config.in | 10 ---------- elks/arch/i86/defconfig | 7 ------- tools/Makefile | 8 +++----- 5 files changed, 3 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index 73d5c6509..68c878d18 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ *.a *.1.gz Kbuild -dev86 cross # @@ -33,7 +32,6 @@ target *.orig *.rej /*.patch -elks_todo # # Debugging stuff diff --git a/config-emu86 b/config-emu86 index ff47e91e5..e30e183dd 100644 --- a/config-emu86 +++ b/config-emu86 @@ -2,14 +2,6 @@ # Automatically generated make config: don't edit # -# -# Cross build chain -# - -# CONFIG_COMPILER_1 is not set -CONFIG_COMPILER_2=y -# CONFIG_COMPILER_3 is not set - # # Kernel & Hardware # diff --git a/config.in b/config.in index cc12763b3..571690dcc 100644 --- a/config.in +++ b/config.in @@ -4,16 +4,6 @@ mainmenu_name "ELKS Main" -mainmenu_option next_comment - comment 'Cross build chain' - - choice 'Cross compiler' \ - "bcc CONFIG_COMPILER_1 \ - gcc-ia16 CONFIG_COMPILER_2 \ - gcc-elks CONFIG_COMPILER_3" bcc - -endmenu - # # ELKS Kernel # diff --git a/elks/arch/i86/defconfig b/elks/arch/i86/defconfig index 4ecb86f11..434260420 100644 --- a/elks/arch/i86/defconfig +++ b/elks/arch/i86/defconfig @@ -2,13 +2,6 @@ # Automatically generated make config: don't edit # -# -# Cross build chain -# -CONFIG_COMPILER_1=y -# CONFIG_COMPILER_2 is not set -# CONFIG_COMPILER_3 is not set - # # Kernel & Hardware # diff --git a/tools/Makefile b/tools/Makefile index dcfed6d0a..93e910424 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -13,6 +13,8 @@ all:: # SRCDIR, DISTDIR, BUILDDIR and CROSSDIR must be set in environment # DEV86 (including BIN86, BCC and C library) +# Only sources now as not used any more for ELKS build +# but still for test with EMU86 DEV86_VER=dfb9b428df88dd3c2256f978351fa9959caf5c07 DEV86_DIST=dev86-$(DEV86_VER) @@ -27,11 +29,7 @@ $(DISTDIR)/$(DEV86_DIST).zip: mv $(DEV86_DIST) dev86 touch .dev86.src -.dev86.build: .dev86.src - cd dev86 && make PREFIX=$(CROSSDIR) install - touch .dev86.build - -all:: .dev86.build +all:: .dev86.src # BINUTILS for IA16 From 7ea329d283624258cb35eab0f423c65f52838690 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Mon, 4 Mar 2019 21:04:38 +0100 Subject: [PATCH 12/20] Cleanup of remaining DEV86 stuff Issue #225 --- Documentation/historic/README | 94 --------------- Documentation/historic/RELNOTES | 8 -- .../html/user/writing_apps_in_C.html | 17 +-- Documentation/text/compile-on-winnt.txt | 110 ------------------ Documentation/text/debug.txt | 33 ------ elkscmd/build_hd_image.sh | 4 + nano-X/src/build_hd_nano_image.sh | 4 + tools/Makefile | 19 --- 8 files changed, 11 insertions(+), 278 deletions(-) delete mode 100644 Documentation/historic/README delete mode 100755 Documentation/text/compile-on-winnt.txt delete mode 100755 Documentation/text/debug.txt diff --git a/Documentation/historic/README b/Documentation/historic/README deleted file mode 100644 index 44b1321f2..000000000 --- a/Documentation/historic/README +++ /dev/null @@ -1,94 +0,0 @@ -(1) Introduction -(2) Trying out ELKS using the disk images -(3) Compiling your own kernel - - - -(1) Introduction - -Hello, and welcome to the exciting world of Linux-8086, ELKS, or the -Embeddable Linux Kernel Subset! This is a project which will eventually -produce a Linux-like OS for the 8086 (186, 286) as well as for the Psion -series of processors. But, as you have this file, you probably already -know that, so let's get down to business. - - - -(2) Trying out ELKS using the images - -So you want to give ELKS a try, but you don't want all the fuss and bother -of compiling the kernel and the tools yourself. No problem. All you need -to do is grab the images.zip file from the download section of -http://www.elks.ecs.soton.ac.uk/ and save it to its own directory. These -files can be copied to disks and used to boot ELKS. For details of which -files you want and how to use them, please see the INSTALL file included -in this distribution. - - - -(3) Compiling your own kernel - -Compiling your own kernel is a bit more involved, but we'll get through -it. First, you're going to need a few files from the download section of -http://www.elks.ecs.soton.ac.uk/ - - elks-x.x.xx.tar.gz - images.zip - elkscmd-xxxxxxxx.tar.gz - Dev86bin-x.xx.x.tar.gz - -Okay, so you've got the files. Personally, I like to keep them in /ELKS/ -so that's what I'll assume you're doing. So cd to /ELKS and let's get -started. The first thing we need to do is install the development tools. - - cp Dev86bin-x.x.xx.tar.gz / - cd / - tar xvzf Dev86bin-x.x.xx.tar.gz - rm Dev86bin-x.x.xx.tar.gz - -Now you should have the 8086 development tools installed. Next, we need to -cd back to /ELKS/ and untar the ELKS kernel sources. - - cd /ELKS - tar xvzf elks-x.x.xx.tar.gz - cd ./elks - -Now that we're in the source directory, we can start setting up the -kernel. The first thing that needs to be done is - - make config - -You'll be asked a few questions about how you want the kernel set up. For -now, we'll accept the defaults and just keep hitting enter until we get to -the end, then - - make - -You'll see a lot of warnings go by for a few minutes, and then we'll -assume a perfect compile. So we'll now have a diskette image file with our -new kernel on it. We'll assume we built for the 8086. The image is a -little buried, so we'll have to dig into the source tree to find it. - - cd /ELKS/elks/arch/i86/ - ls - -If the compile was successful, you'll have an "Image" file here, and -you'll have to get it onto a diskette. I'll assume "/dev/fd0". - - dd if=Image of=/dev/fd0 bs=8192 - -This will be your boot disk, but you'll need a root disk, too, so - - cd /ELKS/ - unzip images.zip - dd if=root of=/dev/fd0 bs=8192 - -After that, you should be able to use the boot and root disks and watch -ELKS work its Linux-like magic on your machine. Have fun! - ---------------------------------------------------------------------- - -If you have any suggestions for this readme send your comments to -semjaza@mytalk.com or linux-8086@vger.kernel.org - ---Phillip J Rhoades diff --git a/Documentation/historic/RELNOTES b/Documentation/historic/RELNOTES index 9d91efce0..6ba5a3947 100644 --- a/Documentation/historic/RELNOTES +++ b/Documentation/historic/RELNOTES @@ -473,7 +473,6 @@ VERSION 0.0.66 NOTES * Added code to doshd_release() so that floppy changes don't cause corruption from old buffers. * Small change to stack_check() %d changed to %ld for t_endbrk. - * Implemented Rob. de Bath changes for Dev86v13. * Added a simple ramdisk driver which can access up to 8 64K ramdisks. See Documentation/ramdisk.txt. * Re-organised the way the debugging macros work, so they now have @@ -781,13 +780,6 @@ VERSION 0.0.53(.1) NOTES again. (I suspect the bug predates bug reports though). Instead of going to the next track/head it was going back one sector, which was bad. - * If you don't know already, this release is meant to install - over/into Dev86 0.0.11, so if you haven't gotten it already *get - it now!!!* To get everything working you have to unpack Dev86, - then unpack elks, build the (slightly-modified) Dev86, and then - build the kernel with it. This is done so that you don't have to - manually change dev86, and it dosen't really change anything - except the libc/syscall directory and the rules.86 file. * minish unpacks into the tests/ directory, along with a new makefile. * Optimization is turned off, since there appears to be something diff --git a/Documentation/html/user/writing_apps_in_C.html b/Documentation/html/user/writing_apps_in_C.html index dec4b0b82..34c3513fa 100644 --- a/Documentation/html/user/writing_apps_in_C.html +++ b/Documentation/html/user/writing_apps_in_C.html @@ -31,20 +31,9 @@

Writing applications for ELKS in C

-

ELKS - and application programs for ELKS are cross-compiled on a standard - Linux system with the dev86 package. This contains the bcc C - compiler, the ld86 linker, the as86 assembler and the ar86 - archiver. You can download the dev86 package from the repository - of your Linux distribution or download it here: - https://github.com/jbruchon/dev86 - and compile and install it from this source code.

-

The - package also includes the elksemu program which allows 8086 ELKS - programs to be run under Linux-i386. These programs can be - compiled using the bcc compiler. However, elksemu will not run on - 64bit Linux distributions. Therefore test the programs using Qemu - instead as described in the next chapter.

+

ELKS and application programs for ELKS are cross-compiled on + a standard Linux system with GCC-IA16.

+

Test the programs using Qemu as described in the next chapter.

For a start let's compile a „hello world“ program and run that in ELKS. Here is the code:

diff --git a/Documentation/text/compile-on-winnt.txt b/Documentation/text/compile-on-winnt.txt deleted file mode 100755 index b066ba537..000000000 --- a/Documentation/text/compile-on-winnt.txt +++ /dev/null @@ -1,110 +0,0 @@ -Date: Thu, 28 May 1998 13:57:06 +0100 -From: Paul Roberts -To: linux-8086 -Subject: Compiling ELKS on NT - -This briefly describes the steps I have taken to compile ELKS on NT 4.0: - -1) Download and install gnuwin32 beta 19. - (from www.cygnus.com) - -2) Change the mount points in the registry to binary. - Use regedit to edit the keys under - "HKEY_CURRENT_USER\Software\Cygnus Solutions\CYGWIN.DLL - setup\b15.0\mounts\". - Under each key there is a variable fBinary which needs - changing from 0 to 1 this makes the cygnus c-librarys - handle files in binary mode by default. If you don't - do this you get spurious CR\LF conversion happening. - -3) Find an editor that will edit unix files without - converting them to a dos file. - -4) Download and extract Dev86src-0.14.3.tar.gz (I have - \gnuwin32\b19\H-i386-cygwin32\ mounted as /usr and - extract every thing to /usr/src). - -5) Hack makefile.in: - a) Change the definitions of INDAT INEXE INSCR to remove - flags for owner and group; - b) Remove elksemu from the target all; - c) Remove install-emu from the target install. - -6) Hack linux-86/man/Makefile: - Remove "-o xxxx -g xxxxx" from install lines. - -7) Edit some of the libc makefiles to change refs from "sh" to "bash" - - a) linux-86\libc\gnu_i386\Makefile(30): from "sh mksyscall" to "bash - mksyscall" - b) linux-86\libc\i386sys\Makefile(27): from "sh mksyscall" to "bash - mksyscall" - c) linux-86\libc\syscall\Makefile(33): from "sh mksyscall" to "bash - mksyscall" - -8) Edit linux-86\ld\objdump.c: - change line 19 from "FILE * ifd = stdin;" to "FILE * ifd;" - insert line 67 "ifd = stdin;" - -9) cd /usr/src/linux-86 - -10) make install - -Assuming that Dev86 all compiled, linked, installed, etc. correctly: - -11) Download and extract elks-0.0.71.tar.gz - -12) cd /usr/src/elks - -13) Unfortunately make config doesn't work with cygwin32 bash so - cp arch/i86/defconfig .config - -14) make dep - -15) make - -NOTE: There are 4 .S files that are preprocessed into .s files when the -kernel is built; unfortunately Windows thinks these are the same files so if -you "make clean" these get deleted. These aren't files that I've changed so -I just extract them from the archive each time I make clean. - -to run ELKS in an NT VM - -1) cd /usr/src/elks - -2) make clean - -3) Edit elks/include/linuxmt/config.h: - change these defines: - #define DEF_INITSEG 0x0100 - #define DEF_SETUPSEG 0x0120 - to: - #define DEF_INITSEG 0x9000 - #define DEF_SETUPSEG 0x9020 - -4) Extract the following files from the archive: - arch/i86/boot/bootsect.S - arch/i86/boot/setup.S - arch/i86/lib/setupb.S - arch/i86/lib/setupw.S - -5) make - -6) Write a program that loads elks/arch/i86/tools/system - to DEF_SYSSEG, then does all that - elks/arch/boot/setup.S does. Compile that using bcc as - a .com file (-Md) - -I've done step 5 and it works and boots the kernel and reads a root disk and -seems fine, although NT complains when it probes the Hard Disk during -initialization. -I'll release the sources as soon as they are vaguely tidy :) - -I don't know if any of this works on 95 although I guess it should. - -Things TODO! - * Write some tools for creating/editing root disks from NT (I'm kindof - working on this); - * Write an NT VDD to fake direct hard disk access for a VM (I've read - the docs on how to do this and it looks possible (it should be possible - for the VM to use an image file as a virtual hard disk)). diff --git a/Documentation/text/debug.txt b/Documentation/text/debug.txt deleted file mode 100755 index 22b16c15b..000000000 --- a/Documentation/text/debug.txt +++ /dev/null @@ -1,33 +0,0 @@ - Chad Page - 3/2/97 - -Here's a little document about how to build and debug the ELKS kernel... it's -probably going to be missing things for quite a while :) - -part 1: Setting up the build environment ----------------------------------------- - - First, you should have the source tar for Dev86-0.14.5 or later. -Once you have both Dev86 and the latest ELKS sources, you're ready to start. - - You should untar Dev86, and the ELKS files (use -tar -xvzf _filename_ to unpack the tarfiles). - - Then, build the Dev86 libraries (all the defaults are fine), and -after you install it, go into the elks directory and enter 'make'. If -all goes well, you will have your first ELKS kernel, configured identically -to the one provided as the bootdisk. - -part 2: Configuring your new ELKS kernel ----------------------------------------- - - Usually, all you have to change is $/include/linuxmt/config.h to set -the rootdisk device. For our purposes, set the rootdisk to 0x3c0 so you can -use the second floppy drive as the root device (this makes it fast). Then -rebuild the kernel. - -part 3: MAKE (and run) ELKS FAST! - (or, better hacking through dosemu) ------------------------------------ - - dosemu is extremely useful for shortening the edit/build/run cycle. diff --git a/elkscmd/build_hd_image.sh b/elkscmd/build_hd_image.sh index 7a7da1a3f..3e7498c2c 100755 --- a/elkscmd/build_hd_image.sh +++ b/elkscmd/build_hd_image.sh @@ -1,5 +1,9 @@ #!/bin/bash +# BROKEN SCRIPT +# DEV86 is no more linked to this project +# See issue jbruchon/elks#199 + # This script generates a bootable hard disk image for Qemu. It copies # the files from the fd1440 floppy image to this hard disk image and the # bootblocks and mbr from dev86 to the hard disk image. diff --git a/nano-X/src/build_hd_nano_image.sh b/nano-X/src/build_hd_nano_image.sh index 5fdc78858..33f73e19b 100755 --- a/nano-X/src/build_hd_nano_image.sh +++ b/nano-X/src/build_hd_nano_image.sh @@ -1,5 +1,9 @@ #!/bin/bash +# BROKEN SCRIPT +# DEV86 is no more linked to this project +# See issue jbruchon/elks#199 + # This script generates a bootable hard disk image for Qemu. It copies # the files from the full3 floppy image to this hard disk image and the # bootblocks and mbr from dev86 to the hard disk image. diff --git a/tools/Makefile b/tools/Makefile index 6770df5a1..15081b98e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -12,25 +12,6 @@ all:: # SRCDIR, DISTDIR, BUILDDIR and CROSSDIR must be set in environment -# DEV86 (including BIN86, BCC and C library) -# Only sources now as not used any more for ELKS build -# but still for test with EMU86 - -DEV86_VER=dfb9b428df88dd3c2256f978351fa9959caf5c07 -DEV86_DIST=dev86-$(DEV86_VER) - -$(DISTDIR)/$(DEV86_DIST).zip: - cd $(DISTDIR) && wget https://github.com/jbruchon/dev86/archive/$(DEV86_VER).zip -O $(DEV86_DIST).zip - -.dev86.src: $(DISTDIR)/$(DEV86_DIST).zip - -rm -rf $(DEV86_DIST) - unzip -q $(DISTDIR)/$(DEV86_DIST).zip - -rm -rf dev86 - mv $(DEV86_DIST) dev86 - touch .dev86.src - -all:: .dev86.src - # BINUTILS for IA16 BINUTILS_VER=184ba458e1ab8e46d09c3dee48790e93141793f2 From 46f929803270fa2cf2351f2e96d0cd19f0799efc Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Thu, 7 Mar 2019 22:07:05 +0100 Subject: [PATCH 13/20] [rom] Fix wrong jump to kernel entry Regression from #231. --- elks/arch/i86/boot/setup.S | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/elks/arch/i86/boot/setup.S b/elks/arch/i86/boot/setup.S index 545d84490..94311397a 100644 --- a/elks/arch/i86/boot/setup.S +++ b/elks/arch/i86/boot/setup.S @@ -361,12 +361,12 @@ no_psmouse: cmpw $KERNEL_MAGICNUMBER,0 jne aouterr - cmpb $0x04,3 //;prozessortype = 8086 + cmpb $0x04,3 // processor type = 8086 jne test1 jmp aout_ok test1: - cmpb $0x10,3 //;prozessortype = 80386 + cmpb $0x10,3 // processor type = 80386 jne aouterr jmp aout_ok @@ -440,21 +440,23 @@ size_ok: */ #if defined(CONFIG_ROMCODE) - mov 0x10,%dx //;bbs size - mov 0x0c,%si //;data size - mov 0x08,%bx //;text size +// BX,CX,DX,SI,DS,ES are expected in kernel crt0.S - mov %es,%cx - mov %cx,%ds + mov 0x10,%dx // bss size + mov 0x0c,%si // data size + mov 0x08,%bx // text size + mov 0x18,%ax // entry point + mov %es,%cx // data segment + mov %cx,%ds #ifdef CONFIG_ROM_DEBUG int $3 // break for debugger just before kernel #endif - mov $SYSSEG+2,%bp - pushw %bp - pushw 0x18 //; entry point - lretw + mov $SYSSEG+2,%di + push %di + push %ax + lret //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Case for kernel in disk to be relocated From e5c6e5fe589b0a2329d463fb80d696b385ef7230 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Fri, 8 Mar 2019 21:57:32 +0100 Subject: [PATCH 14/20] [mkromfs] Fix type mismatch in superblock Issue #225 --- elks/tools/list.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/elks/tools/list.h b/elks/tools/list.h index 5dc71778c..7f93c4518 100644 --- a/elks/tools/list.h +++ b/elks/tools/list.h @@ -5,10 +5,10 @@ #ifndef _LIST_H #define _LIST_H -typedef unsigned char byte_t; +typedef unsigned char byte_t; -typedef unsigned int u16_t; -typedef unsigned long u32_t; +typedef unsigned short u16_t; +typedef unsigned long u32_t; struct list_node_s { From e005026b504fe31ac44141c59300631af23de39d Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Sat, 9 Mar 2019 10:10:35 +0100 Subject: [PATCH 15/20] [libc] Fix test on syscall return value Issue #225 --- libc/system/syscall0.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/system/syscall0.s b/libc/system/syscall0.s index a52104107..03082b578 100644 --- a/libc/system/syscall0.s +++ b/libc/system/syscall0.s @@ -16,7 +16,7 @@ _syscall_0: int $0x80 _syscall_test: - test %ax,%ax + cmp $0,%ax jge _syscall_ok neg %ax mov %ax,errno From 9f188239312782917a31ee70fa0c30e1044fd1cc Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Sat, 9 Mar 2019 23:06:56 +0100 Subject: [PATCH 16/20] [build] More consistent i186 & i286 options Close #237 --- elks/Makefile-rules | 11 +++++------ elkscmd/Make.defs | 6 +----- libc/Makefile.inc | 4 ++-- tools/Makefile | 4 ++-- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/elks/Makefile-rules b/elks/Makefile-rules index 89a6e7548..683305b29 100644 --- a/elks/Makefile-rules +++ b/elks/Makefile-rules @@ -133,7 +133,7 @@ else endif CROSS_CC = ia16-elf-gcc -CROSS_CFLAGS = -fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding +CROSS_CFLAGS = -fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding -melks ######################################################################### # Define architecture-specific flags. @@ -152,7 +152,6 @@ endif ######################################################################### # Define CPU-specific flags. -# Issue #233: different option names for GCC-IA16 and AS-IA16 ifeq ($(MK_CPU), 8086) CPU_AS = -mtune=i8086 @@ -162,13 +161,13 @@ endif ifeq ($(MK_CPU), 80186) CPU_AS = -mtune=i186 - CPU_CC = -mtune=i80186 + CPU_CC = -mtune=i186 CPU_LD = endif ifeq ($(MK_CPU), 80286) CPU_AS = -mtune=i286 - CPU_CC = -mtune=i80286 + CPU_CC = -mtune=i286 CPU_LD = endif @@ -200,8 +199,8 @@ ifneq ($(USEBCC), N) AS = ia16-elf-as ASFLAGS = $(CPU_AS) $(ARCH_AS) -CC = $(CROSS_CC) -Os -CFLAGS = $(CROSS_CFLAGS) $(CPU_CC) $(ARCH_CC) $(CFLBASE) -Wall +CC = $(CROSS_CC) +CFLAGS = $(CROSS_CFLAGS) $(CPU_CC) $(ARCH_CC) $(CFLBASE) -Wall -Os LD = ia16-elf-ld LDFLAGS = $(CPU_LD) -s AR = ia16-elf-ar diff --git a/elkscmd/Make.defs b/elkscmd/Make.defs index 8bf41bdc4..90139572b 100644 --- a/elkscmd/Make.defs +++ b/elkscmd/Make.defs @@ -72,13 +72,9 @@ ELKS_VSN=$(shell printf '%s.%s.%s-pre%s' $(E_V) | sed 's/-pre$$//') # Determine compiler variables for this target. ifeq ($(PLATFORM),i86-ELKS) -# CC=bcc CC=ia16-elf-gcc -# CFLBASE=-0 -O -ansi - CFLBASE=-fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding -mtune=i8086 -Wall -Os -# LD=ld86 + CFLBASE=-fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding -mtune=i8086 -Wall -Os -melks LD=ia16-elf-ld -# LDFLAGS=-s -ansi LDFLAGS= -T $(TOPDIR)/elks/elks-small.ld # TODO: move crt0 to begin of object files LDLIBS='-(' $(TOPDIR)/libc/crt0.o $(TOPDIR)/libc/libc.a '-)' diff --git a/libc/Makefile.inc b/libc/Makefile.inc index 352552910..b242d1ffa 100644 --- a/libc/Makefile.inc +++ b/libc/Makefile.inc @@ -7,14 +7,14 @@ DEFINES=-D__LIBC__ -D__LIBC_VER__='"$(VERSION)"' -D__HAS_NO_FLOATS__ SDEFS=$(DEFINES) CDEFS=$(DEFINES) -ARCH=-mtune=i8086 -fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding +ARCH=-mtune=i8086 -fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding -melks CC=ia16-elf-gcc AS=ia16-elf-as AR=ia16-elf-ar LD=ia16-elf-ld -CFLAGS=$(ARCH) $(INCLUDES) $(CDEFS) -Os -Wall +CFLAGS=$(ARCH) $(INCLUDES) $(CDEFS) -Wall -Os ASFLAGS=-mtune=i8086 LDFLAGS=-mtune=i8086 diff --git a/tools/Makefile b/tools/Makefile index 15081b98e..759060918 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -39,7 +39,7 @@ all:: .binutils.build # GCC for IA16 -GCC_VER=eb57e7ea98ebf30ff455fbde1af4c7279cc030bc +GCC_VER=2aa70f8c292e4e67b980d7468a011206130bfd7d GCC_DIST=gcc-ia16-$(GCC_VER) $(DISTDIR)/$(GCC_DIST).zip: @@ -64,7 +64,7 @@ all:: .gcc.build # EMU86 -EMU86_VER=ff4b425aa86e053ed71ab7222b048b8951243d76 +EMU86_VER=5ea2e76a30c75223c484c3b1bd2f67646e3cfa94 EMU86_DIST=emu86-$(EMU86_VER) $(DISTDIR)/$(EMU86_DIST).zip: From 93b57f474cb0e3fa9917b4783781cd405c944b04 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Tue, 12 Mar 2019 21:29:26 +0100 Subject: [PATCH 17/20] [libc] Data segment starts with nil data Issue #225 --- elks/Makefile-rules | 2 +- elks/elks-small.ld | 2 +- elkscmd/Make.defs | 4 ++-- libc/crt0.S | 10 +++++++--- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/elks/Makefile-rules b/elks/Makefile-rules index 683305b29..e6644d501 100644 --- a/elks/Makefile-rules +++ b/elks/Makefile-rules @@ -57,7 +57,7 @@ include $(TOPDIR)/Make.defs VERSION = 0 # (0-255) PATCHLEVEL = 2 # (0-255) -SUBLEVEL = 0 # (0-255) +SUBLEVEL = 1 # (0-255) #PRE = 1 # (0-255) If not a pre, comment this line. ######################################################################### diff --git a/elks/elks-small.ld b/elks/elks-small.ld index 72899e0db..5b2c937e8 100644 --- a/elks/elks-small.ld +++ b/elks/elks-small.ld @@ -18,7 +18,7 @@ SECTIONS { _begintext = ALIGN(0x20); .text 0 : AT(_begintext) { *(.text*); . = ALIGN(0x10); } _begindata = _begintext + .; - .data 0 : AT(_begindata) { *(.rodata*) *(.data*) } + .data 0 : AT(_begindata) { *(.nildata*) *(.rodata*) *(.data*) } .bss : { *(.bss) *(COMMON) } /DISCARD/ : { *(.comment) } } diff --git a/elkscmd/Make.defs b/elkscmd/Make.defs index 90139572b..5b90ca193 100644 --- a/elkscmd/Make.defs +++ b/elkscmd/Make.defs @@ -75,9 +75,9 @@ ifeq ($(PLATFORM),i86-ELKS) CC=ia16-elf-gcc CFLBASE=-fno-inline -mcmodel=small -mno-segment-relocation-stuff -ffreestanding -mtune=i8086 -Wall -Os -melks LD=ia16-elf-ld - LDFLAGS= -T $(TOPDIR)/elks/elks-small.ld + LDFLAGS=-T $(TOPDIR)/elks/elks-small.ld $(TOPDIR)/libc/crt0.o # TODO: move crt0 to begin of object files - LDLIBS='-(' $(TOPDIR)/libc/crt0.o $(TOPDIR)/libc/libc.a '-)' + LDLIBS='-(' $(TOPDIR)/libc/libc.a '-)' CHECK=gcc -c -o .null.o -Wall -pedantic AS=ia16-elf-as ASFLAGS=-mtune=i8086 diff --git a/libc/crt0.S b/libc/crt0.S index dbcd408c4..cdf91f32c 100644 --- a/libc/crt0.S +++ b/libc/crt0.S @@ -1,4 +1,5 @@ -# C runtime bootstrap +// C runtime bootstrap +// This must be the first module of the executable .code16 @@ -14,8 +15,6 @@ entry: jmp _startup - .global exit - // C runtime startup // Stack is empty and immediately followed by argc, argv and envp @@ -37,6 +36,8 @@ _startup: call exit // no return int $3 + .global exit + exit: push %bp mov %sp,%bp @@ -56,6 +57,9 @@ _exit_end: .extern _cleanup // Zero data for null pointers (near & far) +// Will be linked as first section in data segment + + .section .nildata .word 0 .word 0 From 1e95f4689ca739d794219fd1ebe66352834bd711 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Wed, 13 Mar 2019 17:58:46 +0100 Subject: [PATCH 18/20] No unit tests in default configuration Issue #225 --- elks/arch/i86/defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elks/arch/i86/defconfig b/elks/arch/i86/defconfig index 434260420..336132724 100644 --- a/elks/arch/i86/defconfig +++ b/elks/arch/i86/defconfig @@ -204,7 +204,7 @@ CONFIG_APP_PREMS=y CONFIG_APP_PRN_UTILS=y CONFIG_APP_SYS_UTILS=y CONFIG_APP_SCREEN=y -CONFIG_APP_TEST=y +# CONFIG_APP_TEST is not set CONFIG_APP_XVI=y # From 4d36220db04e6800a3ac7c1295566e729e63a211 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Wed, 13 Mar 2019 18:01:36 +0100 Subject: [PATCH 19/20] [init] Fix array size for shell arguments Issue #225 --- elkscmd/sys_utils/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elkscmd/sys_utils/init.c b/elkscmd/sys_utils/init.c index 6573fa0be..59b4a6422 100644 --- a/elkscmd/sys_utils/init.c +++ b/elkscmd/sys_utils/init.c @@ -257,7 +257,7 @@ void makefork(void) pid_t respawn(const char **a) { int pid; - char *argv[4], buf[128]; + char *argv[5], buf[128]; int fd; char *devtty; From 18a46aac6d45e41b59dccf46229a9d8a408c5cf7 Mon Sep 17 00:00:00 2001 From: mfld-fr Date: Wed, 13 Mar 2019 22:51:58 +0100 Subject: [PATCH 20/20] Fix compiler check in main build.sh --- build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 567dba81d..f56c2b074 100755 --- a/build.sh +++ b/build.sh @@ -34,12 +34,12 @@ clean_exit () { . tools/env.sh # Check tools -if [ ! -x "$CROSSDIR/bin/bcc" ] +if [ ! -x "$CROSSDIR/bin/ia16-elf-gcc" ] then - echo "ERROR: BCC not found. You must build the cross tools" + echo "ERROR: GCC-IA16 not found. You must build the cross tools" echo " before attempting to build ELKS. Run tools/build.sh" echo " to automatically build that cross tools. Aborting." - exit 1 + clean_exit 1 fi # Working directory