mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
Compare commits
109 Commits
make-clean
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14c53db07c | ||
|
|
c56fb088ef | ||
|
|
fe363c5403 | ||
|
|
9f1a9ae92e | ||
|
|
d9b2c0f38f | ||
|
|
165232d694 | ||
|
|
7a4966e670 | ||
|
|
dfa3c412d9 | ||
|
|
f49877920e | ||
|
|
2704ff880f | ||
|
|
8378274572 | ||
|
|
0e637e9663 | ||
|
|
a1f85a9c7f | ||
|
|
76d5b5874e | ||
|
|
51f88950eb | ||
|
|
f9d1222bd7 | ||
|
|
d37909e409 | ||
|
|
f5631d8bda | ||
|
|
9a9ae7d6fd | ||
|
|
64ab8643b5 | ||
|
|
f7fd63acb4 | ||
|
|
8bd7403ae3 | ||
|
|
5efacb1a2b | ||
|
|
7207c96a6f | ||
|
|
21bc996705 | ||
|
|
438fd5bbd2 | ||
|
|
101846e423 | ||
|
|
fba7f7da9b | ||
|
|
115099698a | ||
|
|
4f3d0c981c | ||
|
|
96af3a1165 | ||
|
|
6cabff4bbb | ||
|
|
71708e84ce | ||
|
|
3d70b18c23 | ||
|
|
842acf2eaa | ||
|
|
b9463f442b | ||
|
|
7ceeb4f8ed | ||
|
|
fc8051f724 | ||
|
|
64ba9b5389 | ||
|
|
1286b86f07 | ||
|
|
8101b43fc5 | ||
|
|
efaffd9182 | ||
|
|
6197531c90 | ||
|
|
b94937ff38 | ||
|
|
2cb54d48a9 | ||
|
|
a7389454bb | ||
|
|
45d118101a | ||
|
|
e4a703000a | ||
|
|
8a4a75e721 | ||
|
|
4cb621d24d | ||
|
|
ff5826c54e | ||
|
|
b7ce13cbf8 | ||
|
|
e71249a15b | ||
|
|
19323ec218 | ||
|
|
cc8b81e7cc | ||
|
|
a7efdabefc | ||
|
|
57774795af | ||
|
|
9d99542299 | ||
|
|
e02089e28a | ||
|
|
2bcfec3e60 | ||
|
|
4a01746be2 | ||
|
|
914ef57844 | ||
|
|
089ae11181 | ||
|
|
ae13cd77fc | ||
|
|
3f21e90fca | ||
|
|
5f14118d73 | ||
|
|
b874ff71de | ||
|
|
397013922c | ||
|
|
85c36839d5 | ||
|
|
196d37b28a | ||
|
|
e8086be768 | ||
|
|
82dd474e3b | ||
|
|
58f36203b1 | ||
|
|
425f899302 | ||
|
|
febe89c61b | ||
|
|
3e50be491b | ||
|
|
dfc7f310d6 | ||
|
|
a6a9352a00 | ||
|
|
eb1d784c0d | ||
|
|
d1092099d0 | ||
|
|
bc621bed9c | ||
|
|
60eebbe732 | ||
|
|
345995000a | ||
|
|
ef18bf5f3e | ||
|
|
6f3b3b6d28 | ||
|
|
846eebc66c | ||
|
|
75d47ccdad | ||
|
|
456123fe7f | ||
|
|
5733c99ba1 | ||
|
|
391e7e39ad | ||
|
|
f5f0e17e78 | ||
|
|
f6f0082a0e | ||
|
|
c84b1fc1ff | ||
|
|
e35307a7e3 | ||
|
|
911114c286 | ||
|
|
9e998ca108 | ||
|
|
99695dec0b | ||
|
|
0ec7094877 | ||
|
|
a471e73adf | ||
|
|
c76bf8e20b | ||
|
|
309bbd8c8c | ||
|
|
d6e5769bc5 | ||
|
|
976b6ae7e1 | ||
|
|
8af96cb6cb | ||
|
|
febe690623 | ||
|
|
e36ebff16e | ||
|
|
6a1fd36b3a | ||
|
|
feebeb6751 | ||
|
|
1b2c798467 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
|||||||
*.a
|
*.a
|
||||||
/library/compiler.log
|
/library/compiler.log
|
||||||
/library/netinclude
|
/library/netinclude
|
||||||
|
*.map
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ WARNINGS = \
|
|||||||
# -Wconversion -Wshadow
|
# -Wconversion -Wshadow
|
||||||
|
|
||||||
INCLUDES = -Iinclude -I. -Inetinclude
|
INCLUDES = -Iinclude -I. -Inetinclude
|
||||||
#OPTIONS = -fno-builtin -fno-common -DDEBUG
|
#OPTIONS = -fno-builtin -fno-common
|
||||||
OPTIONS = -fno-builtin -fno-common -DNDEBUG
|
OPTIONS = -fno-builtin -fno-common -DNDEBUG
|
||||||
#OPTIONS = -fno-builtin -fno-common -DNDEBUG -D__THREAD_SAFE
|
#OPTIONS = -fno-builtin -fno-common -DNDEBUG -D__THREAD_SAFE
|
||||||
#OPTIONS = -fno-builtin -fno-common -D__MEM_DEBUG
|
#OPTIONS = -fno-builtin -fno-common -D__MEM_DEBUG
|
||||||
@@ -261,6 +261,7 @@ C_LIB = \
|
|||||||
stdio_iobhookentry.o \
|
stdio_iobhookentry.o \
|
||||||
stdio_lock.o \
|
stdio_lock.o \
|
||||||
stdio_locksemaphorename.o \
|
stdio_locksemaphorename.o \
|
||||||
|
stdio_long_path.o \
|
||||||
stdio_nostdio.o \
|
stdio_nostdio.o \
|
||||||
stdio_openiob.o \
|
stdio_openiob.o \
|
||||||
stdio_parent_of_fh.o \
|
stdio_parent_of_fh.o \
|
||||||
@@ -491,13 +492,13 @@ C_LIB = \
|
|||||||
UNIX_LIB = \
|
UNIX_LIB = \
|
||||||
unix.lib_rev.o \
|
unix.lib_rev.o \
|
||||||
dirent_closedir.o \
|
dirent_closedir.o \
|
||||||
dirent_rewinddir.o \
|
|
||||||
dirent_opendir.o \
|
dirent_opendir.o \
|
||||||
dirent_readdir.o \
|
dirent_readdir.o \
|
||||||
|
dirent_rewinddir.o \
|
||||||
fcntl_creat.o \
|
fcntl_creat.o \
|
||||||
fcntl_fcntl.o \
|
fcntl_fcntl.o \
|
||||||
fcntl_open.o \
|
|
||||||
fcntl_get_default_file.o \
|
fcntl_get_default_file.o \
|
||||||
|
fcntl_open.o \
|
||||||
getopt_getopt_long.o \
|
getopt_getopt_long.o \
|
||||||
mount_convertinfo.o \
|
mount_convertinfo.o \
|
||||||
mount_statfs.o \
|
mount_statfs.o \
|
||||||
@@ -505,18 +506,19 @@ UNIX_LIB = \
|
|||||||
resource_setrlimit.o \
|
resource_setrlimit.o \
|
||||||
stat_chmod.o \
|
stat_chmod.o \
|
||||||
stat_fstat.o \
|
stat_fstat.o \
|
||||||
stat_lstat.o \
|
|
||||||
stat_lock.o \
|
stat_lock.o \
|
||||||
|
stat_lstat.o \
|
||||||
stat_mkdir.o \
|
stat_mkdir.o \
|
||||||
stat_rmdir.o \
|
stat_rmdir.o \
|
||||||
stat_stat.o \
|
stat_stat.o \
|
||||||
stdio_ctermid.o \
|
stdio_ctermid.o \
|
||||||
stdio_fdhookentry.o \
|
stdio_fdhookentry.o \
|
||||||
stdio_fflush.o \
|
stdio_fflush.o \
|
||||||
|
stdio_file_init.o \
|
||||||
stdio_fopen.o \
|
stdio_fopen.o \
|
||||||
stdio_init_exit.o \
|
stdio_init_exit.o \
|
||||||
stdio_file_init.o \
|
|
||||||
stdio_locksemaphorename.o \
|
stdio_locksemaphorename.o \
|
||||||
|
stdio_long_path.o \
|
||||||
stdio_openiob.o \
|
stdio_openiob.o \
|
||||||
stdio_popen.o \
|
stdio_popen.o \
|
||||||
stdio_record_locking.o \
|
stdio_record_locking.o \
|
||||||
@@ -526,17 +528,28 @@ UNIX_LIB = \
|
|||||||
stdlib_alloca_cleanup.o \
|
stdlib_alloca_cleanup.o \
|
||||||
stdlib_alloca_trap.o \
|
stdlib_alloca_trap.o \
|
||||||
stdlib_arg.o \
|
stdlib_arg.o \
|
||||||
|
stdlib_calloc.o \
|
||||||
|
stdlib_decay_unused_slabs.o \
|
||||||
stdlib_expand_wildcard.o \
|
stdlib_expand_wildcard.o \
|
||||||
stdlib_expand_wildcard_check.o \
|
stdlib_expand_wildcard_check.o \
|
||||||
|
stdlib_free.o \
|
||||||
|
stdlib_free_unused_slabs.o \
|
||||||
stdlib_getmemstats.o \
|
stdlib_getmemstats.o \
|
||||||
|
stdlib_get_slab_allocations.o \
|
||||||
|
stdlib_get_slab_stats.o \
|
||||||
|
stdlib_get_slab_usage.o \
|
||||||
stdlib_main.o \
|
stdlib_main.o \
|
||||||
stdlib_main_stub.o \
|
stdlib_main_stub.o \
|
||||||
|
stdlib_malloc.o \
|
||||||
stdlib_mkdtemp.o \
|
stdlib_mkdtemp.o \
|
||||||
stdlib_mkstemp.o \
|
stdlib_mkstemp.o \
|
||||||
stdlib_mktemp.o \
|
stdlib_mktemp.o \
|
||||||
stdlib_malloc.o \
|
|
||||||
stdlib_realloc.o \
|
stdlib_realloc.o \
|
||||||
|
stdlib_red_black.o \
|
||||||
stdlib_resetmemstats.o \
|
stdlib_resetmemstats.o \
|
||||||
|
stdlib_slab.o \
|
||||||
|
stdlib_slab_max_size.o \
|
||||||
|
stdlib_slab_purge_threshold.o \
|
||||||
stdlib_system.o \
|
stdlib_system.o \
|
||||||
systeminfo_sysinfo.o \
|
systeminfo_sysinfo.o \
|
||||||
termios_cfgetispeed.o \
|
termios_cfgetispeed.o \
|
||||||
@@ -940,6 +953,7 @@ AMIGA_LIB = \
|
|||||||
amiga_hotkey.o \
|
amiga_hotkey.o \
|
||||||
amiga_invertstring.o \
|
amiga_invertstring.o \
|
||||||
amiga_newlist.o \
|
amiga_newlist.o \
|
||||||
|
amiga_pools.o \
|
||||||
amiga_rangerand.o \
|
amiga_rangerand.o \
|
||||||
amiga_remtof.o \
|
amiga_remtof.o \
|
||||||
amiga_rexxvars.o \
|
amiga_rexxvars.o \
|
||||||
@@ -1155,6 +1169,34 @@ $(LIBC_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h include/std
|
|||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_alloca.o : stdlib_alloca.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_calloc.o : stdlib_calloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_decay_unused_slabs.o : stdlib_decay_unused_slabs.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_free.o : stdlib_free.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_get_slab_allocations.o : stdlib_get_slab_allocations.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_get_slab_stats.o : stdlib_get_slab_stats.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_get_slab_usage.o : stdlib_get_slab_usage.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_malloc.o : stdlib_malloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_realloc.o : stdlib_realloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_slab.o : stdlib_slab.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_slab_purge_threshold.o : stdlib_slab_purge_threshold.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
# The -fbaserel32 option requires the CPU type to be 68020, too.
|
# The -fbaserel32 option requires the CPU type to be 68020, too.
|
||||||
ifneq (,$(findstring fbaserel32,$(CODE_FLAGS)))
|
ifneq (,$(findstring fbaserel32,$(CODE_FLAGS)))
|
||||||
LOCAL_CODE_FLAGS := $(CODE_FLAGS) $(CODE_TYPE)
|
LOCAL_CODE_FLAGS := $(CODE_FLAGS) $(CODE_TYPE)
|
||||||
|
|||||||
@@ -29,7 +29,11 @@ RANLIB := ppc-amigaos-ranlib
|
|||||||
COPY := cp -p
|
COPY := cp -p
|
||||||
DELETE := rm -rf
|
DELETE := rm -rf
|
||||||
MAKEDIR := mkdir -p
|
MAKEDIR := mkdir -p
|
||||||
LOG_COMMAND := 2>&1 | tee -a compiler.log
|
# Enabling the LOG_COMMAND has the consequence that a rule will not
|
||||||
|
# fail on an error because only the exit status from the tee command
|
||||||
|
# will be considered
|
||||||
|
#LOG_COMMAND := 2>&1 | tee -a compiler.log
|
||||||
|
LOG_COMMAND :=
|
||||||
# You may need to request a specific compiler version in order to
|
# You may need to request a specific compiler version in order to
|
||||||
# build the baserel versions of the library. At this time of
|
# build the baserel versions of the library. At this time of
|
||||||
# writing (2008-11-06) GCC 4.0.4 and below support the -mbaserel
|
# writing (2008-11-06) GCC 4.0.4 and below support the -mbaserel
|
||||||
@@ -54,13 +58,13 @@ LOG_COMMAND := 2>&1 | tee -a compiler.log
|
|||||||
|
|
||||||
WARNINGS := \
|
WARNINGS := \
|
||||||
-Wall -W -Wpointer-arith -Wsign-compare -Wmissing-prototypes \
|
-Wall -W -Wpointer-arith -Wsign-compare -Wmissing-prototypes \
|
||||||
-Wundef -Wbad-function-cast -Wmissing-declarations -Wunused -Wwrite-strings \
|
-Wundef -Wmissing-declarations -Wunused -Wwrite-strings \
|
||||||
-Wno-deprecated-declarations \
|
-Wno-deprecated-declarations -Wno-unused-label \
|
||||||
|
|
||||||
# -Wconversion -Wshadow
|
# -Wconversion -Wshadow -Wbad-function-cast
|
||||||
|
|
||||||
INCLUDES := -Iinclude -I. -I$(SDK_INCLUDE)
|
INCLUDES := -Iinclude -I. -I$(SDK_INCLUDE)
|
||||||
OPTIONS := -DUSE_64_BIT_INTS -D__USE_INLINE__ -Wa,-mregnames -fno-common -std=gnu99 -mcrt=clib2
|
OPTIONS := -DUSE_64_BIT_INTS -D__USE_INLINE__ -Wa,-mregnames -fno-builtin -fno-common -std=c99 -nostdlib
|
||||||
OPTIMIZE := -DNDEBUG -O3
|
OPTIMIZE := -DNDEBUG -O3
|
||||||
|
|
||||||
#DEBUG := -ggdb
|
#DEBUG := -ggdb
|
||||||
@@ -93,7 +97,11 @@ include libm.gmk
|
|||||||
include libnet.gmk
|
include libnet.gmk
|
||||||
include libdebug.gmk
|
include libdebug.gmk
|
||||||
include libamiga.gmk
|
include libamiga.gmk
|
||||||
include libprofile.gmk
|
|
||||||
|
# Olaf (2019-08-22): Please note that "profile_profil.o" can no longer
|
||||||
|
# be built, presumably for lack of header files needed
|
||||||
|
# to build it properly.
|
||||||
|
#include libprofile.gmk
|
||||||
|
|
||||||
all-targets: \
|
all-targets: \
|
||||||
lib/crt0.o \
|
lib/crt0.o \
|
||||||
@@ -160,6 +168,12 @@ cvs-tag:
|
|||||||
|
|
||||||
# General build rules for all object files and the individual libraries
|
# General build rules for all object files and the individual libraries
|
||||||
|
|
||||||
|
#NO_AGGRESSIVE_LOOP_OPTIMIZATIONS := -fno-aggressive-loop-optimizations
|
||||||
|
|
||||||
|
lib/crtbegin.o : CFLAGS += $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
|
lib/crtbegin.o : crtbegin.c
|
||||||
|
@$(COMPILE)
|
||||||
|
|
||||||
lib/%.o : AFLAGS += $(LARGEDATA)
|
lib/%.o : AFLAGS += $(LARGEDATA)
|
||||||
lib/%.o : %.S
|
lib/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
@@ -171,6 +185,11 @@ lib/small-data/%.o : AFLAGS += $(SMALLDATA)
|
|||||||
lib/small-data/%.o : %.S
|
lib/small-data/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
|
lib/small-data/crtbegin.o : CFLAGS += $(SMALLDATA) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
|
lib/small-data/crtbegin.o : crtbegin.c
|
||||||
|
@$(COMPILE)
|
||||||
|
|
||||||
|
lib/small-data/%.o : CFLAGS += $(SMALLDATA)
|
||||||
lib/small-data/%.o : %.c
|
lib/small-data/%.o : %.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@@ -178,6 +197,11 @@ lib/soft-float/%.o : AFLAGS += $(SOFTFLOAT)
|
|||||||
lib/soft-float/%.o : %.S
|
lib/soft-float/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
|
lib/soft-float/crtbegin.o : CFLAGS += $(SOFTFLOAT) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
|
lib/soft-float/crtbegin.o : crtbegin.c
|
||||||
|
@$(COMPILE)
|
||||||
|
|
||||||
|
lib/soft-float/%.o : CFLAGS += $(SOFTFLOAT)
|
||||||
lib/soft-float/%.o : %.c
|
lib/soft-float/%.o : %.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@@ -185,6 +209,11 @@ lib/baserel/%.o : AFLAGS += $(BASEREL)
|
|||||||
lib/baserel/%.o : %.S
|
lib/baserel/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
|
lib/baserel/crtbegin.o : CFLAGS += $(BASEREL) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
|
lib/baserel/crtbegin.o : crtbegin.c
|
||||||
|
@$(COMPILE)
|
||||||
|
|
||||||
|
lib/baserel/%.o : CFLAGS += $(BASEREL)
|
||||||
lib/baserel/%.o : %.c
|
lib/baserel/%.o : %.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@@ -192,6 +221,11 @@ lib.threadsafe/%.o : AFLAGS += $(LARGEDATA) $(THREADSAFE)
|
|||||||
lib.threadsafe/%.o : %.S
|
lib.threadsafe/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
|
lib.threadsafe/crtbegin.o : CFLAGS += $(THREADSAFE) $(LARGEDATA) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
|
lib.threadsafe/crtbegin.o : crtbegin.c
|
||||||
|
@$(COMPILE)
|
||||||
|
|
||||||
|
lib.threadsafe/%.o : CFLAGS += $(THREADSAFE) $(LARGEDATA)
|
||||||
lib.threadsafe/%.o : %.c
|
lib.threadsafe/%.o : %.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@@ -199,6 +233,11 @@ lib.threadsafe/small-data/%.o : AFLAGS += $(SMALLDATA) $(THREADSAFE)
|
|||||||
lib.threadsafe/small-data/%.o : %.S
|
lib.threadsafe/small-data/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
|
lib.threadsafe/small-data/crtbegin.o : CFLAGS += $(THREADSAFE) $(SMALLDATA) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
|
lib.threadsafe/small-data/crtbegin.o : crtbegin.c
|
||||||
|
@$(COMPILE)
|
||||||
|
|
||||||
|
lib.threadsafe/small-data/%.o : CFLAGS += $(THREADSAFE) $(SMALLDATA)
|
||||||
lib.threadsafe/small-data/%.o : %.c
|
lib.threadsafe/small-data/%.o : %.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@@ -206,6 +245,11 @@ lib.threadsafe/soft-float/%.o : AFLAGS += $(SOFTFLOAT) $(THREADSAFE)
|
|||||||
lib.threadsafe/soft-float/%.o : %.S
|
lib.threadsafe/soft-float/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
|
lib.threadsafe/soft-float/crtbegin.o : CFLAGS += $(THREADSAFE) $(SOFTFLOAT) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
|
lib.threadsafe/soft-float/crtbegin.o : crtbegin.c
|
||||||
|
@$(COMPILE)
|
||||||
|
|
||||||
|
lib.threadsafe/soft-float/%.o : CFLAGS += $(THREADSAFE) $(SOFTFLOAT)
|
||||||
lib.threadsafe/soft-float/%.o : %.c
|
lib.threadsafe/soft-float/%.o : %.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@@ -213,6 +257,11 @@ lib.threadsafe/baserel/%.o : AFLAGS += $(BASEREL) $(THREADSAFE)
|
|||||||
lib.threadsafe/baserel/%.o : %.S
|
lib.threadsafe/baserel/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
|
lib.threadsafe/baserel/crtbegin.o : CFLAGS += $(THREADSAFE) $(BASEREL) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
|
lib.threadsafe/baserel/crtbegin.o : crtbegin.c
|
||||||
|
@$(COMPILE)
|
||||||
|
|
||||||
|
lib.threadsafe/baserel/%.o : CFLAGS += $(THREADSAFE) $(BASEREL)
|
||||||
lib.threadsafe/baserel/%.o : %.c
|
lib.threadsafe/baserel/%.o : %.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@@ -231,7 +280,7 @@ $(CC) $(AFLAGS) -o $@ -c $< $(LOG_COMMAND)
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
define MAKELIB
|
define MAKELIB
|
||||||
-$(MAKEDIR) $@
|
-$(MAKEDIR) $(@D)
|
||||||
$(DELETE) $@
|
$(DELETE) $@
|
||||||
echo "Making $@"
|
echo "Making $@"
|
||||||
$(AR) $@ $^ $(LOG_COMMAND)
|
$(AR) $@ $^ $(LOG_COMMAND)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 213
|
#define REVISION 216
|
||||||
#define DATE "4.12.2016"
|
#define DATE "10.7.2025"
|
||||||
#define VERS "amiga.lib 1.213"
|
#define VERS "amiga.lib 1.216"
|
||||||
#define VSTRING "amiga.lib 1.213 (4.12.2016)\r\n"
|
#define VSTRING "amiga.lib 1.216 (10.7.2025)\r\n"
|
||||||
#define VERSTAG "\0$VER: amiga.lib 1.213 (4.12.2016)"
|
#define VERSTAG "\0$VER: amiga.lib 1.216 (10.7.2025)"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
213
|
216
|
||||||
|
|||||||
562
library/amiga_pools.c
Normal file
562
library/amiga_pools.c
Normal file
@@ -0,0 +1,562 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2021 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <exec/memory.h>
|
||||||
|
#include <exec/alerts.h>
|
||||||
|
#include <exec/lists.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#include <proto/exec.h>
|
||||||
|
#include <clib/alib_protos.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* This signature identifies a large allocation on the list
|
||||||
|
* which contains both puddles and such large memory allocations.
|
||||||
|
*/
|
||||||
|
#define IS_LARGE_ALLOCATION 0
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* A private memory pool, as used by this implementation of the
|
||||||
|
* pool memory management functions.
|
||||||
|
*/
|
||||||
|
struct MemoryPool
|
||||||
|
{
|
||||||
|
struct MinList mp_PuddleMinList; /* Both puddles and large allocations
|
||||||
|
* are stored in this list. The puddles
|
||||||
|
* are stored near the head of the list
|
||||||
|
* and the large allocations are stored
|
||||||
|
* near the tail of the list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ULONG mp_MemoryFlags; /* Memory attributes for allocation,
|
||||||
|
* which may also include MEMF_CLEAR.
|
||||||
|
*/
|
||||||
|
ULONG mp_PuddleSize; /* Largest allocation which will fit
|
||||||
|
* into a single puddle.
|
||||||
|
*/
|
||||||
|
ULONG mp_PuddleSizeThreshold; /* Allocations which exceed this size
|
||||||
|
* will be allocated separately and not
|
||||||
|
* make use of the puddles.
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* The management data structure associated with a separate large memory
|
||||||
|
* allocation. This is distinct from the puddles.
|
||||||
|
*/
|
||||||
|
struct LargeAllocation
|
||||||
|
{
|
||||||
|
struct MinNode la_MinNode;
|
||||||
|
|
||||||
|
ULONG la_Signature; /* Must be set to IS_LARGE_ALLOCATION */
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* This combines a plain Node, a MemHeader and a LargeAllocation. They
|
||||||
|
* all overlap to some degree. The "puddle" is really a MemHeader from
|
||||||
|
* which the individual memory allocations are made.
|
||||||
|
*
|
||||||
|
* For reference, here is how the individual data structures look like.
|
||||||
|
* The 'struct MinNode' is used by the 'struct LargeAllocation' and you
|
||||||
|
* can see that the LargeAllocation.la_Signature overlaps the
|
||||||
|
* Node.ln_Type and Node.ln_Pri fields. The 'struct MemHeader' begins
|
||||||
|
* with a 'struct Node' and is initialized so that the Node.ln_Type and
|
||||||
|
* Node.ln_Pri are never zero. This is why LargeAllocation.la_Signature
|
||||||
|
* being zero is key to identifying large allocations which along with
|
||||||
|
* the MemHeaders share the same storage list.
|
||||||
|
*
|
||||||
|
* struct MinNode {
|
||||||
|
* struct MinNode * mln_Succ;
|
||||||
|
* struct MinNode * mln_Pred;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct LargeAllocation {
|
||||||
|
* struct MinNode la_MinNode;
|
||||||
|
* ULONG la_Signature;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct Node {
|
||||||
|
* struct Node * ln_Succ;
|
||||||
|
* struct Node * ln_Pred;
|
||||||
|
* UBYTE ln_Type;
|
||||||
|
* BYTE ln_Pri;
|
||||||
|
* char * ln_Name;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct MemHeader {
|
||||||
|
* struct Node mh_Node;
|
||||||
|
* UWORD mh_Attributes;
|
||||||
|
* struct MemChunk * mh_First;
|
||||||
|
* APTR mh_Lower;
|
||||||
|
* APTR mh_Upper;
|
||||||
|
* ULONG mh_Free;
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
union PuddleUnion
|
||||||
|
{
|
||||||
|
struct Node pu_Node;
|
||||||
|
struct MemHeader pu_MemHeader;
|
||||||
|
struct LargeAllocation pu_LargeAllocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Our local Kickstart 1.x compatible implementation of FreeVec(). */
|
||||||
|
static VOID free_vec(APTR allocation)
|
||||||
|
{
|
||||||
|
if (allocation != NULL)
|
||||||
|
{
|
||||||
|
ULONG * mem = allocation;
|
||||||
|
|
||||||
|
FreeMem(&mem[-1], mem[-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Our local Kickstart 1.x compatible implementation of AllocVec(). */
|
||||||
|
static APTR alloc_vec(ULONG size, ULONG flags)
|
||||||
|
{
|
||||||
|
ULONG * mem = NULL;
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
/* Note: no overflow testing is being performed! */
|
||||||
|
size += sizeof(*mem);
|
||||||
|
|
||||||
|
mem = AllocMem(size, flags);
|
||||||
|
if (mem != NULL)
|
||||||
|
(*mem++) = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
VOID LibDeletePool(APTR pool)
|
||||||
|
{
|
||||||
|
/* If possible, use the operating system implementation
|
||||||
|
* instead of this reimplementation.
|
||||||
|
*/
|
||||||
|
#if ! defined(__amigaos4__)
|
||||||
|
if (SysBase->LibNode.lib_Version >= 39)
|
||||||
|
{
|
||||||
|
DeletePool(pool);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* ! defined(__amigaos4__) */
|
||||||
|
|
||||||
|
if (pool != NULL)
|
||||||
|
{
|
||||||
|
struct MemoryPool * mp = pool;
|
||||||
|
struct MinNode * mln_next;
|
||||||
|
struct MinNode * mln;
|
||||||
|
|
||||||
|
for (mln = mp->mp_PuddleMinList.mlh_Head ;
|
||||||
|
mln->mln_Succ != NULL ;
|
||||||
|
mln = mln_next)
|
||||||
|
{
|
||||||
|
mln_next = mln->mln_Succ;
|
||||||
|
|
||||||
|
free_vec(mln);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeMem(mp, sizeof(*mp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Note: puddle size should not be 0 or every single memory allocation
|
||||||
|
* will result in an AllocVec() call.
|
||||||
|
*/
|
||||||
|
APTR LibCreatePool(
|
||||||
|
ULONG memory_flags,
|
||||||
|
ULONG puddle_size,
|
||||||
|
ULONG threshold_size)
|
||||||
|
{
|
||||||
|
struct MemoryPool * mp = NULL;
|
||||||
|
APTR result = NULL;
|
||||||
|
|
||||||
|
/* If possible, use the operating system implementation
|
||||||
|
* instead of this reimplementation.
|
||||||
|
*/
|
||||||
|
#if ! defined(__amigaos4__)
|
||||||
|
if (SysBase->LibNode.lib_Version >= 39)
|
||||||
|
{
|
||||||
|
return CreatePool(memory_flags, puddle_size, threshold_size);
|
||||||
|
}
|
||||||
|
#endif /* ! defined(__amigaos4__) */
|
||||||
|
|
||||||
|
/* The threshold size must be less than or equal
|
||||||
|
* to the puddle size.
|
||||||
|
*/
|
||||||
|
if (threshold_size > puddle_size)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Round up the puddle size to the size of a
|
||||||
|
* memory block, as managed by Allocate().
|
||||||
|
*
|
||||||
|
* Note: no overflow checking is performed!
|
||||||
|
*/
|
||||||
|
puddle_size = (puddle_size + MEM_BLOCKMASK) & ~MEM_BLOCKMASK;
|
||||||
|
|
||||||
|
mp = AllocMem(sizeof(*mp), MEMF_ANY);
|
||||||
|
if (mp == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
NewList((struct List *)&mp->mp_PuddleMinList);
|
||||||
|
|
||||||
|
mp->mp_MemoryFlags = memory_flags;
|
||||||
|
mp->mp_PuddleSize = puddle_size;
|
||||||
|
mp->mp_PuddleSizeThreshold = threshold_size;
|
||||||
|
|
||||||
|
result = mp;
|
||||||
|
mp = NULL;
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
if (mp != NULL)
|
||||||
|
LibDeletePool(mp);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Creates a new puddle from which memory allocations up to a certain size
|
||||||
|
* will be made. Returns the new puddle or NULL for failure.
|
||||||
|
*
|
||||||
|
* Note: No overflow testing is performed when allocating the puddle.
|
||||||
|
*/
|
||||||
|
static union PuddleUnion * create_new_puddle(struct MemoryPool * mp)
|
||||||
|
{
|
||||||
|
ULONG memory_flags = mp->mp_MemoryFlags;
|
||||||
|
ULONG puddle_size = mp->mp_PuddleSize;
|
||||||
|
union PuddleUnion * result = NULL;
|
||||||
|
union PuddleUnion * pu;
|
||||||
|
struct MemHeader * mh;
|
||||||
|
struct MemChunk * mc;
|
||||||
|
|
||||||
|
/* The extra sizeof(APTR) is needed for aligning the
|
||||||
|
* allocatable memory chunks within the memory header.
|
||||||
|
*
|
||||||
|
* Note: no overflow checking is performed!
|
||||||
|
*
|
||||||
|
* Also note that the original memory allocation flags are
|
||||||
|
* being used, which may include MEMF_CLEAR. This means that
|
||||||
|
* if MEMF_CLEAR is set, the initial allocation will be
|
||||||
|
* cleared and then the individual puddle allocations made
|
||||||
|
* through LibAllocPooled() will be cleared, too.
|
||||||
|
*/
|
||||||
|
pu = alloc_vec(sizeof(pu->pu_MemHeader) + sizeof(LONG) + puddle_size, memory_flags);
|
||||||
|
if (pu == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
mh = &pu->pu_MemHeader;
|
||||||
|
|
||||||
|
/* The first allocatable memory chunk follows the memory header
|
||||||
|
* and must be aligned to a 64 bit address. This happens to be
|
||||||
|
* the smallest allocatable memory unit (MEM_BLOCKSIZE == 8).
|
||||||
|
*/
|
||||||
|
mc = (struct MemChunk *)(((ULONG)&mh[1] + sizeof(LONG)) & ~MEM_BLOCKMASK);
|
||||||
|
|
||||||
|
mc->mc_Next = NULL;
|
||||||
|
mc->mc_Bytes = puddle_size;
|
||||||
|
|
||||||
|
/* Both ln_Type and ln_Pri must be non-zero! This allows them to
|
||||||
|
* be identified as small puddles as compared to the large puddles
|
||||||
|
* which have the la_Signature member set to IS_LARGE_ALLOCATION.
|
||||||
|
* The 'struct Node' which introduces the 'struct MemHeader'
|
||||||
|
* overlaps the 'struct LargeAllocation' in the Node.ln_Type/ln_Pri
|
||||||
|
* fields. This is why the test for la_Signature == IS_LARGE_ALLOCATION
|
||||||
|
* works.
|
||||||
|
*/
|
||||||
|
mh->mh_Node.ln_Type = NT_MEMORY;
|
||||||
|
mh->mh_Node.ln_Pri = mh->mh_Node.ln_Type;
|
||||||
|
|
||||||
|
mh->mh_Node.ln_Name = (char *)&"\0Pool"[1]; /* The memory name must be an odd address. */
|
||||||
|
mh->mh_Attributes = memory_flags;
|
||||||
|
mh->mh_First = mc;
|
||||||
|
mh->mh_Lower = mc;
|
||||||
|
mh->mh_Upper = &((BYTE *)mc)[puddle_size];
|
||||||
|
mh->mh_Free = puddle_size;
|
||||||
|
|
||||||
|
/* Puddles are always added at the head of the list. */
|
||||||
|
AddHead((struct List *)&mp->mp_PuddleMinList, &pu->pu_Node);
|
||||||
|
|
||||||
|
result = pu;
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Note: No overflow testing is performed when making a large allocation. */
|
||||||
|
APTR LibAllocPooled(APTR pool, ULONG mem_size)
|
||||||
|
{
|
||||||
|
struct MemoryPool * mp;
|
||||||
|
union PuddleUnion * pu;
|
||||||
|
APTR result = NULL;
|
||||||
|
|
||||||
|
/* If possible, use the operating system implementation
|
||||||
|
* instead of this reimplementation.
|
||||||
|
*/
|
||||||
|
#if ! defined(__amigaos4__)
|
||||||
|
if (SysBase->LibNode.lib_Version >= 39)
|
||||||
|
{
|
||||||
|
return AllocPooled(pool, mem_size);
|
||||||
|
}
|
||||||
|
#endif /* ! defined(__amigaos4__) */
|
||||||
|
|
||||||
|
/* No pool or no memory to allocate? */
|
||||||
|
if (pool == NULL || mem_size == 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
mp = pool;
|
||||||
|
|
||||||
|
/* Requested allocation size is still within the threshold limit? */
|
||||||
|
if (mem_size <= mp->mp_PuddleSizeThreshold)
|
||||||
|
{
|
||||||
|
/* Search for the first puddle from which memory may be
|
||||||
|
* allocated. If no such puddle exists, it will have
|
||||||
|
* to be created. Instead of puddles we might end up
|
||||||
|
* finding a large memory allocation instead. This is
|
||||||
|
* also an indication that a new puddle will have to
|
||||||
|
* be created.
|
||||||
|
*/
|
||||||
|
pu = (union PuddleUnion *)mp->mp_PuddleMinList.mlh_Head;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* We just reached the end of the puddle list or this
|
||||||
|
* is a large allocation? We can't use an existing puddle to
|
||||||
|
* allocate memory, so we have to make a new one.
|
||||||
|
*/
|
||||||
|
if (pu->pu_Node.ln_Succ == NULL || pu->pu_LargeAllocation.la_Signature == IS_LARGE_ALLOCATION)
|
||||||
|
{
|
||||||
|
/* We need to create another puddle, which is added to
|
||||||
|
* the head of the list. Then the search for allocatable
|
||||||
|
* memory in the puddle list will resume there.
|
||||||
|
*/
|
||||||
|
pu = create_new_puddle(mp);
|
||||||
|
if (pu == NULL)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to allocate memory from this puddle.*/
|
||||||
|
result = Allocate(&pu->pu_MemHeader, mem_size);
|
||||||
|
if (result != NULL)
|
||||||
|
{
|
||||||
|
/* If the allocation needs to be zeroed, clear
|
||||||
|
* the entire allocated memory which Allocate()
|
||||||
|
* returned. It's been rounded up to be a
|
||||||
|
* multiple of MEM_BLOCKSIZE.
|
||||||
|
*
|
||||||
|
* Note that the puddle will have been allocated
|
||||||
|
* with MEMF_CLEAR already, which does not render
|
||||||
|
* the following memset() call redundant, but
|
||||||
|
* making the initial puddle allocation use
|
||||||
|
* MEMF_CLEAR is definitely redundant.
|
||||||
|
*/
|
||||||
|
if ((mp->mp_MemoryFlags & MEMF_CLEAR) != 0)
|
||||||
|
memset(result, 0, (mem_size + MEM_BLOCKMASK) & ~MEM_BLOCKMASK);
|
||||||
|
|
||||||
|
/* And we're good. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try the next puddle on the list. */
|
||||||
|
pu = (union PuddleUnion *)pu->pu_Node.ln_Succ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* No, we need to allocate this memory chunk separately. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct LargeAllocation * la;
|
||||||
|
|
||||||
|
/* Note: no overflow checking is performed! */
|
||||||
|
pu = alloc_vec(sizeof(pu->pu_LargeAllocation) + mem_size, mp->mp_MemoryFlags);
|
||||||
|
if (pu == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* This identifies it as a separate large allocation. */
|
||||||
|
pu->pu_LargeAllocation.la_Signature = IS_LARGE_ALLOCATION;
|
||||||
|
|
||||||
|
/* The separate large allocations are stored near the end
|
||||||
|
* of the list. The puddles are always stored at the beginning
|
||||||
|
* of the list.
|
||||||
|
*/
|
||||||
|
AddTail((struct List *)&mp->mp_PuddleMinList, &pu->pu_Node);
|
||||||
|
|
||||||
|
la = &pu->pu_LargeAllocation;
|
||||||
|
|
||||||
|
result = &la[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Note: The size of the allocation to free must match
|
||||||
|
* exactly or memory will remain unfreed. Furthermore,
|
||||||
|
* the wrong allocation size may lead to general
|
||||||
|
* memory corruption.
|
||||||
|
*/
|
||||||
|
VOID LibFreePooled(APTR pool, APTR memory, ULONG size)
|
||||||
|
{
|
||||||
|
/* If possible, use the operating system implementation
|
||||||
|
* instead of this reimplementation.
|
||||||
|
*/
|
||||||
|
#if ! defined(__amigaos4__)
|
||||||
|
if (SysBase->LibNode.lib_Version >= 39)
|
||||||
|
{
|
||||||
|
FreePooled(pool, memory, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* ! defined(__amigaos4__) */
|
||||||
|
|
||||||
|
if (pool != NULL && memory != NULL)
|
||||||
|
{
|
||||||
|
struct MemoryPool * mp = pool;
|
||||||
|
|
||||||
|
/* This allocation was made from a puddle? */
|
||||||
|
if (size <= mp->mp_PuddleSizeThreshold)
|
||||||
|
{
|
||||||
|
union PuddleUnion * pu_deallocation = NULL;
|
||||||
|
union PuddleUnion * pu;
|
||||||
|
|
||||||
|
/* Try to find the puddle which contains this
|
||||||
|
* allocation.
|
||||||
|
*/
|
||||||
|
for (pu = (union PuddleUnion *)mp->mp_PuddleMinList.mlh_Head ;
|
||||||
|
pu->pu_Node.ln_Succ != NULL ;
|
||||||
|
pu = (union PuddleUnion *)pu->pu_Node.ln_Succ)
|
||||||
|
{
|
||||||
|
/* Did we reach the end of the puddle list? Then
|
||||||
|
* the given memory address and/or size may be
|
||||||
|
* invalid...
|
||||||
|
*/
|
||||||
|
if (pu->pu_LargeAllocation.la_Signature == IS_LARGE_ALLOCATION)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Is this the memory header which contains the
|
||||||
|
* memory allocation?
|
||||||
|
*/
|
||||||
|
if (pu->pu_MemHeader.mh_Lower <= memory && memory < pu->pu_MemHeader.mh_Upper)
|
||||||
|
{
|
||||||
|
/* Free the allocation and remember where it
|
||||||
|
* came from. We will make use of this below to
|
||||||
|
* free now unused puddles.
|
||||||
|
*/
|
||||||
|
Deallocate(&pu->pu_MemHeader, memory, size);
|
||||||
|
|
||||||
|
pu_deallocation = pu;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Did we succeed in releasing this memory allocation? */
|
||||||
|
if (pu_deallocation != NULL)
|
||||||
|
{
|
||||||
|
APTR upper;
|
||||||
|
|
||||||
|
/* The more frequently memory is freed from a
|
||||||
|
* specific puddle, the easier it should become
|
||||||
|
* to find it on the list again. We try to move it
|
||||||
|
* closer to the beginning of the list unless it
|
||||||
|
* is already at the head of the list.
|
||||||
|
*/
|
||||||
|
if (mp->mp_PuddleMinList.mlh_Head != (struct MinNode *)pu)
|
||||||
|
{
|
||||||
|
/* This puddle precedes the one from which we
|
||||||
|
* just released an allocation.
|
||||||
|
*/
|
||||||
|
struct Node * pred = pu->pu_Node.ln_Pred;
|
||||||
|
struct Node * before;
|
||||||
|
|
||||||
|
/* Put this puddle at the head of the list? */
|
||||||
|
if (pred == (struct Node *)mp->mp_PuddleMinList.mlh_Head)
|
||||||
|
before = NULL;
|
||||||
|
/* No, insert it in front of its predecessor. */
|
||||||
|
else
|
||||||
|
before = pred->ln_Pred;
|
||||||
|
|
||||||
|
Remove(&pu->pu_Node);
|
||||||
|
Insert((struct List *)&mp->mp_PuddleMinList, &pu->pu_Node, before);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Has this puddle been emptied? */
|
||||||
|
upper = &((BYTE *)pu->pu_MemHeader.mh_Lower)[pu->pu_MemHeader.mh_Free];
|
||||||
|
if (upper == pu->pu_MemHeader.mh_Upper)
|
||||||
|
{
|
||||||
|
/* Then we may remove and free it now. */
|
||||||
|
Remove(&pu->pu_Node);
|
||||||
|
|
||||||
|
free_vec(pu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Something's wrong :-( */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Alert(AN_BadFreeAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* No, this is a large allocation which must be freed as it is. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct LargeAllocation * la = &((struct LargeAllocation *)memory)[-1];
|
||||||
|
|
||||||
|
Remove((struct Node *)&la->la_MinNode);
|
||||||
|
|
||||||
|
free_vec(la);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 213
|
#define REVISION 217
|
||||||
#define DATE "4.12.2016"
|
#define DATE "10.7.2025"
|
||||||
#define VERS "c.lib 1.213"
|
#define VERS "c.lib 1.217"
|
||||||
#define VSTRING "c.lib 1.213 (4.12.2016)\r\n"
|
#define VSTRING "c.lib 1.217 (10.7.2025)\r\n"
|
||||||
#define VERSTAG "\0$VER: c.lib 1.213 (4.12.2016)"
|
#define VERSTAG "\0$VER: c.lib 1.217 (10.7.2025)"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
213
|
217
|
||||||
|
|||||||
164
library/changes
164
library/changes
@@ -1,3 +1,163 @@
|
|||||||
|
c.lib 1.217 (10.7.2025)
|
||||||
|
|
||||||
|
- Added support for handling path names that exceed 255 characters in
|
||||||
|
the AmigaOS 2.x/3.x build. This feature works by replacing calls to the
|
||||||
|
CreateDir(), DeleteFile(), Lock(), MakeLink(), Open(), Rename(),
|
||||||
|
SetComment(), SetFileDate(), SetOwner() and SetProtection() functions
|
||||||
|
with a call to a front-end which breaks down long path names into
|
||||||
|
the individual path components. This is a compile-time option which
|
||||||
|
is enabled through the "library/stdio_long_path.h" header file.
|
||||||
|
|
||||||
|
Note that this feature is by default disabled for AmigaOS 4 because
|
||||||
|
its dos.library already transparently performs the long path
|
||||||
|
processing.
|
||||||
|
|
||||||
|
- The raise() function no longer directly calls abort() because that
|
||||||
|
function in turn would have invoked raise(SIGABRT), triggering an
|
||||||
|
infinite loop. Instead, raise() now invokes the __abort() function
|
||||||
|
which abort() would have called via raise(SIGABRT).
|
||||||
|
|
||||||
|
- fgets() no longer leverages the __getc() macro, which in the
|
||||||
|
original implementation added excessive overhead for even small
|
||||||
|
read operations. Instead, fgets() now focuses on copying data
|
||||||
|
stored in the FILE read buffer, transferring the buffered data
|
||||||
|
in bulk, if possible. The same kind of changes are present in
|
||||||
|
the gets() function.
|
||||||
|
|
||||||
|
- fputs() and puts() no longer leverage the __putc() macro. As with
|
||||||
|
the fgets() implementation, the focus is now on enabling bulk
|
||||||
|
data transfer, eliminating the __putc() macro overhead. For line
|
||||||
|
buffered output, both fputs() and puts() will check if the text
|
||||||
|
ends with a line feed and, if so, will output everything up to
|
||||||
|
and including the line feed. If enabled, Ctrl+C checking will
|
||||||
|
occur for every single line written.
|
||||||
|
|
||||||
|
- fread() and fwrite() no longer leverage the __getc() and
|
||||||
|
__putc() macros. Their focus is on enabling bulk data transfer
|
||||||
|
instead.
|
||||||
|
|
||||||
|
- The setvbuf() function now correctly sets the buffer size to the
|
||||||
|
value of BUFSIZ if a buffer size of 0 is specified. Previously,
|
||||||
|
setvbuf() would have disabled buffering for the FILE instead (this
|
||||||
|
was a bug).
|
||||||
|
|
||||||
|
Failure to allocate a buffer of the specified non-zero size is
|
||||||
|
now caught and results in the setvbuf() function to indicate
|
||||||
|
failure, setting the errno variable to ENOBUFS.
|
||||||
|
|
||||||
|
- The alloca() library function (which is a built-in function for
|
||||||
|
gcc, for example) now calls abort() rather than returning NULL.
|
||||||
|
|
||||||
|
- Changed the numeric overflow check which the calloc() function
|
||||||
|
uses, simplifying it.
|
||||||
|
|
||||||
|
- The memory management debugging code in stdlib_free.c is no longer
|
||||||
|
reusing the allocation size value to indicate that an allocation
|
||||||
|
should never be freed. This indication is now stored in a separate
|
||||||
|
flags field.
|
||||||
|
|
||||||
|
- The memory debugging code in malloc() now checks if the combined
|
||||||
|
size of the management data structures and front/back padding
|
||||||
|
stay within the bounds of a 32 bit integer.
|
||||||
|
|
||||||
|
The list of memory nodes to be freed is now initialized first.
|
||||||
|
Previously, the list would be left uninitialized if the attempt to
|
||||||
|
allocate memory for memory arbitration semaphore had failed.
|
||||||
|
|
||||||
|
- The realloc() function now obtains the original size of the
|
||||||
|
allocation from a dedicated field of the data structure which
|
||||||
|
precedes the allocation, whose purpose is to track the
|
||||||
|
allocation until it is freed. Previously, obtaining the relevant
|
||||||
|
allocation size information was encapsulated by a "clever"
|
||||||
|
macro.
|
||||||
|
|
||||||
|
With memory debugging enabled, the stored allocation size no
|
||||||
|
longer says how much memory, padding included, is being used.
|
||||||
|
Instead, the requested allocation size is stored unchanged, with
|
||||||
|
the total allocation size derived from this number. The idea is
|
||||||
|
to make it harder to mistake the original allocation size for
|
||||||
|
the padded one and vice versa.
|
||||||
|
|
||||||
|
- The use of the optional slab allocator now has to be deliberately
|
||||||
|
enabled in the "library/stdlib_memory.h" header file.
|
||||||
|
|
||||||
|
- The minimum size of an allocation managed by the optional slab
|
||||||
|
allocator is now 16 bytes instead of 8 because the management
|
||||||
|
data structure for each allocation now includes a flags field.
|
||||||
|
|
||||||
|
- The minimum size of a slab is now 4096 bytes.
|
||||||
|
|
||||||
|
- The optional slab allocator now checks for integer overflows when
|
||||||
|
processing allocation requests, taking into account the size of
|
||||||
|
the actual allocation, including padding. The task of figuring
|
||||||
|
out how much padding is needed now rests in a function which
|
||||||
|
calculates the total overhead.
|
||||||
|
|
||||||
|
- The usleep() function now correctly returns 0 and the function
|
||||||
|
prototype reflects this, too. Thanks go to capehill who raised
|
||||||
|
this issue.
|
||||||
|
|
||||||
|
- The "struct dirent" which is used by the readdir() function now
|
||||||
|
features a "d_type" member which indicates the kind of directory
|
||||||
|
entry the respective entry represents. For the time being,
|
||||||
|
the type can be one of DT_DIR (directory, or hard link to a
|
||||||
|
directory), DT_REG (file, or hard link to a file) or DT_LINK (soft
|
||||||
|
link). How do you know if the "d_type" member is available?
|
||||||
|
Check if the _DIRENT_HAVE_D_TYPE macro is defined. If it is, then
|
||||||
|
you can make use of the "d_type" member.
|
||||||
|
|
||||||
|
- Implemented the fixes for the tgamma() and tgammaf() functions
|
||||||
|
which were prompted by sodero. Thank you very much!
|
||||||
|
|
||||||
|
- The sqrt() function now returns a plain NAN if the function
|
||||||
|
parameter is < 0. Thanks go to sodero for providing the fix.
|
||||||
|
|
||||||
|
- The definition of "locale_t" is now based upon an incomplete
|
||||||
|
structure, with locale_t being a pointer to it. This change was
|
||||||
|
was provided by sacredbanana. Thank you very much!
|
||||||
|
|
||||||
|
|
||||||
|
amiga.lib 1.216 (10.7.2025)
|
||||||
|
|
||||||
|
- Added a 'C' implementation of the pools.lib functions which were
|
||||||
|
merged with the Kickstart/Workbench 3.0 era amiga.lib. This
|
||||||
|
implementation provides the LibDeletePool(), LibCreatePool(),
|
||||||
|
LibAllocPooled() and LibFreePooled() functions which had not
|
||||||
|
been available before in clib2.
|
||||||
|
|
||||||
|
Please note that these functions are largely obsolete and only
|
||||||
|
helpful for code which must run on Kickstart 2.04. The current
|
||||||
|
implementation performs no error checking for integer overflows,
|
||||||
|
just like the original pools.lib implementation.
|
||||||
|
|
||||||
|
|
||||||
|
c.lib 1.216 (xxx)
|
||||||
|
|
||||||
|
- Add some wchar and multibyte-string related functions to allow gcc
|
||||||
|
building a libstdc++ library with wide char support. For now, the
|
||||||
|
functions are mostly stub ones only. They can be implemented on
|
||||||
|
demand.
|
||||||
|
|
||||||
|
|
||||||
|
c.lib 1.215 (26.6.2017)
|
||||||
|
|
||||||
|
- Added -fno-aggressive-loop-optimizations option when building crtbegin.c
|
||||||
|
to work around constructor/destructor hack with GCC 5.4.0 on AmigaOS 4.
|
||||||
|
|
||||||
|
- Added -fno-builtin option to fix conflicts with builtin memset()
|
||||||
|
with GCC 5.4.0 on AmigaOS 4.
|
||||||
|
|
||||||
|
|
||||||
|
c.lib 1.214 (27.4.2017)
|
||||||
|
|
||||||
|
- Added integer overflow test to calloc().
|
||||||
|
|
||||||
|
- Tiny change in getopt_long() so that the value pointed to by longindex
|
||||||
|
is always initialized to an invalid index position (that being -1),
|
||||||
|
instead of 0. The value of 0 can break some shell commands, most notably
|
||||||
|
GNU wget.
|
||||||
|
|
||||||
|
|
||||||
c.lib 1.213 (4.12.2016)
|
c.lib 1.213 (4.12.2016)
|
||||||
|
|
||||||
- Added the __decay_unused_slabs() function which brings all currently
|
- Added the __decay_unused_slabs() function which brings all currently
|
||||||
@@ -150,7 +310,7 @@ c.lib 1.206 (24.4.2015)
|
|||||||
|
|
||||||
- Removed the remains of all the stack extension and stack overflow/underflow
|
- Removed the remains of all the stack extension and stack overflow/underflow
|
||||||
checking code. It never actually worked. The bit that does work is the stack
|
checking code. It never actually worked. The bit that does work is the stack
|
||||||
usage measurement code, plus the bit that sets up the the custom stack
|
usage measurement code, plus the bit that sets up the custom stack
|
||||||
according to local setting or by calling a query function.
|
according to local setting or by calling a query function.
|
||||||
|
|
||||||
|
|
||||||
@@ -1328,7 +1488,7 @@ c.lib 1.187 (29.1.2005)
|
|||||||
adding/subtracting the local time zone.
|
adding/subtracting the local time zone.
|
||||||
|
|
||||||
- Changed the algorithm that calculates the number of days that have passed
|
- Changed the algorithm that calculates the number of days that have passed
|
||||||
so far as used by the the __convert_time() function and the conversion
|
so far as used by the __convert_time() function and the conversion
|
||||||
code in strftime().
|
code in strftime().
|
||||||
|
|
||||||
- Also changed the algorithm used by strftime() to produce the week numbers
|
- Also changed the algorithm used by strftime() to produce the week numbers
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: crtbegin.c,v 1.13 2010-08-21 11:37:03 obarthel Exp $
|
* crtbegin.c
|
||||||
*
|
*
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
@@ -48,7 +48,12 @@
|
|||||||
* Dummy constructor and destructor array. The linker script will put these at the
|
* Dummy constructor and destructor array. The linker script will put these at the
|
||||||
* very beginning of section ".ctors" and ".dtors". crtend.o contains a similar entry
|
* very beginning of section ".ctors" and ".dtors". crtend.o contains a similar entry
|
||||||
* with a NULL pointer entry and is put at the end of the sections. This way, the init
|
* with a NULL pointer entry and is put at the end of the sections. This way, the init
|
||||||
* code can find the global constructor/destructor pointers
|
* code can find the global constructor/destructor pointers.
|
||||||
|
*
|
||||||
|
* WARNING:
|
||||||
|
* This hack does not work correctly with GCC 5 and higher. The optimizer
|
||||||
|
* will see a one element array and act appropriately. The current workaround
|
||||||
|
* is to use -fno-aggressive-loop-optimizations when compiling this file.
|
||||||
*/
|
*/
|
||||||
static void (*__CTOR_LIST__[1]) (void) __attribute__(( used, section(".ctors"), aligned(sizeof(void (*)(void))) ));
|
static void (*__CTOR_LIST__[1]) (void) __attribute__(( used, section(".ctors"), aligned(sizeof(void (*)(void))) ));
|
||||||
static void (*__DTOR_LIST__[1]) (void) __attribute__(( used, section(".dtors"), aligned(sizeof(void (*)(void))) ));
|
static void (*__DTOR_LIST__[1]) (void) __attribute__(( used, section(".dtors"), aligned(sizeof(void (*)(void))) ));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 213
|
#define REVISION 215
|
||||||
#define DATE "4.12.2016"
|
#define DATE "26.6.2017"
|
||||||
#define VERS "debug.lib 1.213"
|
#define VERS "debug.lib 1.215"
|
||||||
#define VSTRING "debug.lib 1.213 (4.12.2016)\r\n"
|
#define VSTRING "debug.lib 1.215 (26.6.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: debug.lib 1.213 (4.12.2016)"
|
#define VERSTAG "\0$VER: debug.lib 1.215 (26.6.2017)"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
213
|
215
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ CLIB_DESTRUCTOR(dirent_exit)
|
|||||||
|
|
||||||
if(__directory_list.mlh_Head != NULL)
|
if(__directory_list.mlh_Head != NULL)
|
||||||
{
|
{
|
||||||
while(NOT IsListEmpty((struct List *)&__directory_list))
|
while(NOT IsMinListEmpty(&__directory_list))
|
||||||
closedir((DIR *)__directory_list.mlh_Head);
|
closedir((DIR *)__directory_list.mlh_Head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ opendir(const char * path_name)
|
|||||||
UnLockDosList(LDF_VOLUMES|LDF_READ);
|
UnLockDosList(LDF_VOLUMES|LDF_READ);
|
||||||
|
|
||||||
/* Bail out if we cannot present anything. */
|
/* Bail out if we cannot present anything. */
|
||||||
if(IsListEmpty((struct List *)&dh->dh_VolumeList))
|
if(IsMinListEmpty(&dh->dh_VolumeList))
|
||||||
{
|
{
|
||||||
__set_errno(ENOMEM);
|
__set_errno(ENOMEM);
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: dirent_readdir.c,v 1.10 2006-09-25 14:51:15 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -79,9 +77,11 @@ readdir(DIR * directory_pointer)
|
|||||||
|
|
||||||
dh->dh_Position++;
|
dh->dh_Position++;
|
||||||
|
|
||||||
dh->dh_DirectoryEntry.d_ino = 0;
|
|
||||||
strcpy(dh->dh_DirectoryEntry.d_name,".");
|
strcpy(dh->dh_DirectoryEntry.d_name,".");
|
||||||
|
|
||||||
|
dh->dh_DirectoryEntry.d_ino = 0;
|
||||||
|
dh->dh_DirectoryEntry.d_type = DT_DIR;
|
||||||
|
|
||||||
result = &dh->dh_DirectoryEntry;
|
result = &dh->dh_DirectoryEntry;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -93,7 +93,7 @@ readdir(DIR * directory_pointer)
|
|||||||
|
|
||||||
assert( (((ULONG)name) & 3) == 0 );
|
assert( (((ULONG)name) & 3) == 0 );
|
||||||
|
|
||||||
if(dh->dh_VolumeNode == NULL && NOT IsListEmpty((struct List *)&dh->dh_VolumeList))
|
if(dh->dh_VolumeNode == NULL && NOT IsMinListEmpty(&dh->dh_VolumeList))
|
||||||
dh->dh_VolumeNode = (struct Node *)dh->dh_VolumeList.mlh_Head;
|
dh->dh_VolumeNode = (struct Node *)dh->dh_VolumeList.mlh_Head;
|
||||||
|
|
||||||
strcpy(name,"\1:"); /* BSTR for ":" */
|
strcpy(name,"\1:"); /* BSTR for ":" */
|
||||||
@@ -115,8 +115,9 @@ readdir(DIR * directory_pointer)
|
|||||||
assert( sizeof(dh->dh_DirectoryEntry.d_name) >= sizeof(fib->fib_FileName) );
|
assert( sizeof(dh->dh_DirectoryEntry.d_name) >= sizeof(fib->fib_FileName) );
|
||||||
|
|
||||||
strcpy(dh->dh_DirectoryEntry.d_name,fib->fib_FileName);
|
strcpy(dh->dh_DirectoryEntry.d_name,fib->fib_FileName);
|
||||||
|
|
||||||
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
|
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
|
||||||
|
dh->dh_DirectoryEntry.d_type = DT_DIR;
|
||||||
|
|
||||||
result = &dh->dh_DirectoryEntry;
|
result = &dh->dh_DirectoryEntry;
|
||||||
}
|
}
|
||||||
@@ -147,10 +148,11 @@ readdir(DIR * directory_pointer)
|
|||||||
|
|
||||||
dh->dh_Position++;
|
dh->dh_Position++;
|
||||||
|
|
||||||
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
|
|
||||||
|
|
||||||
strcpy(dh->dh_DirectoryEntry.d_name,".");
|
strcpy(dh->dh_DirectoryEntry.d_name,".");
|
||||||
|
|
||||||
|
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
|
||||||
|
dh->dh_DirectoryEntry.d_type = DT_DIR;
|
||||||
|
|
||||||
result = &dh->dh_DirectoryEntry;
|
result = &dh->dh_DirectoryEntry;
|
||||||
}
|
}
|
||||||
else if (dh->dh_Position == 1)
|
else if (dh->dh_Position == 1)
|
||||||
@@ -176,10 +178,11 @@ readdir(DIR * directory_pointer)
|
|||||||
|
|
||||||
SHOWMSG("returning ..");
|
SHOWMSG("returning ..");
|
||||||
|
|
||||||
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
|
|
||||||
|
|
||||||
strcpy(dh->dh_DirectoryEntry.d_name,"..");
|
strcpy(dh->dh_DirectoryEntry.d_name,"..");
|
||||||
|
|
||||||
|
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
|
||||||
|
dh->dh_DirectoryEntry.d_type = DT_DIR;
|
||||||
|
|
||||||
result = &dh->dh_DirectoryEntry;
|
result = &dh->dh_DirectoryEntry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,12 +195,23 @@ readdir(DIR * directory_pointer)
|
|||||||
|
|
||||||
if(ExNext(dh->dh_DirLock,&dh->dh_FileInfo))
|
if(ExNext(dh->dh_DirLock,&dh->dh_FileInfo))
|
||||||
{
|
{
|
||||||
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
|
int type;
|
||||||
|
|
||||||
assert( sizeof(dh->dh_DirectoryEntry.d_name) >= sizeof(dh->dh_FileInfo.fib_FileName) );
|
assert( sizeof(dh->dh_DirectoryEntry.d_name) >= sizeof(dh->dh_FileInfo.fib_FileName) );
|
||||||
|
|
||||||
strcpy(dh->dh_DirectoryEntry.d_name,dh->dh_FileInfo.fib_FileName);
|
strcpy(dh->dh_DirectoryEntry.d_name,dh->dh_FileInfo.fib_FileName);
|
||||||
|
|
||||||
|
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
|
||||||
|
|
||||||
|
if (dh->dh_FileInfo.fib_DirEntryType == ST_SOFTLINK)
|
||||||
|
type = DT_LNK;
|
||||||
|
else if (dh->dh_FileInfo.fib_DirEntryType < 0)
|
||||||
|
type = DT_REG;
|
||||||
|
else
|
||||||
|
type = DT_DIR;
|
||||||
|
|
||||||
|
dh->dh_DirectoryEntry.d_type = type;
|
||||||
|
|
||||||
result = &dh->dh_DirectoryEntry;
|
result = &dh->dh_DirectoryEntry;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ static int getopt_long_internal(int argc, const char **argv, const char *optstri
|
|||||||
optp = strchr(optstring, c);
|
optp = strchr(optstring, c);
|
||||||
|
|
||||||
/* We never find a long option in a compound option */
|
/* We never find a long option in a compound option */
|
||||||
*longindex = 0;
|
*longindex = -1;
|
||||||
|
|
||||||
/* Check if it's legal */
|
/* Check if it's legal */
|
||||||
if (c == ':' || (optp == NULL))
|
if (c == ':' || (optp == NULL))
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: dirent.h,v 1.7 2006-01-08 12:06:14 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -71,12 +69,41 @@ typedef long DIR;
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* The POSIX requirements for the 'struct dirent' cover little more than
|
||||||
|
* the 'd_ino' and 'd_name' fields. Because it is useful, the 'd_type'
|
||||||
|
* field identifies the type of object in question. This was added with
|
||||||
|
* clib2 1.217 (10.7.2025), and you can find out if the 'd_type' field
|
||||||
|
* is available in the 'struct dirent' by checking if the
|
||||||
|
* _DIRENT_HAVE_D_TYPE macro is defined.
|
||||||
|
*/
|
||||||
struct dirent
|
struct dirent
|
||||||
{
|
{
|
||||||
ino_t d_ino;
|
ino_t d_ino;
|
||||||
char d_name[NAME_MAX+1];
|
char d_name[NAME_MAX+1];
|
||||||
|
int d_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define _DIRENT_HAVE_D_TYPE
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Note that the directory entry type is not a POSIX feature, but it will
|
||||||
|
* make life easier for porting code which expects the 'd_type' structure
|
||||||
|
* member in the 'struct dirent'.
|
||||||
|
*
|
||||||
|
* The following types are not all supported on the Amiga. For the time being,
|
||||||
|
* DT_DIR (directory), DT_REG (regular file) and DT_LNK (soft link) should make
|
||||||
|
* sense.
|
||||||
|
*/
|
||||||
|
#define DT_UNKNOWN 0
|
||||||
|
#define DT_FIFO 1
|
||||||
|
#define DT_CHR 2
|
||||||
|
#define DT_DIR 4
|
||||||
|
#define DT_BLK 6
|
||||||
|
#define DT_REG 8
|
||||||
|
#define DT_LNK 10
|
||||||
|
#define DT_SOCK 12
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
extern DIR * opendir(const char * path_name);
|
extern DIR * opendir(const char * path_name);
|
||||||
|
|||||||
@@ -359,7 +359,7 @@ extern unsigned int (* __get_default_stack_size)(void);
|
|||||||
/*
|
/*
|
||||||
* This library falls back onto locale.library to perform string collation
|
* This library falls back onto locale.library to perform string collation
|
||||||
* in strcoll(), character conversion in toupper() and various other
|
* in strcoll(), character conversion in toupper() and various other
|
||||||
* functions. This may not your intention. To restrict the library to use
|
* functions. This may not be your intention. To restrict the library to use
|
||||||
* only the "C" language locale, declare the following variable in your
|
* only the "C" language locale, declare the following variable in your
|
||||||
* code and set it to FALSE, so that it overrides the default settings.
|
* code and set it to FALSE, so that it overrides the default settings.
|
||||||
* The variable value is checked during program startup and, if set to
|
* The variable value is checked during program startup and, if set to
|
||||||
|
|||||||
@@ -166,6 +166,8 @@ extern int errno;
|
|||||||
|
|
||||||
#define EILSEQ 85 /* Encoding error detected */
|
#define EILSEQ 85 /* Encoding error detected */
|
||||||
|
|
||||||
|
#define ENOTSUP 86 /* Not supported */
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: locale.h,v 1.5 2006-01-08 12:06:14 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -59,6 +57,13 @@ extern "C" {
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Forward declaration */
|
||||||
|
struct __locale_t;
|
||||||
|
|
||||||
|
typedef struct __locale_t *locale_t;
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
struct lconv
|
struct lconv
|
||||||
{
|
{
|
||||||
char * decimal_point; /* Decimal point character (non-monetary). */
|
char * decimal_point; /* Decimal point character (non-monetary). */
|
||||||
|
|||||||
@@ -61,7 +61,11 @@ extern "C" {
|
|||||||
|
|
||||||
typedef int ptrdiff_t;
|
typedef int ptrdiff_t;
|
||||||
typedef unsigned int size_t;
|
typedef unsigned int size_t;
|
||||||
|
|
||||||
|
/* wchar_t is a built-in type in C++ */
|
||||||
|
#ifndef __cplusplus
|
||||||
typedef unsigned short wchar_t;
|
typedef unsigned short wchar_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,10 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#endif /* _STDDEF_H */
|
#endif /* _STDDEF_H */
|
||||||
|
|
||||||
|
#ifndef _SYS_CLIB2_STDC_H
|
||||||
|
#include <sys/clib2_stdc.h>
|
||||||
|
#endif /* _SYS_CLIB2_STDC_H */
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -365,7 +369,7 @@ void __get_slab_allocations(__slab_allocation_callback callback);
|
|||||||
* You supply a function which will be called for each line of the JSON
|
* You supply a function which will be called for each line of the JSON
|
||||||
* data produced. You can store this data in a file, or in the clipboard,
|
* data produced. You can store this data in a file, or in the clipboard,
|
||||||
* for later use. Your function must return 0 if it wants to be called
|
* for later use. Your function must return 0 if it wants to be called
|
||||||
* again, or return -1 if it wants to stop (e.g. if an error occured
|
* again, or return -1 if it wants to stop (e.g. if an error occurred
|
||||||
* when writing the JSON data to disk). The same "user_data" pointer which
|
* when writing the JSON data to disk). The same "user_data" pointer which
|
||||||
* you pass to __get_slab_stats() will be passed to your callback function.
|
* you pass to __get_slab_stats() will be passed to your callback function.
|
||||||
*
|
*
|
||||||
@@ -447,6 +451,11 @@ extern lldiv_t lldiv(long long n,long long d);
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
extern int mbtowc(wchar_t *restrict pwc, const char *restrict s, size_t n);
|
||||||
|
extern int wctomb(char *s, wchar_t wchar);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
#endif /* __GNUC__ || (__STDC_VERSION__ && __STDC_VERSION__ >= 199901L) */
|
#endif /* __GNUC__ || (__STDC_VERSION__ && __STDC_VERSION__ >= 199901L) */
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ extern int strcmp(const char *s1, const char * s2);
|
|||||||
extern int strncmp(const char *s1, const char *s2, size_t n);
|
extern int strncmp(const char *s1, const char *s2, size_t n);
|
||||||
extern char *strcpy(char *dest, const char *src);
|
extern char *strcpy(char *dest, const char *src);
|
||||||
extern char *strncpy(char *dest, const char *src, size_t n);
|
extern char *strncpy(char *dest, const char *src, size_t n);
|
||||||
|
extern size_t strnlen(const char *s, size_t maxlen);
|
||||||
extern size_t strlen(const char *s);
|
extern size_t strlen(const char *s);
|
||||||
extern char *strchr(const char *s, int c);
|
extern char *strchr(const char *s, int c);
|
||||||
extern char *strrchr(const char *s, int c);
|
extern char *strrchr(const char *s, int c);
|
||||||
|
|||||||
73
library/include/sys/param.h
Normal file
73
library/include/sys/param.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* $Id: $
|
||||||
|
*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2017 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*****************************************************************************
|
||||||
|
*
|
||||||
|
* Documentation and source code for this library, and the most recent library
|
||||||
|
* build are available from <https://github.com/adtools/clib2>.
|
||||||
|
*
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_PARAM_H
|
||||||
|
#define _SYS_PARAM_H
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* The following is not part of the ISO 'C' (1994) standard. */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif /* _UNISTD_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||||
|
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* _SYS_MOUNT_H */
|
||||||
@@ -106,10 +106,24 @@ extern size_t strftime(char *s, size_t maxsize, const char *format,
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Timespec declaration */
|
||||||
|
struct timespec
|
||||||
|
{
|
||||||
|
time_t tv_secs;
|
||||||
|
long tv_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef tv_sec
|
||||||
|
#define tv_sec tv_secs
|
||||||
|
#endif /* tv_sec */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
extern char * asctime_r(const struct tm *tm,char * buffer);
|
extern char * asctime_r(const struct tm *tm,char * buffer);
|
||||||
extern char * ctime_r(const time_t *tptr,char * buffer);
|
extern char * ctime_r(const time_t *tptr,char * buffer);
|
||||||
extern struct tm * gmtime_r(const time_t *t,struct tm * tm_ptr);
|
extern struct tm * gmtime_r(const time_t *t,struct tm * tm_ptr);
|
||||||
extern struct tm * localtime_r(const time_t *t,struct tm * tm_ptr);
|
extern struct tm * localtime_r(const time_t *t,struct tm * tm_ptr);
|
||||||
|
extern void tzset(void);
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ extern int readlink(const char * path_name, char * buffer, int buffer_size);
|
|||||||
extern int chdir(const char * path_name);
|
extern int chdir(const char * path_name);
|
||||||
extern int lockf(int file_descriptor, int function, off_t size);
|
extern int lockf(int file_descriptor, int function, off_t size);
|
||||||
extern unsigned int sleep(unsigned int seconds);
|
extern unsigned int sleep(unsigned int seconds);
|
||||||
extern void usleep(unsigned long microseconds);
|
extern int usleep(unsigned long microseconds);
|
||||||
extern int getopt(int argc, char * const argv[], const char *opts);
|
extern int getopt(int argc, char * const argv[], const char *opts);
|
||||||
extern pid_t getpid(void);
|
extern pid_t getpid(void);
|
||||||
extern char *realpath(const char *file_name, char *resolved_name);
|
extern char *realpath(const char *file_name, char *resolved_name);
|
||||||
|
|||||||
@@ -43,6 +43,10 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _SYS_CLIB2_STDC_H
|
||||||
|
#include <sys/clib2_stdc.h>
|
||||||
|
#endif /* _SYS_CLIB2_STDC_H */
|
||||||
|
|
||||||
#ifndef _STDDEF_H
|
#ifndef _STDDEF_H
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#endif /* _STDDEF_H */
|
#endif /* _STDDEF_H */
|
||||||
@@ -59,6 +63,14 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#endif /* _TIME_H */
|
#endif /* _TIME_H */
|
||||||
|
|
||||||
|
#ifndef _LOCALE_H
|
||||||
|
#include <locale.h>
|
||||||
|
#endif /* _LOCALE_H */
|
||||||
|
|
||||||
|
#ifndef _STDINT_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -68,8 +80,6 @@ extern "C" {
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
#define WEOF (-1)
|
#define WEOF (-1)
|
||||||
#define WCHAR_MAX 65535
|
|
||||||
#define WCHAR_MIN 0
|
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
@@ -81,7 +91,6 @@ typedef long mbstate_t;
|
|||||||
extern wint_t btowc(int c);
|
extern wint_t btowc(int c);
|
||||||
extern int wctob(wint_t c);
|
extern int wctob(wint_t c);
|
||||||
extern int mbsinit(const mbstate_t *ps);
|
extern int mbsinit(const mbstate_t *ps);
|
||||||
extern size_t mbrlen(wchar_t *pwc, const char * s, size_t n, mbstate_t *ps);
|
|
||||||
extern size_t wcrtomb(char *s, wchar_t wc, mbstate_t *ps);
|
extern size_t wcrtomb(char *s, wchar_t wc, mbstate_t *ps);
|
||||||
extern size_t mbsrtowcs(wchar_t *pwcs, const char **src, size_t n, mbstate_t *ps);
|
extern size_t mbsrtowcs(wchar_t *pwcs, const char **src, size_t n, mbstate_t *ps);
|
||||||
extern size_t wcsrtombs(char *s, const wchar_t **src, size_t n, mbstate_t *ps);
|
extern size_t wcsrtombs(char *s, const wchar_t **src, size_t n, mbstate_t *ps);
|
||||||
@@ -161,7 +170,7 @@ extern int swprintf(wchar_t *s, const wchar_t *format, ...);
|
|||||||
|
|
||||||
extern int vfwprintf(FILE *stream,const wchar_t *format,va_list arg);
|
extern int vfwprintf(FILE *stream,const wchar_t *format,va_list arg);
|
||||||
extern int vwprintf(const wchar_t *format,va_list arg);
|
extern int vwprintf(const wchar_t *format,va_list arg);
|
||||||
extern int vswprintf(char *s, const wchar_t *format,va_list arg);
|
extern int vswprintf(wchar_t *s, size_t maxlen, const wchar_t *format, va_list arg);
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
@@ -174,16 +183,24 @@ extern size_t wcsftime(wchar_t *s, size_t maxsize, const wchar_t *format, const
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || defined(__cplusplus)
|
||||||
|
|
||||||
|
extern size_t mbrlen(const char *restrict s, size_t n, mbstate_t *restrict ps);
|
||||||
|
extern size_t mbrtowc(wchar_t *restrict pwc, const char *restrict s, size_t n, mbstate_t *restrict ps);
|
||||||
|
extern int mbsinit(const mbstate_t *ps);
|
||||||
|
extern size_t mbsnrtowcs(wchar_t *restrict dst, const char **restrict src, size_t nmc, size_t len, mbstate_t *restrict ps);
|
||||||
|
extern size_t mbsrtowcs(wchar_t *restrict dst, const char **restrict src, size_t len, mbstate_t *restrict ps);
|
||||||
|
|
||||||
|
extern size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict ps);
|
||||||
|
extern int wcscoll(const wchar_t *ws1, const wchar_t *ws2);
|
||||||
|
extern int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t loc);
|
||||||
|
extern size_t wcscspn(const wchar_t *s, const wchar_t *c);
|
||||||
|
extern size_t wcsnrtombs(char *restrict dst, const wchar_t **restrict src, size_t nwc, size_t len, mbstate_t *restrict ps);
|
||||||
|
extern wchar_t * wcsrchr(const wchar_t *ws, wchar_t wc);
|
||||||
|
extern size_t wcsrtombs(char *restrict dst, const wchar_t **restrict src, size_t len, mbstate_t *restrict ps);
|
||||||
extern long long wcstoll(const wchar_t *str, wchar_t **ptr, int base);
|
extern long long wcstoll(const wchar_t *str, wchar_t **ptr, int base);
|
||||||
extern unsigned long long wcstoull(const wchar_t *str, wchar_t **ptr, int base);
|
extern unsigned long long wcstoull(const wchar_t *str, wchar_t **ptr, int base);
|
||||||
|
|
||||||
extern size_t mbrtowc_l(wchar_t *restrict pwc, const char *restrict s, size_t n, mbstate_t *restrict ps, locale_t loc);
|
|
||||||
extern int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t loc);
|
|
||||||
extern size_t wcscspn(const wchar_t *ws1, const wchar_t *ws2);
|
|
||||||
extern wchar_t * wcsrchr(const wchar_t *ws, wchar_t wc);
|
|
||||||
|
|
||||||
#endif /* __STDC_VERSION__ && __STDC_VERSION__ >= 199901L */
|
#endif /* __STDC_VERSION__ && __STDC_VERSION__ >= 199901L */
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ AMIGA_LIB = \
|
|||||||
amiga_hotkey.o \
|
amiga_hotkey.o \
|
||||||
amiga_invertstring.o \
|
amiga_invertstring.o \
|
||||||
amiga_newlist.o \
|
amiga_newlist.o \
|
||||||
|
amiga_pools.o \
|
||||||
amiga_rangerand.o \
|
amiga_rangerand.o \
|
||||||
amiga_remtof.o \
|
amiga_remtof.o \
|
||||||
amiga_rexxvars.o \
|
amiga_rexxvars.o \
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ LIBS += \
|
|||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
# Olaf (2019-08-22): Please note that "profile_profil.o" can no longer
|
||||||
|
# be built, presumably for lack of header files needed
|
||||||
|
# to build it properly.
|
||||||
|
|
||||||
C_LIB := \
|
C_LIB := \
|
||||||
c.lib_rev.o \
|
c.lib_rev.o \
|
||||||
ctype_isalnum.o \
|
ctype_isalnum.o \
|
||||||
@@ -66,7 +70,6 @@ C_LIB := \
|
|||||||
mount_convertinfo.o \
|
mount_convertinfo.o \
|
||||||
mount_fstatfs.o \
|
mount_fstatfs.o \
|
||||||
mount_statfs.o \
|
mount_statfs.o \
|
||||||
profile_profil.o \
|
|
||||||
signal_checkabort.o \
|
signal_checkabort.o \
|
||||||
signal_data.o \
|
signal_data.o \
|
||||||
signal_kill.o \
|
signal_kill.o \
|
||||||
@@ -234,6 +237,7 @@ C_LIB := \
|
|||||||
stdlib_main_stub.o \
|
stdlib_main_stub.o \
|
||||||
stdlib_malloc.o \
|
stdlib_malloc.o \
|
||||||
stdlib_math.o \
|
stdlib_math.o \
|
||||||
|
stdlib_mbtowc.o \
|
||||||
stdlib_mkdtemp.o \
|
stdlib_mkdtemp.o \
|
||||||
stdlib_mkstemp.o \
|
stdlib_mkstemp.o \
|
||||||
stdlib_mktemp.o \
|
stdlib_mktemp.o \
|
||||||
@@ -310,6 +314,7 @@ C_LIB := \
|
|||||||
string_strncat.o \
|
string_strncat.o \
|
||||||
string_strncmp.o \
|
string_strncmp.o \
|
||||||
string_strncpy.o \
|
string_strncpy.o \
|
||||||
|
string_strnlen.o \
|
||||||
string_strpbrk.o \
|
string_strpbrk.o \
|
||||||
string_strrchr.o \
|
string_strrchr.o \
|
||||||
string_strspn.o \
|
string_strspn.o \
|
||||||
@@ -336,6 +341,7 @@ C_LIB := \
|
|||||||
time_numbertostring.o \
|
time_numbertostring.o \
|
||||||
time_strftime.o \
|
time_strftime.o \
|
||||||
time_time.o \
|
time_time.o \
|
||||||
|
time_tzset.o \
|
||||||
time_weekday.o \
|
time_weekday.o \
|
||||||
uio_readv.o \
|
uio_readv.o \
|
||||||
uio_writev.o \
|
uio_writev.o \
|
||||||
@@ -372,7 +378,79 @@ C_LIB := \
|
|||||||
unistd_unlink.o \
|
unistd_unlink.o \
|
||||||
unistd_usleep.o \
|
unistd_usleep.o \
|
||||||
utime_utime.o \
|
utime_utime.o \
|
||||||
utsname_uname.o
|
utsname_uname.o \
|
||||||
|
wchar_btowc.o \
|
||||||
|
wchar_fgetwc.o \
|
||||||
|
wchar_fgetws.o \
|
||||||
|
wchar_fputwc.o \
|
||||||
|
wchar_fputws.o \
|
||||||
|
wchar_fwide.o \
|
||||||
|
wchar_fwprintf.o \
|
||||||
|
wchar_fwscanf.o \
|
||||||
|
wchar_getwc.o \
|
||||||
|
wchar_getwchar.o \
|
||||||
|
wchar_mbrlen.o \
|
||||||
|
wchar_mbrtowc.o \
|
||||||
|
wchar_mbsinit.o \
|
||||||
|
wchar_mbsrtowcs.o \
|
||||||
|
wchar_putwc.o \
|
||||||
|
wchar_putwchar.o \
|
||||||
|
wchar_swprintf.o \
|
||||||
|
wchar_swscanf.o \
|
||||||
|
wchar_ungetwc.o \
|
||||||
|
wchar_vfwprintf.o \
|
||||||
|
wchar_vswprintf.o \
|
||||||
|
wchar_vwprintf.o \
|
||||||
|
wchar_wcrtomb.o \
|
||||||
|
wchar_wcscat.o \
|
||||||
|
wchar_wcschr.o \
|
||||||
|
wchar_wcscmp.o \
|
||||||
|
wchar_wcscoll.o \
|
||||||
|
wchar_wcscpy.o \
|
||||||
|
wchar_wcscspn.o \
|
||||||
|
wchar_wcsftime.o \
|
||||||
|
wchar_wcslen.o \
|
||||||
|
wchar_wcsncat.o \
|
||||||
|
wchar_wcsncmp.o \
|
||||||
|
wchar_wcsncpy.o \
|
||||||
|
wchar_wscoll.o \
|
||||||
|
wchar_wcspbrk.o \
|
||||||
|
wchar_wcsrtombs.o \
|
||||||
|
wchar_wcsspn.o \
|
||||||
|
wchar_wcstod.o \
|
||||||
|
wchar_wcstok.o \
|
||||||
|
wchar_wcstol.o \
|
||||||
|
wchar_wcstoll.o \
|
||||||
|
wchar_wcstoul.o \
|
||||||
|
wchar_wcstoull.o \
|
||||||
|
wchar_wcsxfrm.o \
|
||||||
|
wchar_wctob.o \
|
||||||
|
wchar_wmemchr.o \
|
||||||
|
wchar_wmemcmp.o \
|
||||||
|
wchar_wmemcpy.o \
|
||||||
|
wchar_wmemmove.o \
|
||||||
|
wchar_wmemset.o \
|
||||||
|
wchar_wprintf.o \
|
||||||
|
wchar_wscanf.o \
|
||||||
|
wchar_wscoll.o \
|
||||||
|
wctype_iswalnum.o \
|
||||||
|
wctype_iswalpha.o \
|
||||||
|
wctype_iswblank.o \
|
||||||
|
wctype_iswcntrl.o \
|
||||||
|
wctype_iswctype.o \
|
||||||
|
wctype_iswdigit.o \
|
||||||
|
wctype_iswgraph.o \
|
||||||
|
wctype_iswlower.o \
|
||||||
|
wctype_iswprint.o \
|
||||||
|
wctype_iswpunc.o \
|
||||||
|
wctype_iswspace.o \
|
||||||
|
wctype_iswupper.o \
|
||||||
|
wctype_iswxdigit.o \
|
||||||
|
wctype_towctrans.o \
|
||||||
|
wctype_towlower.o \
|
||||||
|
wctype_towupper.o \
|
||||||
|
wctype_wctrans.o \
|
||||||
|
wctype_wctype.o
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -22,13 +22,13 @@ LIBS += \
|
|||||||
UNIX_LIB := \
|
UNIX_LIB := \
|
||||||
unix.lib_rev.o \
|
unix.lib_rev.o \
|
||||||
dirent_closedir.o \
|
dirent_closedir.o \
|
||||||
dirent_rewinddir.o \
|
|
||||||
dirent_opendir.o \
|
dirent_opendir.o \
|
||||||
dirent_readdir.o \
|
dirent_readdir.o \
|
||||||
|
dirent_rewinddir.o \
|
||||||
fcntl_creat.o \
|
fcntl_creat.o \
|
||||||
fcntl_fcntl.o \
|
fcntl_fcntl.o \
|
||||||
fcntl_open.o \
|
|
||||||
fcntl_get_default_file.o \
|
fcntl_get_default_file.o \
|
||||||
|
fcntl_open.o \
|
||||||
getopt_getopt_long.o \
|
getopt_getopt_long.o \
|
||||||
mount_convertinfo.o \
|
mount_convertinfo.o \
|
||||||
mount_statfs.o \
|
mount_statfs.o \
|
||||||
@@ -36,16 +36,16 @@ UNIX_LIB := \
|
|||||||
resource_setrlimit.o \
|
resource_setrlimit.o \
|
||||||
stat_chmod.o \
|
stat_chmod.o \
|
||||||
stat_fstat.o \
|
stat_fstat.o \
|
||||||
stat_lstat.o \
|
|
||||||
stat_lock.o \
|
stat_lock.o \
|
||||||
|
stat_lstat.o \
|
||||||
stat_mkdir.o \
|
stat_mkdir.o \
|
||||||
stat_rmdir.o \
|
stat_rmdir.o \
|
||||||
stat_stat.o \
|
stat_stat.o \
|
||||||
stdio_ctermid.o \
|
stdio_ctermid.o \
|
||||||
stdio_fdhookentry.o \
|
stdio_fdhookentry.o \
|
||||||
stdio_fflush.o \
|
stdio_fflush.o \
|
||||||
stdio_fopen.o \
|
|
||||||
stdio_file_init.o \
|
stdio_file_init.o \
|
||||||
|
stdio_fopen.o \
|
||||||
stdio_init_exit.o \
|
stdio_init_exit.o \
|
||||||
stdio_locksemaphorename.o \
|
stdio_locksemaphorename.o \
|
||||||
stdio_openiob.o \
|
stdio_openiob.o \
|
||||||
@@ -60,15 +60,17 @@ UNIX_LIB := \
|
|||||||
stdlib_dlopen.o \
|
stdlib_dlopen.o \
|
||||||
stdlib_expand_wildcard.o \
|
stdlib_expand_wildcard.o \
|
||||||
stdlib_expand_wildcard_check.o \
|
stdlib_expand_wildcard_check.o \
|
||||||
|
stdlib_free.o \
|
||||||
stdlib_getmemstats.o \
|
stdlib_getmemstats.o \
|
||||||
stdlib_main.o \
|
stdlib_main.o \
|
||||||
stdlib_main_stub.o \
|
stdlib_main_stub.o \
|
||||||
|
stdlib_malloc.o \
|
||||||
stdlib_mkdtemp.o \
|
stdlib_mkdtemp.o \
|
||||||
stdlib_mkstemp.o \
|
stdlib_mkstemp.o \
|
||||||
stdlib_mktemp.o \
|
stdlib_mktemp.o \
|
||||||
stdlib_malloc.o \
|
|
||||||
stdlib_realloc.o \
|
stdlib_realloc.o \
|
||||||
stdlib_resetmemstats.o \
|
stdlib_resetmemstats.o \
|
||||||
|
stdlib_slab.o \
|
||||||
stdlib_system.o \
|
stdlib_system.o \
|
||||||
systeminfo_sysinfo.o \
|
systeminfo_sysinfo.o \
|
||||||
termios_cfgetispeed.o \
|
termios_cfgetispeed.o \
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 213
|
#define REVISION 215
|
||||||
#define DATE "4.12.2016"
|
#define DATE "26.6.2017"
|
||||||
#define VERS "m.lib 1.213"
|
#define VERS "m.lib 1.215"
|
||||||
#define VSTRING "m.lib 1.213 (4.12.2016)\r\n"
|
#define VSTRING "m.lib 1.215 (26.6.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: m.lib 1.213 (4.12.2016)"
|
#define VERSTAG "\0$VER: m.lib 1.215 (26.6.2017)"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
213
|
215
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 213
|
#define REVISION 214
|
||||||
#define DATE "4.12.2016"
|
#define DATE "27.4.2017"
|
||||||
#define VERS "m881.lib 1.213"
|
#define VERS "m881.lib 1.214"
|
||||||
#define VSTRING "m881.lib 1.213 (4.12.2016)\r\n"
|
#define VSTRING "m881.lib 1.214 (27.4.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: m881.lib 1.213 (4.12.2016)"
|
#define VERSTAG "\0$VER: m881.lib 1.214 (27.4.2017)"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
213
|
214
|
||||||
|
|||||||
@@ -93,6 +93,13 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef IsMinListEmpty
|
||||||
|
#define IsMinListEmpty(ml) \
|
||||||
|
((struct MinList *)((ml)->mlh_TailPred) == (struct MinList *)(ml))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
#ifndef AMIGA_COMPILER_H
|
#ifndef AMIGA_COMPILER_H
|
||||||
|
|
||||||
#ifdef __SASC
|
#ifdef __SASC
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: math_sqrt.c,v 1.9 2006-09-22 07:54:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -251,7 +249,8 @@ sqrt(double x)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = 0;
|
result = NAN;
|
||||||
|
|
||||||
__set_errno(EDOM);
|
__set_errno(EDOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: math_tgamma.c,v 1.3 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -54,13 +52,11 @@ double
|
|||||||
tgamma(double x)
|
tgamma(double x)
|
||||||
{
|
{
|
||||||
int gamma_sign;
|
int gamma_sign;
|
||||||
double y;
|
double y;
|
||||||
|
|
||||||
y = __lgamma(x,&gamma_sign);
|
y = __lgamma(x, &gamma_sign);
|
||||||
if (gamma_sign < 0)
|
|
||||||
y = -y;
|
|
||||||
|
|
||||||
return y;
|
return gamma_sign * exp(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: math_tgammaf.c,v 1.3 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
@@ -56,11 +54,9 @@ tgammaf(float x)
|
|||||||
int gamma_sign;
|
int gamma_sign;
|
||||||
float y;
|
float y;
|
||||||
|
|
||||||
y = __lgammaf(x,&gamma_sign);
|
y = __lgammaf(x, &gamma_sign);
|
||||||
if (gamma_sign < 0)
|
|
||||||
y = -y;
|
|
||||||
|
|
||||||
return y;
|
return gamma_sign * expf(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 213
|
#define REVISION 215
|
||||||
#define DATE "4.12.2016"
|
#define DATE "26.6.2017"
|
||||||
#define VERS "net.lib 1.213"
|
#define VERS "net.lib 1.215"
|
||||||
#define VSTRING "net.lib 1.213 (4.12.2016)\r\n"
|
#define VSTRING "net.lib 1.215 (26.6.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: net.lib 1.213 (4.12.2016)"
|
#define VERSTAG "\0$VER: net.lib 1.215 (26.6.2017)"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
213
|
215
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ profil(unsigned short *buffer, size_t bufSize, size_t offset, unsigned int scale
|
|||||||
ProfileData.CounterStart = GetCounterStart();
|
ProfileData.CounterStart = GetCounterStart();
|
||||||
|
|
||||||
/* Set interrupt vector */
|
/* Set interrupt vector */
|
||||||
CounterInt.is_Code = (void (*)())CounterIntFn;
|
CounterInt.is_Code = (void (*)(void))CounterIntFn;
|
||||||
CounterInt.is_Data = &ProfileData;
|
CounterInt.is_Data = &ProfileData;
|
||||||
IPM->SetInterruptVector(1, &CounterInt);
|
IPM->SetInterruptVector(1, &CounterInt);
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ raise(int sig)
|
|||||||
assert( SIGABRT <= sig && sig <= SIGTERM );
|
assert( SIGABRT <= sig && sig <= SIGTERM );
|
||||||
|
|
||||||
/* This has to be a well-known and supported signal. */
|
/* This has to be a well-known and supported signal. */
|
||||||
if(sig < SIGABRT || sig > SIGTERM)
|
if (sig < SIGABRT || sig > SIGTERM)
|
||||||
{
|
{
|
||||||
SHOWMSG("unknown signal number");
|
SHOWMSG("unknown signal number");
|
||||||
|
|
||||||
@@ -80,48 +80,49 @@ raise(int sig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Can we deliver the signal? */
|
/* Can we deliver the signal? */
|
||||||
if(FLAG_IS_CLEAR(__signals_blocked, (1 << sig)) &&
|
if (FLAG_IS_CLEAR(__signals_blocked, (1 << sig)) &&
|
||||||
FLAG_IS_CLEAR(local_signals_blocked, (1 << sig)))
|
FLAG_IS_CLEAR(local_signals_blocked, (1 << sig)))
|
||||||
{
|
{
|
||||||
signal_handler_t handler;
|
signal_handler_t handler;
|
||||||
|
|
||||||
/* Which handler is installed for this signal? */
|
/* Which handler is installed for this signal? */
|
||||||
handler = __signal_handler_table[sig - SIGABRT];
|
handler = __signal_handler_table[sig - SIGABRT];
|
||||||
|
|
||||||
/* Should we ignore this signal? */
|
/* Should we handle this signal rather than ignoring it? */
|
||||||
if(handler != SIG_IGN)
|
if (handler != SIG_IGN)
|
||||||
{
|
{
|
||||||
/* Block delivery of this signal to prevent recursion. */
|
/* Block delivery of this signal to prevent recursion. */
|
||||||
SET_FLAG(local_signals_blocked,(1 << sig));
|
SET_FLAG(local_signals_blocked, (1 << sig));
|
||||||
|
|
||||||
/* The default behaviour is to drop into abort(), or do
|
/* The default behaviour is to drop into abort(), or do
|
||||||
something very much like it. */
|
* something very much like it.
|
||||||
if(handler == SIG_DFL)
|
*/
|
||||||
|
if (handler == SIG_DFL)
|
||||||
{
|
{
|
||||||
SHOWMSG("this is the default handler");
|
SHOWMSG("this is the default handler");
|
||||||
|
|
||||||
if(sig == SIGINT)
|
if (sig == SIGINT)
|
||||||
{
|
{
|
||||||
char break_string[80];
|
char break_string[80];
|
||||||
|
|
||||||
/* Turn off ^C checking for good. */
|
/* Turn off ^C checking for good. */
|
||||||
__check_abort_enabled = FALSE;
|
__check_abort_enabled = FALSE;
|
||||||
|
|
||||||
Fault(ERROR_BREAK,NULL,break_string,(LONG)sizeof(break_string));
|
Fault(ERROR_BREAK, NULL, break_string, (LONG)sizeof(break_string));
|
||||||
|
|
||||||
__print_termination_message(break_string);
|
__print_termination_message(break_string);
|
||||||
|
|
||||||
SHOWMSG("bye, bye...");
|
SHOWMSG("bye, bye...");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop straight into abort(), which might call signal()
|
/* Drop straight into __abort(), which will
|
||||||
again but is otherwise guaranteed to eventually
|
eventually land us in _exit(). Note that
|
||||||
land us in _exit(). */
|
abort() calls raise(SIGABRT). */
|
||||||
abort();
|
__abort();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SHOWMSG("calling the handler");
|
SHOWMSG("calling the signal handler");
|
||||||
|
|
||||||
(*handler)(sig);
|
(*handler)(sig);
|
||||||
|
|
||||||
@@ -129,7 +130,7 @@ raise(int sig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Unblock signal delivery again. */
|
/* Unblock signal delivery again. */
|
||||||
CLEAR_FLAG(local_signals_blocked,(1 << sig));
|
CLEAR_FLAG(local_signals_blocked, (1 << sig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_fgets.c,v 1.6 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -46,6 +44,7 @@
|
|||||||
char *
|
char *
|
||||||
fgets(char *s,int n,FILE *stream)
|
fgets(char *s,int n,FILE *stream)
|
||||||
{
|
{
|
||||||
|
struct iob * file = (struct iob *)stream;
|
||||||
char * result = s;
|
char * result = s;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
@@ -57,14 +56,14 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
|
|
||||||
assert( s != NULL && stream != NULL );
|
assert( s != NULL && stream != NULL );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
flockfile(stream);
|
flockfile(stream);
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(s == NULL || stream == NULL)
|
if (s == NULL || stream == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("invalid parameters");
|
SHOWMSG("invalid parameters");
|
||||||
|
|
||||||
@@ -75,7 +74,7 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
}
|
}
|
||||||
#endif /* CHECK_FOR_NULL_POINTERS */
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||||
|
|
||||||
if(n <= 0)
|
if (n <= 0)
|
||||||
{
|
{
|
||||||
SHOWMSG("no work to be done");
|
SHOWMSG("no work to be done");
|
||||||
|
|
||||||
@@ -86,7 +85,7 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
/* Take care of the checks and data structure changes that
|
/* Take care of the checks and data structure changes that
|
||||||
* need to be handled only once for this stream.
|
* need to be handled only once for this stream.
|
||||||
*/
|
*/
|
||||||
if(__fgetc_check(stream) < 0)
|
if (__fgetc_check(stream) < 0)
|
||||||
{
|
{
|
||||||
result = NULL;
|
result = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -98,12 +97,83 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
/* One off for the terminating '\0'. */
|
/* One off for the terminating '\0'. */
|
||||||
n--;
|
n--;
|
||||||
|
|
||||||
while(n-- > 0)
|
assert( 0 <= file->iob_BufferReadBytes );
|
||||||
|
assert( file->iob_BufferReadBytes <= file->iob_BufferSize );
|
||||||
|
assert( file->iob_BufferPosition <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
while (n > 0)
|
||||||
{
|
{
|
||||||
c = __getc(stream);
|
/* If there is data in the buffer, try to copy it directly
|
||||||
if(c == EOF)
|
* into the string buffer. If there is a line feed in the
|
||||||
|
* buffer, too, try to conclude the read operation.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferPosition < file->iob_BufferReadBytes)
|
||||||
{
|
{
|
||||||
if(ferror(stream))
|
const unsigned char * buffer = &file->iob_Buffer[file->iob_BufferPosition];
|
||||||
|
size_t num_bytes_in_buffer;
|
||||||
|
const unsigned char * lf;
|
||||||
|
|
||||||
|
/* Copy only as much data as will fit into the string buffer. */
|
||||||
|
assert( file->iob_BufferReadBytes >= file->iob_BufferPosition );
|
||||||
|
|
||||||
|
num_bytes_in_buffer = file->iob_BufferReadBytes - file->iob_BufferPosition;
|
||||||
|
if (num_bytes_in_buffer > (size_t)n)
|
||||||
|
num_bytes_in_buffer = n;
|
||||||
|
|
||||||
|
/* Try to find a line feed character which could conclude
|
||||||
|
* the read operation if the remaining buffer data, including
|
||||||
|
* the line feed character, fit into the string buffer.
|
||||||
|
*/
|
||||||
|
lf = (unsigned char *)memchr(buffer, '\n', num_bytes_in_buffer);
|
||||||
|
if(lf != NULL)
|
||||||
|
{
|
||||||
|
size_t num_characters_in_line = lf + 1 - buffer;
|
||||||
|
|
||||||
|
/* Give the user a chance to abort what could otherwise
|
||||||
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
assert( num_characters_in_line <= num_bytes_in_buffer );
|
||||||
|
|
||||||
|
/* Copy the remainder of the read buffer into the
|
||||||
|
* string buffer, including the terminating line
|
||||||
|
* feed character.
|
||||||
|
*/
|
||||||
|
memmove(s, buffer, num_characters_in_line);
|
||||||
|
s += num_characters_in_line;
|
||||||
|
|
||||||
|
assert( file->iob_BufferPosition + num_characters_in_line <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferPosition += num_characters_in_line;
|
||||||
|
|
||||||
|
/* And that concludes the line read operation. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(s, buffer, num_bytes_in_buffer);
|
||||||
|
s += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
assert( file->iob_BufferPosition + num_bytes_in_buffer <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferPosition += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
/* Stop if the string buffer has been filled. */
|
||||||
|
assert( n >= num_bytes_in_buffer );
|
||||||
|
|
||||||
|
n -= num_bytes_in_buffer;
|
||||||
|
if (n == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the next buffered character; this will refill the read
|
||||||
|
* buffer, if necessary.
|
||||||
|
*/
|
||||||
|
c = __getc(stream);
|
||||||
|
if (c == EOF)
|
||||||
|
{
|
||||||
|
if (ferror(stream))
|
||||||
{
|
{
|
||||||
/* Just to be on the safe side. */
|
/* Just to be on the safe side. */
|
||||||
(*s) = '\0';
|
(*s) = '\0';
|
||||||
@@ -113,8 +183,9 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that we return NULL if we really
|
/* Make sure that we return NULL if we really
|
||||||
didn't read anything at all */
|
* didn't read anything at all.
|
||||||
if(s == result)
|
*/
|
||||||
|
if (s == result)
|
||||||
result = NULL;
|
result = NULL;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -122,8 +193,11 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
|
|
||||||
(*s++) = c;
|
(*s++) = c;
|
||||||
|
|
||||||
if(c == '\n')
|
if (c == '\n')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
assert( n > 0 );
|
||||||
|
n--;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*s) = '\0';
|
(*s) = '\0';
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_fputs.c,v 1.7 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -43,10 +41,12 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Both fputs() and puts() share this function. */
|
||||||
int
|
int
|
||||||
fputs(const char *s, FILE *stream)
|
__fputs(const char *s, int line_feed, FILE *stream)
|
||||||
{
|
{
|
||||||
struct iob * file = (struct iob *)stream;
|
struct iob * file = (struct iob *)stream;
|
||||||
|
size_t total_size;
|
||||||
int result = EOF;
|
int result = EOF;
|
||||||
int buffer_mode;
|
int buffer_mode;
|
||||||
int c;
|
int c;
|
||||||
@@ -58,12 +58,12 @@ fputs(const char *s, FILE *stream)
|
|||||||
|
|
||||||
assert( s != NULL && stream != NULL );
|
assert( s != NULL && stream != NULL );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(s == NULL || stream == NULL)
|
if (s == NULL || stream == NULL)
|
||||||
{
|
{
|
||||||
__set_errno(EFAULT);
|
__set_errno(EFAULT);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -77,37 +77,261 @@ fputs(const char *s, FILE *stream)
|
|||||||
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
||||||
assert( file->iob_BufferSize > 0 );
|
assert( file->iob_BufferSize > 0 );
|
||||||
|
|
||||||
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
|
if (__fputc_check(stream) < 0)
|
||||||
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
|
|
||||||
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
|
||||||
|
|
||||||
if(__fputc_check(stream) < 0)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
while((c = (*s++)) != '\0')
|
assert( 0 <= file->iob_BufferWriteBytes );
|
||||||
|
assert( file->iob_BufferWriteBytes <= file->iob_BufferSize );
|
||||||
|
assert( file->iob_BufferPosition <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
/* We perform line buffering to improve readability of the
|
||||||
|
* buffered text if buffering was disabled and the output
|
||||||
|
* goes to an interactive stream.
|
||||||
|
*/
|
||||||
|
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
|
||||||
|
if (buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||||
{
|
{
|
||||||
if(__putc(c,stream,buffer_mode) == EOF)
|
struct fd * fd = __fd[file->iob_Descriptor];
|
||||||
goto out;
|
|
||||||
|
__fd_lock(fd);
|
||||||
|
|
||||||
|
if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE))
|
||||||
|
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
||||||
|
|
||||||
|
__fd_unlock(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
total_size = strlen(s);
|
||||||
|
if (total_size > 0)
|
||||||
|
{
|
||||||
|
if (buffer_mode == IOBF_BUFFER_MODE_LINE)
|
||||||
|
{
|
||||||
|
while (total_size > 0)
|
||||||
|
{
|
||||||
|
/* Is there still room in the write buffer to store
|
||||||
|
* more of the string?
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
|
||||||
|
size_t num_buffer_bytes;
|
||||||
|
const char * lf;
|
||||||
|
|
||||||
|
/* Give the user a chance to abort what could otherwise
|
||||||
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
/* Store only as many characters as will fit into the write buffer. */
|
||||||
|
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
|
||||||
|
if (total_size < num_buffer_bytes)
|
||||||
|
num_buffer_bytes = total_size;
|
||||||
|
|
||||||
|
/* Try to find a line feed in the string. If there is one,
|
||||||
|
* reduce the number of characters to write to the sequence
|
||||||
|
* which ends with the line feed character.
|
||||||
|
*/
|
||||||
|
lf = memchr(s, '\n', num_buffer_bytes);
|
||||||
|
if (lf != NULL)
|
||||||
|
{
|
||||||
|
assert( (size_t)(lf + 1 - s) <= num_buffer_bytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = lf + 1 - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( num_buffer_bytes > 0 );
|
||||||
|
|
||||||
|
memmove(buffer, s, num_buffer_bytes);
|
||||||
|
s += num_buffer_bytes;
|
||||||
|
|
||||||
|
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferWriteBytes += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Write the buffer to disk if it's full or contains a line feed. */
|
||||||
|
if ((lf != NULL || __iob_write_buffer_is_full(file)) && __flush_iob_write_buffer(file) < 0)
|
||||||
|
{
|
||||||
|
/* Abort with error. */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stop as soon as no further data needs to be written. */
|
||||||
|
assert( total_size >= num_buffer_bytes );
|
||||||
|
|
||||||
|
total_size -= num_buffer_bytes;
|
||||||
|
if (total_size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If there is again room in the output buffer,
|
||||||
|
* repeat this optimization.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (*s++);
|
||||||
|
|
||||||
|
if (__putc_line_buffered(c, (FILE *)file) == EOF)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
total_size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||||
|
{
|
||||||
|
ssize_t num_bytes_written;
|
||||||
|
|
||||||
|
/* We bypass the buffer entirely. */
|
||||||
|
num_bytes_written = write(file->iob_Descriptor, s, total_size);
|
||||||
|
if (num_bytes_written == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (total_size > 0)
|
||||||
|
{
|
||||||
|
/* If there is more data to be written than the write buffer will hold
|
||||||
|
* and the write buffer is empty anyway, then we'll bypass the write
|
||||||
|
* buffer entirely.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes == 0 && total_size >= (size_t)file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
ssize_t num_bytes_written;
|
||||||
|
|
||||||
|
/* We bypass the buffer entirely. */
|
||||||
|
num_bytes_written = write(file->iob_Descriptor, s, total_size);
|
||||||
|
if (num_bytes_written == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is there still room in the write buffer to store
|
||||||
|
* more of the string?
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
|
||||||
|
size_t num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Give the user a chance to abort what could otherwise
|
||||||
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
/* Store only as many characters as will fit into the write buffer. */
|
||||||
|
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
|
||||||
|
if (total_size < num_buffer_bytes)
|
||||||
|
num_buffer_bytes = total_size;
|
||||||
|
|
||||||
|
assert( num_buffer_bytes > 0 );
|
||||||
|
|
||||||
|
memmove(buffer, s, num_buffer_bytes);
|
||||||
|
s += num_buffer_bytes;
|
||||||
|
|
||||||
|
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferWriteBytes += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Write a full buffer to disk. */
|
||||||
|
if (__iob_write_buffer_is_full(file) && __flush_iob_write_buffer(file) < 0)
|
||||||
|
{
|
||||||
|
/* Abort with error. */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stop as soon as no further data needs to be written. */
|
||||||
|
assert( total_size >= num_buffer_bytes );
|
||||||
|
|
||||||
|
total_size -= num_buffer_bytes;
|
||||||
|
if (total_size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If there is again room in the output buffer,
|
||||||
|
* try this optimization again.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (*s++);
|
||||||
|
|
||||||
|
if (__putc_fully_buffered(c, (FILE *)file) == EOF)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
total_size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line_feed != 0 && __putc(line_feed, stream, buffer_mode) == EOF)
|
||||||
|
goto out;
|
||||||
|
|
||||||
result = OK;
|
result = OK;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
/* Note: if buffering is disabled for this stream, then we still
|
/* Note: if buffering is disabled for this stream, then we still
|
||||||
may have buffered data around, queued to be printed right now.
|
* may have buffered data around, queued to be printed right now.
|
||||||
This is intended to improve performance as it takes more effort
|
* This is intended to improve performance as it takes more effort
|
||||||
to write a single character to a file than to write a bunch. */
|
* to write a single character to a file than to write a bunch.
|
||||||
if(result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
*/
|
||||||
|
if (result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
||||||
{
|
{
|
||||||
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
|
if (__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
|
||||||
{
|
{
|
||||||
SHOWMSG("couldn't flush the write buffer");
|
SHOWMSG("couldn't flush the write buffer");
|
||||||
result = EOF;
|
result = EOF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
funlockfile(stream);
|
if (stream != NULL)
|
||||||
|
funlockfile(stream);
|
||||||
|
|
||||||
|
RETURN(result);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
int
|
||||||
|
fputs(const char *s, FILE *stream)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
ENTER();
|
||||||
|
|
||||||
|
SHOWSTRING(s);
|
||||||
|
SHOWPOINTER(stream);
|
||||||
|
|
||||||
|
assert( s != NULL && stream != NULL );
|
||||||
|
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
|
{
|
||||||
|
if (s == NULL || stream == NULL)
|
||||||
|
{
|
||||||
|
__set_errno(EFAULT);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||||
|
|
||||||
|
result = __fputs(s, 0, stream);
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
return(result);
|
return(result);
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_fread.c,v 1.7 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -59,14 +57,14 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
assert( ptr != NULL && stream != NULL );
|
assert( ptr != NULL && stream != NULL );
|
||||||
assert( (int)element_size >= 0 && (int)count >= 0 );
|
assert( (int)element_size >= 0 && (int)count >= 0 );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
flockfile(stream);
|
flockfile(stream);
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(ptr == NULL || stream == NULL)
|
if (ptr == NULL || stream == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("invalid parameters");
|
SHOWMSG("invalid parameters");
|
||||||
|
|
||||||
@@ -80,7 +78,7 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
||||||
assert( file->iob_BufferSize > 0 );
|
assert( file->iob_BufferSize > 0 );
|
||||||
|
|
||||||
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_IN_USE))
|
if (FLAG_IS_CLEAR(file->iob_Flags, IOBF_IN_USE))
|
||||||
{
|
{
|
||||||
SHOWMSG("this file is not even in use");
|
SHOWMSG("this file is not even in use");
|
||||||
|
|
||||||
@@ -91,7 +89,7 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_READ))
|
if (FLAG_IS_CLEAR(file->iob_Flags, IOBF_READ))
|
||||||
{
|
{
|
||||||
SHOWMSG("this file is not read-enabled");
|
SHOWMSG("this file is not read-enabled");
|
||||||
|
|
||||||
@@ -102,29 +100,114 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(element_size > 0 && count > 0)
|
/* So that we can tell error and 'end of file' conditions apart. */
|
||||||
|
clearerr(stream);
|
||||||
|
|
||||||
|
if (element_size > 0 && count > 0)
|
||||||
{
|
{
|
||||||
size_t total_bytes_read = 0;
|
size_t total_bytes_read = 0;
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
unsigned char * data = ptr;
|
unsigned char * data = ptr;
|
||||||
|
ssize_t num_bytes_read;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if(__fgetc_check((FILE *)file) < 0)
|
if (__fgetc_check((FILE *)file) < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
/* Check for overflow. */
|
||||||
total_size = element_size * count;
|
total_size = element_size * count;
|
||||||
|
if (element_size != (total_size / count))
|
||||||
|
goto out;
|
||||||
|
|
||||||
SHOWVALUE(total_size);
|
SHOWVALUE(total_size);
|
||||||
|
|
||||||
while(total_size-- > 0)
|
/* No buffering enabled? */
|
||||||
|
if ((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
||||||
{
|
{
|
||||||
c = __getc(file);
|
/* We bypass the buffer entirely. */
|
||||||
if(c == EOF)
|
num_bytes_read = read(file->iob_Descriptor, data, total_size);
|
||||||
break;
|
if (num_bytes_read == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags,IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
(*data++) = c;
|
if (num_bytes_read == 0)
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_EOF_REACHED);
|
||||||
|
|
||||||
total_bytes_read++;
|
total_bytes_read = num_bytes_read;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (total_size > 0)
|
||||||
|
{
|
||||||
|
/* If the read buffer is empty and there is more data to be
|
||||||
|
* read, we'll bypass the buffer entirely. Note that we try
|
||||||
|
* to read a complete full buffer worth's of data, not just
|
||||||
|
* a few bytes.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferReadBytes == 0 && total_size >= (size_t)file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
/* We bypass the buffer entirely. */
|
||||||
|
num_bytes_read = read(file->iob_Descriptor, data, total_size);
|
||||||
|
if (num_bytes_read == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_bytes_read == 0)
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_EOF_REACHED);
|
||||||
|
|
||||||
|
total_bytes_read += num_bytes_read;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there is still data in the read buffer, try to copy it
|
||||||
|
* directly into the output buffer.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferPosition < file->iob_BufferReadBytes)
|
||||||
|
{
|
||||||
|
const unsigned char * buffer = &file->iob_Buffer[file->iob_BufferPosition];
|
||||||
|
size_t num_bytes_in_buffer;
|
||||||
|
|
||||||
|
/* Copy as much data as will fit. */
|
||||||
|
assert( file->iob_BufferReadBytes >= file->iob_BufferPosition );
|
||||||
|
|
||||||
|
num_bytes_in_buffer = file->iob_BufferReadBytes - file->iob_BufferPosition;
|
||||||
|
if (total_size < num_bytes_in_buffer)
|
||||||
|
num_bytes_in_buffer = total_size;
|
||||||
|
|
||||||
|
assert( num_bytes_in_buffer > 0 );
|
||||||
|
|
||||||
|
memmove(data, buffer, num_bytes_in_buffer);
|
||||||
|
data += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
assert( file->iob_BufferPosition + num_bytes_in_buffer <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferPosition += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
total_bytes_read += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
/* Stop if the string buffer has been filled. */
|
||||||
|
assert( total_size >= num_bytes_in_buffer );
|
||||||
|
|
||||||
|
/* Are we finished yet? */
|
||||||
|
total_size -= num_bytes_in_buffer;
|
||||||
|
if (total_size == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the next byte and/or refill the read buffer. */
|
||||||
|
c = __getc(file);
|
||||||
|
if (c == EOF)
|
||||||
|
break;
|
||||||
|
|
||||||
|
(*data++) = c;
|
||||||
|
|
||||||
|
total_size--;
|
||||||
|
total_bytes_read++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SHOWVALUE(total_bytes_read);
|
SHOWVALUE(total_bytes_read);
|
||||||
@@ -137,9 +220,6 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
SHOWVALUE(count);
|
SHOWVALUE(count);
|
||||||
|
|
||||||
SHOWMSG("either element size or count is zero");
|
SHOWMSG("either element size or count is zero");
|
||||||
|
|
||||||
/* Don't let this appear like an EOF or error. */
|
|
||||||
clearerr((FILE *)file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D(("total number of elements read = %ld",result));
|
D(("total number of elements read = %ld",result));
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_fwrite.c,v 1.12 2010-10-20 13:12:58 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -59,14 +57,14 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
assert( ptr != NULL && stream != NULL );
|
assert( ptr != NULL && stream != NULL );
|
||||||
assert( (int)element_size >= 0 && (int)count >= 0 );
|
assert( (int)element_size >= 0 && (int)count >= 0 );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
flockfile(stream);
|
flockfile(stream);
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(ptr == NULL || stream == NULL)
|
if (ptr == NULL || stream == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("invalid parameters");
|
SHOWMSG("invalid parameters");
|
||||||
|
|
||||||
@@ -78,9 +76,8 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
|
|
||||||
assert( __is_valid_iob(file) );
|
assert( __is_valid_iob(file) );
|
||||||
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
||||||
assert( file->iob_BufferSize > 0 );
|
|
||||||
|
|
||||||
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_IN_USE))
|
if (FLAG_IS_CLEAR(file->iob_Flags,IOBF_IN_USE))
|
||||||
{
|
{
|
||||||
SHOWMSG("this file is not even in use");
|
SHOWMSG("this file is not even in use");
|
||||||
|
|
||||||
@@ -91,7 +88,7 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_WRITE))
|
if (FLAG_IS_CLEAR(file->iob_Flags,IOBF_WRITE))
|
||||||
{
|
{
|
||||||
SHOWMSG("this stream is not write-enabled");
|
SHOWMSG("this stream is not write-enabled");
|
||||||
|
|
||||||
@@ -102,69 +99,242 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(element_size > 0 && count > 0)
|
clearerr((FILE *)file);
|
||||||
|
|
||||||
|
if (element_size > 0 && count > 0)
|
||||||
{
|
{
|
||||||
const unsigned char * data = (unsigned char *)ptr;
|
const unsigned char * s = (unsigned char *)ptr;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
int buffer_mode;
|
int buffer_mode;
|
||||||
size_t total_bytes_written = 0;
|
size_t total_bytes_written = 0;
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
|
|
||||||
|
/* Check for overflow. */
|
||||||
total_size = element_size * count;
|
total_size = element_size * count;
|
||||||
|
if (element_size != (total_size / count))
|
||||||
if(__fputc_check((FILE *)file) < 0)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (__fputc_check((FILE *)file) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* If this is an unbuffered interactive stream, we will switch
|
||||||
|
* to line buffered mode in order to improve readability of
|
||||||
|
* the output.
|
||||||
|
*/
|
||||||
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
|
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
|
||||||
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
|
if (buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||||
{
|
{
|
||||||
struct fd * fd = __fd[file->iob_Descriptor];
|
struct fd * fd = __fd[file->iob_Descriptor];
|
||||||
|
|
||||||
__fd_lock(fd);
|
__fd_lock(fd);
|
||||||
|
|
||||||
if(FLAG_IS_SET(fd->fd_Flags,FDF_IS_INTERACTIVE))
|
if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE))
|
||||||
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
||||||
|
|
||||||
__fd_unlock(fd);
|
__fd_unlock(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(buffer_mode == IOBF_BUFFER_MODE_LINE)
|
if (buffer_mode == IOBF_BUFFER_MODE_LINE)
|
||||||
{
|
{
|
||||||
while(total_size-- > 0)
|
assert( file->iob_BufferSize > 0 );
|
||||||
|
|
||||||
|
while (total_size > 0)
|
||||||
{
|
{
|
||||||
c = (*data++);
|
/* Is there still room in the write buffer to store
|
||||||
|
* more of the data?
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
|
||||||
|
size_t num_buffer_bytes;
|
||||||
|
const unsigned char * lf;
|
||||||
|
|
||||||
if(__putc_line_buffered(c,(FILE *)file) == EOF)
|
/* Give the user a chance to abort what could otherwise
|
||||||
goto out;
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
/* Store only as many characters as will fit into the write buffer. */
|
||||||
|
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
|
||||||
|
if (total_size < num_buffer_bytes)
|
||||||
|
num_buffer_bytes = total_size;
|
||||||
|
|
||||||
|
/* Try to find a line feed in the string. If there is one,
|
||||||
|
* reduce the number of characters to write to the sequence
|
||||||
|
* which ends with the line feed character.
|
||||||
|
*/
|
||||||
|
lf = (unsigned char *)memchr(s, '\n', num_buffer_bytes);
|
||||||
|
if (lf != NULL)
|
||||||
|
{
|
||||||
|
assert( (size_t)(lf + 1 - s) <= num_buffer_bytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = lf + 1 - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( num_buffer_bytes > 0 );
|
||||||
|
|
||||||
|
memmove(buffer, s, num_buffer_bytes);
|
||||||
|
s += num_buffer_bytes;
|
||||||
|
|
||||||
|
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferWriteBytes += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Write the buffer to disk if the buffer is full
|
||||||
|
* or contains a line feed.
|
||||||
|
*/
|
||||||
|
if ((lf != NULL || __iob_write_buffer_is_full(file)) && __flush_iob_write_buffer(file) < 0)
|
||||||
|
{
|
||||||
|
/* Abort with error. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_written += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Stop as soon as no further data needs to be written. */
|
||||||
|
assert( total_size >= num_buffer_bytes );
|
||||||
|
|
||||||
|
total_size -= num_buffer_bytes;
|
||||||
|
if (total_size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If there is again room in the output buffer,
|
||||||
|
* repeat this optimization.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (*s++);
|
||||||
|
|
||||||
|
if (__putc_line_buffered(c, (FILE *)file) == EOF)
|
||||||
|
break;
|
||||||
|
|
||||||
|
total_size--;
|
||||||
total_bytes_written++;
|
total_bytes_written++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||||
|
{
|
||||||
|
ssize_t num_bytes_written;
|
||||||
|
|
||||||
|
/* We bypass the buffer entirely. */
|
||||||
|
num_bytes_written = write(file->iob_Descriptor, s, total_size);
|
||||||
|
if (num_bytes_written == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_written = (size_t)num_bytes_written;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while(total_size-- > 0)
|
assert( file->iob_BufferSize > 0 );
|
||||||
|
|
||||||
|
while (total_size > 0)
|
||||||
{
|
{
|
||||||
c = (*data++);
|
/* If there is more data to be written than the write buffer will hold
|
||||||
|
* and the write buffer is empty anyway, then we'll bypass the write
|
||||||
|
* buffer entirely. Note that we try to store a complete full buffer
|
||||||
|
* worth's of data, not just a few bytes.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes == 0 && total_size >= (size_t)file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
ssize_t num_bytes_written;
|
||||||
|
|
||||||
if(__putc_fully_buffered(c,(FILE *)file) == EOF)
|
/* We bypass the buffer entirely. */
|
||||||
goto out;
|
num_bytes_written = write(file->iob_Descriptor, s, total_size);
|
||||||
|
if (num_bytes_written == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_written += num_bytes_written;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is there still room in the write buffer to store
|
||||||
|
* more of the data?
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
|
||||||
|
size_t num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Give the user a chance to abort what could otherwise
|
||||||
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
/* Store only as many bytes as will fit into the write buffer. */
|
||||||
|
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
|
||||||
|
if (total_size < num_buffer_bytes)
|
||||||
|
num_buffer_bytes = total_size;
|
||||||
|
|
||||||
|
assert( num_buffer_bytes > 0 );
|
||||||
|
|
||||||
|
memmove(buffer, s, num_buffer_bytes);
|
||||||
|
s += num_buffer_bytes;
|
||||||
|
|
||||||
|
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferWriteBytes += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Write a full buffer to disk. */
|
||||||
|
if (__iob_write_buffer_is_full(file) && __flush_iob_write_buffer(file) < 0)
|
||||||
|
{
|
||||||
|
/* Abort with error. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_written += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Stop as soon as no further data needs to be written. */
|
||||||
|
assert( total_size >= num_buffer_bytes );
|
||||||
|
|
||||||
|
total_size -= num_buffer_bytes;
|
||||||
|
if (total_size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If there is again room in the output buffer,
|
||||||
|
* try this optimization again.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (*s++);
|
||||||
|
|
||||||
|
if (__putc_fully_buffered(c, (FILE *)file) == EOF)
|
||||||
|
break;
|
||||||
|
|
||||||
|
total_size--;
|
||||||
total_bytes_written++;
|
total_bytes_written++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
if ((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
||||||
{
|
{
|
||||||
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
|
if (__iob_write_buffer_is_valid(file))
|
||||||
goto out;
|
__flush_iob_write_buffer(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = total_bytes_written / element_size;
|
result = total_bytes_written / element_size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Don't let this appear like an EOF or error. */
|
SHOWVALUE(element_size);
|
||||||
clearerr((FILE *)file);
|
SHOWVALUE(count);
|
||||||
|
|
||||||
|
SHOWMSG("either element size or count is zero");
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_gets.c,v 1.6 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -46,6 +44,8 @@
|
|||||||
char *
|
char *
|
||||||
gets(char *s)
|
gets(char *s)
|
||||||
{
|
{
|
||||||
|
FILE * stream = stdin;
|
||||||
|
struct iob * file = (struct iob *)stream;
|
||||||
char * result = s;
|
char * result = s;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
@@ -53,16 +53,16 @@ gets(char *s)
|
|||||||
|
|
||||||
SHOWPOINTER(s);
|
SHOWPOINTER(s);
|
||||||
|
|
||||||
assert( s != NULL && stdin != NULL );
|
assert( s != NULL );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
flockfile(stdin);
|
flockfile(stream);
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(s == NULL || stdin == NULL)
|
if (s == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("invalid parameters");
|
SHOWMSG("invalid parameters");
|
||||||
|
|
||||||
@@ -77,21 +77,84 @@ gets(char *s)
|
|||||||
/* Take care of the checks and data structure changes that
|
/* Take care of the checks and data structure changes that
|
||||||
* need to be handled only once for this stream.
|
* need to be handled only once for this stream.
|
||||||
*/
|
*/
|
||||||
if(__fgetc_check(stdin) < 0)
|
if (__fgetc_check(stream) < 0)
|
||||||
{
|
{
|
||||||
result = NULL;
|
result = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* So that we can tell error and 'end of file' conditions apart. */
|
/* So that we can tell error and 'end of file' conditions apart. */
|
||||||
clearerr(stdin);
|
clearerr(stream);
|
||||||
|
|
||||||
while(TRUE)
|
assert( 0 <= file->iob_BufferReadBytes );
|
||||||
|
assert( file->iob_BufferReadBytes <= file->iob_BufferSize );
|
||||||
|
assert( file->iob_BufferPosition <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
{
|
{
|
||||||
c = __getc(stdin);
|
/* If there is data in the buffer, try to copy it directly
|
||||||
if(c == EOF)
|
* into the string buffer. If there is a line feed in the
|
||||||
|
* buffer, too, try to conclude the read operation.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferPosition < file->iob_BufferReadBytes)
|
||||||
{
|
{
|
||||||
if(ferror(stdin))
|
size_t num_bytes_in_buffer = file->iob_BufferReadBytes - file->iob_BufferPosition;
|
||||||
|
const unsigned char * buffer = &file->iob_Buffer[file->iob_BufferPosition];
|
||||||
|
const unsigned char * lf;
|
||||||
|
|
||||||
|
assert( file->iob_BufferReadBytes >= file->iob_BufferPosition );
|
||||||
|
|
||||||
|
/* Try to find a line feed character which could conclude
|
||||||
|
* the read operation if the remaining buffer data, including
|
||||||
|
* the line feed character, fit into the string buffer.
|
||||||
|
*/
|
||||||
|
lf = (unsigned char *)memchr(buffer, '\n', num_bytes_in_buffer);
|
||||||
|
if (lf != NULL)
|
||||||
|
{
|
||||||
|
size_t num_characters_in_line = lf + 1 - buffer;
|
||||||
|
|
||||||
|
assert( num_characters_in_line <= num_bytes_in_buffer );
|
||||||
|
|
||||||
|
/* Give the user a chance to abort what could otherwise
|
||||||
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
/* Copy the remainder of the read buffer into the
|
||||||
|
* string buffer, omitting the terminating line
|
||||||
|
* feed character. This is the difference between
|
||||||
|
* gets() and fgets(): fgets() will keep the
|
||||||
|
* terminating line feed character, but gets()
|
||||||
|
* will drop it.
|
||||||
|
*/
|
||||||
|
assert( num_characters_in_line > 0 );
|
||||||
|
|
||||||
|
memmove(s, buffer, num_characters_in_line - 1);
|
||||||
|
s += num_characters_in_line - 1;
|
||||||
|
|
||||||
|
assert( file->iob_BufferPosition + num_characters_in_line <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferPosition += num_characters_in_line;
|
||||||
|
|
||||||
|
/* And that concludes the line read operation. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( num_bytes_in_buffer > 0 );
|
||||||
|
|
||||||
|
memmove(s, buffer, num_bytes_in_buffer);
|
||||||
|
s += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
assert( file->iob_BufferPosition + num_bytes_in_buffer <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferPosition += num_bytes_in_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = __getc(stream);
|
||||||
|
if (c == EOF)
|
||||||
|
{
|
||||||
|
if (ferror(stream))
|
||||||
{
|
{
|
||||||
/* Just to be on the safe side. */
|
/* Just to be on the safe side. */
|
||||||
(*s) = '\0';
|
(*s) = '\0';
|
||||||
@@ -101,14 +164,15 @@ gets(char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that we return NULL if we really
|
/* Make sure that we return NULL if we really
|
||||||
didn't read anything at all */
|
* didn't read anything at all.
|
||||||
if(s == result)
|
*/
|
||||||
|
if (s == result)
|
||||||
result = NULL;
|
result = NULL;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c == '\n')
|
if (c == '\n')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
(*s++) = c;
|
(*s++) = c;
|
||||||
@@ -120,7 +184,7 @@ gets(char *s)
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
funlockfile(stdin);
|
funlockfile(stream);
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
return(result);
|
return(result);
|
||||||
|
|||||||
581
library/stdio_long_path.c
Normal file
581
library/stdio_long_path.c
Normal file
@@ -0,0 +1,581 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2023 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __amigaos4__
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* We don't want the replacement functions to become active when buliding
|
||||||
|
* this file.
|
||||||
|
*/
|
||||||
|
#define __DISABLE_LONG_PATHS
|
||||||
|
|
||||||
|
#ifndef _STDIO_LONG_PATH_H
|
||||||
|
#include "stdio_long_path.h"
|
||||||
|
#endif /* _STDIO_LONG_PATH_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#include <proto/exec.h>
|
||||||
|
#include <proto/dos.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Split an AmigaDOS path name into a sequence of the individual path
|
||||||
|
* pieces. A path name may be empty, it may include a device name,
|
||||||
|
* a series of directory names or even "/" references to the
|
||||||
|
* parent directory and a file, directory or link name.
|
||||||
|
*
|
||||||
|
* split_path() is modeled on the SplitName() function in that it
|
||||||
|
* will copy each path piece into the supplied buffer, returning -1
|
||||||
|
* if the last piece has been copied. If -2 is returned, it means
|
||||||
|
* that the piece buffer is too short for the path piece to be
|
||||||
|
* copied.
|
||||||
|
*/
|
||||||
|
static LONG
|
||||||
|
split_path(CONST TEXT * path, TEXT * piece, LONG old_position, LONG size)
|
||||||
|
{
|
||||||
|
LONG length_copied = 0;
|
||||||
|
TEXT c;
|
||||||
|
|
||||||
|
/* The piece has to be NUL-terminated, which reduces the
|
||||||
|
* usable size of the piece buffer.
|
||||||
|
*/
|
||||||
|
size--;
|
||||||
|
|
||||||
|
/* Is the piece buffer too short? */
|
||||||
|
if (size <= 0)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
/* Is this not an empty string, which stands for the
|
||||||
|
* current directory?
|
||||||
|
*/
|
||||||
|
if (path[0] != '\0')
|
||||||
|
{
|
||||||
|
/* Adjust the starting position for scanning the path name,
|
||||||
|
* which simplifies the loop below.
|
||||||
|
*/
|
||||||
|
path += old_position;
|
||||||
|
|
||||||
|
while (size-- >= 0)
|
||||||
|
{
|
||||||
|
c = path[length_copied];
|
||||||
|
|
||||||
|
/* Was this the end of the path name? */
|
||||||
|
if (c == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
(*piece++) = c;
|
||||||
|
length_copied++;
|
||||||
|
|
||||||
|
/* Is this a device name separator, which may appear
|
||||||
|
* exactly once in a path name? Then we will have to
|
||||||
|
* keep it.
|
||||||
|
*/
|
||||||
|
if (c == ':' && old_position == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Is there a '/' at the end of this path piece? */
|
||||||
|
else if (c == '/')
|
||||||
|
{
|
||||||
|
/* Is this in fact a single '/' which represents a
|
||||||
|
* reference to the parent directory? Then we need
|
||||||
|
* to keep it, otherwise it will have to be removed.
|
||||||
|
*/
|
||||||
|
if (length_copied > 1)
|
||||||
|
{
|
||||||
|
/* Make sure that the trailing '/' will
|
||||||
|
* be removed from the piece.
|
||||||
|
*/
|
||||||
|
piece--;
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is the piece buffer too short? */
|
||||||
|
if (size < 0)
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure that the piece is NUL-terminated. */
|
||||||
|
(*piece) = '\0';
|
||||||
|
|
||||||
|
/* Is the separator character at the end of the path name,
|
||||||
|
* or is this an empty string (with path_length == 0)?
|
||||||
|
*/
|
||||||
|
if (path[length_copied] == '\0')
|
||||||
|
return -1; /* This is the last piece of the path name. */
|
||||||
|
|
||||||
|
/* Continue path processing at this position. */
|
||||||
|
return old_position + length_copied;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* If a path name exceeds 255 characters, break down the path into individual
|
||||||
|
* pieces, traveling to the end of the path and invoke a callback function
|
||||||
|
* with the current directory set and the name of the file/directory/link
|
||||||
|
* provided along with additional parameters needed to carry out a file
|
||||||
|
* system operation.
|
||||||
|
*
|
||||||
|
* For path names shorter than 256 characters, no extra work will be done
|
||||||
|
* and the callback function will be invoked directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef LONG (*callback_f)(CONST TEXT * name, LONG arg1, LONG arg2);
|
||||||
|
|
||||||
|
static void
|
||||||
|
long_path_workaround(
|
||||||
|
CONST TEXT * path_name, LONG arg1, LONG arg2,
|
||||||
|
LONG * result_ptr,
|
||||||
|
callback_f callback)
|
||||||
|
{
|
||||||
|
TEXT piece[256];
|
||||||
|
LONG path_name_len;
|
||||||
|
LONG len;
|
||||||
|
CONST TEXT * colon;
|
||||||
|
BPTR reference_dir = (BPTR)NULL;
|
||||||
|
BPTR old_current_dir = (BPTR)NULL;
|
||||||
|
LONG position = 0;
|
||||||
|
BPTR lock;
|
||||||
|
|
||||||
|
path_name_len = strlen(path_name);
|
||||||
|
|
||||||
|
/* Only go through with the extra effort to resolve the path
|
||||||
|
* if this job requires a file system and not a handler (such
|
||||||
|
* as "NIL:" or "CON:") and if the path name exceeds 255
|
||||||
|
* characters.
|
||||||
|
*/
|
||||||
|
if (path_name_len > 255 && IsFileSystem(path_name))
|
||||||
|
{
|
||||||
|
/* Does the path begin with a device name, or a reference
|
||||||
|
* to the root directory of a volume?
|
||||||
|
*/
|
||||||
|
colon = strchr(path_name, ':');
|
||||||
|
if (colon != NULL)
|
||||||
|
{
|
||||||
|
/* We need to copy the name of the device, which must
|
||||||
|
* not exceed 255 characters, including the colon
|
||||||
|
* character. Volume and device names should never
|
||||||
|
* exceed 30 characters, but accidents may still
|
||||||
|
* happen...
|
||||||
|
*/
|
||||||
|
len = (LONG)(colon - path_name) + 1;
|
||||||
|
if (len > 255)
|
||||||
|
{
|
||||||
|
SetIoErr(ERROR_LINE_TOO_LONG);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Obtain a shared lock on the device or root
|
||||||
|
* directory. We are using Lock() because it
|
||||||
|
* implies that the handler is a file system
|
||||||
|
* and not, for example, "NIL:" or "CON:".
|
||||||
|
*/
|
||||||
|
CopyMem(path_name, piece, len);
|
||||||
|
piece[len] = '\0';
|
||||||
|
|
||||||
|
reference_dir = Lock(piece, SHARED_LOCK);
|
||||||
|
if (reference_dir == (BPTR)NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* We took care of the device or root directory name. */
|
||||||
|
path_name += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the path name, one piece at a time, relative
|
||||||
|
* to a Lock on its parent directory. This repeats
|
||||||
|
* until the last piece of the path has been found.
|
||||||
|
* Each loop iteration will reuse the Lock of the
|
||||||
|
* previous iteration as the parent directory.
|
||||||
|
*/
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* Obtain the next piece of the path. */
|
||||||
|
position = split_path(path_name, piece, position, sizeof(piece));
|
||||||
|
|
||||||
|
/* Is the piece too long? */
|
||||||
|
if (position == -2)
|
||||||
|
{
|
||||||
|
SetIoErr(ERROR_LINE_TOO_LONG);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Access the next piece of the path relative to a
|
||||||
|
* specific directory? Otherwise, we use the current
|
||||||
|
* directory of the current Process. Because the current
|
||||||
|
* directory may be an exclusive lock we cannot
|
||||||
|
* conveniently fall back onto DupLock() or
|
||||||
|
* Lock("", SHARED_LOCK) instead.
|
||||||
|
*/
|
||||||
|
if (reference_dir != (BPTR)NULL)
|
||||||
|
old_current_dir = CurrentDir(reference_dir);
|
||||||
|
|
||||||
|
/* Unless this is the final piece of the path
|
||||||
|
* (split_path() will return -1), we will need to call
|
||||||
|
* Lock() and make use of shared locks.
|
||||||
|
*/
|
||||||
|
if (position != -1)
|
||||||
|
{
|
||||||
|
lock = Lock(piece, SHARED_LOCK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lock = (BPTR)NULL;
|
||||||
|
|
||||||
|
/* Time to do what we came here for. */
|
||||||
|
(*result_ptr) = (*callback)(piece, arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reference_dir != (BPTR)NULL)
|
||||||
|
CurrentDir(old_current_dir);
|
||||||
|
|
||||||
|
/* Stop as soon as we reach the end of the path or
|
||||||
|
* if the Lock could not be obtained.
|
||||||
|
*/
|
||||||
|
if (position == -1 || lock == (BPTR)NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Look at the next piece of the remaining path.
|
||||||
|
* Free the current reference directory Lock and
|
||||||
|
* replace it with the Lock obtained above.
|
||||||
|
*/
|
||||||
|
UnLock(reference_dir);
|
||||||
|
reference_dir = lock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*result_ptr) = (*callback)(path_name, arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
UnLock(reference_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
lock_callback(CONST TEXT * name, LONG type)
|
||||||
|
{
|
||||||
|
return Lock(name, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPTR
|
||||||
|
__new_lock(CONST TEXT * name, LONG type )
|
||||||
|
{
|
||||||
|
BPTR result = (BPTR)NULL;
|
||||||
|
|
||||||
|
long_path_workaround(name, type, 0, (LONG *)&result, (callback_f)lock_callback);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
set_owner_callback(CONST TEXT * name, LONG owner_info)
|
||||||
|
{
|
||||||
|
return SetOwner(name, owner_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_set_owner(CONST TEXT * name, LONG owner_info)
|
||||||
|
{
|
||||||
|
LONG success = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, owner_info, 0, &success, (callback_f)set_owner_callback);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
set_comment_callback(CONST TEXT * name, LONG comment)
|
||||||
|
{
|
||||||
|
return SetComment(name, (STRPTR)comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_set_comment(CONST TEXT * name, CONST TEXT * comment)
|
||||||
|
{
|
||||||
|
LONG success = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, (LONG)comment, 0, &success, (callback_f)set_comment_callback);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
set_protect_callback(CONST TEXT * name, LONG protect)
|
||||||
|
{
|
||||||
|
return SetProtection(name, protect);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_set_protection(CONST TEXT * name, LONG protect)
|
||||||
|
{
|
||||||
|
LONG success = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, protect, 0, &success, (callback_f)set_protect_callback);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
set_file_date_callback(CONST TEXT * name, LONG date)
|
||||||
|
{
|
||||||
|
return SetFileDate(name, (struct DateStamp *)date);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_set_file_date(CONST TEXT * name, CONST struct DateStamp * date)
|
||||||
|
{
|
||||||
|
LONG success = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, (LONG)date, 0, &success, (callback_f)set_file_date_callback);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
open_callback(CONST TEXT * name, LONG mode)
|
||||||
|
{
|
||||||
|
return Open(name, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPTR
|
||||||
|
__new_open(CONST TEXT * name, LONG mode)
|
||||||
|
{
|
||||||
|
BPTR file = (BPTR)NULL;
|
||||||
|
|
||||||
|
long_path_workaround(name, mode, 0, (LONG *)&file, (callback_f)open_callback);
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
delete_file_callback(CONST TEXT * name)
|
||||||
|
{
|
||||||
|
return DeleteFile(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_delete_file(CONST TEXT * name)
|
||||||
|
{
|
||||||
|
LONG successful = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, 0, 0, &successful, (callback_f)delete_file_callback);
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
create_dir_callback(CONST TEXT * name)
|
||||||
|
{
|
||||||
|
return CreateDir(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPTR
|
||||||
|
__new_create_dir(CONST TEXT * name)
|
||||||
|
{
|
||||||
|
BPTR lock = (BPTR)NULL;
|
||||||
|
|
||||||
|
long_path_workaround(name, 0, 0, (LONG *)&lock, (callback_f)create_dir_callback);
|
||||||
|
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
make_link_callback(CONST TEXT * name, LONG dest, LONG soft)
|
||||||
|
{
|
||||||
|
return MakeLink(name, dest, soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_make_link(CONST TEXT * name, LONG dest, LONG soft)
|
||||||
|
{
|
||||||
|
LONG success = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, dest, soft, (LONG *)&success, (callback_f)make_link_callback);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
struct rename_arg
|
||||||
|
{
|
||||||
|
BPTR dir_lock;
|
||||||
|
TEXT name[256+4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct rename_arg *
|
||||||
|
create_rename_arg(void)
|
||||||
|
{
|
||||||
|
struct rename_arg * arg;
|
||||||
|
|
||||||
|
arg = AllocMem(sizeof(*arg), MEMF_PUBLIC);
|
||||||
|
if (arg != NULL)
|
||||||
|
arg->dir_lock = (BPTR)NULL;
|
||||||
|
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_rename_arg(struct rename_arg * arg)
|
||||||
|
{
|
||||||
|
if (arg != NULL)
|
||||||
|
{
|
||||||
|
UnLock(arg->dir_lock);
|
||||||
|
FreeMem(arg, sizeof(*arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
rename_callback(CONST TEXT * name, struct rename_arg * arg)
|
||||||
|
{
|
||||||
|
BOOL successful = FALSE;
|
||||||
|
LONG name_len;
|
||||||
|
BPTR old_lock;
|
||||||
|
|
||||||
|
old_lock = CurrentDir((BPTR)NULL);
|
||||||
|
CurrentDir(old_lock);
|
||||||
|
|
||||||
|
if (old_lock != (BPTR)NULL)
|
||||||
|
{
|
||||||
|
arg->dir_lock = DupLock(old_lock);
|
||||||
|
if (arg->dir_lock != (BPTR)NULL)
|
||||||
|
successful = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
successful = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (successful)
|
||||||
|
{
|
||||||
|
name_len = strlen(name);
|
||||||
|
if (name_len > 255)
|
||||||
|
name_len = 255;
|
||||||
|
|
||||||
|
arg->name[0] = name_len;
|
||||||
|
CopyMem(name, &arg->name[1], name_len);
|
||||||
|
arg->name[1+name_len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_rename(CONST TEXT * oldName, CONST TEXT * newName)
|
||||||
|
{
|
||||||
|
struct rename_arg * from = NULL;
|
||||||
|
struct rename_arg * to = NULL;
|
||||||
|
struct MsgPort * filesys_port;
|
||||||
|
LONG successful = FALSE;
|
||||||
|
|
||||||
|
if (IsFileSystem(oldName) && IsFileSystem(newName) && (strlen(oldName) > 255 || strlen(newName) > 255))
|
||||||
|
{
|
||||||
|
from = create_rename_arg();
|
||||||
|
if (from == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
to = create_rename_arg();
|
||||||
|
if (to == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
long_path_workaround(oldName, (LONG)from, 0, (LONG *)&successful, (callback_f)rename_callback);
|
||||||
|
if (successful == FALSE)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
long_path_workaround(newName, (LONG)to, 0, (LONG *)&successful, (callback_f)rename_callback);
|
||||||
|
if (successful == FALSE)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (from->dir_lock == (BPTR)NULL && to->dir_lock == (BPTR)NULL)
|
||||||
|
{
|
||||||
|
filesys_port = GetFileSysTask();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (from->dir_lock == (BPTR)NULL || to->dir_lock == (BPTR)NULL ||
|
||||||
|
SameLock(from->dir_lock, to->dir_lock) == LOCK_DIFFERENT)
|
||||||
|
{
|
||||||
|
SetIoErr(ERROR_RENAME_ACROSS_DEVICES);
|
||||||
|
|
||||||
|
successful = FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
filesys_port = ((struct FileLock *)BADDR(from->dir_lock))->fl_Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
successful = DoPkt4(filesys_port, ACTION_RENAME_OBJECT,
|
||||||
|
from->dir_lock, MKBADDR(from->name),
|
||||||
|
to->dir_lock, MKBADDR(to->name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
successful = Rename(oldName, newName);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
delete_rename_arg(from);
|
||||||
|
delete_rename_arg(to);
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* __amigaos4__ */
|
||||||
168
library/stdio_long_path.h
Normal file
168
library/stdio_long_path.h
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2023 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDIO_LONG_PATH_H
|
||||||
|
#define _STDIO_LONG_PATH_H
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* This option enables support for long path names under Kickstart 2.04
|
||||||
|
* and beyond. Because this workaround is not needed for AmigaOS4, it will
|
||||||
|
* be ignored if you try to enable it.
|
||||||
|
*
|
||||||
|
* Caution: Enable this feature only here in the "stdio_headers.h" file,
|
||||||
|
* never as a compiler option. This is to make sure that all the
|
||||||
|
* source code which makes use of this feature is rebuilt when
|
||||||
|
* you change this file.
|
||||||
|
*/
|
||||||
|
/*#define __USE_LONG_PATHS*/
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __amigaos4__
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef PROTO_DOS_H
|
||||||
|
#include <proto/dos.h>
|
||||||
|
#endif /* PROTO_DOS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
extern BPTR __new_lock(CONST TEXT * name, LONG type );
|
||||||
|
extern LONG __new_set_owner(CONST TEXT * name, LONG owner_info);
|
||||||
|
extern LONG __new_set_comment(CONST TEXT * name, CONST TEXT * comment);
|
||||||
|
extern LONG __new_set_protection(CONST TEXT * name, LONG protect);
|
||||||
|
extern LONG __new_set_file_date(CONST TEXT * name, CONST struct DateStamp * date);
|
||||||
|
extern BPTR __new_open(CONST TEXT * name, LONG mode);
|
||||||
|
extern LONG __new_delete_file(CONST TEXT * name);
|
||||||
|
extern BPTR __new_create_dir(CONST TEXT * name);
|
||||||
|
extern LONG __new_make_link(CONST TEXT * name, LONG dest, LONG soft);
|
||||||
|
extern LONG __new_rename(CONST TEXT * oldName, CONST TEXT * newName);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* We don't want the replacement functions to become active when building
|
||||||
|
* the "stdio_long_path.c" file.
|
||||||
|
*/
|
||||||
|
#if ! defined(__DISABLE_LONG_PATHS) && defined(__USE_LONG_PATHS)
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(Lock)
|
||||||
|
#undef Lock
|
||||||
|
#endif /* Lock */
|
||||||
|
|
||||||
|
#define Lock(name, type) __new_lock((name), (type))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(SetOwner)
|
||||||
|
#undef SetOwner
|
||||||
|
#endif /* SetOwner */
|
||||||
|
|
||||||
|
#define SetOwner(name, owner_info) __new_set_owner((name), (owner_info))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(SetComment)
|
||||||
|
#undef SetComment
|
||||||
|
#endif /* SetComment */
|
||||||
|
|
||||||
|
#define SetComment(name, comment) __new_set_comment((name), (comment))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(SetProtection)
|
||||||
|
#undef SetProtection
|
||||||
|
#endif /* SetProtection */
|
||||||
|
|
||||||
|
#define SetProtection(name, protect) __new_set_protection((name), (protect))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(SetFileDate)
|
||||||
|
#undef SetFileDate
|
||||||
|
#endif /* SetFileDate */
|
||||||
|
|
||||||
|
#define SetFileDate(name, date) __new_set_file_date((name), (date))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(Open)
|
||||||
|
#undef Open
|
||||||
|
#endif /* Open */
|
||||||
|
|
||||||
|
#define Open(name, mode) __new_open((name), (mode))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(DeleteFile)
|
||||||
|
#undef DeleteFile
|
||||||
|
#endif /* DeleteFile */
|
||||||
|
|
||||||
|
#define DeleteFile(name) __new_delete_file(name)
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(CreateDir)
|
||||||
|
#undef CreateDir
|
||||||
|
#endif /* CreateDir */
|
||||||
|
|
||||||
|
#define CreateDir(name) __new_create_dir(name)
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(MakeLink)
|
||||||
|
#undef MakeLink
|
||||||
|
#endif /* MakeLink */
|
||||||
|
|
||||||
|
#define MakeLink(name, dest, soft) __new_make_link((name), (dest), (soft))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(Rename)
|
||||||
|
#undef Rename
|
||||||
|
#endif /* Rename */
|
||||||
|
|
||||||
|
#define Rename(oldName, newName) __new_rename((oldName), (newName))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* !__DISABLE_LONG_PATHS && __USE_LONG_PATHS */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* __amigaos4__ */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* _STDIO_LONG_PATH_H */
|
||||||
@@ -162,6 +162,11 @@ extern int __fputc(int c,FILE *stream,int buffer_mode);
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* stdio_fputs.c */
|
||||||
|
extern int __fputs(const char *s, int line_feed, FILE *stream);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
/* stdio_sscanf_hook_entry.c */
|
/* stdio_sscanf_hook_entry.c */
|
||||||
extern int __sscanf_hook_entry(struct iob *string,struct file_action_message *fam);
|
extern int __sscanf_hook_entry(struct iob *string,struct file_action_message *fam);
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_puts.c,v 1.8 2006-01-08 12:04:25 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -46,10 +44,7 @@
|
|||||||
int
|
int
|
||||||
puts(const char *s)
|
puts(const char *s)
|
||||||
{
|
{
|
||||||
struct iob * file = (struct iob *)stdout;
|
|
||||||
int result = EOF;
|
int result = EOF;
|
||||||
int buffer_mode;
|
|
||||||
int c;
|
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
@@ -57,11 +52,6 @@ puts(const char *s)
|
|||||||
|
|
||||||
assert( s != NULL );
|
assert( s != NULL );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
|
||||||
__check_abort();
|
|
||||||
|
|
||||||
flockfile(stdout);
|
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(s == NULL)
|
if(s == NULL)
|
||||||
@@ -72,45 +62,13 @@ puts(const char *s)
|
|||||||
}
|
}
|
||||||
#endif /* CHECK_FOR_NULL_POINTERS */
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||||
|
|
||||||
assert( __is_valid_iob(file) );
|
if (__fputs(s, '\n', stdout) == EOF)
|
||||||
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
|
||||||
assert( file->iob_BufferSize > 0 );
|
|
||||||
|
|
||||||
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
|
|
||||||
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
|
|
||||||
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
|
||||||
|
|
||||||
if(__fputc_check(stdout) < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
while((c = (*s++)) != '\0')
|
|
||||||
{
|
|
||||||
if(__putc(c,stdout,buffer_mode) == EOF)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(__putc('\n',stdout,buffer_mode) == EOF)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
result = OK;
|
result = OK;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
/* Note: if buffering is disabled for this stream, then we still
|
|
||||||
may have buffered data around, queued to be printed right now.
|
|
||||||
This is intended to improve performance as it takes more effort
|
|
||||||
to write a single character to a file than to write a bunch. */
|
|
||||||
if(result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
|
||||||
{
|
|
||||||
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
|
|
||||||
{
|
|
||||||
SHOWMSG("couldn't flush the write buffer");
|
|
||||||
result = EOF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
funlockfile(stdout);
|
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ remove_locked_region_node(struct FileLockSemaphore * fls,struct fd * fd,LONG sta
|
|||||||
/* Check if there are any locked regions left.
|
/* Check if there are any locked regions left.
|
||||||
* If not, mark the entire file as unlocked.
|
* If not, mark the entire file as unlocked.
|
||||||
*/
|
*/
|
||||||
if(IsListEmpty((struct List *)&which_lock->fln_LockedRegionList))
|
if(IsMinListEmpty(&which_lock->fln_LockedRegionList))
|
||||||
{
|
{
|
||||||
SHOWMSG("no more regions are locked; removing the file lock node");
|
SHOWMSG("no more regions are locked; removing the file lock node");
|
||||||
|
|
||||||
@@ -705,7 +705,7 @@ cleanup_locked_records(struct fd * fd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsListEmpty((struct List *)&which_lock->fln_LockedRegionList))
|
if(IsMinListEmpty(&which_lock->fln_LockedRegionList))
|
||||||
{
|
{
|
||||||
SHOWMSG("no more regions are locked; removing the file lock node");
|
SHOWMSG("no more regions are locked; removing the file lock node");
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_setvbuf.c,v 1.11 2008-09-04 12:07:58 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -114,20 +112,28 @@ setvbuf(FILE *stream,char *buf,int bufmode,size_t size)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A buffer size of 0 bytes defaults to unbuffered operation. */
|
/* A buffer size of 0 bytes will cause the default buffer size to be used. */
|
||||||
if(size == 0)
|
if(size == 0)
|
||||||
bufmode = IOBF_BUFFER_MODE_NONE;
|
|
||||||
|
|
||||||
/* If a certain buffer size is requested but no buffer was provided,
|
|
||||||
allocate some memory for it. */
|
|
||||||
if(size > 0 && buf == NULL)
|
|
||||||
{
|
{
|
||||||
/* Allocate a little more memory than necessary. */
|
size = BUFSIZ;
|
||||||
new_buffer = malloc(size + (__cache_line_size-1));
|
buf = NULL;
|
||||||
if(new_buffer == NULL)
|
}
|
||||||
|
|
||||||
|
if(bufmode != IOBF_BUFFER_MODE_NONE)
|
||||||
|
{
|
||||||
|
/* If a certain buffer size is requested but no buffer was provided,
|
||||||
|
allocate some memory for it. */
|
||||||
|
if(size > 0 && buf == NULL)
|
||||||
{
|
{
|
||||||
__set_errno(ENOBUFS);
|
assert( size <= ((size + (__cache_line_size-1)) & ~(__cache_line_size-1)) );
|
||||||
goto out;
|
|
||||||
|
/* Allocate a little more memory than necessary. */
|
||||||
|
new_buffer = malloc(size + (__cache_line_size-1));
|
||||||
|
if(new_buffer == NULL)
|
||||||
|
{
|
||||||
|
__set_errno(ENOBUFS);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,15 +46,8 @@
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
abort(void)
|
__abort(void)
|
||||||
{
|
{
|
||||||
/* Try to call the signal handler that might be in charge of
|
|
||||||
handling cleanup operations, etc. */
|
|
||||||
raise(SIGABRT);
|
|
||||||
|
|
||||||
/* If the signal handler returns it means that we still have
|
|
||||||
to terminate the program. */
|
|
||||||
|
|
||||||
__check_abort_enabled = FALSE;
|
__check_abort_enabled = FALSE;
|
||||||
|
|
||||||
__print_termination_message(NULL);
|
__print_termination_message(NULL);
|
||||||
@@ -63,3 +56,17 @@ abort(void)
|
|||||||
does not trigger the exit trap. */
|
does not trigger the exit trap. */
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
abort(void)
|
||||||
|
{
|
||||||
|
/* Try to call the signal handler that might be in charge of
|
||||||
|
handling cleanup operations, etc. */
|
||||||
|
raise(SIGABRT);
|
||||||
|
|
||||||
|
/* If the signal handler returns it means that we still have
|
||||||
|
to terminate the program. */
|
||||||
|
__abort();
|
||||||
|
}
|
||||||
|
|||||||
@@ -69,11 +69,36 @@ struct MemoryContextNode
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* The default behaviour for alloca() failing is to
|
||||||
|
* terminate the program rather than let it stumble
|
||||||
|
* into a NULL-pointer reference.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
default_alloca_trap(void)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
CLIB_CONSTRUCTOR(alloca_init)
|
||||||
|
{
|
||||||
|
ENTER();
|
||||||
|
|
||||||
|
__alloca_trap = default_alloca_trap;
|
||||||
|
|
||||||
|
NewList((struct List *)&alloca_memory_list);
|
||||||
|
|
||||||
|
LEAVE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
CLIB_DESTRUCTOR(alloca_exit)
|
CLIB_DESTRUCTOR(alloca_exit)
|
||||||
{
|
{
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
/* Clean this up, too, just to be safe. */
|
/* This list should remain empty. */
|
||||||
NewList((struct List *)&alloca_memory_list);
|
NewList((struct List *)&alloca_memory_list);
|
||||||
|
|
||||||
LEAVE();
|
LEAVE();
|
||||||
@@ -83,18 +108,18 @@ CLIB_DESTRUCTOR(alloca_exit)
|
|||||||
|
|
||||||
/* Cleans up after all alloca() allocations that have been made so far. */
|
/* Cleans up after all alloca() allocations that have been made so far. */
|
||||||
static void
|
static void
|
||||||
alloca_cleanup(const char * file,int line)
|
alloca_cleanup(const char * file, int line)
|
||||||
{
|
{
|
||||||
void * stack_pointer = __get_sp();
|
void * stack_pointer = __get_sp();
|
||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
/* Initialize this if it hasn't been taken care of yet. */
|
/* Initialize this if it hasn't been taken care of yet. */
|
||||||
if(alloca_memory_list.mlh_Head == NULL)
|
if (alloca_memory_list.mlh_Head == NULL)
|
||||||
NewList((struct List *)&alloca_memory_list);
|
NewList((struct List *)&alloca_memory_list);
|
||||||
|
|
||||||
/* Is this worth cleaning up? */
|
/* Is this worth cleaning up? */
|
||||||
if(NOT IsListEmpty((struct List *)&alloca_memory_list))
|
if (NOT IsListEmpty((struct List *)&alloca_memory_list))
|
||||||
{
|
{
|
||||||
struct MemoryContextNode * mcn_prev;
|
struct MemoryContextNode * mcn_prev;
|
||||||
struct MemoryContextNode * mcn;
|
struct MemoryContextNode * mcn;
|
||||||
@@ -106,21 +131,24 @@ alloca_cleanup(const char * file,int line)
|
|||||||
we move up from the end to the top of the list, the closer we get
|
we move up from the end to the top of the list, the closer we get
|
||||||
to the allocations made in the context of a stack frame near to
|
to the allocations made in the context of a stack frame near to
|
||||||
where were currently are. */
|
where were currently are. */
|
||||||
for(mcn = (struct MemoryContextNode *)alloca_memory_list.mlh_TailPred ;
|
for (mcn = (struct MemoryContextNode *)alloca_memory_list.mlh_TailPred ;
|
||||||
mcn->mcn_MinNode.mln_Pred != NULL && mcn->mcn_StackPointer < stack_pointer ;
|
mcn->mcn_MinNode.mln_Pred != NULL && mcn->mcn_StackPointer < stack_pointer ;
|
||||||
mcn = mcn_prev)
|
mcn = mcn_prev)
|
||||||
{
|
{
|
||||||
mcn_prev = (struct MemoryContextNode *)mcn->mcn_MinNode.mln_Pred;
|
mcn_prev = (struct MemoryContextNode *)mcn->mcn_MinNode.mln_Pred;
|
||||||
|
|
||||||
Remove((struct Node *)mcn);
|
Remove((struct Node *)mcn);
|
||||||
|
|
||||||
__free_memory(mcn->mcn_Memory,TRUE,file,line);
|
/* Note: force the memory to be freed because it
|
||||||
__free_memory(mcn,FALSE,file,line);
|
has gone out of scope. */
|
||||||
|
__free_memory(mcn->mcn_Memory, TRUE, file, line);
|
||||||
|
|
||||||
|
__free_memory(mcn, FALSE, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop the cleanup callback if there's nothing to be cleaned
|
/* Drop the cleanup callback if there's nothing to be cleaned
|
||||||
up any more. */
|
up any more. */
|
||||||
if(IsListEmpty((struct List *)&alloca_memory_list))
|
if (IsListEmpty((struct List *)&alloca_memory_list))
|
||||||
__alloca_cleanup = NULL;
|
__alloca_cleanup = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +158,7 @@ alloca_cleanup(const char * file,int line)
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
__static void *
|
__static void *
|
||||||
__alloca(size_t size,const char * file,int line)
|
__alloca(size_t size, const char * file, int line)
|
||||||
{
|
{
|
||||||
void * stack_pointer = __get_sp();
|
void * stack_pointer = __get_sp();
|
||||||
struct MemoryContextNode * mcn;
|
struct MemoryContextNode * mcn;
|
||||||
@@ -138,27 +166,23 @@ __alloca(size_t size,const char * file,int line)
|
|||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
/* Initialize this if it hasn't been taken care of yet. */
|
|
||||||
if(alloca_memory_list.mlh_Head == NULL)
|
|
||||||
NewList((struct List *)&alloca_memory_list);
|
|
||||||
|
|
||||||
__alloca_cleanup = alloca_cleanup;
|
__alloca_cleanup = alloca_cleanup;
|
||||||
(*__alloca_cleanup)(file,line);
|
(*__alloca_cleanup)(file, line);
|
||||||
|
|
||||||
mcn = __allocate_memory(sizeof(*mcn),FALSE,file,line);
|
mcn = __allocate_memory(sizeof(*mcn), FALSE, file, line);
|
||||||
if(mcn == NULL)
|
if (mcn == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("not enough memory");
|
SHOWMSG("not enough memory");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate memory which cannot be run through realloc() or free(). */
|
/* Allocate memory which cannot be run through realloc() or free(). */
|
||||||
mcn->mcn_Memory = __allocate_memory(size,TRUE,file,line);
|
mcn->mcn_Memory = __allocate_memory(size, TRUE, file, line);
|
||||||
if(mcn->mcn_Memory == NULL)
|
if (mcn->mcn_Memory == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("not enough memory");
|
SHOWMSG("not enough memory");
|
||||||
|
|
||||||
__free(mcn,file,line);
|
__free(mcn, file, line);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +190,7 @@ __alloca(size_t size,const char * file,int line)
|
|||||||
|
|
||||||
assert( alloca_memory_list.mlh_Head != NULL );
|
assert( alloca_memory_list.mlh_Head != NULL );
|
||||||
|
|
||||||
AddTail((struct List *)&alloca_memory_list,(struct Node *)mcn);
|
AddTail((struct List *)&alloca_memory_list, (struct Node *)mcn);
|
||||||
|
|
||||||
result = mcn->mcn_Memory;
|
result = mcn->mcn_Memory;
|
||||||
|
|
||||||
@@ -176,10 +200,14 @@ __alloca(size_t size,const char * file,int line)
|
|||||||
|
|
||||||
/* If we are about to return NULL and a trap function is
|
/* If we are about to return NULL and a trap function is
|
||||||
provided, call it rather than returning NULL. */
|
provided, call it rather than returning NULL. */
|
||||||
if(result == NULL && __alloca_trap != NULL)
|
if (result == NULL && __alloca_trap != NULL)
|
||||||
(*__alloca_trap)();
|
{
|
||||||
|
__alloca_cleanup = NULL;
|
||||||
|
|
||||||
return(result);
|
(*__alloca_trap)();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@@ -191,5 +219,5 @@ alloca(size_t size)
|
|||||||
|
|
||||||
result = __alloca(size,NULL,0);
|
result = __alloca(size,NULL,0);
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
37
library/stdlib_calloc.c
Normal file → Executable file
37
library/stdlib_calloc.c
Normal file → Executable file
@@ -48,36 +48,51 @@
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
__static void *
|
__static void *
|
||||||
__calloc(size_t num_elements,size_t element_size,const char * file,int line)
|
__calloc(size_t num_elements, size_t element_size, const char * file UNUSED, int line UNUSED)
|
||||||
{
|
{
|
||||||
void * result = NULL;
|
void * result = NULL;
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
/*__check_memory_allocations(file,line);*/
|
__check_memory_allocations(file, line);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
total_size = num_elements * element_size;
|
/* Check for overflow. */
|
||||||
|
total_size = element_size * num_elements;
|
||||||
|
if (num_elements > 0 && element_size > 0 && element_size != (total_size / num_elements))
|
||||||
|
{
|
||||||
|
D(("calloc(num_elements=%ld, element_size=%ld) overflow"));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
result = __malloc(total_size,file,line);
|
/* Note: malloc(0) may allocate memory and will also
|
||||||
if(result != NULL)
|
* initialize its contents to zero.
|
||||||
memset(result,0,total_size);
|
*/
|
||||||
else
|
result = __malloc(total_size, file, line);
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
SHOWMSG("memory allocation failure");
|
SHOWMSG("memory allocation failure");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
return(result);
|
if (total_size > 0)
|
||||||
|
memset(result, 0, total_size);
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void *
|
void *
|
||||||
calloc(size_t num_elements,size_t element_size)
|
calloc(size_t num_elements, size_t element_size)
|
||||||
{
|
{
|
||||||
void * result;
|
void * result;
|
||||||
|
|
||||||
result = __calloc(num_elements,element_size,NULL,0);
|
result = __calloc(num_elements, element_size, NULL, 0);
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,18 +59,18 @@ get_hex_char(int n)
|
|||||||
{
|
{
|
||||||
char result;
|
char result;
|
||||||
|
|
||||||
if(0 <= n && n <= 9)
|
if (0 <= n && n <= 9)
|
||||||
result = n + '0';
|
result = n + '0';
|
||||||
else
|
else
|
||||||
result = n + 'A' - 10;
|
result = n + 'A' - 10;
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC VOID
|
STATIC VOID
|
||||||
int_to_hex(unsigned long v,char * buffer,int min_digits)
|
int_to_hex(unsigned long v, char * buffer, int min_digits)
|
||||||
{
|
{
|
||||||
int i,j,c;
|
int i, j, c;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
@@ -81,12 +81,12 @@ int_to_hex(unsigned long v,char * buffer,int min_digits)
|
|||||||
|
|
||||||
buffer[i++] = get_hex_char(c);
|
buffer[i++] = get_hex_char(c);
|
||||||
}
|
}
|
||||||
while(v > 0);
|
while (v > 0);
|
||||||
|
|
||||||
while(i < min_digits)
|
while (i < min_digits)
|
||||||
buffer[i++] = '0';
|
buffer[i++] = '0';
|
||||||
|
|
||||||
for(j = 0 ; j < i / 2 ; j++)
|
for (j = 0 ; j < i / 2 ; j++)
|
||||||
{
|
{
|
||||||
c = buffer[i - 1 - j];
|
c = buffer[i - 1 - j];
|
||||||
buffer[i - 1 - j] = buffer[j];
|
buffer[i - 1 - j] = buffer[j];
|
||||||
@@ -97,47 +97,47 @@ int_to_hex(unsigned long v,char * buffer,int min_digits)
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATIC VOID
|
STATIC VOID
|
||||||
dump_memory(unsigned char * m,int size,int ignore)
|
dump_memory(const unsigned char * m, int size, int ignore)
|
||||||
{
|
{
|
||||||
const int mod = 20;
|
const int mod = 20;
|
||||||
int position,i,c;
|
int position, i, c;
|
||||||
char buffer[120];
|
char buffer[120];
|
||||||
char hex[10];
|
char hex[10];
|
||||||
|
|
||||||
buffer[0] = '\0';
|
buffer[0] = '\0';
|
||||||
|
|
||||||
for(i = 0 ; i < size ; i++)
|
for (i = 0 ; i < size ; i++)
|
||||||
{
|
{
|
||||||
position = i % mod;
|
position = i % mod;
|
||||||
if(position == 0)
|
if (position == 0)
|
||||||
{
|
{
|
||||||
if(buffer[0] != '\0')
|
if (buffer[0] != '\0')
|
||||||
{
|
{
|
||||||
int len = sizeof(buffer)-1;
|
int len = sizeof(buffer)-1;
|
||||||
|
|
||||||
while(len > 0 && buffer[len-1] == ' ')
|
while (len > 0 && buffer[len-1] == ' ')
|
||||||
len--;
|
len--;
|
||||||
|
|
||||||
buffer[len] = '\0';
|
buffer[len] = '\0';
|
||||||
|
|
||||||
kprintf("[%s] %s\n",__program_name,buffer);
|
kprintf("[%s] %s\n", __program_name, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(buffer,' ',sizeof(buffer)-1);
|
memset(buffer, ' ', sizeof(buffer)-1);
|
||||||
|
|
||||||
int_to_hex((unsigned long)&m[i],hex,8);
|
int_to_hex((unsigned long)&m[i], hex, 8);
|
||||||
|
|
||||||
memmove(buffer,hex,8);
|
memmove(buffer, hex, 8);
|
||||||
hex[9] = ':';
|
hex[9] = ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m[i] != ignore)
|
if (m[i] != ignore)
|
||||||
{
|
{
|
||||||
buffer[10 + 2 * position + 0] = get_hex_char(m[i] >> 4);
|
buffer[10 + 2 * position + 0] = get_hex_char(m[i] >> 4);
|
||||||
buffer[10 + 2 * position + 1] = get_hex_char(m[i] & 15);
|
buffer[10 + 2 * position + 1] = get_hex_char(m[i] & 15);
|
||||||
|
|
||||||
c = m[i];
|
c = m[i];
|
||||||
if(c < ' ' || (c >= 127 && c <= 160))
|
if (c < ' ' || (127 <= c && c < 160))
|
||||||
c = '.';
|
c = '.';
|
||||||
|
|
||||||
buffer[10 + 2 * mod + 1 + position] = c;
|
buffer[10 + 2 * mod + 1 + position] = c;
|
||||||
@@ -149,111 +149,111 @@ dump_memory(unsigned char * m,int size,int ignore)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(buffer[0] != '\0')
|
if (buffer[0] != '\0')
|
||||||
{
|
{
|
||||||
int len = sizeof(buffer)-1;
|
int len = sizeof(buffer)-1;
|
||||||
|
|
||||||
while(len > 0 && buffer[len-1] == ' ')
|
while (len > 0 && buffer[len-1] == ' ')
|
||||||
len--;
|
len--;
|
||||||
|
|
||||||
buffer[len] = '\0';
|
buffer[len] = '\0';
|
||||||
|
|
||||||
kprintf("[%s] %s\n",__program_name,buffer);
|
kprintf("[%s] %s\n", __program_name, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
STATIC VOID
|
STATIC VOID
|
||||||
check_memory_node(struct MemoryNode * mn,const char * file,int line)
|
check_memory_node(struct MemoryNode * mn, const char * file, int line)
|
||||||
{
|
{
|
||||||
ULONG size = GET_MN_SIZE(mn);
|
ULONG size = mn->mn_OriginalSize;
|
||||||
unsigned char * head = (unsigned char *)(mn + 1);
|
const unsigned char * head = (unsigned char *)&mn[1];
|
||||||
unsigned char * body = head + MALLOC_HEAD_SIZE;
|
const unsigned char * body = &head[MALLOC_HEAD_SIZE];
|
||||||
unsigned char * tail = body + size;
|
const unsigned char * tail = &body[size];
|
||||||
int max_head_damage = 0;
|
int max_head_damage = 0;
|
||||||
int max_tail_damage = 0;
|
int max_tail_damage = 0;
|
||||||
int max_body_damage = 0;
|
int max_body_damage = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 1 ; i <= MALLOC_HEAD_SIZE ; i++)
|
for (i = 1 ; i <= MALLOC_HEAD_SIZE ; i++)
|
||||||
{
|
{
|
||||||
if(head[MALLOC_HEAD_SIZE - i] != MALLOC_HEAD_FILL)
|
if (head[MALLOC_HEAD_SIZE - i] != MALLOC_HEAD_FILL)
|
||||||
max_head_damage = i;
|
max_head_damage = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(max_head_damage > 0)
|
if (max_head_damage > 0)
|
||||||
{
|
{
|
||||||
kprintf("[%s] ",__program_name);
|
kprintf("[%s] ", __program_name);
|
||||||
|
|
||||||
if(file != NULL)
|
if (file != NULL)
|
||||||
kprintf("%s:%ld:",file,line);
|
kprintf("%s:%ld:", file, line);
|
||||||
|
|
||||||
kprintf("At least %ld bytes were damaged in front of allocation 0x%08lx..0x%08lx, size = %ld",
|
kprintf("At least %ld bytes were damaged in front of allocation 0x%08lx..0x%08lx, size = %ld",
|
||||||
max_head_damage,
|
max_head_damage,
|
||||||
body,body + size - 1,size);
|
body, body + size - 1, size);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if (mn->mn_File != NULL)
|
||||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||||
|
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
|
|
||||||
dump_memory(head,MALLOC_HEAD_SIZE,MALLOC_HEAD_FILL);
|
dump_memory(head, MALLOC_HEAD_SIZE, MALLOC_HEAD_FILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0 ; i < MALLOC_TAIL_SIZE ; i++)
|
for (i = 0 ; i < MALLOC_TAIL_SIZE ; i++)
|
||||||
{
|
{
|
||||||
if(tail[i] != MALLOC_TAIL_FILL)
|
if (tail[i] != MALLOC_TAIL_FILL)
|
||||||
max_tail_damage = i+1;
|
max_tail_damage = i+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(max_tail_damage > 0)
|
if (max_tail_damage > 0)
|
||||||
{
|
{
|
||||||
kprintf("[%s] ",__program_name);
|
kprintf("[%s] ", __program_name);
|
||||||
|
|
||||||
if(file != NULL)
|
if (file != NULL)
|
||||||
kprintf("%s:%ld:",file,line);
|
kprintf("%s:%ld:", file, line);
|
||||||
|
|
||||||
kprintf("At least %ld bytes were damaged behind allocation 0x%08lx..0x%08lx, size = %ld (with damage = %ld)",
|
kprintf("At least %ld bytes were damaged behind allocation 0x%08lx..0x%08lx, size = %ld (with damage = %ld)",
|
||||||
max_tail_damage,
|
max_tail_damage,
|
||||||
body,body + size - 1,
|
body, body + size - 1,
|
||||||
size,size+max_tail_damage);
|
size, size + max_tail_damage);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if (mn->mn_File != NULL)
|
||||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||||
|
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
|
|
||||||
dump_memory(tail,MALLOC_TAIL_SIZE,MALLOC_TAIL_FILL);
|
dump_memory(tail, MALLOC_TAIL_SIZE, MALLOC_TAIL_FILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mn->mn_AlreadyFree)
|
if (mn->mn_AlreadyFree)
|
||||||
{
|
{
|
||||||
ULONG j;
|
ULONG j;
|
||||||
|
|
||||||
for(j = 0 ; j < size ; j++)
|
for (j = 0 ; j < size ; j++)
|
||||||
{
|
{
|
||||||
if(body[j] != MALLOC_FREE_FILL)
|
if (body[j] != MALLOC_FREE_FILL)
|
||||||
max_body_damage = j+1;
|
max_body_damage = j+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(max_body_damage > 0)
|
if (max_body_damage > 0)
|
||||||
{
|
{
|
||||||
kprintf("[%s] ",__program_name);
|
kprintf("[%s] ", __program_name);
|
||||||
|
|
||||||
if(file != NULL)
|
if (file != NULL)
|
||||||
kprintf("%s:%ld:",file,line);
|
kprintf("%s:%ld:", file, line);
|
||||||
|
|
||||||
kprintf("At least %ld bytes were damaged in freed allocation 0x%08lx..0x%08lx, size = %ld",
|
kprintf("At least %ld bytes were damaged in freed allocation 0x%08lx..0x%08lx, size = %ld",
|
||||||
max_body_damage,
|
max_body_damage,
|
||||||
body,body + size - 1,size);
|
body, body + size - 1, size);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if (mn->mn_File != NULL)
|
||||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||||
|
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
|
|
||||||
dump_memory(body,size,MALLOC_FREE_FILL);
|
dump_memory(body, size, MALLOC_FREE_FILL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,17 +261,17 @@ check_memory_node(struct MemoryNode * mn,const char * file,int line)
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
__check_memory_allocations(const char * file,int line)
|
__check_memory_allocations(const char * file, int line)
|
||||||
{
|
{
|
||||||
struct MemoryNode * mn;
|
struct MemoryNode * mn;
|
||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
for(mn = (struct MemoryNode *)__memory_list.mlh_Head ;
|
for (mn = (struct MemoryNode *)__memory_list.mlh_Head ;
|
||||||
mn->mn_MinNode.mln_Succ != NULL ;
|
mn->mn_MinNode.mln_Succ != NULL ;
|
||||||
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
|
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
|
||||||
{
|
{
|
||||||
check_memory_node(mn,file,line);
|
check_memory_node(mn, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
__memory_unlock();
|
__memory_unlock();
|
||||||
@@ -290,7 +290,7 @@ __find_memory_node(void * address)
|
|||||||
|
|
||||||
#if defined(__USE_MEM_TREES)
|
#if defined(__USE_MEM_TREES)
|
||||||
{
|
{
|
||||||
result = __red_black_tree_find(&__memory_tree,address);
|
result = __red_black_tree_find(&__memory_tree, address);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
@@ -298,11 +298,11 @@ __find_memory_node(void * address)
|
|||||||
|
|
||||||
result = NULL;
|
result = NULL;
|
||||||
|
|
||||||
for(mn = (struct MemoryNode *)__memory_list.mlh_Head ;
|
for (mn = (struct MemoryNode *)__memory_list.mlh_Head ;
|
||||||
mn->mn_MinNode.mln_Succ != NULL ;
|
mn->mn_MinNode.mln_Succ != NULL ;
|
||||||
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
|
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
|
||||||
{
|
{
|
||||||
if(address == mn->mn_Allocation)
|
if (address == mn->mn_Allocation)
|
||||||
{
|
{
|
||||||
result = mn;
|
result = mn;
|
||||||
break;
|
break;
|
||||||
@@ -331,7 +331,7 @@ __find_memory_node(void * address)
|
|||||||
|
|
||||||
result = &((struct MemoryNode *)address)[-1];
|
result = &((struct MemoryNode *)address)[-1];
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@@ -349,96 +349,84 @@ remove_and_free_memory_node(struct MemoryNode * mn)
|
|||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
|
allocation_size = mn->mn_AllocationSize;
|
||||||
|
|
||||||
#if defined(__MEM_DEBUG)
|
#if defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
Remove((struct Node *)mn);
|
Remove((struct Node *)mn);
|
||||||
|
|
||||||
#if defined(__USE_MEM_TREES)
|
#if defined(__USE_MEM_TREES)
|
||||||
{
|
{
|
||||||
__red_black_tree_remove(&__memory_tree,mn);
|
__red_black_tree_remove(&__memory_tree, mn);
|
||||||
}
|
}
|
||||||
#endif /* __USE_MEM_TREES */
|
#endif /* __USE_MEM_TREES */
|
||||||
|
|
||||||
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + GET_MN_SIZE(mn) + MALLOC_TAIL_SIZE;
|
memset(mn, MALLOC_FREE_FILL, allocation_size);
|
||||||
|
|
||||||
assert( allocation_size == mn->mn_AllocationSize );
|
|
||||||
|
|
||||||
memset(mn,MALLOC_FREE_FILL,allocation_size);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
allocation_size = sizeof(*mn) + GET_MN_SIZE(mn);
|
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
#if defined(__USE_SLAB_ALLOCATOR)
|
#if defined(__USE_SLAB_ALLOCATOR)
|
||||||
{
|
{
|
||||||
/* Are we using the slab allocator? */
|
/* Are we using the slab allocator? */
|
||||||
if(__slab_data.sd_InUse)
|
if (__slab_data.sd_InUse)
|
||||||
{
|
{
|
||||||
__slab_free(mn,allocation_size);
|
/* No need to remove the memory node because it was never
|
||||||
|
* added or has already been removed if the memory debugging
|
||||||
|
* option is in effect.
|
||||||
|
*/
|
||||||
|
__slab_free(mn, allocation_size);
|
||||||
}
|
}
|
||||||
|
/* Are we using the memory pool? */
|
||||||
|
else if (__memory_pool != NULL)
|
||||||
|
{
|
||||||
|
/* No need to remove the memory node because it was never
|
||||||
|
* added or has already been removed if the memory debugging
|
||||||
|
* option is in effect.
|
||||||
|
*/
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreePooled(__memory_pool, mn, allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
/* So we have to do this the hard way... */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(__memory_pool != NULL)
|
#if NOT defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
PROFILE_OFF();
|
Remove((struct Node *)mn);
|
||||||
FreePooled(__memory_pool,mn,allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
}
|
||||||
else
|
#endif /* __MEM_DEBUG */
|
||||||
{
|
|
||||||
#if defined(__MEM_DEBUG)
|
|
||||||
{
|
|
||||||
PROFILE_OFF();
|
|
||||||
FreeMem(mn,allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
struct MinNode * mln = (struct MinNode *)mn;
|
|
||||||
|
|
||||||
mln--;
|
PROFILE_OFF();
|
||||||
|
FreeMem(mn, allocation_size);
|
||||||
Remove((struct Node *)mln);
|
PROFILE_ON();
|
||||||
|
|
||||||
PROFILE_OFF();
|
|
||||||
FreeMem(mln,sizeof(*mln) + allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
#endif /* __MEM_DEBUG */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
if(__memory_pool != NULL)
|
if (__memory_pool != NULL)
|
||||||
{
|
{
|
||||||
|
/* No need to remove the memory node because it was never
|
||||||
|
* added or has already been removed if the memory debugging
|
||||||
|
* option is in effect.
|
||||||
|
*/
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
FreePooled(__memory_pool,mn,allocation_size);
|
FreePooled(__memory_pool, mn, allocation_size);
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if defined(__MEM_DEBUG)
|
#if NOT defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
PROFILE_OFF();
|
Remove((struct Node *)mn);
|
||||||
FreeMem(mn,allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
struct MinNode * mln = (struct MinNode *)mn;
|
|
||||||
|
|
||||||
mln--;
|
|
||||||
|
|
||||||
Remove((struct Node *)mln);
|
|
||||||
|
|
||||||
PROFILE_OFF();
|
|
||||||
FreeMem(mln,sizeof(*mln) + allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
|
/* No need to remove the memory node because the memory
|
||||||
|
* debugging option is in effect.
|
||||||
|
*/
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreeMem(mn, allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __USE_SLAB_ALLOCATOR */
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
@@ -452,37 +440,35 @@ remove_and_free_memory_node(struct MemoryNode * mn)
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
__free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED line)
|
__free_memory_node(struct MemoryNode * mn, const char * UNUSED file, int UNUSED line)
|
||||||
{
|
{
|
||||||
assert(mn != NULL);
|
assert(mn != NULL);
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
ULONG size = GET_MN_SIZE(mn);
|
check_memory_node(mn, file, line);
|
||||||
|
|
||||||
check_memory_node(mn,file,line);
|
if (NOT mn->mn_AlreadyFree)
|
||||||
|
|
||||||
if(NOT mn->mn_AlreadyFree)
|
|
||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name,size,mn->mn_Allocation);
|
kprintf("[%s] - %10ld 0x%08lx [",__program_name, mn->mn_OriginalSize, mn->mn_Allocation);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if (mn->mn_File != NULL)
|
||||||
kprintf("allocated at %s:%ld, ",mn->mn_File,mn->mn_Line);
|
kprintf("allocated at %s:%ld, ", mn->mn_File, mn->mn_Line);
|
||||||
|
|
||||||
kprintf("freed at %s:%ld]\n",file,line);
|
kprintf("freed at %s:%ld]\n", file, line);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
if(__never_free)
|
if (__never_free)
|
||||||
{
|
{
|
||||||
mn->mn_AlreadyFree = TRUE;
|
mn->mn_AlreadyFree = TRUE;
|
||||||
|
|
||||||
mn->mn_FreeFile = (char *)file;
|
mn->mn_FreeFile = (char *)file;
|
||||||
mn->mn_FreeLine = line;
|
mn->mn_FreeLine = line;
|
||||||
|
|
||||||
memset(mn->mn_Allocation,MALLOC_FREE_FILL,size);
|
memset(&mn[1], MALLOC_FREE_FILL, MALLOC_HEAD_SIZE + mn->mn_OriginalSize + MALLOC_TAIL_SIZE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -493,19 +479,19 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
|
|||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name,size,mn->mn_Allocation);
|
kprintf("[%s] - %10ld 0x%08lx [", __program_name, mn->mn_AllocationSize, mn);
|
||||||
|
|
||||||
kprintf("FAILED]\n");
|
kprintf("FAILED]\n");
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
kprintf("[%s] %s:%ld:Allocation at address 0x%08lx, size %ld",
|
kprintf("[%s] %s:%ld:Allocation at address 0x%08lx, size %ld",
|
||||||
__program_name,file,line,mn->mn_Allocation,size);
|
__program_name, file, line, mn->mn_Allocation, mn->mn_OriginalSize);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if (mn->mn_File != NULL)
|
||||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||||
|
|
||||||
kprintf(", has already been freed at %s:%ld.\n",mn->mn_FreeFile,mn->mn_FreeLine);
|
kprintf(", has already been freed at %s:%ld.\n", mn->mn_FreeFile, mn->mn_FreeLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -518,7 +504,7 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
__free_memory(void * ptr,BOOL force,const char * file,int line)
|
__free_memory(void * ptr, BOOL force, const char * file, int line)
|
||||||
{
|
{
|
||||||
struct MemoryNode * mn;
|
struct MemoryNode * mn;
|
||||||
|
|
||||||
@@ -529,7 +515,7 @@ __free_memory(void * ptr,BOOL force,const char * file,int line)
|
|||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
/*if((rand() % 16) == 0)
|
/*if ((rand() % 16) == 0)
|
||||||
__check_memory_allocations(file,line);*/
|
__check_memory_allocations(file,line);*/
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
@@ -538,34 +524,37 @@ __free_memory(void * ptr,BOOL force,const char * file,int line)
|
|||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
if(mn != NULL)
|
if (mn != NULL)
|
||||||
{
|
{
|
||||||
if(force || FLAG_IS_CLEAR(mn->mn_Size, MN_SIZE_NEVERFREE))
|
if (force || FLAG_IS_CLEAR(mn->mn_Flags, MNF_NEVER_FREE))
|
||||||
__free_memory_node(mn,file,line);
|
__free_memory_node(mn, file, line);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name,0,ptr);
|
kprintf("[%s] - %10ld 0x%08lx [", __program_name, 0, ptr);
|
||||||
|
|
||||||
kprintf("FAILED]\n");
|
kprintf("FAILED]\n");
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
kprintf("[%s] %s:%ld:Address for free(0x%08lx) not known.\n",__program_name,file,line,ptr);
|
kprintf("[%s] %s:%ld:Address for free(0x%08lx) not known.\n", __program_name, file, line, ptr);
|
||||||
|
|
||||||
D(("memory allocation at 0x%08lx could not be freed",ptr));
|
D(("memory allocation at 0x%08lx could not be freed", ptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
assert( mn != NULL );
|
assert( mn != NULL );
|
||||||
|
|
||||||
SHOWVALUE(mn->mn_Size);
|
if (FLAG_IS_SET(mn->mn_Flags, MNF_NEVER_FREE))
|
||||||
|
D(("mn->mn_AllocationSize=%ld (0x%08lx), not to be freed", mn->mn_AllocationSize, mn->mn_AllocationSize));
|
||||||
|
else
|
||||||
|
D(("mn->mn_AllocationSize=%ld (0x%08lx)", mn->mn_AllocationSize, mn->mn_AllocationSize));
|
||||||
|
|
||||||
if(mn != NULL && (force || FLAG_IS_CLEAR(mn->mn_Size, MN_SIZE_NEVERFREE)))
|
if (mn != NULL && (force || FLAG_IS_CLEAR(mn->mn_Flags, MNF_NEVER_FREE)))
|
||||||
__free_memory_node(mn,file,line);
|
__free_memory_node(mn, file, line);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
}
|
}
|
||||||
@@ -578,13 +567,13 @@ __free(void * ptr,const char * file,int line)
|
|||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
/* Try to get rid of now unused memory. */
|
/* Try to get rid of now unused memory. */
|
||||||
if(__alloca_cleanup != NULL)
|
if (__alloca_cleanup != NULL)
|
||||||
(*__alloca_cleanup)(file,line);
|
(*__alloca_cleanup)(file, line);
|
||||||
|
|
||||||
__memory_unlock();
|
__memory_unlock();
|
||||||
|
|
||||||
if(ptr != NULL)
|
if (ptr != NULL)
|
||||||
__free_memory(ptr,FALSE,file,line);
|
__free_memory(ptr, FALSE, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@@ -592,5 +581,5 @@ __free(void * ptr,const char * file,int line)
|
|||||||
void
|
void
|
||||||
free(void * ptr)
|
free(void * ptr)
|
||||||
{
|
{
|
||||||
__free(ptr,NULL,0);
|
__free(ptr, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
26
library/stdlib_get_slab_usage.c
Normal file → Executable file
26
library/stdlib_get_slab_usage.c
Normal file → Executable file
@@ -44,14 +44,14 @@
|
|||||||
void
|
void
|
||||||
__get_slab_usage(__slab_usage_callback callback)
|
__get_slab_usage(__slab_usage_callback callback)
|
||||||
{
|
{
|
||||||
if(__slab_data.sd_InUse)
|
if (__slab_data.sd_InUse)
|
||||||
{
|
{
|
||||||
struct __slab_usage_information sui;
|
struct __slab_usage_information sui;
|
||||||
const struct SlabNode * sn;
|
const struct SlabNode * sn;
|
||||||
BOOL stop;
|
BOOL stop;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memset(&sui,0,sizeof(sui));
|
memset(&sui, 0, sizeof(sui));
|
||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
@@ -59,11 +59,11 @@ __get_slab_usage(__slab_usage_callback callback)
|
|||||||
sui.sui_num_single_allocations = __slab_data.sd_NumSingleAllocations;
|
sui.sui_num_single_allocations = __slab_data.sd_NumSingleAllocations;
|
||||||
sui.sui_total_single_allocation_size = __slab_data.sd_TotalSingleAllocationSize;
|
sui.sui_total_single_allocation_size = __slab_data.sd_TotalSingleAllocationSize;
|
||||||
|
|
||||||
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
for (i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||||
{
|
{
|
||||||
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
for (sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||||
sn->sn_MinNode.mln_Succ != NULL ;
|
sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||||
{
|
{
|
||||||
if (sn->sn_UseCount == 0)
|
if (sn->sn_UseCount == 0)
|
||||||
sui.sui_num_empty_slabs++;
|
sui.sui_num_empty_slabs++;
|
||||||
@@ -76,13 +76,15 @@ __get_slab_usage(__slab_usage_callback callback)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sui.sui_num_slabs > 0)
|
if (sui.sui_num_slabs > 0)
|
||||||
{
|
{
|
||||||
for(i = 0, stop = FALSE ; NOT stop && i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
for (i = 0, stop = FALSE ;
|
||||||
|
stop == FALSE && i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ;
|
||||||
|
i++)
|
||||||
{
|
{
|
||||||
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
for (sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||||
sn->sn_MinNode.mln_Succ != NULL ;
|
sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||||
{
|
{
|
||||||
sui.sui_chunk_size = sn->sn_ChunkSize;
|
sui.sui_chunk_size = sn->sn_ChunkSize;
|
||||||
sui.sui_num_chunks = sn->sn_Count;
|
sui.sui_num_chunks = sn->sn_Count;
|
||||||
@@ -91,7 +93,7 @@ __get_slab_usage(__slab_usage_callback callback)
|
|||||||
|
|
||||||
sui.sui_slab_index++;
|
sui.sui_slab_index++;
|
||||||
|
|
||||||
if((*callback)(&sui) != 0)
|
if ((*callback)(&sui) != 0)
|
||||||
{
|
{
|
||||||
stop = TRUE;
|
stop = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -189,6 +189,10 @@ extern BOOL NOCOMMON __lib_startup;
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
extern int __addition_overflows(ULONG x, ULONG y);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
extern void NOCOMMON (*__alloca_trap)(void);
|
extern void NOCOMMON (*__alloca_trap)(void);
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
unsigned long NOCOMMON __maximum_memory_allocated;
|
unsigned long NOCOMMON __maximum_memory_allocated;
|
||||||
unsigned long NOCOMMON __current_memory_allocated;
|
unsigned long NOCOMMON __current_memory_allocated;
|
||||||
|
|
||||||
unsigned long NOCOMMON __maximum_num_memory_chunks_allocated;
|
unsigned long NOCOMMON __maximum_num_memory_chunks_allocated;
|
||||||
unsigned long NOCOMMON __current_num_memory_chunks_allocated;
|
unsigned long NOCOMMON __current_num_memory_chunks_allocated;
|
||||||
|
|
||||||
@@ -74,35 +75,59 @@ struct MinList NOCOMMON __memory_list;
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void *
|
/* Check if the sum of two unsigned 32-bit integers will be larger than what
|
||||||
__allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_name,int UNUSED debug_line_number)
|
* an unsigned 32-bit integer can hold and return the overflow. This
|
||||||
|
* algorithm comes from Henry S. Warren's book "Hacker's delight".
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
__addition_overflows(ULONG x, ULONG y)
|
||||||
{
|
{
|
||||||
struct MemoryNode * mn;
|
ULONG z;
|
||||||
|
|
||||||
|
assert( sizeof(x) == 4 );
|
||||||
|
assert( sizeof(y) == 4 );
|
||||||
|
|
||||||
|
z = (x & y) | ((x | y) & ~(x + y));
|
||||||
|
|
||||||
|
return ((LONG)z) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void *
|
||||||
|
__allocate_memory(
|
||||||
|
size_t size,
|
||||||
|
BOOL never_free,
|
||||||
|
const char * debug_file_name UNUSED,
|
||||||
|
int debug_line_number UNUSED)
|
||||||
|
{
|
||||||
|
struct MemoryNode * mn UNUSED;
|
||||||
size_t allocation_size;
|
size_t allocation_size;
|
||||||
void * result = NULL;
|
void * result = NULL;
|
||||||
size_t original_size;
|
size_t original_size UNUSED;
|
||||||
|
|
||||||
#if defined(UNIX_PATH_SEMANTICS)
|
#if defined(UNIX_PATH_SEMANTICS)
|
||||||
{
|
{
|
||||||
original_size = size;
|
original_size = size;
|
||||||
|
|
||||||
/* The libunix.a flavour accepts zero length memory allocations
|
/* The libunix.a flavour of malloc() accepts zero-length
|
||||||
and quietly turns them into a pointer sized allocations. */
|
memory allocations and quietly turns these into
|
||||||
if(size == 0)
|
pointer-sized allocations. */
|
||||||
size = sizeof(char *);
|
if (size == 0)
|
||||||
|
size = sizeof(BYTE *);
|
||||||
}
|
}
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
/* Zero length allocations are by default rejected. */
|
/* Zero length allocations are by default rejected. */
|
||||||
if(size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
__set_errno(EINVAL);
|
__set_errno(EINVAL);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(__free_memory_threshold > 0 && AvailMem(MEMF_ANY|MEMF_LARGEST) < __free_memory_threshold)
|
if (__free_memory_threshold > 0 && AvailMem(MEMF_ANY|MEMF_LARGEST) < __free_memory_threshold)
|
||||||
{
|
{
|
||||||
SHOWMSG("not enough free memory available to safely proceed with allocation");
|
SHOWMSG("not enough free memory available to safely proceed with allocation");
|
||||||
goto out;
|
goto out;
|
||||||
@@ -114,172 +139,140 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam
|
|||||||
assert( MALLOC_TAIL_SIZE > 0 && (MALLOC_TAIL_SIZE % 4) == 0 );
|
assert( MALLOC_TAIL_SIZE > 0 && (MALLOC_TAIL_SIZE % 4) == 0 );
|
||||||
assert( (sizeof(*mn) % 4) == 0 );
|
assert( (sizeof(*mn) % 4) == 0 );
|
||||||
|
|
||||||
|
if (__addition_overflows(sizeof(*mn) + MALLOC_HEAD_SIZE + MALLOC_TAIL_SIZE, size))
|
||||||
|
{
|
||||||
|
SHOWMSG("integer overflow");
|
||||||
|
|
||||||
|
__set_errno(ENOMEM);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + size + MALLOC_TAIL_SIZE;
|
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + size + MALLOC_TAIL_SIZE;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
/* Round up allocation to a multiple of 32 bits. */
|
if (__addition_overflows(sizeof(*mn), size))
|
||||||
if((size & 3) != 0)
|
{
|
||||||
size += 4 - (size & 3);
|
SHOWMSG("integer overflow");
|
||||||
|
|
||||||
|
__set_errno(ENOMEM);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
allocation_size = sizeof(*mn) + size;
|
allocation_size = sizeof(*mn) + size;
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
/* Integer overflow has occured? */
|
/* Round up allocation to a multiple of 8 bytes. */
|
||||||
if(size == 0 || allocation_size < size)
|
if ((allocation_size % MEM_BLOCKSIZE) > 0)
|
||||||
{
|
{
|
||||||
__set_errno(ENOMEM);
|
size_t padding;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We reuse the MemoryNode.mn_Size field to mark
|
padding = MEM_BLOCKSIZE - (allocation_size % MEM_BLOCKSIZE);
|
||||||
* allocations are not suitable for use with
|
|
||||||
* free() and realloc(). This limits allocation
|
if (__addition_overflows(padding, allocation_size))
|
||||||
* sizes to a little less than 2 GBytes.
|
{
|
||||||
*/
|
SHOWMSG("integer overflow");
|
||||||
if(allocation_size & MN_SIZE_NEVERFREE)
|
|
||||||
{
|
__set_errno(ENOMEM);
|
||||||
__set_errno(ENOMEM);
|
goto out;
|
||||||
goto out;
|
}
|
||||||
|
|
||||||
|
allocation_size += padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__USE_SLAB_ALLOCATOR)
|
#if defined(__USE_SLAB_ALLOCATOR)
|
||||||
{
|
{
|
||||||
/* Are we using the slab allocator? */
|
/* Are we using the slab allocator? */
|
||||||
if(__slab_data.sd_InUse)
|
if (__slab_data.sd_InUse)
|
||||||
{
|
{
|
||||||
mn = __slab_allocate(allocation_size);
|
mn = __slab_allocate(allocation_size);
|
||||||
|
|
||||||
|
SHOWPOINTER(mn);
|
||||||
|
|
||||||
|
assert( (((ULONG)mn) & MEM_BLOCKMASK) == 0 );
|
||||||
|
assert( (((ULONG)&mn[1]) & MEM_BLOCKMASK) == 0 );
|
||||||
}
|
}
|
||||||
|
/* Are we using the memory pool? */
|
||||||
|
else if (__memory_pool != NULL)
|
||||||
|
{
|
||||||
|
PROFILE_OFF();
|
||||||
|
mn = AllocPooled(__memory_pool, allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
/* Then we'll have to do it the hard way... */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (__memory_pool != NULL)
|
PROFILE_OFF();
|
||||||
{
|
mn = AllocMem(allocation_size, MEMF_ANY);
|
||||||
PROFILE_OFF();
|
PROFILE_ON();
|
||||||
mn = AllocPooled(__memory_pool,allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef __MEM_DEBUG
|
|
||||||
{
|
|
||||||
PROFILE_OFF();
|
|
||||||
mn = AllocMem(allocation_size,MEMF_ANY);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
struct MinNode * mln;
|
|
||||||
|
|
||||||
PROFILE_OFF();
|
|
||||||
mln = AllocMem(sizeof(*mln) + allocation_size,MEMF_ANY);
|
|
||||||
PROFILE_ON();
|
|
||||||
|
|
||||||
if(mln != NULL)
|
|
||||||
{
|
|
||||||
AddTail((struct List *)&__memory_list,(struct Node *)mln);
|
|
||||||
|
|
||||||
mn = (struct MemoryNode *)&mln[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mn = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* __MEM_DEBUG */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
if(__memory_pool != NULL)
|
if (__memory_pool != NULL)
|
||||||
{
|
{
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
mn = AllocPooled(__memory_pool,allocation_size);
|
mn = AllocPooled(__memory_pool, allocation_size);
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG
|
PROFILE_OFF();
|
||||||
{
|
mn = AllocMem(allocation_size, MEMF_ANY);
|
||||||
PROFILE_OFF();
|
PROFILE_ON();
|
||||||
mn = AllocMem(allocation_size,MEMF_ANY);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
struct MinNode * mln;
|
|
||||||
|
|
||||||
PROFILE_OFF();
|
|
||||||
mln = AllocMem(sizeof(*mln) + allocation_size,MEMF_ANY);
|
|
||||||
PROFILE_ON();
|
|
||||||
|
|
||||||
if(mln != NULL)
|
|
||||||
{
|
|
||||||
AddTail((struct List *)&__memory_list,(struct Node *)mln);
|
|
||||||
|
|
||||||
mn = (struct MemoryNode *)&mln[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mn = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* __MEM_DEBUG */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __USE_SLAB_ALLOCATOR */
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
|
|
||||||
if(mn == NULL)
|
if (mn == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("not enough memory");
|
SHOWMSG("not enough memory");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
mn->mn_Size = size;
|
mn->mn_AllocationSize = allocation_size;
|
||||||
|
mn->mn_Flags = never_free ? MNF_NEVER_FREE : 0;
|
||||||
if(never_free)
|
|
||||||
SET_FLAG(mn->mn_Size, MN_SIZE_NEVERFREE);
|
|
||||||
|
|
||||||
__current_memory_allocated += allocation_size;
|
__current_memory_allocated += allocation_size;
|
||||||
if(__maximum_memory_allocated < __current_memory_allocated)
|
if (__maximum_memory_allocated < __current_memory_allocated)
|
||||||
__maximum_memory_allocated = __current_memory_allocated;
|
__maximum_memory_allocated = __current_memory_allocated;
|
||||||
|
|
||||||
__current_num_memory_chunks_allocated++;
|
__current_num_memory_chunks_allocated++;
|
||||||
if(__maximum_num_memory_chunks_allocated < __current_num_memory_chunks_allocated)
|
if (__maximum_num_memory_chunks_allocated < __current_num_memory_chunks_allocated)
|
||||||
__maximum_num_memory_chunks_allocated = __current_num_memory_chunks_allocated;
|
__maximum_num_memory_chunks_allocated = __current_num_memory_chunks_allocated;
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
char * head = (char *)(mn + 1);
|
BYTE * head = (BYTE *)&mn[1];
|
||||||
char * body = head + MALLOC_HEAD_SIZE;
|
BYTE * body = &head[MALLOC_HEAD_SIZE];
|
||||||
char * tail = body + size;
|
BYTE * tail = &body[size];
|
||||||
|
|
||||||
AddTail((struct List *)&__memory_list,(struct Node *)mn);
|
|
||||||
|
|
||||||
mn->mn_AlreadyFree = FALSE;
|
mn->mn_AlreadyFree = FALSE;
|
||||||
mn->mn_Allocation = body;
|
mn->mn_Allocation = body;
|
||||||
mn->mn_AllocationSize = allocation_size;
|
mn->mn_OriginalSize = size;
|
||||||
mn->mn_File = (char *)debug_file_name;
|
mn->mn_File = (char *)debug_file_name;
|
||||||
mn->mn_Line = debug_line_number;
|
mn->mn_Line = debug_line_number;
|
||||||
mn->mn_FreeFile = NULL;
|
mn->mn_FreeFile = NULL;
|
||||||
mn->mn_FreeLine = 0;
|
mn->mn_FreeLine = 0;
|
||||||
|
|
||||||
memset(head,MALLOC_HEAD_FILL,MALLOC_HEAD_SIZE);
|
memset(head, MALLOC_HEAD_FILL, MALLOC_HEAD_SIZE);
|
||||||
memset(body,MALLOC_NEW_FILL,size);
|
memset(body, MALLOC_NEW_FILL, size);
|
||||||
memset(tail,MALLOC_TAIL_FILL,MALLOC_TAIL_SIZE);
|
memset(tail, MALLOC_TAIL_FILL, MALLOC_TAIL_SIZE);
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
kprintf("[%s] + %10ld 0x%08lx [",__program_name,size,body);
|
kprintf("[%s] + %10ld 0x%08lx [", __program_name, size, body);
|
||||||
|
|
||||||
kprintf("allocated at %s:%ld]\n",debug_file_name,debug_line_number);
|
kprintf("allocated at %s:%ld]\n", debug_file_name, debug_line_number);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
|
AddTail((struct List *)&__memory_list,(struct Node *)mn);
|
||||||
|
|
||||||
#ifdef __USE_MEM_TREES
|
#ifdef __USE_MEM_TREES
|
||||||
{
|
{
|
||||||
__red_black_tree_insert(&__memory_tree,mn);
|
__red_black_tree_insert(&__memory_tree, mn);
|
||||||
}
|
}
|
||||||
#endif /* __USE_MEM_TREES */
|
#endif /* __USE_MEM_TREES */
|
||||||
|
|
||||||
@@ -287,6 +280,22 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
|
#if defined(__USE_SLAB_ALLOCATOR)
|
||||||
|
{
|
||||||
|
/* If we are using neither the slab allocator nor
|
||||||
|
* the memory pool, then the allocation will have
|
||||||
|
* to be freed later, the hard way.
|
||||||
|
*/
|
||||||
|
if (__slab_data.sd_InUse == FALSE && __memory_pool == NULL)
|
||||||
|
AddTail((struct List *)&__memory_list, (struct Node *)mn);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
if (__memory_pool == NULL)
|
||||||
|
AddTail((struct List *)&__memory_list, (struct Node *)mn);
|
||||||
|
}
|
||||||
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
|
|
||||||
result = &mn[1];
|
result = &mn[1];
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
@@ -294,57 +303,57 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam
|
|||||||
#if defined(UNIX_PATH_SEMANTICS)
|
#if defined(UNIX_PATH_SEMANTICS)
|
||||||
{
|
{
|
||||||
/* Set the zero length allocation contents to NULL. */
|
/* Set the zero length allocation contents to NULL. */
|
||||||
if(original_size == 0)
|
if (original_size == 0 && size >= sizeof(BYTE *))
|
||||||
*(char **)result = NULL;
|
*(BYTE **)result = NULL;
|
||||||
}
|
}
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
|
|
||||||
assert( (((ULONG)result) & 3) == 0 );
|
assert( (((ULONG)result) & MEM_BLOCKMASK) == 0 );
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
if(result == NULL)
|
if (result == NULL)
|
||||||
{
|
{
|
||||||
kprintf("[%s] + %10ld 0x%08lx [",__program_name,size,NULL);
|
kprintf("[%s] + %10ld 0x%08lx [", __program_name, size, NULL);
|
||||||
|
|
||||||
kprintf("FAILED: allocated at %s:%ld]\n",debug_file_name,debug_line_number);
|
kprintf("FAILED: allocated at %s:%ld]\n", debug_file_name, debug_line_number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
__memory_unlock();
|
__memory_unlock();
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
__static void *
|
__static void *
|
||||||
__malloc(size_t size,const char * file,int line)
|
__malloc(size_t size, const char * file, int line)
|
||||||
{
|
{
|
||||||
void * result = NULL;
|
void * result = NULL;
|
||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
/* Try to get rid of now unused memory. */
|
/* Try to get rid of now unused memory. */
|
||||||
if(__alloca_cleanup != NULL)
|
if (__alloca_cleanup != NULL)
|
||||||
(*__alloca_cleanup)(file,line);
|
(*__alloca_cleanup)(file, line);
|
||||||
|
|
||||||
__memory_unlock();
|
__memory_unlock();
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
/*if((rand() % 16) == 0)
|
/*if ((rand() % 16) == 0)
|
||||||
__check_memory_allocations(file,line);*/
|
__check_memory_allocations(file,line);*/
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
/* Allocate memory which can be put through realloc() and free(). */
|
/* Allocate memory which can be put through realloc() and free(). */
|
||||||
result = __allocate_memory(size,FALSE,file,line);
|
result = __allocate_memory(size, FALSE, file, line);
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@@ -354,7 +363,7 @@ malloc(size_t size)
|
|||||||
{
|
{
|
||||||
void * result;
|
void * result;
|
||||||
|
|
||||||
result = __malloc(size,NULL,0);
|
result = __malloc(size, NULL, 0);
|
||||||
|
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
@@ -374,7 +383,7 @@ __memory_lock(void)
|
|||||||
{
|
{
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
|
|
||||||
if(memory_semaphore != NULL)
|
if (memory_semaphore != NULL)
|
||||||
ObtainSemaphore(memory_semaphore);
|
ObtainSemaphore(memory_semaphore);
|
||||||
|
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
@@ -387,7 +396,7 @@ __memory_unlock(void)
|
|||||||
{
|
{
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
|
|
||||||
if(memory_semaphore != NULL)
|
if (memory_semaphore != NULL)
|
||||||
ReleaseSemaphore(memory_semaphore);
|
ReleaseSemaphore(memory_semaphore);
|
||||||
|
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
@@ -403,30 +412,34 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
|
|||||||
{
|
{
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
|
/* Make sure that freeing any memory does not also
|
||||||
|
* trigger the alloca cleanup operations. Otherwise,
|
||||||
|
* the data structures used by alloca() to track
|
||||||
|
* the scope in which allocated memory remains
|
||||||
|
* valid and should not be freed just yet may be
|
||||||
|
* freed, corrupting them.
|
||||||
|
*/
|
||||||
|
__alloca_cleanup = NULL;
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
kprintf("[%s] %ld bytes still allocated upon exit, maximum of %ld bytes allocated at a time.\n",
|
kprintf("[%s] %ld bytes still allocated upon exit, maximum of %ld bytes allocated at a time.\n",
|
||||||
__program_name,__current_memory_allocated,__maximum_memory_allocated);
|
__program_name, __current_memory_allocated, __maximum_memory_allocated);
|
||||||
|
|
||||||
kprintf("[%s] %ld chunks of memory still allocated upon exit, maximum of %ld chunks allocated at a time.\n",
|
kprintf("[%s] %ld chunks of memory still allocated upon exit, maximum of %ld chunks allocated at a time.\n",
|
||||||
__program_name,__current_num_memory_chunks_allocated,__maximum_num_memory_chunks_allocated);
|
__program_name, __current_num_memory_chunks_allocated, __maximum_num_memory_chunks_allocated);
|
||||||
|
|
||||||
__check_memory_allocations(__FILE__,__LINE__);
|
__check_memory_allocations(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
/* Make sure that those memory nodes which were
|
||||||
|
* intended not to be freed will get freed this
|
||||||
|
* time around.
|
||||||
|
*/
|
||||||
__never_free = FALSE;
|
__never_free = FALSE;
|
||||||
|
|
||||||
if(__memory_list.mlh_Head != NULL)
|
|
||||||
{
|
|
||||||
while(NOT IsListEmpty((struct List *)&__memory_list))
|
|
||||||
{
|
|
||||||
((struct MemoryNode *)__memory_list.mlh_Head)->mn_AlreadyFree = FALSE;
|
|
||||||
|
|
||||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__USE_MEM_TREES)
|
#if defined(__USE_MEM_TREES)
|
||||||
{
|
{
|
||||||
|
/* This must remain empty. */
|
||||||
__initialize_red_black_tree(&__memory_tree);
|
__initialize_red_black_tree(&__memory_tree);
|
||||||
}
|
}
|
||||||
#endif /* __USE_MEM_TREES */
|
#endif /* __USE_MEM_TREES */
|
||||||
@@ -438,39 +451,36 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
|
|||||||
/* Is the slab memory allocator enabled? */
|
/* Is the slab memory allocator enabled? */
|
||||||
if (__slab_data.sd_InUse)
|
if (__slab_data.sd_InUse)
|
||||||
{
|
{
|
||||||
|
/* Just release the memory. */
|
||||||
__slab_exit();
|
__slab_exit();
|
||||||
}
|
}
|
||||||
else
|
/* Is the memory pool in use? */
|
||||||
|
else if (__memory_pool != NULL)
|
||||||
{
|
{
|
||||||
if (__memory_pool != NULL)
|
/* Just release the memory. */
|
||||||
|
DeletePool(__memory_pool);
|
||||||
|
__memory_pool = NULL;
|
||||||
|
}
|
||||||
|
/* Do we have to release every single allocation? */
|
||||||
|
else if (__memory_list.mlh_Head != NULL)
|
||||||
|
{
|
||||||
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
NewList((struct List *)&__memory_list);
|
while (NOT IsMinListEmpty(&__memory_list))
|
||||||
|
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, __FILE__, __LINE__);
|
||||||
DeletePool(__memory_pool);
|
|
||||||
__memory_pool = NULL;
|
|
||||||
}
|
}
|
||||||
else if (__memory_list.mlh_Head != NULL)
|
#else
|
||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG
|
while (NOT IsMinListEmpty(&__memory_list))
|
||||||
{
|
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, NULL, 0);
|
||||||
while(NOT IsListEmpty((struct List *)&__memory_list))
|
|
||||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
while(NOT IsListEmpty((struct List *)&__memory_list))
|
|
||||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,NULL,0);
|
|
||||||
}
|
|
||||||
#endif /* __MEM_DEBUG */
|
|
||||||
}
|
}
|
||||||
|
#endif /* __MEM_DEBUG */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
if (__memory_pool != NULL)
|
if (__memory_pool != NULL)
|
||||||
{
|
{
|
||||||
NewList((struct List *)&__memory_list);
|
|
||||||
|
|
||||||
DeletePool(__memory_pool);
|
DeletePool(__memory_pool);
|
||||||
__memory_pool = NULL;
|
__memory_pool = NULL;
|
||||||
}
|
}
|
||||||
@@ -478,19 +488,22 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
|
|||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
while(NOT IsListEmpty((struct List *)&__memory_list))
|
while (NOT IsMinListEmpty(&__memory_list))
|
||||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
|
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, __FILE__, __LINE__);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
while(NOT IsListEmpty((struct List *)&__memory_list))
|
while (NOT IsMinListEmpty(&__memory_list))
|
||||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,NULL,0);
|
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, NULL, 0);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __USE_SLAB_ALLOCATOR */
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
|
|
||||||
|
/* The list of memory allocations must remain empty. */
|
||||||
|
NewList((struct List *)&__memory_list);
|
||||||
|
|
||||||
#if defined(__THREAD_SAFE)
|
#if defined(__THREAD_SAFE)
|
||||||
{
|
{
|
||||||
__delete_semaphore(memory_semaphore);
|
__delete_semaphore(memory_semaphore);
|
||||||
@@ -509,13 +522,7 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
#if defined(__THREAD_SAFE)
|
NewList((struct List *)&__memory_list);
|
||||||
{
|
|
||||||
memory_semaphore = __create_semaphore();
|
|
||||||
if(memory_semaphore == NULL)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
#endif /* __THREAD_SAFE */
|
|
||||||
|
|
||||||
#if defined(__USE_MEM_TREES) && defined(__MEM_DEBUG)
|
#if defined(__USE_MEM_TREES) && defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
@@ -523,27 +530,38 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
}
|
}
|
||||||
#endif /* __USE_MEM_TREES && __MEM_DEBUG */
|
#endif /* __USE_MEM_TREES && __MEM_DEBUG */
|
||||||
|
|
||||||
NewList((struct List *)&__memory_list);
|
#if defined(__THREAD_SAFE)
|
||||||
|
{
|
||||||
|
memory_semaphore = __create_semaphore();
|
||||||
|
if (memory_semaphore == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("could not create memory semaphore");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* __THREAD_SAFE */
|
||||||
|
|
||||||
#if defined(__USE_SLAB_ALLOCATOR)
|
#ifdef __USE_SLAB_ALLOCATOR
|
||||||
{
|
{
|
||||||
/* ZZZ this is just for the purpose of testing */
|
/* ZZZ this is just for the purpose of testing */
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
{
|
{
|
||||||
TEXT slab_size_var[20];
|
TEXT slab_size_var[20];
|
||||||
|
|
||||||
if(GetVar("SLAB_SIZE", slab_size_var, sizeof(slab_size_var), 0) > 0)
|
if (GetVar("SLAB_SIZE", slab_size_var, sizeof(slab_size_var), 0) > 0)
|
||||||
{
|
{
|
||||||
LONG value;
|
LONG value = 0;
|
||||||
|
|
||||||
if(StrToLong(slab_size_var,&value) > 0 && value > 0)
|
if (StrToLong(slab_size_var, &value) > 0 && value > 0)
|
||||||
__slab_max_size = (size_t)value;
|
__slab_max_size = (size_t)value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SHOWVALUE(__slab_max_size);
|
||||||
|
|
||||||
/* Enable the slab memory allocator? */
|
/* Enable the slab memory allocator? */
|
||||||
if(__slab_max_size > 0)
|
if (__slab_max_size > 0)
|
||||||
{
|
{
|
||||||
__slab_init(__slab_max_size);
|
__slab_init(__slab_max_size);
|
||||||
}
|
}
|
||||||
@@ -551,15 +569,27 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
{
|
{
|
||||||
#if defined(__amigaos4__)
|
#if defined(__amigaos4__)
|
||||||
{
|
{
|
||||||
__memory_pool = CreatePool(MEMF_PRIVATE,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
|
__memory_pool = CreatePool(MEMF_PRIVATE, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
|
||||||
|
if (__memory_pool == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("could not create memory pool");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
/* There is no support for memory pools in the operating system
|
/* There is no support for memory pools in the operating system
|
||||||
* prior to Kickstart 3.0 (V39).
|
* prior to Kickstart 3.0 (V39).
|
||||||
*/
|
*/
|
||||||
if(((struct Library *)SysBase)->lib_Version >= 39)
|
if (((struct Library *)SysBase)->lib_Version >= 39)
|
||||||
__memory_pool = CreatePool(MEMF_ANY,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
|
{
|
||||||
|
__memory_pool = CreatePool(MEMF_ANY, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
|
||||||
|
if (__memory_pool == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("could not create memory pool");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* __amigaos4__ */
|
#endif /* __amigaos4__ */
|
||||||
}
|
}
|
||||||
@@ -568,19 +598,31 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
{
|
{
|
||||||
#if defined(__amigaos4__)
|
#if defined(__amigaos4__)
|
||||||
{
|
{
|
||||||
__memory_pool = CreatePool(MEMF_PRIVATE,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
|
__memory_pool = CreatePool(MEMF_PRIVATE, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
|
||||||
|
if (__memory_pool == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("could not create memory pool");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
/* There is no support for memory pools in the operating system
|
/* There is no support for memory pools in the operating system
|
||||||
* prior to Kickstart 3.0 (V39).
|
* prior to Kickstart 3.0 (V39).
|
||||||
*/
|
*/
|
||||||
if(((struct Library *)SysBase)->lib_Version >= 39)
|
if (((struct Library *)SysBase)->lib_Version >= 39)
|
||||||
__memory_pool = CreatePool(MEMF_ANY,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
|
{
|
||||||
|
__memory_pool = CreatePool(MEMF_ANY, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
|
||||||
|
if (__memory_pool == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("could not create memory pool");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* __amigaos4__ */
|
#endif /* __amigaos4__ */
|
||||||
}
|
}
|
||||||
#endif /* __USE_SLAB_ALLOCATOR) */
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
|
|
||||||
success = TRUE;
|
success = TRUE;
|
||||||
|
|
||||||
@@ -589,7 +631,7 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
SHOWVALUE(success);
|
SHOWVALUE(success);
|
||||||
LEAVE();
|
LEAVE();
|
||||||
|
|
||||||
if(success)
|
if (success)
|
||||||
CONSTRUCTOR_SUCCEED();
|
CONSTRUCTOR_SUCCEED();
|
||||||
else
|
else
|
||||||
CONSTRUCTOR_FAIL();
|
CONSTRUCTOR_FAIL();
|
||||||
|
|||||||
@@ -37,9 +37,13 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||||
|
|
||||||
int
|
int
|
||||||
mbtowc(wchar_t *pwc, const char *s, size_t n)
|
mbtowc(wchar_t *restrict pwc, const char *restrict s, size_t n)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
errno = EILSEQ;
|
||||||
return(-1);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
36
library/stdlib_memory.h
Normal file → Executable file
36
library/stdlib_memory.h
Normal file → Executable file
@@ -63,7 +63,7 @@
|
|||||||
/*
|
/*
|
||||||
* Uncomment this to enable the slab allocator.
|
* Uncomment this to enable the slab allocator.
|
||||||
*/
|
*/
|
||||||
#define __USE_SLAB_ALLOCATOR
|
/*#define __USE_SLAB_ALLOCATOR*/
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
@@ -150,27 +150,26 @@ extern char * __getcwd(char * buffer,size_t buffer_size,const char *file,int lin
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
/* If this flag is set in mn_Size, then this memory allocation
|
/* If this flag is set in mn_Flags, then this memory allocation
|
||||||
* cannot be released with free() or used with realloc(). This
|
* cannot be released with free() or used with realloc(). This
|
||||||
* flag is set by alloca().
|
* flag is set by alloca().
|
||||||
*/
|
*/
|
||||||
#define MN_SIZE_NEVERFREE (0x80000000UL)
|
#define MNF_NEVER_FREE (1UL << 0)
|
||||||
|
|
||||||
/* This obtains the allocation size from a memory node, ignoring
|
/* Memory allocations are remembered by this tracking data structure.
|
||||||
* the "never free" flag altogether.
|
* Its size is always a multiple of 8 bytes, which provides memory
|
||||||
|
* address alignment to a 64-bit boundary.
|
||||||
*/
|
*/
|
||||||
#define GET_MN_SIZE(mn) ((mn)->mn_Size & ~MN_SIZE_NEVERFREE)
|
|
||||||
|
|
||||||
struct MemoryNode
|
struct MemoryNode
|
||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG
|
|
||||||
struct MinNode mn_MinNode;
|
struct MinNode mn_MinNode;
|
||||||
|
|
||||||
UBYTE mn_AlreadyFree;
|
ULONG mn_AllocationSize;
|
||||||
UBYTE mn_Pad0[3];
|
ULONG mn_Flags;
|
||||||
|
|
||||||
|
#ifdef __MEM_DEBUG
|
||||||
void * mn_Allocation;
|
void * mn_Allocation;
|
||||||
size_t mn_AllocationSize;
|
size_t mn_OriginalSize;
|
||||||
|
|
||||||
char * mn_FreeFile;
|
char * mn_FreeFile;
|
||||||
int mn_FreeLine;
|
int mn_FreeLine;
|
||||||
@@ -178,17 +177,18 @@ struct MemoryNode
|
|||||||
char * mn_File;
|
char * mn_File;
|
||||||
int mn_Line;
|
int mn_Line;
|
||||||
|
|
||||||
|
UBYTE mn_AlreadyFree;
|
||||||
|
UBYTE mn_Pad1[7];
|
||||||
#ifdef __USE_MEM_TREES
|
#ifdef __USE_MEM_TREES
|
||||||
struct MemoryNode * mn_Left;
|
struct MemoryNode * mn_Left;
|
||||||
struct MemoryNode * mn_Right;
|
struct MemoryNode * mn_Right;
|
||||||
struct MemoryNode * mn_Parent;
|
struct MemoryNode * mn_Parent;
|
||||||
|
|
||||||
UBYTE mn_IsRed;
|
UBYTE mn_IsRed;
|
||||||
UBYTE mn_Pad1[3];
|
UBYTE mn_Pad2[3];
|
||||||
#endif /* __USE_MEM_TREES */
|
#endif /* __USE_MEM_TREES */
|
||||||
|
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
ULONG mn_Size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __USE_MEM_TREES
|
#ifdef __USE_MEM_TREES
|
||||||
@@ -247,12 +247,14 @@ struct SlabNode
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Memory allocations which are not part of a slab are
|
/* Memory allocations which are not part of a slab are
|
||||||
* tracked using this data structure.
|
* tracked using this data structure. This data structure
|
||||||
|
* is supposed to be a multiple of 8 bytes in size.
|
||||||
*/
|
*/
|
||||||
struct SlabSingleAllocation
|
struct SlabSingleAllocation
|
||||||
{
|
{
|
||||||
struct MinNode ssa_MinNode;
|
struct MinNode ssa_MinNode;
|
||||||
ULONG ssa_Size;
|
ULONG ssa_Size;
|
||||||
|
ULONG ssa_Pad;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is the global bookkeeping information for managing
|
/* This is the global bookkeeping information for managing
|
||||||
@@ -264,8 +266,8 @@ struct SlabData
|
|||||||
* which are a power of 2 bytes in size, e.g. 8, 16, 32,
|
* which are a power of 2 bytes in size, e.g. 8, 16, 32,
|
||||||
* 64, 128 bytes. Hence, sd_Slabs[3] keeps track of the slabs
|
* 64, 128 bytes. Hence, sd_Slabs[3] keeps track of the slabs
|
||||||
* which are 8 bytes in size, sd_Slabs[4] is for 16 byte
|
* which are 8 bytes in size, sd_Slabs[4] is for 16 byte
|
||||||
* chunks, etc. The minimum chunk size is 8, which is why
|
* chunks, etc. The minimum chunk size is 16, which is why
|
||||||
* lists 0..2 are not used. Currently, there is an upper limit
|
* lists 0..3 are not used. Currently, there is an upper limit
|
||||||
* of 2^17 bytes per chunk, but you should not be using slab
|
* of 2^17 bytes per chunk, but you should not be using slab
|
||||||
* chunks much larger than 4096 bytes.
|
* chunks much larger than 4096 bytes.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
__static void *
|
__static void *
|
||||||
__realloc(void *ptr,size_t size,const char * file,int line)
|
__realloc(void *ptr, size_t size, const char * file, int line)
|
||||||
{
|
{
|
||||||
void * result = NULL;
|
void * result = NULL;
|
||||||
BOOL locked = FALSE;
|
BOOL locked = FALSE;
|
||||||
@@ -62,23 +62,24 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
|
|
||||||
assert( (int)size >= 0 );
|
assert( (int)size >= 0 );
|
||||||
|
|
||||||
if(ptr == NULL)
|
if (ptr == NULL)
|
||||||
{
|
{
|
||||||
D(("calling malloc(%ld)",size));
|
D(("calling malloc(%ld)", size));
|
||||||
|
|
||||||
result = __malloc(size,file,line);
|
result = __malloc(size, file, line);
|
||||||
}
|
}
|
||||||
#ifndef UNIX_PATH_SEMANTICS
|
#ifndef UNIX_PATH_SEMANTICS
|
||||||
else if (size == 0)
|
else if (size == 0)
|
||||||
{
|
{
|
||||||
D(("calling free(0x%08lx)",ptr));
|
D(("calling free(0x%08lx)",ptr));
|
||||||
|
|
||||||
__free(ptr,file,line);
|
__free(ptr, file, line);
|
||||||
}
|
}
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t old_size;
|
size_t new_allocation_size UNUSED;
|
||||||
|
size_t old_allocation_size;
|
||||||
struct MemoryNode * mn;
|
struct MemoryNode * mn;
|
||||||
BOOL reallocate;
|
BOOL reallocate;
|
||||||
|
|
||||||
@@ -92,16 +93,14 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
/* If we managed to find the memory allocation,
|
/* Quit if we failed to find the memory allocation. */
|
||||||
reallocate it. */
|
if (mn == NULL)
|
||||||
if(mn == NULL)
|
|
||||||
{
|
{
|
||||||
SHOWMSG("allocation not found");
|
SHOWMSG("allocation not found");
|
||||||
|
|
||||||
kprintf("[%s] %s:%ld:Address for realloc(0x%08lx,%ld) not known.\n",__program_name,file,line,ptr,size);
|
kprintf("[%s] %s:%ld:Address for realloc(0x%08lx,%ld) not known.\n",
|
||||||
|
__program_name, file, line, ptr, size);
|
||||||
|
|
||||||
/* Apparently, the address did not qualify for
|
|
||||||
reallocation. */
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,70 +110,114 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
if(mn == NULL || FLAG_IS_SET(mn->mn_Size, MN_SIZE_NEVERFREE))
|
if (mn == NULL || FLAG_IS_SET(mn->mn_Flags, MNF_NEVER_FREE))
|
||||||
{
|
{
|
||||||
SHOWMSG("cannot free this chunk");
|
SHOWMSG("cannot free this chunk");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_size = GET_MN_SIZE(mn);
|
assert( FLAG_IS_CLEAR(mn->mn_Flags, MNF_NEVER_FREE) );
|
||||||
|
|
||||||
/* Don't do anything unless the size of the allocation
|
old_allocation_size = mn->mn_AllocationSize;
|
||||||
has really changed. */
|
|
||||||
|
/* If the memory debug option is enabled, just check if
|
||||||
|
* requested allocation size has changed.
|
||||||
|
*/
|
||||||
#if defined(__MEM_DEBUG)
|
#if defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
reallocate = (old_size != size);
|
reallocate = (mn->mn_OriginalSize != size);
|
||||||
|
|
||||||
|
new_allocation_size = (sizeof(*mn) + MALLOC_HEAD_SIZE + size + MALLOC_TAIL_SIZE + MEM_BLOCKMASK) & ~MEM_BLOCKMASK;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
if(size > old_size)
|
/* The actual size of the allocation is affected by the
|
||||||
|
granularity and minimum allocation size used by the
|
||||||
|
operating system. */
|
||||||
|
new_allocation_size = (sizeof(*mn) + size + MEM_BLOCKMASK) & ~MEM_BLOCKMASK;
|
||||||
|
|
||||||
|
if (new_allocation_size > old_allocation_size)
|
||||||
{
|
{
|
||||||
/* Allocation size should grow. */
|
/* Allocation size should grow. */
|
||||||
reallocate = TRUE;
|
reallocate = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else if (new_allocation_size < old_allocation_size)
|
||||||
{
|
{
|
||||||
/* Optimization: If the block size shrinks by less than half the
|
/* Optimization: If the block size shrinks by less than half the
|
||||||
original allocation size, do not reallocate the
|
original allocation size, do not reallocate the
|
||||||
block and do not copy over the contents of the old
|
block. */
|
||||||
allocation. We also take into account that the
|
reallocate = (size <= old_allocation_size / 2);
|
||||||
actual size of the allocation is affected by a
|
}
|
||||||
certain operating system imposed granularity. */
|
else
|
||||||
reallocate = (size < old_size && size <= old_size / 2);
|
{
|
||||||
|
reallocate = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
if(reallocate)
|
if (reallocate)
|
||||||
{
|
{
|
||||||
void * new_ptr;
|
void * new_ptr;
|
||||||
|
|
||||||
D(("realloc() size has changed; old=%ld, new=%ld",old_size,size));
|
D(("realloc() allocation size has changed; old=%ld, new=%ld", old_allocation_size, new_allocation_size));
|
||||||
|
|
||||||
/* We allocate the new memory chunk before we
|
/* We allocate the new memory chunk before we
|
||||||
attempt to replace the old. */
|
attempt to replace the old one. */
|
||||||
new_ptr = __malloc(size,file,line);
|
new_ptr = __malloc(size, file, line);
|
||||||
if(new_ptr == NULL)
|
if (new_ptr == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("could not reallocate memory");
|
SHOWMSG("could not reallocate memory");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the contents of the old allocation to the new buffer. */
|
/* With memory debugging enabled, the size of the allocation made
|
||||||
if(size > old_size)
|
* will use the requested and not the rounded size of the
|
||||||
size = old_size;
|
* allocation, which can be shorter. We need to deal with this.
|
||||||
|
*/
|
||||||
|
#if defined(__MEM_DEBUG)
|
||||||
|
{
|
||||||
|
struct MemoryNode * new_mn;
|
||||||
|
|
||||||
memmove(new_ptr,ptr,size);
|
new_mn = __find_memory_node(new_ptr);
|
||||||
|
if (new_mn == NULL)
|
||||||
|
{
|
||||||
|
free(new_ptr);
|
||||||
|
|
||||||
|
SHOWMSG("Could not find memory node for new allocation");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure that if the new allocation size is smaller than
|
||||||
|
* the old allocation, we only copy as much data as will fit
|
||||||
|
* into the new allocation.
|
||||||
|
*/
|
||||||
|
if (size > new_mn->mn_OriginalSize)
|
||||||
|
size = new_mn->mn_OriginalSize;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
/* We assume that the total size of the allocation will
|
||||||
|
* include padding. The requested size does not include
|
||||||
|
* the memory node, of course, which is why it is added
|
||||||
|
* here.
|
||||||
|
*/
|
||||||
|
if (size + sizeof(*mn) > old_allocation_size)
|
||||||
|
size = old_allocation_size - sizeof(*mn);
|
||||||
|
}
|
||||||
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
|
memmove(new_ptr, ptr, size);
|
||||||
|
|
||||||
/* Free the old allocation. Since we already know which memory
|
/* Free the old allocation. Since we already know which memory
|
||||||
node is associated with it, we don't call __free() here. */
|
node is associated with it, we don't call __free() here. */
|
||||||
__free_memory_node(mn,file,line);
|
__free_memory_node(mn, file, line);
|
||||||
|
|
||||||
result = new_ptr;
|
result = new_ptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
D(("size didn't actually change that much (%ld -> %ld); returning memory block as is.",old_size,size));
|
D(("size didn't actually change that much (%ld -> %ld); returning memory block as is.",
|
||||||
|
old_allocation_size, new_allocation_size));
|
||||||
|
|
||||||
/* No change in size. */
|
/* No change in size. */
|
||||||
result = ptr;
|
result = ptr;
|
||||||
@@ -183,14 +226,14 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
if(locked)
|
if (locked)
|
||||||
__memory_unlock();
|
__memory_unlock();
|
||||||
|
|
||||||
if(result == NULL)
|
if (result == NULL)
|
||||||
SHOWMSG("ouch! realloc failed");
|
SHOWMSG("ouch! realloc failed");
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
1144
library/stdlib_slab.c
Normal file → Executable file
1144
library/stdlib_slab.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
static const char * error_table[EILSEQ - EPERM + 1] =
|
static const char * error_table[ENOTSUP - EPERM + 1] =
|
||||||
{
|
{
|
||||||
"Operation not permitted",
|
"Operation not permitted",
|
||||||
"No such file or directory",
|
"No such file or directory",
|
||||||
@@ -127,7 +127,8 @@ static const char * error_table[EILSEQ - EPERM + 1] =
|
|||||||
"Identifier removed",
|
"Identifier removed",
|
||||||
"No message of the desired type.",
|
"No message of the desired type.",
|
||||||
"Value too large to be stored in data type.",
|
"Value too large to be stored in data type.",
|
||||||
"Encoding error detected"
|
"Encoding error detected",
|
||||||
|
"Not supported"
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@@ -139,7 +140,7 @@ strerror_r(int number,char * buffer,size_t buffer_size)
|
|||||||
const char * str;
|
const char * str;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if(number < EPERM || number > EILSEQ)
|
if(number < EPERM || number > ENOTSUP)
|
||||||
{
|
{
|
||||||
__set_errno(EINVAL);
|
__set_errno(EINVAL);
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
75
library/string_strnlen.c
Normal file
75
library/string_strnlen.c
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* $Id: string_strlen.c,v 1.4 2006-01-08 12:04:27 obarthel Exp $
|
||||||
|
*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_NULL_POINTER_CHECK_H
|
||||||
|
#include "stdlib_null_pointer_check.h"
|
||||||
|
#endif /* _STDLIB_NULL_POINTER_CHECK_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _STRING_HEADERS_H
|
||||||
|
#include "string_headers.h"
|
||||||
|
#endif /* _STRING_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
size_t
|
||||||
|
strnlen(const char *s, size_t maxlen)
|
||||||
|
{
|
||||||
|
const char * start = s;
|
||||||
|
size_t result = 0;
|
||||||
|
|
||||||
|
assert( s != NULL );
|
||||||
|
|
||||||
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
|
{
|
||||||
|
if(s == NULL)
|
||||||
|
{
|
||||||
|
__set_errno(EFAULT);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||||
|
|
||||||
|
while((maxlen != 0) && ((*s) != '\0'))
|
||||||
|
{
|
||||||
|
s++;
|
||||||
|
maxlen--;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = (size_t)(s - start);
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
151
library/time_mktime.c
Normal file → Executable file
151
library/time_mktime.c
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: time_mktime.c,v 1.10 2006-01-08 12:04:27 obarthel Exp $
|
* $Id: time_mktime.c,v 1.11 2015-06-26 11:22:00 obarthel Exp $
|
||||||
*
|
*
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
@@ -52,9 +52,10 @@ mktime(struct tm *tm)
|
|||||||
{
|
{
|
||||||
DECLARE_UTILITYBASE();
|
DECLARE_UTILITYBASE();
|
||||||
struct ClockData clock_data;
|
struct ClockData clock_data;
|
||||||
ULONG seconds, delta;
|
ULONG seconds;
|
||||||
time_t result = (time_t)-1;
|
time_t result = (time_t)-1;
|
||||||
int max_month_days;
|
LONG combined_seconds;
|
||||||
|
int month, year;
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
@@ -73,116 +74,63 @@ mktime(struct tm *tm)
|
|||||||
}
|
}
|
||||||
#endif /* CHECK_FOR_NULL_POINTERS */
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||||
|
|
||||||
/* The month must be valid. */
|
/* Normalize the year and month. */
|
||||||
if(tm->tm_mon < 0 || tm->tm_mon > 11)
|
year = tm->tm_year + 1900;
|
||||||
|
month = tm->tm_mon + 1;
|
||||||
|
|
||||||
|
if(month < 0 || month > 12)
|
||||||
{
|
{
|
||||||
SHOWVALUE(tm->tm_mon);
|
int y;
|
||||||
SHOWMSG("invalid month");
|
|
||||||
goto out;
|
y = month / 12;
|
||||||
|
|
||||||
|
month -= y * 12;
|
||||||
|
year += y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The day of the month must be valid. */
|
if(month < 1)
|
||||||
if(tm->tm_mday < 1 || tm->tm_mday > 31)
|
|
||||||
{
|
{
|
||||||
SHOWVALUE(tm->tm_mday);
|
month += 12;
|
||||||
SHOWMSG("invalid day of month");
|
year -= 1;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The year must be valid. */
|
/* The year must be valid. Amiga time begins with January 1st, 1978. */
|
||||||
if(tm->tm_year < 78)
|
if(year < 1978)
|
||||||
{
|
{
|
||||||
SHOWVALUE(tm->tm_year);
|
SHOWVALUE(year);
|
||||||
SHOWMSG("invalid year");
|
SHOWMSG("invalid year");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is this the month of February? */
|
/* Convert the first day of the month in the given year
|
||||||
if(tm->tm_mon == 1)
|
into the corresponding number of seconds. */
|
||||||
{
|
memset(&clock_data, 0, sizeof(clock_data));
|
||||||
int year;
|
|
||||||
|
|
||||||
/* We need to have the full year number for the
|
|
||||||
leap year calculation below. */
|
|
||||||
year = tm->tm_year + 1900;
|
|
||||||
|
|
||||||
/* Now for the famous leap year calculation rules... In
|
|
||||||
the given year, how many days are there in the month
|
|
||||||
of February? */
|
|
||||||
if((year % 4) != 0)
|
|
||||||
max_month_days = 28;
|
|
||||||
else if ((year % 400) == 0)
|
|
||||||
max_month_days = 29;
|
|
||||||
else if ((year % 100) == 0)
|
|
||||||
max_month_days = 28;
|
|
||||||
else
|
|
||||||
max_month_days = 29;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static const char days_per_month[12] =
|
|
||||||
{
|
|
||||||
31, 0,31,
|
|
||||||
30,31,30,
|
|
||||||
31,31,30,
|
|
||||||
31,30,31
|
|
||||||
};
|
|
||||||
|
|
||||||
max_month_days = days_per_month[tm->tm_mon];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The day of the month must be valid. */
|
|
||||||
if(tm->tm_mday < 0 || tm->tm_mday > max_month_days)
|
|
||||||
{
|
|
||||||
SHOWVALUE(tm->tm_mday);
|
|
||||||
SHOWMSG("invalid day of month");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The hour must be valid. */
|
|
||||||
if(tm->tm_hour < 0 || tm->tm_hour > 23)
|
|
||||||
{
|
|
||||||
SHOWVALUE(tm->tm_hour);
|
|
||||||
SHOWMSG("invalid hour");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The minute must be valid. */
|
|
||||||
if(tm->tm_min < 0 || tm->tm_min > 59)
|
|
||||||
{
|
|
||||||
SHOWVALUE(tm->tm_min);
|
|
||||||
SHOWMSG("invalid minute");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Note: the number of seconds can be larger than 59
|
|
||||||
in order to account for leap seconds. */
|
|
||||||
if(tm->tm_sec < 0 || tm->tm_sec > 60)
|
|
||||||
{
|
|
||||||
SHOWVALUE(tm->tm_sec);
|
|
||||||
SHOWMSG("invalid seconds");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
clock_data.sec = (tm->tm_sec > 59) ? 59 : tm->tm_sec;
|
|
||||||
clock_data.min = tm->tm_min;
|
|
||||||
clock_data.hour = tm->tm_hour;
|
|
||||||
clock_data.mday = tm->tm_mday;
|
|
||||||
clock_data.month = tm->tm_mon + 1;
|
|
||||||
clock_data.year = tm->tm_year + 1900;
|
|
||||||
|
|
||||||
seconds = Date2Amiga(&clock_data) + (tm->tm_sec - 59);
|
|
||||||
|
|
||||||
/* The AmigaOS "epoch" starts with January 1st, 1978, which was
|
|
||||||
a Sunday. */
|
|
||||||
tm->tm_wday = (seconds / (24 * 60 * 60)) % 7;
|
|
||||||
|
|
||||||
clock_data.mday = 1;
|
clock_data.mday = 1;
|
||||||
clock_data.month = 1;
|
clock_data.month = month;
|
||||||
|
clock_data.year = year;
|
||||||
|
|
||||||
delta = Date2Amiga(&clock_data);
|
seconds = Date2Amiga(&clock_data);
|
||||||
|
|
||||||
tm->tm_yday = (seconds - delta) / (24 * 60 * 60);
|
/* Put the combined number of seconds involved together,
|
||||||
|
covering the seconds/minutes/hours of the day as well
|
||||||
|
as the number of days of the month. This will be added
|
||||||
|
to the number of seconds for the date. */
|
||||||
|
combined_seconds = tm->tm_sec + 60 * (tm->tm_min + 60 * (tm->tm_hour + 24 * (tm->tm_mday-1)));
|
||||||
|
|
||||||
|
/* If the combined number of seconds is negative, adding it
|
||||||
|
* to the number of seconds for the date should not produce
|
||||||
|
* a negative value.
|
||||||
|
*/
|
||||||
|
if(combined_seconds < 0 && seconds < (ULONG)(-combined_seconds))
|
||||||
|
{
|
||||||
|
SHOWVALUE(seconds);
|
||||||
|
SHOWVALUE(combined_seconds);
|
||||||
|
SHOWMSG("invalid combined number of seconds");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
seconds += combined_seconds;
|
||||||
|
|
||||||
__locale_lock();
|
__locale_lock();
|
||||||
|
|
||||||
@@ -193,10 +141,13 @@ mktime(struct tm *tm)
|
|||||||
|
|
||||||
__locale_unlock();
|
__locale_unlock();
|
||||||
|
|
||||||
/* Finally, adjust for the difference between the Unix and the
|
/* Adjust for the difference between the Unix and the
|
||||||
AmigaOS epochs, which differ by 8 years. */
|
AmigaOS epochs, which differ by 8 years. */
|
||||||
result = seconds + UNIX_TIME_OFFSET;
|
result = seconds + UNIX_TIME_OFFSET;
|
||||||
|
|
||||||
|
/* Finally, normalize the provided time and date information. */
|
||||||
|
localtime_r(&result, tm);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
|
|||||||
48
library/time_tzset.c
Normal file
48
library/time_tzset.c
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* $Id: $
|
||||||
|
*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2017 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TIME_HEADERS_H
|
||||||
|
#include "time_headers.h"
|
||||||
|
#endif /* _TIME_HEADERS_H */
|
||||||
|
|
||||||
|
#ifndef _LOCALE_HEADERS_H
|
||||||
|
#include "locale_headers.h"
|
||||||
|
#endif /* _LOCALE_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
tzset(void)
|
||||||
|
{
|
||||||
|
/* For now, do nothing. */
|
||||||
|
}
|
||||||
@@ -69,7 +69,7 @@ CLIB_DESTRUCTOR(unistd_exit)
|
|||||||
|
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
|
|
||||||
if(__unlink_list.mlh_Head != NULL && NOT IsListEmpty((struct List *)&__unlink_list))
|
if(__unlink_list.mlh_Head != NULL && NOT IsMinListEmpty(&__unlink_list))
|
||||||
{
|
{
|
||||||
struct UnlinkNode * uln;
|
struct UnlinkNode * uln;
|
||||||
BPTR old_dir;
|
BPTR old_dir;
|
||||||
|
|||||||
@@ -58,9 +58,19 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
|||||||
struct name_translation_info path_name_nti;
|
struct name_translation_info path_name_nti;
|
||||||
struct name_translation_info buffer_nti;
|
struct name_translation_info buffer_nti;
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
|
|
||||||
|
D_S(struct bcpl_name, bname);
|
||||||
|
const size_t name_size = sizeof(bname->name);
|
||||||
|
|
||||||
BPTR lock = ZERO;
|
BPTR lock = ZERO;
|
||||||
int result = ERROR;
|
int result = ERROR;
|
||||||
int target_length = -1;
|
struct DevProc *dvp = NULL;
|
||||||
|
char * new_name = NULL;
|
||||||
|
char * path_part;
|
||||||
|
size_t name_len;
|
||||||
|
size_t new_name_size;
|
||||||
|
LONG readlink_result;
|
||||||
|
LONG error;
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
@@ -70,12 +80,12 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
|||||||
|
|
||||||
assert( path_name != NULL && buffer != NULL );
|
assert( path_name != NULL && buffer != NULL );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(path_name == NULL || buffer == NULL)
|
if (path_name == NULL || buffer == NULL)
|
||||||
{
|
{
|
||||||
SHOWSTRING("invalid parameters");
|
SHOWSTRING("invalid parameters");
|
||||||
|
|
||||||
@@ -87,9 +97,9 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
|||||||
|
|
||||||
#if defined(UNIX_PATH_SEMANTICS)
|
#if defined(UNIX_PATH_SEMANTICS)
|
||||||
{
|
{
|
||||||
if(__unix_path_semantics)
|
if (__unix_path_semantics)
|
||||||
{
|
{
|
||||||
if(path_name[0] == '\0')
|
if (path_name[0] == '\0')
|
||||||
{
|
{
|
||||||
SHOWMSG("no name given");
|
SHOWMSG("no name given");
|
||||||
|
|
||||||
@@ -97,53 +107,144 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(__translate_unix_to_amiga_path_name(&path_name,&path_name_nti) != 0)
|
if (__translate_unix_to_amiga_path_name(&path_name, &path_name_nti) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
|
|
||||||
D(("trying to get a lock on '%s'",path_name));
|
name_len = strlen(path_name);
|
||||||
|
if (name_len >= name_size)
|
||||||
|
{
|
||||||
|
SHOWMSG("name too long");
|
||||||
|
|
||||||
|
SetIoErr(ERROR_LINE_TOO_LONG);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the name into a BCPL string. */
|
||||||
|
bname->name[0] = name_len;
|
||||||
|
memcpy(&bname->name[1], path_name, name_len);
|
||||||
|
|
||||||
|
/* Get a handle on the device, volume or assignment name in the path. */
|
||||||
|
dvp = GetDeviceProc((STRPTR)path_name, dvp);
|
||||||
|
if (dvp == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("dvp == NULL");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to obtain a lock on the object. It should be a link and not
|
||||||
|
* a file or directory.
|
||||||
|
*/
|
||||||
|
lock = DoPkt(dvp->dvp_Port, ACTION_LOCATE_OBJECT, dvp->dvp_Lock, MKBADDR(bname), SHARED_LOCK, 0, 0);
|
||||||
|
if (lock != ZERO)
|
||||||
|
{
|
||||||
|
SHOWMSG("lock != ZERO");
|
||||||
|
|
||||||
|
SetIoErr(ERROR_OBJECT_WRONG_TYPE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = IoErr();
|
||||||
|
|
||||||
|
if (error != ERROR_IS_SOFT_LINK)
|
||||||
|
{
|
||||||
|
SHOWMSG("not a soft link");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We only need the leading path name. */
|
||||||
|
name_len = ((BYTE *)PathPart(path_name)) - (BYTE *)path_name;
|
||||||
|
|
||||||
|
path_part = malloc(name_len+1);
|
||||||
|
if (path_part == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("path_part too long");
|
||||||
|
|
||||||
|
SetIoErr(ERROR_NO_FREE_STORE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(path_part, path_name, name_len);
|
||||||
|
path_part[name_len] = '\0';
|
||||||
|
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
lock = __lock((STRPTR)path_name,SHARED_LOCK,&target_length,buffer,(size_t)buffer_size);
|
lock = Lock((STRPTR)path_part, SHARED_LOCK);
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
|
|
||||||
if(lock != ZERO)
|
new_name_size = name_size+1;
|
||||||
|
|
||||||
|
/* Provide as much buffer space as possible. */
|
||||||
|
if (buffer_size > 0 && (size_t)buffer_size > new_name_size)
|
||||||
|
new_name_size = buffer_size;
|
||||||
|
|
||||||
|
/* For soft link resolution we need a temporary buffer to
|
||||||
|
let the file system store the resolved path name in. */
|
||||||
|
new_name = malloc(new_name_size);
|
||||||
|
if (new_name == NULL)
|
||||||
{
|
{
|
||||||
__set_errno(EINVAL);
|
SHOWMSG("new_name too long");
|
||||||
goto out;
|
|
||||||
}
|
SetIoErr(ERROR_NO_FREE_STORE);
|
||||||
else if (target_length <= 0) /* No a soft-link. */
|
|
||||||
{
|
|
||||||
__set_errno(__translate_io_error_to_errno(IoErr()));
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(UNIX_PATH_SEMANTICS)
|
/* Now ask the file system to resolve the entire path. */
|
||||||
|
readlink_result = ReadLink(dvp->dvp_Port, lock, (STRPTR)FilePart(path_name), (STRPTR)new_name, (LONG)new_name_size);
|
||||||
|
if (readlink_result < 0)
|
||||||
{
|
{
|
||||||
if(__unix_path_semantics)
|
SHOWMSG("ReadLink");
|
||||||
|
|
||||||
|
/* This will return either -1 (resolution error) or -2
|
||||||
|
(buffer too small). We regard both as trouble. */
|
||||||
|
SetIoErr(ERROR_INVALID_COMPONENT_NAME);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( result > 0 );
|
||||||
|
|
||||||
|
/* If the caller supplied a buffer, copy as much of the name
|
||||||
|
as possible into it. */
|
||||||
|
if (buffer != NULL && buffer_size > 0)
|
||||||
|
{
|
||||||
|
strlcpy(buffer, new_name, buffer_size);
|
||||||
|
|
||||||
|
#if defined(UNIX_PATH_SEMANTICS)
|
||||||
{
|
{
|
||||||
if(__translate_amiga_to_unix_path_name((char const **)&buffer,&buffer_nti) != 0)
|
if (__unix_path_semantics)
|
||||||
goto out;
|
{
|
||||||
|
if (__translate_amiga_to_unix_path_name((char const **)&buffer, &buffer_nti) != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
__restore_path_name((char const **)&buffer,&buffer_nti);
|
__restore_path_name((char const **)&buffer,&buffer_nti);
|
||||||
|
|
||||||
strcpy(buffer,buffer_nti.substitute);
|
strcpy(buffer, buffer_nti.substitute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
|
|
||||||
|
result = strlen(buffer);
|
||||||
|
|
||||||
|
SHOWSTRING(buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
}
|
}
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
|
||||||
|
|
||||||
result = strlen(buffer);
|
|
||||||
|
|
||||||
SHOWSTRING(buffer);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
|
|
||||||
|
if (dvp != NULL)
|
||||||
|
FreeDeviceProc(dvp);
|
||||||
|
|
||||||
UnLock(lock);
|
UnLock(lock);
|
||||||
|
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
return(result);
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: unistd_translateu2a.c,v 1.12 2010-08-20 15:33:36 obarthel Exp $
|
* $Id: unistd_translateu2a.c,v 1.13 2015-06-26 11:22:00 obarthel Exp $
|
||||||
*
|
*
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
@@ -477,7 +477,10 @@ __translate_unix_to_amiga_path_name(char const ** name_ptr,struct name_translati
|
|||||||
for(i = j = 0 ; i < len ; i++)
|
for(i = j = 0 ; i < len ; i++)
|
||||||
{
|
{
|
||||||
if(i < len - 3 && name[i] == '/' && name[i + 1] == '.' && name[i + 2] == '.' && name[i + 3] == '/')
|
if(i < len - 3 && name[i] == '/' && name[i + 1] == '.' && name[i + 2] == '.' && name[i + 3] == '/')
|
||||||
i += 2;
|
{
|
||||||
|
replace[j++] = '/';
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
|
||||||
replace[j++] = name[i];
|
replace[j++] = name[i];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void
|
int
|
||||||
usleep(unsigned long microseconds)
|
usleep(unsigned long microseconds)
|
||||||
{
|
{
|
||||||
ENTER();
|
ENTER();
|
||||||
@@ -51,4 +51,6 @@ usleep(unsigned long microseconds)
|
|||||||
__time_delay(0,microseconds);
|
__time_delay(0,microseconds);
|
||||||
|
|
||||||
LEAVE();
|
LEAVE();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ __wildcard_expand_init(void)
|
|||||||
}
|
}
|
||||||
else if (rc != OK)
|
else if (rc != OK)
|
||||||
{
|
{
|
||||||
/* Some error occured. */
|
/* Some error occurred. */
|
||||||
error = EIO;
|
error = EIO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 213
|
#define REVISION 215
|
||||||
#define DATE "4.12.2016"
|
#define DATE "26.6.2017"
|
||||||
#define VERS "unix.lib 1.213"
|
#define VERS "unix.lib 1.215"
|
||||||
#define VSTRING "unix.lib 1.213 (4.12.2016)\r\n"
|
#define VSTRING "unix.lib 1.215 (26.6.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: unix.lib 1.213 (4.12.2016)"
|
#define VERSTAG "\0$VER: unix.lib 1.215 (26.6.2017)"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
213
|
215
|
||||||
|
|||||||
@@ -37,9 +37,12 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||||
size_t
|
size_t
|
||||||
mbrlen(wchar_t *pwc, const char * s, size_t n, mbstate_t *ps)
|
mbrlen(const char *restrict s, size_t n, mbstate_t *restrict ps)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
/* ZZZ unimplemented */
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
#endif /* __STDC_VERSION__ && __STDC_VERSION__ >= 199901L */
|
||||||
|
|
||||||
|
|||||||
64
library/wchar_mbrtowc.c
Normal file
64
library/wchar_mbrtowc.c
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* $Id: wchar_mbrlen.c,v 1.3 2006-01-08 12:04:27 obarthel Exp $
|
||||||
|
*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _WCHAR_HEADERS_H
|
||||||
|
#include "wchar_headers.h"
|
||||||
|
#endif /* _WCHAR_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Mostly non-working stub based on bionic */
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||||
|
size_t
|
||||||
|
mbrtowc(wchar_t *restrict pwc, const char *restrict s, size_t n, mbstate_t *restrict ps)
|
||||||
|
{
|
||||||
|
if (s == NULL)
|
||||||
|
{
|
||||||
|
s = "";
|
||||||
|
pwc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
{
|
||||||
|
if (pwc)
|
||||||
|
*pwc = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwc)
|
||||||
|
*pwc = *s;
|
||||||
|
|
||||||
|
return (*s != 0);
|
||||||
|
}
|
||||||
|
#endif /* __STDC_VERSION__ && __STDC_VERSION__ >= 199901L */
|
||||||
@@ -40,6 +40,5 @@
|
|||||||
int
|
int
|
||||||
mbsinit(const mbstate_t *ps)
|
mbsinit(const mbstate_t *ps)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
return !ps || !*(unsigned *)ps;
|
||||||
return(0);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
int
|
int
|
||||||
vswprintf(char *s, const wchar_t *format,va_list arg)
|
vswprintf(wchar_t *s, size_t maxlen, const wchar_t *format, va_list arg)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
/* ZZZ unimplemented */
|
||||||
return(0);
|
return(0);
|
||||||
|
|||||||
@@ -35,11 +35,13 @@
|
|||||||
#include "wchar_headers.h"
|
#include "wchar_headers.h"
|
||||||
#endif /* _WCHAR_HEADERS_H */
|
#endif /* _WCHAR_HEADERS_H */
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
wchar_t *
|
wchar_t *
|
||||||
wcscat(wchar_t *dest, const wchar_t *src)
|
wcscat(wchar_t *dest, const wchar_t *src)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
wcscpy(dest + wcslen(dest), src);
|
||||||
return(NULL);
|
return dest;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,12 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
wchar_t *
|
wchar_t *
|
||||||
wcschr(const wchar_t *s, wchar_t c)
|
wcschr(const wchar_t *s, wchar_t c)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
if (!c) return (wchar_t *)s + wcslen(s);
|
||||||
return(NULL);
|
for (; *s && *s != c; s++);
|
||||||
|
return *s ? (wchar_t *)s : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,6 @@
|
|||||||
int
|
int
|
||||||
wcscmp(const wchar_t *s1, const wchar_t * s2)
|
wcscmp(const wchar_t *s1, const wchar_t * s2)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
for (; *s1==*s2 && *s1 && *s2; s1++, s2++);
|
||||||
return(0);
|
return *s1 - *s2;
|
||||||
}
|
}
|
||||||
|
|||||||
45
library/wchar_wcscoll.c
Normal file
45
library/wchar_wcscoll.c
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* $Id: wchar_wscoll.c,v 1.3 2006-01-08 12:04:27 obarthel Exp $
|
||||||
|
*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _WCHAR_HEADERS_H
|
||||||
|
#include "wchar_headers.h"
|
||||||
|
#endif /* _WCHAR_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
int
|
||||||
|
wcscoll(const wchar_t *ws1, const wchar_t *ws2)
|
||||||
|
{
|
||||||
|
/* ZZZ unimplemented */
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
wchar_t *
|
wchar_t *
|
||||||
wcscpy(wchar_t *dest, const wchar_t *src)
|
wcscpy(wchar_t *dest, const wchar_t *src)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
wchar_t *a = dest;
|
||||||
return(NULL);
|
while ((*dest++ = *src++));
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|||||||
50
library/wchar_wcscspn.c
Normal file
50
library/wchar_wcscspn.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* $Id: wchar_wcsspn.c,v 1.3 2006-01-08 12:04:27 obarthel Exp $
|
||||||
|
*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _WCHAR_HEADERS_H
|
||||||
|
#include "wchar_headers.h"
|
||||||
|
#endif /* _WCHAR_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
|
size_t
|
||||||
|
wcscspn(const wchar_t *s, const wchar_t *c)
|
||||||
|
{
|
||||||
|
const wchar_t *a;
|
||||||
|
if (!c[0]) return wcslen(s);
|
||||||
|
if (!c[1]) return (s=wcschr(a=s, *c)) ? (size_t)(s-a) : wcslen(a);
|
||||||
|
for (a=s; *s && !wcschr(c, *s); s++);
|
||||||
|
return s-a;
|
||||||
|
}
|
||||||
@@ -37,9 +37,12 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
wcslen(const wchar_t *s)
|
wcslen(const wchar_t *s)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
const wchar_t *a;
|
||||||
return(0);
|
for (a=s; *s; s++);
|
||||||
|
return s-a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,14 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
wchar_t *
|
wchar_t *
|
||||||
wcsncat(wchar_t *dest, const wchar_t *src, size_t n)
|
wcsncat(wchar_t *dest, const wchar_t *src, size_t n)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
wchar_t *a = dest;
|
||||||
return(NULL);
|
dest += wcslen(dest);
|
||||||
|
while (n && *src) n--, *dest++ = *src++;
|
||||||
|
*dest++ = 0;
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,11 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
int
|
int
|
||||||
wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n)
|
wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
for (; n && *s1==*s2 && *s1 && *s2; n--, s1++, s2++);
|
||||||
return(0);
|
return n ? *s1 - *s2 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,13 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
wchar_t *
|
wchar_t *
|
||||||
wcsncpy(wchar_t *dest, const wchar_t *src, size_t n)
|
wcsncpy(wchar_t *dest, const wchar_t *src, size_t n)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
wchar_t *a = dest;
|
||||||
return(NULL);
|
while (n && *src) n--, *dest++ = *src++;
|
||||||
|
wmemset(dest, 0, n);
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
wchar_t
|
wchar_t *
|
||||||
wcspbrk(const wchar_t *s, const wchar_t *set)
|
wcspbrk(const wchar_t *s, const wchar_t *set)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
/* ZZZ unimplemented */
|
||||||
|
|||||||
45
library/wchar_wctob.c
Normal file
45
library/wchar_wctob.c
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* $Id: wchar_wmemchr.c,v 1.3 2006-01-08 12:04:27 obarthel Exp $
|
||||||
|
*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _WCHAR_HEADERS_H
|
||||||
|
#include "wchar_headers.h"
|
||||||
|
#endif /* _WCHAR_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
int
|
||||||
|
wctob(wint_t c)
|
||||||
|
{
|
||||||
|
if (c < 128U) return c;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
@@ -37,9 +37,11 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
wchar_t *
|
wchar_t *
|
||||||
wmemchr(const wchar_t *ptr, wchar_t val, size_t len)
|
wmemchr(const wchar_t *ptr, wchar_t val, size_t len)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
for (; len && *ptr != val; len--, ptr++);
|
||||||
return(NULL);
|
return len ? (wchar_t *)ptr : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,11 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
int
|
int
|
||||||
wmemcmp(const wchar_t *ptr1, const wchar_t *ptr2, size_t len)
|
wmemcmp(const wchar_t *ptr1, const wchar_t *ptr2, size_t len)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
for (; len && *ptr1==*ptr2; len--, ptr1++, ptr2++);
|
||||||
return(0);
|
return len ? *ptr1-*ptr2 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,12 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
wchar_t *
|
wchar_t *
|
||||||
wmemcpy(wchar_t *dest, const wchar_t *src, size_t len)
|
wmemcpy(wchar_t *dest, const wchar_t *src, size_t len)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
wchar_t *a = dest;
|
||||||
return(NULL);
|
while (len--) *dest++ = *src++;
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,15 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
wchar_t *
|
wchar_t *
|
||||||
wmemmove(wchar_t *dest, const wchar_t * src, size_t len)
|
wmemmove(wchar_t *dest, const wchar_t * src, size_t len)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
wchar_t *d0 = dest;
|
||||||
return(NULL);
|
if ((size_t)(dest-src) < len)
|
||||||
|
while (len--) dest[len] = src[len];
|
||||||
|
else
|
||||||
|
while (len--) *dest++ = *src++;
|
||||||
|
return d0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,12 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
wchar_t *
|
wchar_t *
|
||||||
wmemset(wchar_t *ptr, int val, size_t len)
|
wmemset(wchar_t *ptr, int val, size_t len)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
wchar_t *ret = ptr;
|
||||||
return(NULL);
|
while (len--) *ptr++ = val;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,10 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
int
|
int
|
||||||
iswalnum(wint_t c)
|
iswalnum(wint_t c)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
return iswdigit(c) || iswalpha(c);
|
||||||
return(0);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,11 +35,12 @@
|
|||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
#endif /* _WCTYPE_HEADERS_H */
|
#endif /* _WCTYPE_HEADERS_H */
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
int
|
int
|
||||||
iswalpha(wint_t c)
|
iswalpha(wint_t c)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
return isalpha(c);
|
||||||
return(0);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,11 +35,14 @@
|
|||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
#endif /* _WCTYPE_HEADERS_H */
|
#endif /* _WCTYPE_HEADERS_H */
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Implementation based on musl */
|
||||||
|
|
||||||
int
|
int
|
||||||
iswblank(wint_t c)
|
iswblank(wint_t c)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
return isblank(c);
|
||||||
return(0);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,11 +35,12 @@
|
|||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
#endif /* _WCTYPE_HEADERS_H */
|
#endif /* _WCTYPE_HEADERS_H */
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
int
|
int
|
||||||
iswcntrl(wint_t c)
|
iswcntrl(wint_t c)
|
||||||
{
|
{
|
||||||
/* ZZZ unimplemented */
|
return iscntrl(c);
|
||||||
return(0);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user