mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
Compare commits
143 Commits
V1_207
...
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 | ||
|
|
053a61fc4b | ||
|
|
4c54ee3f2d | ||
|
|
f491e38b38 | ||
|
|
734ce4c1a9 | ||
|
|
ce345df9da | ||
|
|
5e0fa78d61 | ||
|
|
bc3e19abe5 | ||
|
|
29e02775fb | ||
|
|
5cb27db203 | ||
|
|
4fc1b13945 | ||
|
|
8beaabac4f | ||
|
|
271572ed56 | ||
|
|
e0feef8932 | ||
|
|
07259ed7eb | ||
|
|
3203fcf96a | ||
|
|
bfba44bf83 | ||
|
|
35434bdedc | ||
|
|
17ba18c731 | ||
|
|
78a8c7655e | ||
|
|
184a127860 | ||
|
|
5617c0eacf | ||
|
|
ac710b333e | ||
|
|
d2acae7cd7 | ||
|
|
f8cf752e6a | ||
|
|
0c5b88d2d3 | ||
|
|
1ea8953bd3 | ||
|
|
ff908f8a02 | ||
|
|
525e193113 | ||
|
|
2df2393b81 | ||
|
|
ecd40943e2 | ||
|
|
7e201fea06 | ||
|
|
799ee705e8 | ||
|
|
3425e33cf9 | ||
|
|
ef66e530b7 |
14
.codeclimate.yml
Normal file
14
.codeclimate.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
engines:
|
||||
duplication:
|
||||
enabled: false
|
||||
fixme:
|
||||
enabled: true
|
||||
markdownlint:
|
||||
enabled: true
|
||||
ratings:
|
||||
paths:
|
||||
- "**.c"
|
||||
- "**.h"
|
||||
- "**.l"
|
||||
- "**.md"
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
*.a
|
||||
/library/compiler.log
|
||||
/library/netinclude
|
||||
*.map
|
||||
|
||||
36
.travis.yml
Normal file
36
.travis.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
language: c
|
||||
|
||||
# download and install our required cross compilers
|
||||
install:
|
||||
# Make sure we can install i386 packages as some adtools binaries
|
||||
# requires i386 libraries being installed to work in the 64bit env
|
||||
# of Travis
|
||||
- sudo dpkg --add-architecture i386
|
||||
- sudo apt-get -qq update || true
|
||||
- sudo apt-get -qq install libc6:i386
|
||||
# Install all adtools related stuff we need
|
||||
- curl -L https://dl.bintray.com/jens-maus/adtools/adtools-utils.tar.bz2 | sudo tar xj -C /
|
||||
- if [[ ${BUILD} =~ os3|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-m68k-amigaos.tar.bz2 | sudo tar xj -C / ; fi
|
||||
- if [[ ${BUILD} =~ os4|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-ppc-amigaos.tar.bz2 | sudo tar xj -C / ; fi
|
||||
- if [[ ${BUILD} =~ mos|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-ppc-morphos.tar.bz2 | sudo tar xj -C / ; fi
|
||||
- if [[ ${BUILD} =~ aros-ppc|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-ppc-aros.tar.bz2 | sudo tar xj -C / ; fi
|
||||
- if [[ ${BUILD} =~ aros-i386|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-i386-aros.tar.bz2 | sudo tar xj -C / ; fi
|
||||
- if [[ ${BUILD} =~ aros-x86_64|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-x86_64-aros.tar.bz2 | sudo tar xj -C / ; fi
|
||||
- if [[ ${BUILD} =~ mingw32|release ]]; then sudo apt-get -qq install binutils-mingw-w64-i686 gcc-mingw-w64-i686 ; fi
|
||||
|
||||
# set the PATH variable to the directories the cross compilers are installed.
|
||||
before_script:
|
||||
- export PATH=/usr/local/amiga/bin:/opt/m68k-amigaos/bin:/opt/ppc-amigaos/bin:/opt/ppc-morphos/bin:${PATH}
|
||||
|
||||
# specify a list of variables to test (here we test the build for our supported
|
||||
# list of operating systems).
|
||||
env:
|
||||
- BUILD="-f GNUmakefile.68k OS=os3"
|
||||
- BUILD="-f GNUmakefile.os4 OS=os4"
|
||||
|
||||
# the build command to execute for each test
|
||||
script:
|
||||
- make -C library -j1 ${BUILD}
|
||||
29
LICENSE
Normal file
29
LICENSE
Normal file
@@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2016, Olaf Barthel
|
||||
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.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
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 HOLDER 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.
|
||||
@@ -1,4 +1,9 @@
|
||||
# An ISO 'C' (1994) compliant runtime library for the Amiga
|
||||
# clib2 – An ISO 'C' (1994) compliant runtime library for AmigaOS
|
||||
|
||||
[](https://travis-ci.org/adtools/clib2)
|
||||
[](https://codeclimate.com/github/adtools/clib2)
|
||||
[](https://opensource.org/licenses/BSD-3-Clause)
|
||||
[](https://github.com/adtools/clib2/issues)
|
||||
|
||||
## What is this?
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ WARNINGS = \
|
||||
# -Wconversion -Wshadow
|
||||
|
||||
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 -D__THREAD_SAFE
|
||||
#OPTIONS = -fno-builtin -fno-common -D__MEM_DEBUG
|
||||
@@ -261,6 +261,7 @@ C_LIB = \
|
||||
stdio_iobhookentry.o \
|
||||
stdio_lock.o \
|
||||
stdio_locksemaphorename.o \
|
||||
stdio_long_path.o \
|
||||
stdio_nostdio.o \
|
||||
stdio_openiob.o \
|
||||
stdio_parent_of_fh.o \
|
||||
@@ -327,11 +328,15 @@ C_LIB = \
|
||||
stdlib_exit.o \
|
||||
stdlib_free.o \
|
||||
stdlib_free_unused_slabs.o \
|
||||
stdlib_decay_unused_slabs.o \
|
||||
stdlib_getdefstacksize.o \
|
||||
stdlib_getenv.o \
|
||||
stdlib_getmemstats.o \
|
||||
stdlib_getsp.o \
|
||||
stdlib_get_errno.o \
|
||||
stdlib_get_slab_usage.o \
|
||||
stdlib_get_slab_allocations.o \
|
||||
stdlib_get_slab_stats.o \
|
||||
stdlib_isresident.o \
|
||||
stdlib_labs.o \
|
||||
stdlib_llabs.o \
|
||||
@@ -371,6 +376,7 @@ C_LIB = \
|
||||
stdlib_showerror.o \
|
||||
stdlib_slab.o \
|
||||
stdlib_slab_max_size.o \
|
||||
stdlib_slab_purge_threshold.o \
|
||||
stdlib_srand.o \
|
||||
stdlib_stacksize.o \
|
||||
stdlib_stack_usage.o \
|
||||
@@ -486,13 +492,13 @@ C_LIB = \
|
||||
UNIX_LIB = \
|
||||
unix.lib_rev.o \
|
||||
dirent_closedir.o \
|
||||
dirent_rewinddir.o \
|
||||
dirent_opendir.o \
|
||||
dirent_readdir.o \
|
||||
dirent_rewinddir.o \
|
||||
fcntl_creat.o \
|
||||
fcntl_fcntl.o \
|
||||
fcntl_open.o \
|
||||
fcntl_get_default_file.o \
|
||||
fcntl_open.o \
|
||||
getopt_getopt_long.o \
|
||||
mount_convertinfo.o \
|
||||
mount_statfs.o \
|
||||
@@ -500,18 +506,19 @@ UNIX_LIB = \
|
||||
resource_setrlimit.o \
|
||||
stat_chmod.o \
|
||||
stat_fstat.o \
|
||||
stat_lstat.o \
|
||||
stat_lock.o \
|
||||
stat_lstat.o \
|
||||
stat_mkdir.o \
|
||||
stat_rmdir.o \
|
||||
stat_stat.o \
|
||||
stdio_ctermid.o \
|
||||
stdio_fdhookentry.o \
|
||||
stdio_fflush.o \
|
||||
stdio_file_init.o \
|
||||
stdio_fopen.o \
|
||||
stdio_init_exit.o \
|
||||
stdio_file_init.o \
|
||||
stdio_locksemaphorename.o \
|
||||
stdio_long_path.o \
|
||||
stdio_openiob.o \
|
||||
stdio_popen.o \
|
||||
stdio_record_locking.o \
|
||||
@@ -521,17 +528,28 @@ UNIX_LIB = \
|
||||
stdlib_alloca_cleanup.o \
|
||||
stdlib_alloca_trap.o \
|
||||
stdlib_arg.o \
|
||||
stdlib_calloc.o \
|
||||
stdlib_decay_unused_slabs.o \
|
||||
stdlib_expand_wildcard.o \
|
||||
stdlib_expand_wildcard_check.o \
|
||||
stdlib_free.o \
|
||||
stdlib_free_unused_slabs.o \
|
||||
stdlib_getmemstats.o \
|
||||
stdlib_get_slab_allocations.o \
|
||||
stdlib_get_slab_stats.o \
|
||||
stdlib_get_slab_usage.o \
|
||||
stdlib_main.o \
|
||||
stdlib_main_stub.o \
|
||||
stdlib_malloc.o \
|
||||
stdlib_mkdtemp.o \
|
||||
stdlib_mkstemp.o \
|
||||
stdlib_mktemp.o \
|
||||
stdlib_malloc.o \
|
||||
stdlib_realloc.o \
|
||||
stdlib_red_black.o \
|
||||
stdlib_resetmemstats.o \
|
||||
stdlib_slab.o \
|
||||
stdlib_slab_max_size.o \
|
||||
stdlib_slab_purge_threshold.o \
|
||||
stdlib_system.o \
|
||||
systeminfo_sysinfo.o \
|
||||
termios_cfgetispeed.o \
|
||||
@@ -935,6 +953,7 @@ AMIGA_LIB = \
|
||||
amiga_hotkey.o \
|
||||
amiga_invertstring.o \
|
||||
amiga_newlist.o \
|
||||
amiga_pools.o \
|
||||
amiga_rangerand.o \
|
||||
amiga_remtof.o \
|
||||
amiga_rexxvars.o \
|
||||
@@ -1122,21 +1141,59 @@ $(LIBC_OBJS)/stdlib_getdefstacksize.o : stdlib_getdefstacksize.c stdlib_gcc_help
|
||||
|
||||
$(LIBC_OBJS)/stdlib_shell_escape.o : stdlib_shell_escape.c stdlib_gcc_help.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_alloca.o : stdlib_alloca.c stdlib_memory.h
|
||||
$(LIBC_OBJS)/stdlib_alloca.o : stdlib_alloca.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_calloc.o : stdlib_calloc.c stdlib_memory.h
|
||||
$(LIBC_OBJS)/stdlib_calloc.o : stdlib_calloc.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_free.o : stdlib_free.c stdlib_memory.h
|
||||
$(LIBC_OBJS)/stdlib_free.o : stdlib_free.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_malloc.o : stdlib_malloc.c stdlib_memory.h
|
||||
$(LIBC_OBJS)/stdlib_malloc.o : stdlib_malloc.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_slab.o : stdlib_slab.c stdlib_memory.h
|
||||
$(LIBC_OBJS)/stdlib_slab.o : stdlib_slab.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h
|
||||
$(LIBC_OBJS)/stdlib_slab_purge_threshold.o : stdlib_slab_purge_threshold.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_realloc.o : stdlib_realloc.c stdlib_memory.h
|
||||
$(LIBC_OBJS)/stdlib_get_slab_stats.o : stdlib_get_slab_stats.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h
|
||||
$(LIBC_OBJS)/stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_decay_unused_slabs.o : stdlib_decay_unused_slabs.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_get_slab_usage.o : stdlib_get_slab_usage.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_get_slab_allocations.o : stdlib_get_slab_allocations.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_realloc.o : stdlib_realloc.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
$(LIBC_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h include/stdlib.h
|
||||
|
||||
##############################################################################
|
||||
|
||||
$(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
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
@@ -29,7 +29,11 @@ RANLIB := ppc-amigaos-ranlib
|
||||
COPY := cp -p
|
||||
DELETE := rm -rf
|
||||
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
|
||||
# build the baserel versions of the library. At this time of
|
||||
# writing (2008-11-06) GCC 4.0.4 and below support the -mbaserel
|
||||
@@ -54,12 +58,13 @@ LOG_COMMAND := 2>&1 | tee -a compiler.log
|
||||
|
||||
WARNINGS := \
|
||||
-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-unused-label \
|
||||
|
||||
# -Wconversion -Wshadow
|
||||
# -Wconversion -Wshadow -Wbad-function-cast
|
||||
|
||||
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
|
||||
|
||||
#DEBUG := -ggdb
|
||||
@@ -92,7 +97,11 @@ include libm.gmk
|
||||
include libnet.gmk
|
||||
include libdebug.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: \
|
||||
lib/crt0.o \
|
||||
@@ -159,6 +168,12 @@ cvs-tag:
|
||||
|
||||
# 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 : %.S
|
||||
@$(ASSEMBLE)
|
||||
@@ -170,6 +185,11 @@ lib/small-data/%.o : AFLAGS += $(SMALLDATA)
|
||||
lib/small-data/%.o : %.S
|
||||
@$(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
|
||||
@$(COMPILE)
|
||||
|
||||
@@ -177,6 +197,11 @@ lib/soft-float/%.o : AFLAGS += $(SOFTFLOAT)
|
||||
lib/soft-float/%.o : %.S
|
||||
@$(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
|
||||
@$(COMPILE)
|
||||
|
||||
@@ -184,6 +209,11 @@ lib/baserel/%.o : AFLAGS += $(BASEREL)
|
||||
lib/baserel/%.o : %.S
|
||||
@$(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
|
||||
@$(COMPILE)
|
||||
|
||||
@@ -191,6 +221,11 @@ lib.threadsafe/%.o : AFLAGS += $(LARGEDATA) $(THREADSAFE)
|
||||
lib.threadsafe/%.o : %.S
|
||||
@$(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
|
||||
@$(COMPILE)
|
||||
|
||||
@@ -198,6 +233,11 @@ lib.threadsafe/small-data/%.o : AFLAGS += $(SMALLDATA) $(THREADSAFE)
|
||||
lib.threadsafe/small-data/%.o : %.S
|
||||
@$(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
|
||||
@$(COMPILE)
|
||||
|
||||
@@ -205,6 +245,11 @@ lib.threadsafe/soft-float/%.o : AFLAGS += $(SOFTFLOAT) $(THREADSAFE)
|
||||
lib.threadsafe/soft-float/%.o : %.S
|
||||
@$(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
|
||||
@$(COMPILE)
|
||||
|
||||
@@ -212,6 +257,11 @@ lib.threadsafe/baserel/%.o : AFLAGS += $(BASEREL) $(THREADSAFE)
|
||||
lib.threadsafe/baserel/%.o : %.S
|
||||
@$(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
|
||||
@$(COMPILE)
|
||||
|
||||
@@ -230,7 +280,7 @@ $(CC) $(AFLAGS) -o $@ -c $< $(LOG_COMMAND)
|
||||
endef
|
||||
|
||||
define MAKELIB
|
||||
-$(MAKEDIR) $@
|
||||
-$(MAKEDIR) $(@D)
|
||||
$(DELETE) $@
|
||||
echo "Making $@"
|
||||
$(AR) $@ $^ $(LOG_COMMAND)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define VERSION 1
|
||||
#define REVISION 207
|
||||
#define DATE "18.11.2016"
|
||||
#define VERS "amiga.lib 1.207"
|
||||
#define VSTRING "amiga.lib 1.207 (18.11.2016)\r\n"
|
||||
#define VERSTAG "\0$VER: amiga.lib 1.207 (18.11.2016)"
|
||||
#define REVISION 216
|
||||
#define DATE "10.7.2025"
|
||||
#define VERS "amiga.lib 1.216"
|
||||
#define VSTRING "amiga.lib 1.216 (10.7.2025)\r\n"
|
||||
#define VERSTAG "\0$VER: amiga.lib 1.216 (10.7.2025)"
|
||||
|
||||
@@ -1 +1 @@
|
||||
207
|
||||
216
|
||||
|
||||
@@ -79,6 +79,8 @@ DoTimer(struct timeval *tv,LONG unit,LONG command)
|
||||
struct MsgPort * mp;
|
||||
LONG error;
|
||||
|
||||
PROFILE_OFF();
|
||||
|
||||
assert( tv != NULL );
|
||||
|
||||
#if defined(__amigaos4__)
|
||||
@@ -129,14 +131,10 @@ DoTimer(struct timeval *tv,LONG unit,LONG command)
|
||||
tr->tr_time.tv_secs = tv->tv_secs;
|
||||
tr->tr_time.tv_micro = tv->tv_micro;
|
||||
|
||||
PROFILE_OFF();
|
||||
|
||||
SetSignal(0,(1UL << mp->mp_SigBit));
|
||||
|
||||
error = DoIO((struct IORequest *)tr);
|
||||
|
||||
PROFILE_ON();
|
||||
|
||||
tv->tv_secs = tr->tr_time.tv_secs;
|
||||
tv->tv_micro = tr->tr_time.tv_micro;
|
||||
|
||||
@@ -161,5 +159,7 @@ DoTimer(struct timeval *tv,LONG unit,LONG command)
|
||||
}
|
||||
#endif /* __amigaos4__ */
|
||||
|
||||
PROFILE_ON();
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,9 +262,8 @@ STATIC VOID
|
||||
_SetValue(struct Environment * env,struct NexxStr * value,struct Node * symbol_table_node)
|
||||
{
|
||||
STATIC CONST UWORD code[] = { 0x4EAE,0xFFAC,0x4E75 }; /* jsr -84(a6) ; rts */
|
||||
struct Node * result;
|
||||
|
||||
result = (struct Node *)EmulateTags(code,
|
||||
EmulateTags(code,
|
||||
ET_RegisterA0,env,
|
||||
ET_RegisterA1,value,
|
||||
ET_RegisterD0,symbol_table_node,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define VERSION 1
|
||||
#define REVISION 207
|
||||
#define DATE "18.11.2016"
|
||||
#define VERS "c.lib 1.207"
|
||||
#define VSTRING "c.lib 1.207 (18.11.2016)\r\n"
|
||||
#define VERSTAG "\0$VER: c.lib 1.207 (18.11.2016)"
|
||||
#define REVISION 217
|
||||
#define DATE "10.7.2025"
|
||||
#define VERS "c.lib 1.217"
|
||||
#define VSTRING "c.lib 1.217 (10.7.2025)\r\n"
|
||||
#define VERSTAG "\0$VER: c.lib 1.217 (10.7.2025)"
|
||||
|
||||
@@ -1 +1 @@
|
||||
207
|
||||
217
|
||||
|
||||
281
library/changes
281
library/changes
@@ -1,3 +1,280 @@
|
||||
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)
|
||||
|
||||
- Added the __decay_unused_slabs() function which brings all currently
|
||||
empty slabs which are still protected from reuse closer to getting
|
||||
reused or released.
|
||||
|
||||
- The slab-test program now exercises the memory allocation functions
|
||||
to a greater degree. Memory is allocated in random chunk sizes,
|
||||
the allocations are resized (to other random chunk sizes),
|
||||
33% of all allocations are randomly freed, empty slabs readied for
|
||||
reuse then discarded. The output in JSON format now shows a bit
|
||||
more information as to what is being done.
|
||||
|
||||
- Rewrote __get_slab_stats() to use setjmp() and longjmp() in the
|
||||
print() callback invocation.
|
||||
|
||||
- __get_slab_stats() now reports how many times a slab was reused
|
||||
after having stuck around in the "empty slab" list.
|
||||
|
||||
- Changing the slab size through an environment variable is now
|
||||
a feature of the debug build.
|
||||
|
||||
- Small changes to allow the library to be built with SAS/C again.
|
||||
This includes adding code to disable/re-enable profiling,
|
||||
fixing "stdlib_profile.h" and updating the smakefiles.
|
||||
|
||||
- Still not sure what it does, but _CXV45 now sits along with _CX25
|
||||
and _CX35 in "sas_cxv.asm". "sas_cxv54.asm" is not needed any
|
||||
more.
|
||||
|
||||
- Found the last use of MEMF_PRIVATE which should have been compiled
|
||||
only for the OS4 version.
|
||||
|
||||
|
||||
c.lib 1.212 (27.11.2016)
|
||||
|
||||
- Unused slabs which get recycled are no longer reinitialized from
|
||||
scratch if their chunk size matches what the allocator needed.
|
||||
If the chunk size matches, the list of available chunks is
|
||||
left unchanged, and just the various counters are reset.
|
||||
|
||||
- Added __get_slab_stats() function.
|
||||
|
||||
- Added support for global __slab_purge_threshold tuning variable.
|
||||
|
||||
|
||||
c.lib 1.211 (23.11.2016)
|
||||
|
||||
- Added more consistency checking to the slab allocator, which is
|
||||
built if DEBUG is defined in "stdlib_slab.c".
|
||||
|
||||
- Memory allocations are no longer guaranteed to be aligned to
|
||||
64 bit word boundaries. In fact, this has not even worked
|
||||
reliably in the past 10 years.
|
||||
|
||||
- Memory allocation request sizes are now rounded to multiples of
|
||||
32 bit words (the size of an address pointer) instead to the
|
||||
size of a 64 bit word.
|
||||
|
||||
- Reduced the memory footprint of the memory allocation management
|
||||
data structures by reusing the most significant bit of the
|
||||
memory allocation size. This allows many more allocations to fit
|
||||
into the 32 byte chunk slabs, but limits the maximum memory
|
||||
allocation size to a little less than 2 GBytes.
|
||||
|
||||
- Added integer overflow checks to the memory management code.
|
||||
|
||||
- Reduced the memory management overhead further. This cuts an
|
||||
additional 8 bytes per allocation, unless neither the slab
|
||||
allocator nor memory pools are available. With this reduction
|
||||
the slab allocator is able to use 16 byte chunks, which cover
|
||||
memory allocation requests of 1..8 bytes.
|
||||
|
||||
- Fixed a bug caused by returning an allocation back to a slab
|
||||
which passed the wrong pointer.
|
||||
|
||||
|
||||
c.lib 1.210 (22.11.2016)
|
||||
|
||||
- Added __get_slab_allocations() function which will report information
|
||||
about each memory allocation made by the slab allocator which does
|
||||
not come from a slab.
|
||||
|
||||
- If the first slab in the list of slabs which share the same chunk
|
||||
size has no more room, it means that all other slabs following
|
||||
it have no room either. This speeds up the test to find a slab with
|
||||
free space, which can now abort and directly proceed to allocate
|
||||
memory for a new slab.
|
||||
|
||||
- If an empty slab's decay count hits zero, it is moved to the front
|
||||
of the empty slab list to be reclaimed more quickly.
|
||||
|
||||
- Allocations made from the slab now carry a pointer back to the
|
||||
slab which they are a part of. This speeds up deallocation but
|
||||
has the downside of making the smallest usable slab chunk size
|
||||
64 bytes, which is double what used to be the minimum before.
|
||||
|
||||
|
||||
c.lib 1.209 (21.11.2016)
|
||||
|
||||
- The maximum slab size is now 2^17 bytes (= 131072). If you request
|
||||
a slab size larger than this, you will get slab sizes of 131072
|
||||
bytes instead.
|
||||
|
||||
- Enabling the memory management debugging code no longer produces
|
||||
compiler errors.
|
||||
|
||||
|
||||
c.lib 1.208 (19.11.2016)
|
||||
|
||||
- Updated <stdlib.h> with new functions and data structures for
|
||||
use with the slab allocator.
|
||||
|
||||
- Added __get_slab_usage() function which can be used to query
|
||||
the slab allocator memory usage at runtime.
|
||||
|
||||
|
||||
c.lib 1.207 (18.11.2016)
|
||||
|
||||
- Added a slab allocator which replaces the use of memory pools or the
|
||||
@@ -33,7 +310,7 @@ c.lib 1.206 (24.4.2015)
|
||||
|
||||
- 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
|
||||
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.
|
||||
|
||||
|
||||
@@ -1211,7 +1488,7 @@ c.lib 1.187 (29.1.2005)
|
||||
adding/subtracting the local time zone.
|
||||
|
||||
- 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().
|
||||
|
||||
- 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
|
||||
*
|
||||
@@ -48,7 +48,12 @@
|
||||
* 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
|
||||
* 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 (*__DTOR_LIST__[1]) (void) __attribute__(( used, section(".dtors"), aligned(sizeof(void (*)(void))) ));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define VERSION 1
|
||||
#define REVISION 207
|
||||
#define DATE "18.11.2016"
|
||||
#define VERS "debug.lib 1.207"
|
||||
#define VSTRING "debug.lib 1.207 (18.11.2016)\r\n"
|
||||
#define VERSTAG "\0$VER: debug.lib 1.207 (18.11.2016)"
|
||||
#define REVISION 215
|
||||
#define DATE "26.6.2017"
|
||||
#define VERS "debug.lib 1.215"
|
||||
#define VSTRING "debug.lib 1.215 (26.6.2017)\r\n"
|
||||
#define VERSTAG "\0$VER: debug.lib 1.215 (26.6.2017)"
|
||||
|
||||
@@ -1 +1 @@
|
||||
207
|
||||
215
|
||||
|
||||
@@ -125,7 +125,7 @@ CLIB_DESTRUCTOR(dirent_exit)
|
||||
|
||||
if(__directory_list.mlh_Head != NULL)
|
||||
{
|
||||
while(NOT IsListEmpty((struct List *)&__directory_list))
|
||||
while(NOT IsMinListEmpty(&__directory_list))
|
||||
closedir((DIR *)__directory_list.mlh_Head);
|
||||
}
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ opendir(const char * path_name)
|
||||
UnLockDosList(LDF_VOLUMES|LDF_READ);
|
||||
|
||||
/* Bail out if we cannot present anything. */
|
||||
if(IsListEmpty((struct List *)&dh->dh_VolumeList))
|
||||
if(IsMinListEmpty(&dh->dh_VolumeList))
|
||||
{
|
||||
__set_errno(ENOMEM);
|
||||
goto out;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: dirent_readdir.c,v 1.10 2006-09-25 14:51:15 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>
|
||||
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -79,9 +77,11 @@ readdir(DIR * directory_pointer)
|
||||
|
||||
dh->dh_Position++;
|
||||
|
||||
dh->dh_DirectoryEntry.d_ino = 0;
|
||||
strcpy(dh->dh_DirectoryEntry.d_name,".");
|
||||
|
||||
dh->dh_DirectoryEntry.d_ino = 0;
|
||||
dh->dh_DirectoryEntry.d_type = DT_DIR;
|
||||
|
||||
result = &dh->dh_DirectoryEntry;
|
||||
}
|
||||
else
|
||||
@@ -93,7 +93,7 @@ readdir(DIR * directory_pointer)
|
||||
|
||||
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;
|
||||
|
||||
strcpy(name,"\1:"); /* BSTR for ":" */
|
||||
@@ -117,6 +117,7 @@ readdir(DIR * directory_pointer)
|
||||
strcpy(dh->dh_DirectoryEntry.d_name,fib->fib_FileName);
|
||||
|
||||
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
|
||||
dh->dh_DirectoryEntry.d_type = DT_DIR;
|
||||
|
||||
result = &dh->dh_DirectoryEntry;
|
||||
}
|
||||
@@ -147,10 +148,11 @@ readdir(DIR * directory_pointer)
|
||||
|
||||
dh->dh_Position++;
|
||||
|
||||
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
|
||||
|
||||
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;
|
||||
}
|
||||
else if (dh->dh_Position == 1)
|
||||
@@ -176,10 +178,11 @@ readdir(DIR * directory_pointer)
|
||||
|
||||
SHOWMSG("returning ..");
|
||||
|
||||
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -192,12 +195,23 @@ readdir(DIR * directory_pointer)
|
||||
|
||||
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) );
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -296,7 +296,7 @@ static int getopt_long_internal(int argc, const char **argv, const char *optstri
|
||||
optp = strchr(optstring, c);
|
||||
|
||||
/* We never find a long option in a compound option */
|
||||
*longindex = 0;
|
||||
*longindex = -1;
|
||||
|
||||
/* Check if it's legal */
|
||||
if (c == ':' || (optp == NULL))
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: dirent.h,v 1.7 2006-01-08 12:06:14 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>
|
||||
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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
|
||||
{
|
||||
ino_t d_ino;
|
||||
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);
|
||||
|
||||
@@ -359,7 +359,7 @@ extern unsigned int (* __get_default_stack_size)(void);
|
||||
/*
|
||||
* This library falls back onto locale.library to perform string collation
|
||||
* 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
|
||||
* 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
|
||||
|
||||
@@ -166,6 +166,8 @@ extern int errno;
|
||||
|
||||
#define EILSEQ 85 /* Encoding error detected */
|
||||
|
||||
#define ENOTSUP 86 /* Not supported */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: locale.h,v 1.5 2006-01-08 12:06:14 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>
|
||||
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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
|
||||
{
|
||||
char * decimal_point; /* Decimal point character (non-monetary). */
|
||||
|
||||
@@ -61,7 +61,11 @@ extern "C" {
|
||||
|
||||
typedef int ptrdiff_t;
|
||||
typedef unsigned int size_t;
|
||||
|
||||
/* wchar_t is a built-in type in C++ */
|
||||
#ifndef __cplusplus
|
||||
typedef unsigned short wchar_t;
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
@@ -47,6 +47,10 @@
|
||||
#include <stddef.h>
|
||||
#endif /* _STDDEF_H */
|
||||
|
||||
#ifndef _SYS_CLIB2_STDC_H
|
||||
#include <sys/clib2_stdc.h>
|
||||
#endif /* _SYS_CLIB2_STDC_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -161,6 +165,227 @@ extern int rand_r(unsigned int * seed);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* You can switch the built-in memory allocator, which is a thin wrapper
|
||||
* around the AmigaOS built-in memory management system, to use a slab
|
||||
* allocator. For this to work, you need to declare a global variable
|
||||
* and set it to the size of the slabs to be used. This variable must
|
||||
* be initialized at load time when the clib2 startup code runs:
|
||||
*
|
||||
* unsigned long __slab_max_size = 4096;
|
||||
*/
|
||||
|
||||
extern unsigned long __slab_max_size;
|
||||
|
||||
/*
|
||||
* The slab allocator will periodically free all currently unused memory.
|
||||
* You can control how much memory should be released, instead of
|
||||
* releasing everything.
|
||||
*
|
||||
* This would make the slab allocator release only up to 512 KBytes of
|
||||
* unused memory at a time:
|
||||
*
|
||||
* unsigned long __slab_purge_threshold = 512 * 1024;
|
||||
*/
|
||||
|
||||
extern unsigned long __slab_purge_threshold;
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* If you are using the slab allocator and need to quickly release the
|
||||
* memory of all slabs which are currently unused, you can call the
|
||||
* following function to do so.
|
||||
*
|
||||
* Please note that this function works within the context of the memory
|
||||
* allocation system and is not safe to call from interrupt code. It may
|
||||
* break a Forbid() or Disable() condition.
|
||||
*/
|
||||
extern void __free_unused_slabs(void);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* You can accelerate the reuse of currently unused slabs by calling
|
||||
* the __decay_unused_slabs() function. Each call decrements the decay
|
||||
* counter until it reaches 0, at which point an unused slab can be
|
||||
* reused instead of allocating a new slab. Also, at 0 unused slabs
|
||||
* will be freed by the allocator.
|
||||
*
|
||||
* Please note that this function works within the context of the memory
|
||||
* allocation system and is not safe to call from interrupt code. It may
|
||||
* break a Forbid() or Disable() condition.
|
||||
*/
|
||||
extern void __decay_unused_slabs(void);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* You can obtain runtime statistics about the slab allocator by
|
||||
* invoking the __get_slab_usage() function which in turn invokes
|
||||
* your callback function for each single slab currently in play.
|
||||
*
|
||||
* Your callback function must return 0 if it wants to be called again,
|
||||
* for the next slab, or return -1 to stop. Note that your callback
|
||||
* function may not be called if the slab allocator is currently
|
||||
* not operational.
|
||||
*
|
||||
* Please note that this function works within the context of the memory
|
||||
* allocation system and is not safe to call from interrupt code. It may
|
||||
* break a Forbid() or Disable() condition.
|
||||
*/
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* This is what your callback function will see when it is invoked. */
|
||||
struct __slab_usage_information
|
||||
{
|
||||
/* The size of all slabs, in bytes. */
|
||||
size_t sui_slab_size;
|
||||
|
||||
/* Number of allocations which are not managed by slabs, but
|
||||
* are handled separate.
|
||||
*/
|
||||
size_t sui_num_single_allocations;
|
||||
|
||||
/* Total number of bytes allocated for memory not managed
|
||||
* by slabs. This includes the management overhead for
|
||||
* each allocation.
|
||||
*/
|
||||
size_t sui_total_single_allocation_size;
|
||||
|
||||
/* Number of slabs currently in play. This can be 0. */
|
||||
size_t sui_num_slabs;
|
||||
|
||||
/* Number of currently unused slabs which contain no data. */
|
||||
size_t sui_num_empty_slabs;
|
||||
|
||||
/* Number of slabs in use which are completely filled with data. */
|
||||
size_t sui_num_full_slabs;
|
||||
|
||||
/* Total number of bytes allocated for all slabs. */
|
||||
size_t sui_total_slab_allocation_size;
|
||||
|
||||
/*
|
||||
* The following data is updated for each slab which
|
||||
* your callback function sees.
|
||||
*/
|
||||
|
||||
/* Index number of the slab being reported (0 = no slabs are in use). */
|
||||
int sui_slab_index;
|
||||
|
||||
/* How large are the memory chunks managed by this slab? */
|
||||
size_t sui_chunk_size;
|
||||
|
||||
/* How many memory chunks fit into this slab? */
|
||||
size_t sui_num_chunks;
|
||||
|
||||
/* How many memory chunks in this slab are being used? */
|
||||
size_t sui_num_chunks_used;
|
||||
|
||||
/* How many time was this slab reused without reinitializing
|
||||
* it all over again from scratch?
|
||||
*/
|
||||
size_t sui_num_reused;
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
typedef int (*__slab_usage_callback)(const struct __slab_usage_information * sui);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void __get_slab_usage(__slab_usage_callback callback);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* You can obtain runtime statistics about the memory allocations
|
||||
* which the slab allocator did not fit into slabs. This works
|
||||
* just like __get_slab_usage() in that the callback function
|
||||
* you provide will be called for each single allocation that
|
||||
* is not part of a slab.
|
||||
*
|
||||
* Your callback function must return 0 if it wants to be called again,
|
||||
* for the next slab, or return -1 to stop. Note that your callback
|
||||
* function may not be called if the slab allocator did not
|
||||
* allocate memory outside of slabs.
|
||||
*
|
||||
* Please note that this function works within the context of the memory
|
||||
* allocation system and is not safe to call from interrupt code. It may
|
||||
* break a Forbid() or Disable() condition.
|
||||
*/
|
||||
|
||||
/* This is what your callback function will see when it is invoked. */
|
||||
struct __slab_allocation_information
|
||||
{
|
||||
/* Number of allocations which are not managed by slabs, but
|
||||
* are handled separate.
|
||||
*/
|
||||
size_t sai_num_single_allocations;
|
||||
|
||||
/* Total number of bytes allocated for memory not managed
|
||||
* by slabs. This includes the management overhead for
|
||||
* each allocation.
|
||||
*/
|
||||
size_t sai_total_single_allocation_size;
|
||||
|
||||
/*
|
||||
* The following data is updated for each slab which
|
||||
* your callback function sees.
|
||||
*/
|
||||
|
||||
/* Index number of the allocation being reported (0 = no allocations
|
||||
* outside of slabs are in use).
|
||||
*/
|
||||
int sai_allocation_index;
|
||||
|
||||
/* Size of this allocation, as requested by the program which
|
||||
* called malloc(), realloc() or alloca().
|
||||
*/
|
||||
size_t sai_allocation_size;
|
||||
|
||||
/* Total size of this allocation, including management data
|
||||
* structure overhead.
|
||||
*/
|
||||
size_t sai_total_allocation_size;
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
typedef int (*__slab_allocation_callback)(const struct __slab_allocation_information * sui);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void __get_slab_allocations(__slab_allocation_callback callback);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* You can obtain information about the memory managed by the slab allocator,
|
||||
* as well as additional information about the slab allocator's performance
|
||||
* in JSON format. This format can be used for more detailed analysis.
|
||||
*
|
||||
* 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,
|
||||
* 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 occurred
|
||||
* 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.
|
||||
*
|
||||
* Please note that this function works within the context of the memory
|
||||
* allocation system and is not safe to call from interrupt code. It may
|
||||
* break a Forbid() or Disable() condition.
|
||||
*/
|
||||
|
||||
typedef int (* __slab_status_callback)(void * user_data, const char * line, size_t line_length);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
extern void __get_slab_stats(void * user_data, __slab_status_callback callback);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* You can request to use the alloca() variant that actually does allocate
|
||||
* memory from the system rather than the current stack frame, which will
|
||||
@@ -226,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) */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
@@ -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 char *strcpy(char *dest, const char *src);
|
||||
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 char *strchr(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 * ctime_r(const time_t *tptr,char * buffer);
|
||||
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 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 lockf(int file_descriptor, int function, off_t size);
|
||||
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 pid_t getpid(void);
|
||||
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
|
||||
#include <stddef.h>
|
||||
#endif /* _STDDEF_H */
|
||||
@@ -59,6 +63,14 @@
|
||||
#include <time.h>
|
||||
#endif /* _TIME_H */
|
||||
|
||||
#ifndef _LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif /* _LOCALE_H */
|
||||
|
||||
#ifndef _STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -68,8 +80,6 @@ extern "C" {
|
||||
/****************************************************************************/
|
||||
|
||||
#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 int wctob(wint_t c);
|
||||
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 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);
|
||||
@@ -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 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 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 */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
@@ -46,6 +46,7 @@ AMIGA_LIB = \
|
||||
amiga_hotkey.o \
|
||||
amiga_invertstring.o \
|
||||
amiga_newlist.o \
|
||||
amiga_pools.o \
|
||||
amiga_rangerand.o \
|
||||
amiga_remtof.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_rev.o \
|
||||
ctype_isalnum.o \
|
||||
@@ -66,7 +70,6 @@ C_LIB := \
|
||||
mount_convertinfo.o \
|
||||
mount_fstatfs.o \
|
||||
mount_statfs.o \
|
||||
profile_profil.o \
|
||||
signal_checkabort.o \
|
||||
signal_data.o \
|
||||
signal_kill.o \
|
||||
@@ -212,12 +215,16 @@ C_LIB := \
|
||||
stdlib_dosbase.o \
|
||||
stdlib_exit.o \
|
||||
stdlib_free.o \
|
||||
stdlib_decay_unused_slabs.o \
|
||||
stdlib_free_unused_slabs.o \
|
||||
stdlib_getdefstacksize.o \
|
||||
stdlib_getenv.o \
|
||||
stdlib_getmemstats.o \
|
||||
stdlib_getsp.o \
|
||||
stdlib_get_errno.o \
|
||||
stdlib_get_slab_usage.o \
|
||||
stdlib_get_slab_allocations.o \
|
||||
stdlib_get_slab_stats.o \
|
||||
stdlib_isresident.o \
|
||||
stdlib_labs.o \
|
||||
stdlib_llabs.o \
|
||||
@@ -230,6 +237,7 @@ C_LIB := \
|
||||
stdlib_main_stub.o \
|
||||
stdlib_malloc.o \
|
||||
stdlib_math.o \
|
||||
stdlib_mbtowc.o \
|
||||
stdlib_mkdtemp.o \
|
||||
stdlib_mkstemp.o \
|
||||
stdlib_mktemp.o \
|
||||
@@ -258,6 +266,7 @@ C_LIB := \
|
||||
stdlib_showerror.o \
|
||||
stdlib_slab.o \
|
||||
stdlib_slab_max_size.o \
|
||||
stdlib_slab_purge_threshold.o \
|
||||
stdlib_srand.o \
|
||||
stdlib_stacksize.o \
|
||||
stdlib_stack_usage.o \
|
||||
@@ -305,6 +314,7 @@ C_LIB := \
|
||||
string_strncat.o \
|
||||
string_strncmp.o \
|
||||
string_strncpy.o \
|
||||
string_strnlen.o \
|
||||
string_strpbrk.o \
|
||||
string_strrchr.o \
|
||||
string_strspn.o \
|
||||
@@ -331,6 +341,7 @@ C_LIB := \
|
||||
time_numbertostring.o \
|
||||
time_strftime.o \
|
||||
time_time.o \
|
||||
time_tzset.o \
|
||||
time_weekday.o \
|
||||
uio_readv.o \
|
||||
uio_writev.o \
|
||||
@@ -367,7 +378,79 @@ C_LIB := \
|
||||
unistd_unlink.o \
|
||||
unistd_usleep.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_rev.o \
|
||||
dirent_closedir.o \
|
||||
dirent_rewinddir.o \
|
||||
dirent_opendir.o \
|
||||
dirent_readdir.o \
|
||||
dirent_rewinddir.o \
|
||||
fcntl_creat.o \
|
||||
fcntl_fcntl.o \
|
||||
fcntl_open.o \
|
||||
fcntl_get_default_file.o \
|
||||
fcntl_open.o \
|
||||
getopt_getopt_long.o \
|
||||
mount_convertinfo.o \
|
||||
mount_statfs.o \
|
||||
@@ -36,16 +36,16 @@ UNIX_LIB := \
|
||||
resource_setrlimit.o \
|
||||
stat_chmod.o \
|
||||
stat_fstat.o \
|
||||
stat_lstat.o \
|
||||
stat_lock.o \
|
||||
stat_lstat.o \
|
||||
stat_mkdir.o \
|
||||
stat_rmdir.o \
|
||||
stat_stat.o \
|
||||
stdio_ctermid.o \
|
||||
stdio_fdhookentry.o \
|
||||
stdio_fflush.o \
|
||||
stdio_fopen.o \
|
||||
stdio_file_init.o \
|
||||
stdio_fopen.o \
|
||||
stdio_init_exit.o \
|
||||
stdio_locksemaphorename.o \
|
||||
stdio_openiob.o \
|
||||
@@ -60,15 +60,17 @@ UNIX_LIB := \
|
||||
stdlib_dlopen.o \
|
||||
stdlib_expand_wildcard.o \
|
||||
stdlib_expand_wildcard_check.o \
|
||||
stdlib_free.o \
|
||||
stdlib_getmemstats.o \
|
||||
stdlib_main.o \
|
||||
stdlib_main_stub.o \
|
||||
stdlib_malloc.o \
|
||||
stdlib_mkdtemp.o \
|
||||
stdlib_mkstemp.o \
|
||||
stdlib_mktemp.o \
|
||||
stdlib_malloc.o \
|
||||
stdlib_realloc.o \
|
||||
stdlib_resetmemstats.o \
|
||||
stdlib_slab.o \
|
||||
stdlib_system.o \
|
||||
systeminfo_sysinfo.o \
|
||||
termios_cfgetispeed.o \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define VERSION 1
|
||||
#define REVISION 207
|
||||
#define DATE "18.11.2016"
|
||||
#define VERS "m.lib 1.207"
|
||||
#define VSTRING "m.lib 1.207 (18.11.2016)\r\n"
|
||||
#define VERSTAG "\0$VER: m.lib 1.207 (18.11.2016)"
|
||||
#define REVISION 215
|
||||
#define DATE "26.6.2017"
|
||||
#define VERS "m.lib 1.215"
|
||||
#define VSTRING "m.lib 1.215 (26.6.2017)\r\n"
|
||||
#define VERSTAG "\0$VER: m.lib 1.215 (26.6.2017)"
|
||||
|
||||
@@ -1 +1 @@
|
||||
207
|
||||
215
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define VERSION 1
|
||||
#define REVISION 207
|
||||
#define DATE "18.11.2016"
|
||||
#define VERS "m881.lib 1.207"
|
||||
#define VSTRING "m881.lib 1.207 (18.11.2016)\r\n"
|
||||
#define VERSTAG "\0$VER: m881.lib 1.207 (18.11.2016)"
|
||||
#define REVISION 214
|
||||
#define DATE "27.4.2017"
|
||||
#define VERS "m881.lib 1.214"
|
||||
#define VSTRING "m881.lib 1.214 (27.4.2017)\r\n"
|
||||
#define VERSTAG "\0$VER: m881.lib 1.214 (27.4.2017)"
|
||||
|
||||
@@ -1 +1 @@
|
||||
207
|
||||
214
|
||||
|
||||
@@ -93,6 +93,13 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifndef IsMinListEmpty
|
||||
#define IsMinListEmpty(ml) \
|
||||
((struct MinList *)((ml)->mlh_TailPred) == (struct MinList *)(ml))
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifndef AMIGA_COMPILER_H
|
||||
|
||||
#ifdef __SASC
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: math_sqrt.c,v 1.9 2006-09-22 07:54:24 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>
|
||||
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -251,7 +249,8 @@ sqrt(double x)
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 0;
|
||||
result = NAN;
|
||||
|
||||
__set_errno(EDOM);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: math_tgamma.c,v 1.3 2006-01-08 12:04:24 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>
|
||||
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -56,11 +54,9 @@ tgamma(double x)
|
||||
int gamma_sign;
|
||||
double y;
|
||||
|
||||
y = __lgamma(x,&gamma_sign);
|
||||
if (gamma_sign < 0)
|
||||
y = -y;
|
||||
y = __lgamma(x, &gamma_sign);
|
||||
|
||||
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
|
||||
*
|
||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||
@@ -56,11 +54,9 @@ tgammaf(float x)
|
||||
int gamma_sign;
|
||||
float y;
|
||||
|
||||
y = __lgammaf(x,&gamma_sign);
|
||||
if (gamma_sign < 0)
|
||||
y = -y;
|
||||
y = __lgammaf(x, &gamma_sign);
|
||||
|
||||
return y;
|
||||
return gamma_sign * expf(y);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define VERSION 1
|
||||
#define REVISION 207
|
||||
#define DATE "18.11.2016"
|
||||
#define VERS "net.lib 1.207"
|
||||
#define VSTRING "net.lib 1.207 (18.11.2016)\r\n"
|
||||
#define VERSTAG "\0$VER: net.lib 1.207 (18.11.2016)"
|
||||
#define REVISION 215
|
||||
#define DATE "26.6.2017"
|
||||
#define VERS "net.lib 1.215"
|
||||
#define VSTRING "net.lib 1.215 (26.6.2017)\r\n"
|
||||
#define VERSTAG "\0$VER: net.lib 1.215 (26.6.2017)"
|
||||
|
||||
@@ -1 +1 @@
|
||||
207
|
||||
215
|
||||
|
||||
@@ -136,7 +136,7 @@ profil(unsigned short *buffer, size_t bufSize, size_t offset, unsigned int scale
|
||||
ProfileData.CounterStart = GetCounterStart();
|
||||
|
||||
/* Set interrupt vector */
|
||||
CounterInt.is_Code = (void (*)())CounterIntFn;
|
||||
CounterInt.is_Code = (void (*)(void))CounterIntFn;
|
||||
CounterInt.is_Data = &ProfileData;
|
||||
IPM->SetInterruptVector(1, &CounterInt);
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
xdef __CXV25
|
||||
xdef __CXV35
|
||||
xdef __CXV45
|
||||
xdef __CXNRM5
|
||||
xdef __CXTAB5
|
||||
|
||||
@@ -74,6 +75,43 @@ L44: MOVE.W D0,D1
|
||||
MOVEM.L (SP)+,D2-D5/A1
|
||||
RTS
|
||||
|
||||
__CXV45:
|
||||
|
||||
MOVE.L D0,D1
|
||||
SWAP D1
|
||||
AND.W #$7FFF,D1
|
||||
CMP.W #$80,D1
|
||||
BLT .1
|
||||
CMP.W #$7F80,D1
|
||||
BGE .3
|
||||
ASR.L #3,D0
|
||||
AND.L #$8FFFFFFF,D0
|
||||
ADD.L #$38000000,D0
|
||||
SWAP D1
|
||||
AND.L #7,D1
|
||||
ROR.L #3,D1
|
||||
.2 RTS
|
||||
|
||||
.1 TST.L D1
|
||||
BEQ.S .2
|
||||
MOVEM.L D2-D5,-(SP)
|
||||
SWAP D0
|
||||
MOVE.W D0,D4
|
||||
AND.W #$8000,D4
|
||||
MOVE.W #$39D0,D5
|
||||
MOVEQ #0,D0
|
||||
SWAP D1
|
||||
JSR __CXNRM5(PC)
|
||||
MOVEM.L (SP)+,D2-D5
|
||||
RTS
|
||||
|
||||
.3 ASR.L #3,D0
|
||||
OR.L #$7FF00000,D0
|
||||
SWAP D1
|
||||
AND.L #7,D1
|
||||
ROR.L #3,D1
|
||||
RTS
|
||||
|
||||
__CXNRM5:
|
||||
|
||||
CMP.L #$20,D0
|
||||
|
||||
106
library/sas_cxv52.asm
Normal file
106
library/sas_cxv52.asm
Normal file
@@ -0,0 +1,106 @@
|
||||
*
|
||||
* :ts=8
|
||||
*
|
||||
* Adapted from reassembled SAS/C runtime library code.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
|
||||
xdef __CXV52
|
||||
xdef __CXV53
|
||||
|
||||
xref __CXFERR
|
||||
|
||||
section text,code
|
||||
|
||||
__CXV52:
|
||||
|
||||
MOVEM.L D2/D3,-(SP)
|
||||
MOVEQ #-1,D3
|
||||
MOVE.L D0,D2
|
||||
BPL.W lab04A
|
||||
CMPI.L #$BFF00000,D0
|
||||
BCS.W lab07A
|
||||
MOVEM.L D0/D1/A0/A1,-(SP)
|
||||
PEA (2).L
|
||||
JSR __CXFERR
|
||||
ADDQ.W #4,SP
|
||||
MOVEM.L (SP)+,D0/D1/A0/A1
|
||||
BRA.W lab07A
|
||||
|
||||
__CXV53:
|
||||
|
||||
MOVEM.L D2/D3,-(SP)
|
||||
MOVE.L #$7FFFFFFF,D3
|
||||
MOVE.L D0,D2
|
||||
BPL.W lab04A
|
||||
ADDQ.L #1,D3
|
||||
EOR.L D3,D0
|
||||
lab04A: SWAP D0
|
||||
MOVE.W D0,D2
|
||||
ANDI.W #$7FF0,D2
|
||||
EOR.W D2,D0
|
||||
SUBI.W #$3FF0,D2
|
||||
BLT.W lab07A
|
||||
EORI.W #$10,D0
|
||||
SWAP D0
|
||||
ASR.W #4,D2
|
||||
SUBI.W #$14,D2
|
||||
BGT.W lab09A
|
||||
NEG.W D2
|
||||
LSR.L D2,D0
|
||||
TST.L D2
|
||||
BMI.W lab0B2
|
||||
BRA.W lab0B4
|
||||
|
||||
lab07A: MOVEQ #0,D0
|
||||
BRA.W lab0B4
|
||||
|
||||
lab080: MOVEM.L D0/D1/A0/A1,-(SP)
|
||||
PEA (2).L
|
||||
JSR __CXFERR
|
||||
ADDQ.W #4,SP
|
||||
MOVEM.L (SP)+,D0/D1/A0/A1
|
||||
MOVE.L D3,D0
|
||||
BRA.W lab0B4
|
||||
|
||||
lab09A: CMPI.W #11,D2
|
||||
BGT.B lab080
|
||||
EOR.L D1,D0
|
||||
ROL.L D2,D0
|
||||
LSL.L D2,D1
|
||||
EOR.L D1,D0
|
||||
CMP.L D3,D0
|
||||
BHI.B lab080
|
||||
TST.L D2
|
||||
BPL.W lab0B4
|
||||
lab0B2: NEG.L D0
|
||||
lab0B4: MOVEM.L (SP)+,D2/D3
|
||||
RTS
|
||||
|
||||
end
|
||||
@@ -1,6 +1,4 @@
|
||||
*
|
||||
* $Id: sas_cxv54.asm,v 1.1.1.1 2004-07-26 16:31:04 obarthel Exp $
|
||||
*
|
||||
* :ts=8
|
||||
*
|
||||
* Adapted from reassembled SAS/C runtime library code.
|
||||
@@ -38,7 +36,8 @@
|
||||
xdef __CXV54
|
||||
xref __CXFERR
|
||||
|
||||
__CXV54
|
||||
__CXV54:
|
||||
|
||||
MOVEM.L A0/A1,-(SP)
|
||||
MOVE.L D4,A0
|
||||
SWAP D0
|
||||
@@ -47,11 +46,11 @@ __CXV54
|
||||
EOR.W D4,D0
|
||||
SUB.W #$3800,D0
|
||||
CMP.W #$10,D0
|
||||
BLT lbC000098
|
||||
BLT lab098
|
||||
CMP.W #$FEF,D0
|
||||
BLT lbC000102
|
||||
BLT lab102
|
||||
CMP.W #$47F0,D0
|
||||
BLT lbC000058
|
||||
BLT lab058
|
||||
SWAP D0
|
||||
LSL.L #3,D0
|
||||
ROL.L #3,D1
|
||||
@@ -59,17 +58,16 @@ __CXV54
|
||||
EOR.L D1,D0
|
||||
SWAP D0
|
||||
OR.W #$7F80,D0
|
||||
BRA lbC000112
|
||||
BRA lab112
|
||||
|
||||
lbC000058
|
||||
CMP.W #$FF0,D0
|
||||
BGE lbC000074
|
||||
lab058: CMP.W #$FF0,D0
|
||||
BGE lab074
|
||||
CMP.L #$FFFF0FEF,D0
|
||||
BNE lbC000102
|
||||
BNE lab102
|
||||
CMP.L #$F0000000,D1
|
||||
BCS lbC000102
|
||||
lbC000074
|
||||
MOVEM.L D0/D1/A0/A1,-(SP)
|
||||
BCS lab102
|
||||
|
||||
lab074: MOVEM.L D0/D1/A0/A1,-(SP)
|
||||
PEA 2.L
|
||||
JSR __CXFERR
|
||||
ADDQ.W #4,SP
|
||||
@@ -78,63 +76,56 @@ lbC000074
|
||||
EOR.W D4,D0
|
||||
SWAP D0
|
||||
MOVEQ #0,D1
|
||||
BRA lbC000116
|
||||
BRA lab116
|
||||
|
||||
lbC000098
|
||||
CMP.W #$FE90,D0
|
||||
BGE lbC0000C4
|
||||
lab098: CMP.W #$FE90,D0
|
||||
BGE lab0C4
|
||||
ADD.W #$3800,D0
|
||||
OR.L D1,D0
|
||||
BEQ lbC000112
|
||||
BEQ lab112
|
||||
MOVEM.L D0/D1/A0/A1,-(SP)
|
||||
PEA 1.L
|
||||
JSR __CXFERR
|
||||
ADDQ.W #4,SP
|
||||
MOVEM.L (SP)+,D0/D1/A0/A1
|
||||
MOVEQ #0,D0
|
||||
BRA lbC000112
|
||||
BRA lab112
|
||||
|
||||
lbC0000C4
|
||||
MOVE.L D5,A1
|
||||
lab0C4: MOVE.L D5,A1
|
||||
MOVE.W D0,D5
|
||||
AND.W #15,D0
|
||||
EOR.W #$10,D0
|
||||
SWAP D0
|
||||
ASR.W #4,D5
|
||||
ADDQ.W #2,D5
|
||||
BGE lbC0000E6
|
||||
BGE lab0E6
|
||||
NEG.W D5
|
||||
LSR.L D5,D0
|
||||
MOVEQ #0,D5
|
||||
ADDX.L D5,D0
|
||||
BRA lbC0000F6
|
||||
BRA lab0F6
|
||||
|
||||
lbC0000E6
|
||||
CLR.W D1
|
||||
lab0E6: CLR.W D1
|
||||
LSL.L D5,D0
|
||||
ADDQ.W #1,D5
|
||||
ROXL.L D5,D1
|
||||
AND.L #15,D1
|
||||
ADDX.L D1,D0
|
||||
lbC0000F6
|
||||
MOVE.L A1,D5
|
||||
lab0F6: MOVE.L A1,D5
|
||||
SWAP D0
|
||||
EOR.W D4,D0
|
||||
SWAP D0
|
||||
BRA lbC000116
|
||||
BRA lab116
|
||||
|
||||
lbC000102
|
||||
SWAP D0
|
||||
lab102: SWAP D0
|
||||
LSL.L #3,D0
|
||||
ROXL.L #4,D1
|
||||
AND.L #7,D1
|
||||
ADDX.L D1,D0
|
||||
SWAP D0
|
||||
lbC000112
|
||||
EOR.W D4,D0
|
||||
lab112: EOR.W D4,D0
|
||||
SWAP D0
|
||||
lbC000116
|
||||
MOVE.L A0,D4
|
||||
lab116: MOVE.L A0,D4
|
||||
MOVEM.L (SP)+,A0/A1
|
||||
RTS
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ raise(int sig)
|
||||
assert( SIGABRT <= sig && sig <= SIGTERM );
|
||||
|
||||
/* This has to be a well-known and supported signal. */
|
||||
if(sig < SIGABRT || sig > SIGTERM)
|
||||
if (sig < SIGABRT || sig > SIGTERM)
|
||||
{
|
||||
SHOWMSG("unknown signal number");
|
||||
|
||||
@@ -80,7 +80,7 @@ raise(int sig)
|
||||
}
|
||||
|
||||
/* 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)))
|
||||
{
|
||||
signal_handler_t handler;
|
||||
@@ -88,40 +88,41 @@ raise(int sig)
|
||||
/* Which handler is installed for this signal? */
|
||||
handler = __signal_handler_table[sig - SIGABRT];
|
||||
|
||||
/* Should we ignore this signal? */
|
||||
if(handler != SIG_IGN)
|
||||
/* Should we handle this signal rather than ignoring it? */
|
||||
if (handler != SIG_IGN)
|
||||
{
|
||||
/* 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
|
||||
something very much like it. */
|
||||
if(handler == SIG_DFL)
|
||||
* something very much like it.
|
||||
*/
|
||||
if (handler == SIG_DFL)
|
||||
{
|
||||
SHOWMSG("this is the default handler");
|
||||
|
||||
if(sig == SIGINT)
|
||||
if (sig == SIGINT)
|
||||
{
|
||||
char break_string[80];
|
||||
|
||||
/* Turn off ^C checking for good. */
|
||||
__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);
|
||||
|
||||
SHOWMSG("bye, bye...");
|
||||
}
|
||||
|
||||
/* Drop straight into abort(), which might call signal()
|
||||
again but is otherwise guaranteed to eventually
|
||||
land us in _exit(). */
|
||||
abort();
|
||||
/* Drop straight into __abort(), which will
|
||||
eventually land us in _exit(). Note that
|
||||
abort() calls raise(SIGABRT). */
|
||||
__abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
SHOWMSG("calling the handler");
|
||||
SHOWMSG("calling the signal handler");
|
||||
|
||||
(*handler)(sig);
|
||||
|
||||
@@ -129,7 +130,7 @@ raise(int sig)
|
||||
}
|
||||
|
||||
/* Unblock signal delivery again. */
|
||||
CLEAR_FLAG(local_signals_blocked,(1 << sig));
|
||||
CLEAR_FLAG(local_signals_blocked, (1 << sig));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
1621
library/smakefile
1621
library/smakefile
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: stdio_fgets.c,v 1.6 2006-01-08 12:04:24 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>
|
||||
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -46,6 +44,7 @@
|
||||
char *
|
||||
fgets(char *s,int n,FILE *stream)
|
||||
{
|
||||
struct iob * file = (struct iob *)stream;
|
||||
char * result = s;
|
||||
int c;
|
||||
|
||||
@@ -57,14 +56,14 @@ fgets(char *s,int n,FILE *stream)
|
||||
|
||||
assert( s != NULL && stream != NULL );
|
||||
|
||||
if(__check_abort_enabled)
|
||||
if (__check_abort_enabled)
|
||||
__check_abort();
|
||||
|
||||
flockfile(stream);
|
||||
|
||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||
{
|
||||
if(s == NULL || stream == NULL)
|
||||
if (s == NULL || stream == NULL)
|
||||
{
|
||||
SHOWMSG("invalid parameters");
|
||||
|
||||
@@ -75,7 +74,7 @@ fgets(char *s,int n,FILE *stream)
|
||||
}
|
||||
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||
|
||||
if(n <= 0)
|
||||
if (n <= 0)
|
||||
{
|
||||
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
|
||||
* need to be handled only once for this stream.
|
||||
*/
|
||||
if(__fgetc_check(stream) < 0)
|
||||
if (__fgetc_check(stream) < 0)
|
||||
{
|
||||
result = NULL;
|
||||
goto out;
|
||||
@@ -98,12 +97,83 @@ fgets(char *s,int n,FILE *stream)
|
||||
/* One off for the terminating '\0'. */
|
||||
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)
|
||||
{
|
||||
/* If there is data in the buffer, try to copy it directly
|
||||
* 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)
|
||||
{
|
||||
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 (c == EOF)
|
||||
{
|
||||
if(ferror(stream))
|
||||
if (ferror(stream))
|
||||
{
|
||||
/* Just to be on the safe side. */
|
||||
(*s) = '\0';
|
||||
@@ -113,8 +183,9 @@ fgets(char *s,int n,FILE *stream)
|
||||
}
|
||||
|
||||
/* Make sure that we return NULL if we really
|
||||
didn't read anything at all */
|
||||
if(s == result)
|
||||
* didn't read anything at all.
|
||||
*/
|
||||
if (s == result)
|
||||
result = NULL;
|
||||
|
||||
break;
|
||||
@@ -122,8 +193,11 @@ fgets(char *s,int n,FILE *stream)
|
||||
|
||||
(*s++) = c;
|
||||
|
||||
if(c == '\n')
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
assert( n > 0 );
|
||||
n--;
|
||||
}
|
||||
|
||||
(*s) = '\0';
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: stdio_fputs.c,v 1.7 2006-01-08 12:04:24 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>
|
||||
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -43,10 +41,12 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Both fputs() and puts() share this function. */
|
||||
int
|
||||
fputs(const char *s, FILE *stream)
|
||||
__fputs(const char *s, int line_feed, FILE *stream)
|
||||
{
|
||||
struct iob * file = (struct iob *)stream;
|
||||
size_t total_size;
|
||||
int result = EOF;
|
||||
int buffer_mode;
|
||||
int c;
|
||||
@@ -58,12 +58,12 @@ fputs(const char *s, FILE *stream)
|
||||
|
||||
assert( s != NULL && stream != NULL );
|
||||
|
||||
if(__check_abort_enabled)
|
||||
if (__check_abort_enabled)
|
||||
__check_abort();
|
||||
|
||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||
{
|
||||
if(s == NULL || stream == NULL)
|
||||
if (s == NULL || stream == NULL)
|
||||
{
|
||||
__set_errno(EFAULT);
|
||||
goto out;
|
||||
@@ -77,38 +77,262 @@ fputs(const char *s, FILE *stream)
|
||||
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
||||
assert( file->iob_BufferSize > 0 );
|
||||
|
||||
if (__fputc_check(stream) < 0)
|
||||
goto out;
|
||||
|
||||
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 (buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||
{
|
||||
struct fd * fd = __fd[file->iob_Descriptor];
|
||||
|
||||
__fd_lock(fd);
|
||||
|
||||
if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE))
|
||||
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
||||
|
||||
if(__fputc_check(stream) < 0)
|
||||
goto out;
|
||||
__fd_unlock(fd);
|
||||
}
|
||||
|
||||
while((c = (*s++)) != '\0')
|
||||
total_size = strlen(s);
|
||||
if (total_size > 0)
|
||||
{
|
||||
if(__putc(c,stream,buffer_mode) == EOF)
|
||||
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;
|
||||
|
||||
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)
|
||||
* 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)
|
||||
if (__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
|
||||
{
|
||||
SHOWMSG("couldn't flush the write buffer");
|
||||
result = EOF;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: stdio_fread.c,v 1.7 2006-01-08 12:04:24 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>
|
||||
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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( (int)element_size >= 0 && (int)count >= 0 );
|
||||
|
||||
if(__check_abort_enabled)
|
||||
if (__check_abort_enabled)
|
||||
__check_abort();
|
||||
|
||||
flockfile(stream);
|
||||
|
||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||
{
|
||||
if(ptr == NULL || stream == NULL)
|
||||
if (ptr == NULL || stream == NULL)
|
||||
{
|
||||
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( 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");
|
||||
|
||||
@@ -91,7 +89,7 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
||||
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");
|
||||
|
||||
@@ -102,30 +100,115 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
||||
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_size;
|
||||
unsigned char * data = ptr;
|
||||
ssize_t num_bytes_read;
|
||||
int c;
|
||||
|
||||
if(__fgetc_check((FILE *)file) < 0)
|
||||
if (__fgetc_check((FILE *)file) < 0)
|
||||
goto out;
|
||||
|
||||
/* Check for overflow. */
|
||||
total_size = element_size * count;
|
||||
if (element_size != (total_size / count))
|
||||
goto out;
|
||||
|
||||
SHOWVALUE(total_size);
|
||||
|
||||
while(total_size-- > 0)
|
||||
/* No buffering enabled? */
|
||||
if ((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
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)
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
(*data++) = c;
|
||||
|
||||
total_size--;
|
||||
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);
|
||||
|
||||
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));
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: stdio_fwrite.c,v 1.12 2010-10-20 13:12:58 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>
|
||||
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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( (int)element_size >= 0 && (int)count >= 0 );
|
||||
|
||||
if(__check_abort_enabled)
|
||||
if (__check_abort_enabled)
|
||||
__check_abort();
|
||||
|
||||
flockfile(stream);
|
||||
|
||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||
{
|
||||
if(ptr == NULL || stream == NULL)
|
||||
if (ptr == NULL || stream == NULL)
|
||||
{
|
||||
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( 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");
|
||||
|
||||
@@ -91,7 +88,7 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
|
||||
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");
|
||||
|
||||
@@ -102,69 +99,242 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
|
||||
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;
|
||||
int buffer_mode;
|
||||
size_t total_bytes_written = 0;
|
||||
size_t total_size;
|
||||
|
||||
/* Check for overflow. */
|
||||
total_size = element_size * count;
|
||||
|
||||
if(__fputc_check((FILE *)file) < 0)
|
||||
if (element_size != (total_size / count))
|
||||
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);
|
||||
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||
if (buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||
{
|
||||
struct fd * fd = __fd[file->iob_Descriptor];
|
||||
|
||||
__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;
|
||||
|
||||
__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)
|
||||
goto out;
|
||||
/* 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 = (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++;
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
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. */
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
goto out;
|
||||
if (__iob_write_buffer_is_valid(file))
|
||||
__flush_iob_write_buffer(file);
|
||||
}
|
||||
|
||||
result = total_bytes_written / element_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Don't let this appear like an EOF or error. */
|
||||
clearerr((FILE *)file);
|
||||
SHOWVALUE(element_size);
|
||||
SHOWVALUE(count);
|
||||
|
||||
SHOWMSG("either element size or count is zero");
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: stdio_gets.c,v 1.6 2006-01-08 12:04:24 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>
|
||||
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -46,6 +44,8 @@
|
||||
char *
|
||||
gets(char *s)
|
||||
{
|
||||
FILE * stream = stdin;
|
||||
struct iob * file = (struct iob *)stream;
|
||||
char * result = s;
|
||||
int c;
|
||||
|
||||
@@ -53,16 +53,16 @@ gets(char *s)
|
||||
|
||||
SHOWPOINTER(s);
|
||||
|
||||
assert( s != NULL && stdin != NULL );
|
||||
assert( s != NULL );
|
||||
|
||||
if(__check_abort_enabled)
|
||||
if (__check_abort_enabled)
|
||||
__check_abort();
|
||||
|
||||
flockfile(stdin);
|
||||
flockfile(stream);
|
||||
|
||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||
{
|
||||
if(s == NULL || stdin == NULL)
|
||||
if (s == NULL)
|
||||
{
|
||||
SHOWMSG("invalid parameters");
|
||||
|
||||
@@ -77,21 +77,84 @@ gets(char *s)
|
||||
/* Take care of the checks and data structure changes that
|
||||
* need to be handled only once for this stream.
|
||||
*/
|
||||
if(__fgetc_check(stdin) < 0)
|
||||
if (__fgetc_check(stream) < 0)
|
||||
{
|
||||
result = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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(c == EOF)
|
||||
/* If there is data in the buffer, try to copy it directly
|
||||
* 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. */
|
||||
(*s) = '\0';
|
||||
@@ -101,14 +164,15 @@ gets(char *s)
|
||||
}
|
||||
|
||||
/* Make sure that we return NULL if we really
|
||||
didn't read anything at all */
|
||||
if(s == result)
|
||||
* didn't read anything at all.
|
||||
*/
|
||||
if (s == result)
|
||||
result = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(c == '\n')
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
(*s++) = c;
|
||||
@@ -120,7 +184,7 @@ gets(char *s)
|
||||
|
||||
out:
|
||||
|
||||
funlockfile(stdin);
|
||||
funlockfile(stream);
|
||||
|
||||
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 */
|
||||
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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -46,10 +44,7 @@
|
||||
int
|
||||
puts(const char *s)
|
||||
{
|
||||
struct iob * file = (struct iob *)stdout;
|
||||
int result = EOF;
|
||||
int buffer_mode;
|
||||
int c;
|
||||
|
||||
ENTER();
|
||||
|
||||
@@ -57,11 +52,6 @@ puts(const char *s)
|
||||
|
||||
assert( s != NULL );
|
||||
|
||||
if(__check_abort_enabled)
|
||||
__check_abort();
|
||||
|
||||
flockfile(stdout);
|
||||
|
||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||
{
|
||||
if(s == NULL)
|
||||
@@ -72,45 +62,13 @@ puts(const char *s)
|
||||
}
|
||||
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||
|
||||
assert( __is_valid_iob(file) );
|
||||
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)
|
||||
if (__fputs(s, '\n', stdout) == EOF)
|
||||
goto out;
|
||||
|
||||
result = OK;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ remove_locked_region_node(struct FileLockSemaphore * fls,struct fd * fd,LONG sta
|
||||
/* Check if there are any locked regions left.
|
||||
* 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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/*
|
||||
* $Id: stdio_setvbuf.c,v 1.11 2008-09-04 12:07:58 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>
|
||||
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -114,14 +112,21 @@ setvbuf(FILE *stream,char *buf,int bufmode,size_t size)
|
||||
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)
|
||||
bufmode = IOBF_BUFFER_MODE_NONE;
|
||||
{
|
||||
size = BUFSIZ;
|
||||
buf = 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)
|
||||
{
|
||||
assert( size <= ((size + (__cache_line_size-1)) & ~(__cache_line_size-1)) );
|
||||
|
||||
/* Allocate a little more memory than necessary. */
|
||||
new_buffer = malloc(size + (__cache_line_size-1));
|
||||
if(new_buffer == NULL)
|
||||
@@ -130,6 +135,7 @@ setvbuf(FILE *stream,char *buf,int bufmode,size_t size)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get rid of any buffered data. We're going to replace the buffer. */
|
||||
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
|
||||
|
||||
@@ -46,15 +46,8 @@
|
||||
/****************************************************************************/
|
||||
|
||||
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;
|
||||
|
||||
__print_termination_message(NULL);
|
||||
@@ -63,3 +56,17 @@ abort(void)
|
||||
does not trigger the exit trap. */
|
||||
_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)
|
||||
{
|
||||
ENTER();
|
||||
|
||||
/* Clean this up, too, just to be safe. */
|
||||
/* This list should remain empty. */
|
||||
NewList((struct List *)&alloca_memory_list);
|
||||
|
||||
LEAVE();
|
||||
@@ -83,18 +108,18 @@ CLIB_DESTRUCTOR(alloca_exit)
|
||||
|
||||
/* Cleans up after all alloca() allocations that have been made so far. */
|
||||
static void
|
||||
alloca_cleanup(const char * file,int line)
|
||||
alloca_cleanup(const char * file, int line)
|
||||
{
|
||||
void * stack_pointer = __get_sp();
|
||||
|
||||
__memory_lock();
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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;
|
||||
@@ -106,7 +131,7 @@ alloca_cleanup(const char * file,int line)
|
||||
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
|
||||
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_prev)
|
||||
{
|
||||
@@ -114,13 +139,16 @@ alloca_cleanup(const char * file,int line)
|
||||
|
||||
Remove((struct Node *)mcn);
|
||||
|
||||
__free_memory(mcn->mcn_Memory,TRUE,file,line);
|
||||
__free_memory(mcn,FALSE,file,line);
|
||||
/* Note: force the memory to be freed because it
|
||||
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
|
||||
up any more. */
|
||||
if(IsListEmpty((struct List *)&alloca_memory_list))
|
||||
if (IsListEmpty((struct List *)&alloca_memory_list))
|
||||
__alloca_cleanup = NULL;
|
||||
}
|
||||
|
||||
@@ -130,7 +158,7 @@ alloca_cleanup(const char * file,int line)
|
||||
/****************************************************************************/
|
||||
|
||||
__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();
|
||||
struct MemoryContextNode * mcn;
|
||||
@@ -138,27 +166,23 @@ __alloca(size_t size,const char * file,int line)
|
||||
|
||||
__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)(file,line);
|
||||
(*__alloca_cleanup)(file, line);
|
||||
|
||||
mcn = __allocate_memory(sizeof(*mcn),FALSE,file,line);
|
||||
if(mcn == NULL)
|
||||
mcn = __allocate_memory(sizeof(*mcn), FALSE, file, line);
|
||||
if (mcn == NULL)
|
||||
{
|
||||
SHOWMSG("not enough memory");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Allocate memory which cannot be run through realloc() or free(). */
|
||||
mcn->mcn_Memory = __allocate_memory(size,TRUE,file,line);
|
||||
if(mcn->mcn_Memory == NULL)
|
||||
mcn->mcn_Memory = __allocate_memory(size, TRUE, file, line);
|
||||
if (mcn->mcn_Memory == NULL)
|
||||
{
|
||||
SHOWMSG("not enough memory");
|
||||
|
||||
__free(mcn,file,line);
|
||||
__free(mcn, file, line);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -166,7 +190,7 @@ __alloca(size_t size,const char * file,int line)
|
||||
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
provided, call it rather than returning NULL. */
|
||||
if(result == NULL && __alloca_trap != NULL)
|
||||
(*__alloca_trap)();
|
||||
if (result == NULL && __alloca_trap != NULL)
|
||||
{
|
||||
__alloca_cleanup = NULL;
|
||||
|
||||
return(result);
|
||||
(*__alloca_trap)();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -191,5 +219,5 @@ alloca(size_t size)
|
||||
|
||||
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 *
|
||||
__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;
|
||||
size_t total_size;
|
||||
|
||||
#ifdef __MEM_DEBUG
|
||||
{
|
||||
/*__check_memory_allocations(file,line);*/
|
||||
__check_memory_allocations(file, line);
|
||||
}
|
||||
#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);
|
||||
if(result != NULL)
|
||||
memset(result,0,total_size);
|
||||
else
|
||||
/* Note: malloc(0) may allocate memory and will also
|
||||
* initialize its contents to zero.
|
||||
*/
|
||||
result = __malloc(total_size, file, line);
|
||||
if (result == NULL)
|
||||
{
|
||||
SHOWMSG("memory allocation failure");
|
||||
goto out;
|
||||
}
|
||||
|
||||
return(result);
|
||||
if (total_size > 0)
|
||||
memset(result, 0, total_size);
|
||||
|
||||
out:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void *
|
||||
calloc(size_t num_elements,size_t element_size)
|
||||
calloc(size_t num_elements, size_t element_size)
|
||||
{
|
||||
void * result;
|
||||
|
||||
result = __calloc(num_elements,element_size,NULL,0);
|
||||
result = __calloc(num_elements, element_size, NULL, 0);
|
||||
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
75
library/stdlib_decay_unused_slabs.c
Normal file
75
library/stdlib_decay_unused_slabs.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* :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_HEADERS_H
|
||||
#include "stdlib_headers.h"
|
||||
#endif /* _STDLIB_HEADERS_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifndef _STDLIB_MEMORY_H
|
||||
#include "stdlib_memory.h"
|
||||
#endif /* _STDLIB_MEMORY_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Look at all currently unused slabs, decrementing the decay
|
||||
* counter which prevents them from being reused.
|
||||
*/
|
||||
void
|
||||
__decay_unused_slabs(void)
|
||||
{
|
||||
if(__slab_data.sd_InUse)
|
||||
{
|
||||
struct MinNode * free_node;
|
||||
struct MinNode * free_node_next;
|
||||
struct SlabNode * sn;
|
||||
|
||||
__memory_lock();
|
||||
|
||||
for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ;
|
||||
free_node->mln_Succ != NULL ;
|
||||
free_node = free_node_next)
|
||||
{
|
||||
free_node_next = (struct MinNode *)free_node->mln_Succ;
|
||||
|
||||
/* free_node points to SlabNode.sn_EmptyLink, which
|
||||
* directly follows the SlabNode.sn_MinNode.
|
||||
*/
|
||||
sn = (struct SlabNode *)&free_node[-1];
|
||||
|
||||
if(sn->sn_EmptyDecay > 0)
|
||||
sn->sn_EmptyDecay--;
|
||||
}
|
||||
|
||||
__memory_unlock();
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,8 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#ifndef _STDLIB_HEADERS_H
|
||||
#include "stdlib_headers.h"
|
||||
#endif /* _STDLIB_HEADERS_H */
|
||||
@@ -57,18 +59,18 @@ get_hex_char(int n)
|
||||
{
|
||||
char result;
|
||||
|
||||
if(0 <= n && n <= 9)
|
||||
if (0 <= n && n <= 9)
|
||||
result = n + '0';
|
||||
else
|
||||
result = n + 'A' - 10;
|
||||
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -79,12 +81,12 @@ int_to_hex(unsigned long v,char * buffer,int min_digits)
|
||||
|
||||
buffer[i++] = get_hex_char(c);
|
||||
}
|
||||
while(v > 0);
|
||||
while (v > 0);
|
||||
|
||||
while(i < min_digits)
|
||||
while (i < min_digits)
|
||||
buffer[i++] = '0';
|
||||
|
||||
for(j = 0 ; j < i / 2 ; j++)
|
||||
for (j = 0 ; j < i / 2 ; j++)
|
||||
{
|
||||
c = buffer[i - 1 - j];
|
||||
buffer[i - 1 - j] = buffer[j];
|
||||
@@ -95,47 +97,47 @@ int_to_hex(unsigned long v,char * buffer,int min_digits)
|
||||
}
|
||||
|
||||
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;
|
||||
int position,i,c;
|
||||
int position, i, c;
|
||||
char buffer[120];
|
||||
char hex[10];
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
for(i = 0 ; i < size ; i++)
|
||||
for (i = 0 ; i < size ; i++)
|
||||
{
|
||||
position = i % mod;
|
||||
if(position == 0)
|
||||
if (position == 0)
|
||||
{
|
||||
if(buffer[0] != '\0')
|
||||
if (buffer[0] != '\0')
|
||||
{
|
||||
int len = sizeof(buffer)-1;
|
||||
|
||||
while(len > 0 && buffer[len-1] == ' ')
|
||||
while (len > 0 && buffer[len-1] == ' ')
|
||||
len--;
|
||||
|
||||
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] = ':';
|
||||
}
|
||||
|
||||
if(m[i] != ignore)
|
||||
if (m[i] != ignore)
|
||||
{
|
||||
buffer[10 + 2 * position + 0] = get_hex_char(m[i] >> 4);
|
||||
buffer[10 + 2 * position + 1] = get_hex_char(m[i] & 15);
|
||||
|
||||
c = m[i];
|
||||
if(c < ' ' || (c >= 127 && c <= 160))
|
||||
if (c < ' ' || (127 <= c && c < 160))
|
||||
c = '.';
|
||||
|
||||
buffer[10 + 2 * mod + 1 + position] = c;
|
||||
@@ -147,109 +149,111 @@ dump_memory(unsigned char * m,int size,int ignore)
|
||||
}
|
||||
}
|
||||
|
||||
if(buffer[0] != '\0')
|
||||
if (buffer[0] != '\0')
|
||||
{
|
||||
int len = sizeof(buffer)-1;
|
||||
|
||||
while(len > 0 && buffer[len-1] == ' ')
|
||||
while (len > 0 && buffer[len-1] == ' ')
|
||||
len--;
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
kprintf("[%s] %s\n",__program_name,buffer);
|
||||
kprintf("[%s] %s\n", __program_name, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
STATIC VOID
|
||||
check_memory_node(struct MemoryNode * mn,const char * file,int line)
|
||||
check_memory_node(struct MemoryNode * mn, const char * file, int line)
|
||||
{
|
||||
size_t size = mn->mn_Size;
|
||||
unsigned char * head = (unsigned char *)(mn + 1);
|
||||
unsigned char * body = head + MALLOC_HEAD_SIZE;
|
||||
unsigned char * tail = body + size;
|
||||
ULONG size = mn->mn_OriginalSize;
|
||||
const unsigned char * head = (unsigned char *)&mn[1];
|
||||
const unsigned char * body = &head[MALLOC_HEAD_SIZE];
|
||||
const unsigned char * tail = &body[size];
|
||||
int max_head_damage = 0;
|
||||
int max_tail_damage = 0;
|
||||
int max_body_damage = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
if(max_head_damage > 0)
|
||||
if (max_head_damage > 0)
|
||||
{
|
||||
kprintf("[%s] ",__program_name);
|
||||
kprintf("[%s] ", __program_name);
|
||||
|
||||
if(file != NULL)
|
||||
kprintf("%s:%ld:",file,line);
|
||||
if (file != NULL)
|
||||
kprintf("%s:%ld:", file, line);
|
||||
|
||||
kprintf("At least %ld bytes were damaged in front of allocation 0x%08lx..0x%08lx, size = %ld",
|
||||
max_head_damage,
|
||||
body,body + size - 1,size);
|
||||
body, body + size - 1, size);
|
||||
|
||||
if(mn->mn_File != NULL)
|
||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
||||
if (mn->mn_File != NULL)
|
||||
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if(max_tail_damage > 0)
|
||||
if (max_tail_damage > 0)
|
||||
{
|
||||
kprintf("[%s] ",__program_name);
|
||||
kprintf("[%s] ", __program_name);
|
||||
|
||||
if(file != NULL)
|
||||
kprintf("%s:%ld:",file,line);
|
||||
if (file != NULL)
|
||||
kprintf("%s:%ld:", file, line);
|
||||
|
||||
kprintf("At least %ld bytes were damaged behind allocation 0x%08lx..0x%08lx, size = %ld (with damage = %ld)",
|
||||
max_tail_damage,
|
||||
body,body + size - 1,
|
||||
size,size+max_tail_damage);
|
||||
body, body + size - 1,
|
||||
size, size + max_tail_damage);
|
||||
|
||||
if(mn->mn_File != NULL)
|
||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
||||
if (mn->mn_File != NULL)
|
||||
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||
|
||||
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)
|
||||
{
|
||||
for(i = 0 ; i < size ; i++)
|
||||
ULONG j;
|
||||
|
||||
for (j = 0 ; j < size ; j++)
|
||||
{
|
||||
if(body[i] != MALLOC_FREE_FILL)
|
||||
max_body_damage = i+1;
|
||||
if (body[j] != MALLOC_FREE_FILL)
|
||||
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)
|
||||
kprintf("%s:%ld:",file,line);
|
||||
if (file != NULL)
|
||||
kprintf("%s:%ld:", file, line);
|
||||
|
||||
kprintf("At least %ld bytes were damaged in freed allocation 0x%08lx..0x%08lx, size = %ld",
|
||||
max_body_damage,
|
||||
body,body + size - 1,size);
|
||||
body, body + size - 1, size);
|
||||
|
||||
if(mn->mn_File != NULL)
|
||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
||||
if (mn->mn_File != NULL)
|
||||
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||
|
||||
kprintf("\n");
|
||||
|
||||
dump_memory(body,size,MALLOC_FREE_FILL);
|
||||
dump_memory(body, size, MALLOC_FREE_FILL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,17 +261,17 @@ check_memory_node(struct MemoryNode * mn,const char * file,int line)
|
||||
/****************************************************************************/
|
||||
|
||||
void
|
||||
__check_memory_allocations(const char * file,int line)
|
||||
__check_memory_allocations(const char * file, int line)
|
||||
{
|
||||
struct MemoryNode * mn;
|
||||
|
||||
__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 = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
|
||||
{
|
||||
check_memory_node(mn,file,line);
|
||||
check_memory_node(mn, file, line);
|
||||
}
|
||||
|
||||
__memory_unlock();
|
||||
@@ -286,7 +290,7 @@ __find_memory_node(void * address)
|
||||
|
||||
#if defined(__USE_MEM_TREES)
|
||||
{
|
||||
result = __red_black_tree_find(&__memory_tree,address);
|
||||
result = __red_black_tree_find(&__memory_tree, address);
|
||||
}
|
||||
#else
|
||||
{
|
||||
@@ -294,11 +298,11 @@ __find_memory_node(void * address)
|
||||
|
||||
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 = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
|
||||
{
|
||||
if(address == mn->mn_Allocation)
|
||||
if (address == mn->mn_Allocation)
|
||||
{
|
||||
result = mn;
|
||||
break;
|
||||
@@ -327,7 +331,7 @@ __find_memory_node(void * address)
|
||||
|
||||
result = &((struct MemoryNode *)address)[-1];
|
||||
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -345,25 +349,19 @@ remove_and_free_memory_node(struct MemoryNode * mn)
|
||||
|
||||
__memory_lock();
|
||||
|
||||
allocation_size = mn->mn_AllocationSize;
|
||||
|
||||
#if defined(__MEM_DEBUG)
|
||||
{
|
||||
Remove((struct Node *)mn);
|
||||
|
||||
#if defined(__USE_MEM_TREES) && defined(__MEM_DEBUG)
|
||||
#if defined(__USE_MEM_TREES)
|
||||
{
|
||||
__red_black_tree_remove(&__memory_tree,mn);
|
||||
__red_black_tree_remove(&__memory_tree, mn);
|
||||
}
|
||||
#endif /* __USE_MEM_TREES && __MEM_DEBUG */
|
||||
#endif /* __USE_MEM_TREES */
|
||||
|
||||
#ifdef __MEM_DEBUG
|
||||
{
|
||||
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + mn->mn_Size + MALLOC_TAIL_SIZE;
|
||||
|
||||
assert( allocation_size == mn->mn_AllocationSize );
|
||||
|
||||
memset(mn,MALLOC_FREE_FILL,allocation_size);
|
||||
}
|
||||
#else
|
||||
{
|
||||
allocation_size = sizeof(*mn) + mn->mn_Size;
|
||||
memset(mn, MALLOC_FREE_FILL, allocation_size);
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
|
||||
@@ -371,18 +369,65 @@ remove_and_free_memory_node(struct MemoryNode * mn)
|
||||
{
|
||||
/* Are we using the slab allocator? */
|
||||
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)
|
||||
FreePooled(__memory_pool,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.
|
||||
*/
|
||||
PROFILE_OFF();
|
||||
FreePooled(__memory_pool, mn, allocation_size);
|
||||
PROFILE_ON();
|
||||
}
|
||||
/* So we have to do this the hard way... */
|
||||
else
|
||||
FreeMem(mn,allocation_size);
|
||||
{
|
||||
#if NOT defined(__MEM_DEBUG)
|
||||
{
|
||||
Remove((struct Node *)mn);
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
|
||||
PROFILE_OFF();
|
||||
FreeMem(mn, allocation_size);
|
||||
PROFILE_ON();
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
if (__memory_pool != NULL)
|
||||
FreePooled(__memory_pool,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.
|
||||
*/
|
||||
PROFILE_OFF();
|
||||
FreePooled(__memory_pool, mn, allocation_size);
|
||||
PROFILE_ON();
|
||||
}
|
||||
else
|
||||
FreeMem(mn,allocation_size);
|
||||
{
|
||||
#if NOT defined(__MEM_DEBUG)
|
||||
{
|
||||
Remove((struct Node *)mn);
|
||||
}
|
||||
#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 */
|
||||
|
||||
@@ -395,37 +440,35 @@ remove_and_free_memory_node(struct MemoryNode * mn)
|
||||
/****************************************************************************/
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __MEM_DEBUG
|
||||
{
|
||||
size_t size = mn->mn_Size;
|
||||
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
|
||||
{
|
||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name,mn->mn_Size,mn->mn_Allocation);
|
||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name, mn->mn_OriginalSize, mn->mn_Allocation);
|
||||
|
||||
if(mn->mn_File != NULL)
|
||||
kprintf("allocated at %s:%ld, ",mn->mn_File,mn->mn_Line);
|
||||
if (mn->mn_File != NULL)
|
||||
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 */
|
||||
|
||||
if(__never_free)
|
||||
if (__never_free)
|
||||
{
|
||||
mn->mn_AlreadyFree = TRUE;
|
||||
|
||||
mn->mn_FreeFile = (char *)file;
|
||||
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
|
||||
{
|
||||
@@ -436,19 +479,19 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
|
||||
{
|
||||
#ifdef __MEM_DEBUG_LOG
|
||||
{
|
||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name,mn->mn_Size,mn->mn_Allocation);
|
||||
kprintf("[%s] - %10ld 0x%08lx [", __program_name, mn->mn_AllocationSize, mn);
|
||||
|
||||
kprintf("FAILED]\n");
|
||||
}
|
||||
#endif /* __MEM_DEBUG_LOG */
|
||||
|
||||
kprintf("[%s] %s:%ld:Allocation at address 0x%08lx, size %ld",
|
||||
__program_name,file,line,mn->mn_Allocation,mn->mn_Size);
|
||||
__program_name, file, line, mn->mn_Allocation, mn->mn_OriginalSize);
|
||||
|
||||
if(mn->mn_File != NULL)
|
||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
||||
if (mn->mn_File != NULL)
|
||||
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
|
||||
@@ -461,15 +504,18 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
|
||||
/****************************************************************************/
|
||||
|
||||
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;
|
||||
|
||||
assert(ptr != NULL);
|
||||
|
||||
SHOWPOINTER(ptr);
|
||||
SHOWVALUE(force);
|
||||
|
||||
#ifdef __MEM_DEBUG
|
||||
{
|
||||
/*if((rand() % 16) == 0)
|
||||
/*if ((rand() % 16) == 0)
|
||||
__check_memory_allocations(file,line);*/
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
@@ -478,32 +524,37 @@ __free_memory(void * ptr,BOOL force,const char * file,int line)
|
||||
|
||||
#ifdef __MEM_DEBUG
|
||||
{
|
||||
if(mn != NULL)
|
||||
if (mn != NULL)
|
||||
{
|
||||
if(force || (NOT mn->mn_NeverFree))
|
||||
__free_memory_node(mn,file,line);
|
||||
if (force || FLAG_IS_CLEAR(mn->mn_Flags, MNF_NEVER_FREE))
|
||||
__free_memory_node(mn, file, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
#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");
|
||||
}
|
||||
#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
|
||||
{
|
||||
assert( mn != NULL );
|
||||
|
||||
if(mn != NULL && (force || (NOT mn->mn_NeverFree)))
|
||||
__free_memory_node(mn,file,line);
|
||||
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_Flags, MNF_NEVER_FREE)))
|
||||
__free_memory_node(mn, file, line);
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
}
|
||||
@@ -516,13 +567,13 @@ __free(void * ptr,const char * file,int line)
|
||||
__memory_lock();
|
||||
|
||||
/* Try to get rid of now unused memory. */
|
||||
if(__alloca_cleanup != NULL)
|
||||
(*__alloca_cleanup)(file,line);
|
||||
if (__alloca_cleanup != NULL)
|
||||
(*__alloca_cleanup)(file, line);
|
||||
|
||||
__memory_unlock();
|
||||
|
||||
if(ptr != NULL)
|
||||
__free_memory(ptr,FALSE,file,line);
|
||||
if (ptr != NULL)
|
||||
__free_memory(ptr, FALSE, file, line);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -530,5 +581,5 @@ __free(void * ptr,const char * file,int line)
|
||||
void
|
||||
free(void * ptr)
|
||||
{
|
||||
__free(ptr,NULL,0);
|
||||
__free(ptr, NULL, 0);
|
||||
}
|
||||
|
||||
82
library/stdlib_free_unused_slabs.c
Normal file
82
library/stdlib_free_unused_slabs.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* :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_HEADERS_H
|
||||
#include "stdlib_headers.h"
|
||||
#endif /* _STDLIB_HEADERS_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifndef _STDLIB_MEMORY_H
|
||||
#include "stdlib_memory.h"
|
||||
#endif /* _STDLIB_MEMORY_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Free all currently unused slabs, regardless of whether they
|
||||
* are ready to be purged (SlabNode.sn_EmptyDecay == 0).
|
||||
*/
|
||||
void
|
||||
__free_unused_slabs(void)
|
||||
{
|
||||
if(__slab_data.sd_InUse)
|
||||
{
|
||||
struct MinNode * free_node;
|
||||
struct MinNode * free_node_next;
|
||||
struct SlabNode * sn;
|
||||
|
||||
__memory_lock();
|
||||
|
||||
for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ;
|
||||
free_node->mln_Succ != NULL ;
|
||||
free_node = free_node_next)
|
||||
{
|
||||
free_node_next = (struct MinNode *)free_node->mln_Succ;
|
||||
|
||||
/* free_node points to SlabNode.sn_EmptyLink, which
|
||||
* directly follows the SlabNode.sn_MinNode.
|
||||
*/
|
||||
sn = (struct SlabNode *)&free_node[-1];
|
||||
|
||||
/* Unlink from list of empty slabs. */
|
||||
Remove((struct Node *)free_node);
|
||||
|
||||
/* Unlink from list of slabs of the same size. */
|
||||
Remove((struct Node *)sn);
|
||||
|
||||
PROFILE_OFF();
|
||||
FreeVec(sn);
|
||||
PROFILE_ON();
|
||||
}
|
||||
|
||||
__memory_unlock();
|
||||
}
|
||||
}
|
||||
82
library/stdlib_get_slab_allocations.c
Normal file
82
library/stdlib_get_slab_allocations.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* :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_HEADERS_H
|
||||
#include "stdlib_headers.h"
|
||||
#endif /* _STDLIB_HEADERS_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifndef _STDLIB_MEMORY_H
|
||||
#include "stdlib_memory.h"
|
||||
#endif /* _STDLIB_MEMORY_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void
|
||||
__get_slab_allocations(__slab_allocation_callback callback)
|
||||
{
|
||||
if(__slab_data.sd_InUse)
|
||||
{
|
||||
struct __slab_allocation_information sai;
|
||||
|
||||
memset(&sai,0,sizeof(sai));
|
||||
|
||||
__memory_lock();
|
||||
|
||||
sai.sai_num_single_allocations = __slab_data.sd_NumSingleAllocations;
|
||||
sai.sai_total_single_allocation_size = __slab_data.sd_TotalSingleAllocationSize;
|
||||
|
||||
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
|
||||
{
|
||||
const struct SlabSingleAllocation * ssa;
|
||||
|
||||
for(ssa = (struct SlabSingleAllocation *)__slab_data.sd_SingleAllocations.mlh_Head ;
|
||||
ssa->ssa_MinNode.mln_Succ != NULL ;
|
||||
ssa = (struct SlabSingleAllocation *)ssa->ssa_MinNode.mln_Succ)
|
||||
{
|
||||
sai.sai_allocation_index++;
|
||||
|
||||
sai.sai_allocation_size = ssa->ssa_Size - sizeof(*ssa);
|
||||
sai.sai_total_allocation_size = ssa->ssa_Size;
|
||||
|
||||
if((*callback)(&sai) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*callback)(&sai);
|
||||
}
|
||||
|
||||
__memory_unlock();
|
||||
}
|
||||
}
|
||||
206
library/stdlib_get_slab_stats.c
Normal file
206
library/stdlib_get_slab_stats.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* :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_HEADERS_H
|
||||
#include "stdlib_headers.h"
|
||||
#endif /* _STDLIB_HEADERS_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifndef _STDLIB_MEMORY_H
|
||||
#include "stdlib_memory.h"
|
||||
#endif /* _STDLIB_MEMORY_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
struct context
|
||||
{
|
||||
jmp_buf abort_buf;
|
||||
void * user_data;
|
||||
__slab_status_callback callback;
|
||||
char * buffer;
|
||||
size_t buffer_size;
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static void print(struct context * ct, const char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int len;
|
||||
|
||||
va_start(args,format);
|
||||
len = vsnprintf(ct->buffer, ct->buffer_size, format, args);
|
||||
va_end(args);
|
||||
|
||||
/* This shouldn't happen: the buffer ought to be large enough
|
||||
* to hold every single line.
|
||||
*/
|
||||
if(len >= (int)ct->buffer_size)
|
||||
len = strlen(ct->buffer);
|
||||
|
||||
if((*ct->callback)(ct->user_data, ct->buffer, len) != 0)
|
||||
longjmp(ct->abort_buf,-1);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void
|
||||
__get_slab_stats(void * user_data, __slab_status_callback callback)
|
||||
{
|
||||
if(__slab_data.sd_InUse)
|
||||
{
|
||||
static int times_checked = 1;
|
||||
|
||||
const struct SlabNode * sn;
|
||||
volatile size_t num_empty_slabs = 0;
|
||||
volatile size_t num_full_slabs = 0;
|
||||
volatile size_t num_slabs = 0;
|
||||
volatile size_t slab_allocation_size = 0;
|
||||
volatile size_t total_slab_allocation_size = 0;
|
||||
struct context ct;
|
||||
char line[1024];
|
||||
char time_buffer[40];
|
||||
time_t now;
|
||||
struct tm when;
|
||||
int i;
|
||||
|
||||
memset(&ct, 0, sizeof(ct));
|
||||
|
||||
ct.user_data = user_data;
|
||||
ct.callback = callback;
|
||||
ct.buffer = line;
|
||||
ct.buffer_size = sizeof(line);
|
||||
|
||||
__memory_lock();
|
||||
|
||||
if(setjmp(ct.abort_buf) == 0)
|
||||
{
|
||||
now = time(NULL);
|
||||
localtime_r(&now, &when);
|
||||
|
||||
strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", &when);
|
||||
|
||||
print(&ct,"{\n");
|
||||
|
||||
print(&ct,"\t\"when\": \"%s\",\n", time_buffer);
|
||||
print(&ct,"\t\"times_checked\": %d,\n", times_checked++);
|
||||
print(&ct,"\t\"slab_size\": %zu,\n", __slab_data.sd_StandardSlabSize);
|
||||
print(&ct,"\t\"num_single_allocations\": %zu,\n", __slab_data.sd_NumSingleAllocations);
|
||||
print(&ct,"\t\"total_single_allocation_size\": %zu,\n", __slab_data.sd_TotalSingleAllocationSize);
|
||||
|
||||
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
|
||||
{
|
||||
const struct SlabSingleAllocation * ssa;
|
||||
|
||||
print(&ct,"\t\"single_allocations\": [\n");
|
||||
|
||||
for(ssa = (struct SlabSingleAllocation *)__slab_data.sd_SingleAllocations.mlh_Head ;
|
||||
ssa->ssa_MinNode.mln_Succ != NULL ;
|
||||
ssa = (struct SlabSingleAllocation *)ssa->ssa_MinNode.mln_Succ)
|
||||
{
|
||||
print(&ct,"\t\t{ \"size\": %lu, \"total_size\": %lu }%s\n",
|
||||
ssa->ssa_Size - sizeof(*ssa), ssa->ssa_Size,
|
||||
ssa->ssa_MinNode.mln_Succ->mln_Succ != NULL ? "," : "");
|
||||
}
|
||||
|
||||
print(&ct,"\t],\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
print(&ct,"\t\"single_allocations\": [],\n");
|
||||
}
|
||||
|
||||
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||
{
|
||||
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||
sn->sn_MinNode.mln_Succ != NULL ;
|
||||
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||
{
|
||||
if (sn->sn_UseCount == 0)
|
||||
num_empty_slabs++;
|
||||
else if (sn->sn_UseCount == sn->sn_Count)
|
||||
num_full_slabs++;
|
||||
|
||||
num_slabs++;
|
||||
|
||||
slab_allocation_size += sn->sn_ChunkSize * sn->sn_UseCount;
|
||||
total_slab_allocation_size += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
|
||||
}
|
||||
}
|
||||
|
||||
print(&ct,"\t\"num_slabs\": %zu,\n", num_slabs);
|
||||
print(&ct,"\t\"num_empty_slabs\": %zu,\n", num_empty_slabs);
|
||||
print(&ct,"\t\"num_full_slabs\": %zu,\n", num_full_slabs);
|
||||
print(&ct,"\t\"slab_allocation_size\": %zu,\n", slab_allocation_size);
|
||||
print(&ct,"\t\"total_slab_allocation_size\": %zu,\n", total_slab_allocation_size);
|
||||
|
||||
if(num_slabs > 0)
|
||||
{
|
||||
const char * eol = "";
|
||||
|
||||
print(&ct,"\t\"slabs\": [\n");
|
||||
|
||||
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||
{
|
||||
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||
sn->sn_MinNode.mln_Succ != NULL ;
|
||||
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||
{
|
||||
print(&ct,"%s\t\t{ \"size\": %lu, \"chunks\": %lu, \"chunks_in_use\": %lu, \"times_reused\": %lu, \"empty_decay\": %lu }",
|
||||
eol,
|
||||
sn->sn_ChunkSize,
|
||||
sn->sn_Count,
|
||||
sn->sn_UseCount,
|
||||
sn->sn_NumReused,
|
||||
sn->sn_EmptyDecay);
|
||||
|
||||
eol = ",\n";
|
||||
}
|
||||
}
|
||||
|
||||
print(&ct,"\n\t]\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
print(&ct,"\t\"slabs\": []\n");
|
||||
}
|
||||
|
||||
print(&ct,"}\n");
|
||||
}
|
||||
|
||||
__memory_unlock();
|
||||
}
|
||||
}
|
||||
111
library/stdlib_get_slab_usage.c
Executable file
111
library/stdlib_get_slab_usage.c
Executable file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* :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_HEADERS_H
|
||||
#include "stdlib_headers.h"
|
||||
#endif /* _STDLIB_HEADERS_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#ifndef _STDLIB_MEMORY_H
|
||||
#include "stdlib_memory.h"
|
||||
#endif /* _STDLIB_MEMORY_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void
|
||||
__get_slab_usage(__slab_usage_callback callback)
|
||||
{
|
||||
if (__slab_data.sd_InUse)
|
||||
{
|
||||
struct __slab_usage_information sui;
|
||||
const struct SlabNode * sn;
|
||||
BOOL stop;
|
||||
int i;
|
||||
|
||||
memset(&sui, 0, sizeof(sui));
|
||||
|
||||
__memory_lock();
|
||||
|
||||
sui.sui_slab_size = __slab_data.sd_StandardSlabSize;
|
||||
sui.sui_num_single_allocations = __slab_data.sd_NumSingleAllocations;
|
||||
sui.sui_total_single_allocation_size = __slab_data.sd_TotalSingleAllocationSize;
|
||||
|
||||
for (i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||
{
|
||||
for (sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||
sn->sn_MinNode.mln_Succ != NULL ;
|
||||
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||
{
|
||||
if (sn->sn_UseCount == 0)
|
||||
sui.sui_num_empty_slabs++;
|
||||
else if (sn->sn_Count == sn->sn_UseCount)
|
||||
sui.sui_num_full_slabs++;
|
||||
|
||||
sui.sui_num_slabs++;
|
||||
|
||||
sui.sui_total_slab_allocation_size += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (sui.sui_num_slabs > 0)
|
||||
{
|
||||
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 ;
|
||||
sn->sn_MinNode.mln_Succ != NULL ;
|
||||
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||
{
|
||||
sui.sui_chunk_size = sn->sn_ChunkSize;
|
||||
sui.sui_num_chunks = sn->sn_Count;
|
||||
sui.sui_num_chunks_used = sn->sn_UseCount;
|
||||
sui.sui_num_reused = sn->sn_NumReused;
|
||||
|
||||
sui.sui_slab_index++;
|
||||
|
||||
if ((*callback)(&sui) != 0)
|
||||
{
|
||||
stop = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*callback)(&sui);
|
||||
}
|
||||
|
||||
__memory_unlock();
|
||||
}
|
||||
}
|
||||
@@ -189,6 +189,10 @@ extern BOOL NOCOMMON __lib_startup;
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
extern int __addition_overflows(ULONG x, ULONG y);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
extern void NOCOMMON (*__alloca_trap)(void);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#if defined(__GNUC__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
lldiv_t
|
||||
lldiv(long long n,long long d)
|
||||
{
|
||||
@@ -49,3 +53,7 @@ lldiv(long long n,long long d)
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#endif
|
||||
|
||||
@@ -117,9 +117,20 @@ call_main(void)
|
||||
struct Process * this_process = (struct Process *)FindTask(NULL);
|
||||
UBYTE * arg_str = GetArgStr();
|
||||
size_t arg_str_len = strlen(arg_str);
|
||||
UBYTE * arg_str_copy = AllocVec(arg_str_len+1,MEMF_PRIVATE);
|
||||
UBYTE * arg_str_copy;
|
||||
UBYTE current_dir_name[256];
|
||||
|
||||
#if defined(__amigaos4__)
|
||||
{
|
||||
arg_str_copy = AllocVec(arg_str_len+1,MEMF_PRIVATE);
|
||||
}
|
||||
#else
|
||||
{
|
||||
arg_str_copy = AllocVec(arg_str_len+1,MEMF_ANY);
|
||||
}
|
||||
#endif /* __amigaos4__ */
|
||||
|
||||
|
||||
if(arg_str_copy != NULL && NameFromLock(this_process->pr_CurrentDir,current_dir_name,sizeof(current_dir_name)))
|
||||
{
|
||||
strcpy(arg_str_copy,arg_str);
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#ifndef _STDLIB_HEADERS_H
|
||||
#include "stdlib_headers.h"
|
||||
#endif /* _STDLIB_HEADERS_H */
|
||||
@@ -56,6 +58,7 @@
|
||||
|
||||
unsigned long NOCOMMON __maximum_memory_allocated;
|
||||
unsigned long NOCOMMON __current_memory_allocated;
|
||||
|
||||
unsigned long NOCOMMON __maximum_num_memory_chunks_allocated;
|
||||
unsigned long NOCOMMON __current_num_memory_chunks_allocated;
|
||||
|
||||
@@ -72,54 +75,59 @@ struct MinList NOCOMMON __memory_list;
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
size_t
|
||||
__get_allocation_size(size_t size)
|
||||
/* Check if the sum of two unsigned 32-bit integers will be larger than what
|
||||
* 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)
|
||||
{
|
||||
#ifndef __MEM_DEBUG
|
||||
{
|
||||
size_t total_allocation_size;
|
||||
ULONG z;
|
||||
|
||||
total_allocation_size = sizeof(struct MemoryNode) + size;
|
||||
assert( sizeof(x) == 4 );
|
||||
assert( sizeof(y) == 4 );
|
||||
|
||||
/* Round up the allocation size to the physical allocation granularity. */
|
||||
size += ((total_allocation_size + MEM_BLOCKMASK) & ~((ULONG)MEM_BLOCKMASK)) - total_allocation_size;
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
z = (x & y) | ((x | y) & ~(x + y));
|
||||
|
||||
return(size);
|
||||
return ((LONG)z) < 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void *
|
||||
__allocate_memory(size_t size,BOOL never_free,const char * UNUSED unused_file,int UNUSED unused_line)
|
||||
__allocate_memory(
|
||||
size_t size,
|
||||
BOOL never_free,
|
||||
const char * debug_file_name UNUSED,
|
||||
int debug_line_number UNUSED)
|
||||
{
|
||||
struct MemoryNode * mn;
|
||||
struct MemoryNode * mn UNUSED;
|
||||
size_t allocation_size;
|
||||
void * result = NULL;
|
||||
size_t original_size;
|
||||
size_t original_size UNUSED;
|
||||
|
||||
#if defined(UNIX_PATH_SEMANTICS)
|
||||
{
|
||||
original_size = size;
|
||||
|
||||
/* The libunix.a flavour accepts zero length memory allocations
|
||||
and quietly turns them into a pointer sized allocations. */
|
||||
if(size == 0)
|
||||
size = sizeof(char *);
|
||||
/* The libunix.a flavour of malloc() accepts zero-length
|
||||
memory allocations and quietly turns these into
|
||||
pointer-sized allocations. */
|
||||
if (size == 0)
|
||||
size = sizeof(BYTE *);
|
||||
}
|
||||
#endif /* UNIX_PATH_SEMANTICS */
|
||||
|
||||
__memory_lock();
|
||||
|
||||
/* Zero length allocations are by default rejected. */
|
||||
if(size == 0)
|
||||
if (size == 0)
|
||||
{
|
||||
__set_errno(EINVAL);
|
||||
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");
|
||||
goto out;
|
||||
@@ -131,110 +139,140 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED unused_file,in
|
||||
assert( MALLOC_TAIL_SIZE > 0 && (MALLOC_TAIL_SIZE % 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;
|
||||
}
|
||||
#else
|
||||
{
|
||||
/* Round up the allocation size to the physical allocation granularity. */
|
||||
size = __get_allocation_size(size);
|
||||
if (__addition_overflows(sizeof(*mn), size))
|
||||
{
|
||||
SHOWMSG("integer overflow");
|
||||
|
||||
__set_errno(ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
allocation_size = sizeof(*mn) + size;
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
|
||||
/* Round up allocation to a multiple of 8 bytes. */
|
||||
if ((allocation_size % MEM_BLOCKSIZE) > 0)
|
||||
{
|
||||
size_t padding;
|
||||
|
||||
padding = MEM_BLOCKSIZE - (allocation_size % MEM_BLOCKSIZE);
|
||||
|
||||
if (__addition_overflows(padding, allocation_size))
|
||||
{
|
||||
SHOWMSG("integer overflow");
|
||||
|
||||
__set_errno(ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
allocation_size += padding;
|
||||
}
|
||||
|
||||
#if defined(__USE_SLAB_ALLOCATOR)
|
||||
{
|
||||
/* Are we using the slab allocator? */
|
||||
if (__slab_data.sd_InUse)
|
||||
{
|
||||
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)
|
||||
{
|
||||
mn = AllocPooled(__memory_pool,allocation_size);
|
||||
PROFILE_OFF();
|
||||
mn = AllocPooled(__memory_pool, allocation_size);
|
||||
PROFILE_ON();
|
||||
}
|
||||
/* Then we'll have to do it the hard way... */
|
||||
else
|
||||
{
|
||||
PROFILE_OFF();
|
||||
mn = AllocMem(allocation_size, MEMF_ANY);
|
||||
PROFILE_ON();
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
if (__memory_pool != NULL)
|
||||
{
|
||||
PROFILE_OFF();
|
||||
mn = AllocPooled(__memory_pool, allocation_size);
|
||||
PROFILE_ON();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(__amigaos4__)
|
||||
{
|
||||
mn = AllocMem(allocation_size,MEMF_PRIVATE);
|
||||
}
|
||||
#else
|
||||
{
|
||||
mn = AllocMem(allocation_size,MEMF_ANY);
|
||||
}
|
||||
#endif /* __amigaos4__ */
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
if(__memory_pool != NULL)
|
||||
{
|
||||
mn = AllocPooled(__memory_pool,allocation_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(__amigaos4__)
|
||||
{
|
||||
mn = AllocMem(allocation_size,MEMF_PRIVATE);
|
||||
}
|
||||
#else
|
||||
{
|
||||
mn = AllocMem(allocation_size,MEMF_ANY);
|
||||
}
|
||||
#endif /* __amigaos4__ */
|
||||
PROFILE_OFF();
|
||||
mn = AllocMem(allocation_size, MEMF_ANY);
|
||||
PROFILE_ON();
|
||||
}
|
||||
}
|
||||
#endif /* __USE_SLAB_ALLOCATOR */
|
||||
|
||||
if(mn == NULL)
|
||||
if (mn == NULL)
|
||||
{
|
||||
SHOWMSG("not enough memory");
|
||||
goto out;
|
||||
}
|
||||
|
||||
mn->mn_Size = size;
|
||||
mn->mn_NeverFree = never_free;
|
||||
|
||||
AddTail((struct List *)&__memory_list,(struct Node *)mn);
|
||||
mn->mn_AllocationSize = allocation_size;
|
||||
mn->mn_Flags = never_free ? MNF_NEVER_FREE : 0;
|
||||
|
||||
__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;
|
||||
|
||||
__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;
|
||||
|
||||
#ifdef __MEM_DEBUG
|
||||
{
|
||||
char * head = (char *)(mn + 1);
|
||||
char * body = head + MALLOC_HEAD_SIZE;
|
||||
char * tail = body + size;
|
||||
BYTE * head = (BYTE *)&mn[1];
|
||||
BYTE * body = &head[MALLOC_HEAD_SIZE];
|
||||
BYTE * tail = &body[size];
|
||||
|
||||
mn->mn_AlreadyFree = FALSE;
|
||||
mn->mn_Allocation = body;
|
||||
mn->mn_AllocationSize = allocation_size;
|
||||
mn->mn_File = (char *)file;
|
||||
mn->mn_Line = line;
|
||||
mn->mn_OriginalSize = size;
|
||||
mn->mn_File = (char *)debug_file_name;
|
||||
mn->mn_Line = debug_line_number;
|
||||
mn->mn_FreeFile = NULL;
|
||||
mn->mn_FreeLine = 0;
|
||||
|
||||
memset(head,MALLOC_HEAD_FILL,MALLOC_HEAD_SIZE);
|
||||
memset(body,MALLOC_NEW_FILL,size);
|
||||
memset(tail,MALLOC_TAIL_FILL,MALLOC_TAIL_SIZE);
|
||||
memset(head, MALLOC_HEAD_FILL, MALLOC_HEAD_SIZE);
|
||||
memset(body, MALLOC_NEW_FILL, size);
|
||||
memset(tail, MALLOC_TAIL_FILL, MALLOC_TAIL_SIZE);
|
||||
|
||||
#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",file,line);
|
||||
kprintf("allocated at %s:%ld]\n", debug_file_name, debug_line_number);
|
||||
}
|
||||
#endif /* __MEM_DEBUG_LOG */
|
||||
|
||||
AddTail((struct List *)&__memory_list,(struct Node *)mn);
|
||||
|
||||
#ifdef __USE_MEM_TREES
|
||||
{
|
||||
__red_black_tree_insert(&__memory_tree,mn);
|
||||
__red_black_tree_insert(&__memory_tree, mn);
|
||||
}
|
||||
#endif /* __USE_MEM_TREES */
|
||||
|
||||
@@ -242,6 +280,22 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED unused_file,in
|
||||
}
|
||||
#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];
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
@@ -249,57 +303,57 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED unused_file,in
|
||||
#if defined(UNIX_PATH_SEMANTICS)
|
||||
{
|
||||
/* Set the zero length allocation contents to NULL. */
|
||||
if(original_size == 0)
|
||||
*(char **)result = NULL;
|
||||
if (original_size == 0 && size >= sizeof(BYTE *))
|
||||
*(BYTE **)result = NULL;
|
||||
}
|
||||
#endif /* UNIX_PATH_SEMANTICS */
|
||||
|
||||
assert( (((ULONG)result) & 3) == 0 );
|
||||
assert( (((ULONG)result) & MEM_BLOCKMASK) == 0 );
|
||||
|
||||
out:
|
||||
|
||||
#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",file,line);
|
||||
kprintf("FAILED: allocated at %s:%ld]\n", debug_file_name, debug_line_number);
|
||||
}
|
||||
}
|
||||
#endif /* __MEM_DEBUG_LOG */
|
||||
|
||||
__memory_unlock();
|
||||
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
__static void *
|
||||
__malloc(size_t size,const char * file,int line)
|
||||
__malloc(size_t size, const char * file, int line)
|
||||
{
|
||||
void * result = NULL;
|
||||
|
||||
__memory_lock();
|
||||
|
||||
/* Try to get rid of now unused memory. */
|
||||
if(__alloca_cleanup != NULL)
|
||||
(*__alloca_cleanup)(file,line);
|
||||
if (__alloca_cleanup != NULL)
|
||||
(*__alloca_cleanup)(file, line);
|
||||
|
||||
__memory_unlock();
|
||||
|
||||
#ifdef __MEM_DEBUG
|
||||
{
|
||||
/*if((rand() % 16) == 0)
|
||||
/*if ((rand() % 16) == 0)
|
||||
__check_memory_allocations(file,line);*/
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -309,7 +363,7 @@ malloc(size_t size)
|
||||
{
|
||||
void * result;
|
||||
|
||||
result = __malloc(size,NULL,0);
|
||||
result = __malloc(size, NULL, 0);
|
||||
|
||||
return(result);
|
||||
}
|
||||
@@ -327,8 +381,12 @@ static struct SignalSemaphore * memory_semaphore;
|
||||
void
|
||||
__memory_lock(void)
|
||||
{
|
||||
if(memory_semaphore != NULL)
|
||||
PROFILE_OFF();
|
||||
|
||||
if (memory_semaphore != NULL)
|
||||
ObtainSemaphore(memory_semaphore);
|
||||
|
||||
PROFILE_ON();
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -336,8 +394,12 @@ __memory_lock(void)
|
||||
void
|
||||
__memory_unlock(void)
|
||||
{
|
||||
if(memory_semaphore != NULL)
|
||||
PROFILE_OFF();
|
||||
|
||||
if (memory_semaphore != NULL)
|
||||
ReleaseSemaphore(memory_semaphore);
|
||||
|
||||
PROFILE_ON();
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -350,30 +412,34 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
|
||||
{
|
||||
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
|
||||
{
|
||||
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",
|
||||
__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;
|
||||
|
||||
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)
|
||||
{
|
||||
/* This must remain empty. */
|
||||
__initialize_red_black_tree(&__memory_tree);
|
||||
}
|
||||
#endif /* __USE_MEM_TREES */
|
||||
@@ -385,39 +451,36 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
|
||||
/* Is the slab memory allocator enabled? */
|
||||
if (__slab_data.sd_InUse)
|
||||
{
|
||||
/* Just release the memory. */
|
||||
__slab_exit();
|
||||
}
|
||||
else
|
||||
/* Is the memory pool in use? */
|
||||
else if (__memory_pool != NULL)
|
||||
{
|
||||
if (__memory_pool != NULL)
|
||||
{
|
||||
NewList((struct List *)&__memory_list);
|
||||
|
||||
/* 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
|
||||
{
|
||||
while(NOT IsListEmpty((struct List *)&__memory_list))
|
||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
|
||||
while (NOT IsMinListEmpty(&__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);
|
||||
while (NOT IsMinListEmpty(&__memory_list))
|
||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, NULL, 0);
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
if (__memory_pool != NULL)
|
||||
{
|
||||
NewList((struct List *)&__memory_list);
|
||||
|
||||
DeletePool(__memory_pool);
|
||||
__memory_pool = NULL;
|
||||
}
|
||||
@@ -425,19 +488,22 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
|
||||
{
|
||||
#ifdef __MEM_DEBUG
|
||||
{
|
||||
while(NOT IsListEmpty((struct List *)&__memory_list))
|
||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
|
||||
while (NOT IsMinListEmpty(&__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);
|
||||
while (NOT IsMinListEmpty(&__memory_list))
|
||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, NULL, 0);
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
}
|
||||
}
|
||||
#endif /* __USE_SLAB_ALLOCATOR */
|
||||
|
||||
/* The list of memory allocations must remain empty. */
|
||||
NewList((struct List *)&__memory_list);
|
||||
|
||||
#if defined(__THREAD_SAFE)
|
||||
{
|
||||
__delete_semaphore(memory_semaphore);
|
||||
@@ -456,13 +522,7 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
||||
|
||||
ENTER();
|
||||
|
||||
#if defined(__THREAD_SAFE)
|
||||
{
|
||||
memory_semaphore = __create_semaphore();
|
||||
if(memory_semaphore == NULL)
|
||||
goto out;
|
||||
}
|
||||
#endif /* __THREAD_SAFE */
|
||||
NewList((struct List *)&__memory_list);
|
||||
|
||||
#if defined(__USE_MEM_TREES) && defined(__MEM_DEBUG)
|
||||
{
|
||||
@@ -470,27 +530,38 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
||||
}
|
||||
#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 */
|
||||
#if 0
|
||||
#if DEBUG
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SHOWVALUE(__slab_max_size);
|
||||
|
||||
/* Enable the slab memory allocator? */
|
||||
if(__slab_max_size > 0)
|
||||
if (__slab_max_size > 0)
|
||||
{
|
||||
__slab_init(__slab_max_size);
|
||||
}
|
||||
@@ -498,15 +569,27 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
||||
{
|
||||
#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
|
||||
{
|
||||
/* There is no support for memory pools in the operating system
|
||||
* prior to Kickstart 3.0 (V39).
|
||||
*/
|
||||
if(((struct Library *)SysBase)->lib_Version >= 39)
|
||||
__memory_pool = CreatePool(MEMF_ANY,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
|
||||
if (((struct Library *)SysBase)->lib_Version >= 39)
|
||||
{
|
||||
__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__ */
|
||||
}
|
||||
@@ -515,19 +598,31 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
||||
{
|
||||
#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
|
||||
{
|
||||
/* There is no support for memory pools in the operating system
|
||||
* prior to Kickstart 3.0 (V39).
|
||||
*/
|
||||
if(((struct Library *)SysBase)->lib_Version >= 39)
|
||||
__memory_pool = CreatePool(MEMF_ANY,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
|
||||
if (((struct Library *)SysBase)->lib_Version >= 39)
|
||||
{
|
||||
__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 /* __USE_SLAB_ALLOCATOR) */
|
||||
#endif /* __USE_SLAB_ALLOCATOR */
|
||||
|
||||
success = TRUE;
|
||||
|
||||
@@ -536,7 +631,7 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
||||
SHOWVALUE(success);
|
||||
LEAVE();
|
||||
|
||||
if(success)
|
||||
if (success)
|
||||
CONSTRUCTOR_SUCCEED();
|
||||
else
|
||||
CONSTRUCTOR_FAIL();
|
||||
|
||||
@@ -37,9 +37,13 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||
|
||||
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 */
|
||||
return(-1);
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
73
library/stdlib_memory.h
Normal file → Executable file
73
library/stdlib_memory.h
Normal file → Executable file
@@ -63,8 +63,7 @@
|
||||
/*
|
||||
* Uncomment this to enable the slab allocator.
|
||||
*/
|
||||
#define __USE_SLAB_ALLOCATOR
|
||||
|
||||
/*#define __USE_SLAB_ALLOCATOR*/
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
@@ -125,7 +124,6 @@
|
||||
#define __find_memory_node __find_memory_node_debug
|
||||
#define __free_memory_node __free_memory_node_debug
|
||||
|
||||
#define __get_allocation_size __get_allocation_size_debug
|
||||
#define __allocate_memory __allocate_memory_debug
|
||||
|
||||
#define __memory_pool __memory_pool_debug
|
||||
@@ -152,19 +150,26 @@ extern char * __getcwd(char * buffer,size_t buffer_size,const char *file,int lin
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* If this flag is set in mn_Flags, then this memory allocation
|
||||
* cannot be released with free() or used with realloc(). This
|
||||
* flag is set by alloca().
|
||||
*/
|
||||
#define MNF_NEVER_FREE (1UL << 0)
|
||||
|
||||
/* Memory allocations are remembered by this tracking data structure.
|
||||
* Its size is always a multiple of 8 bytes, which provides memory
|
||||
* address alignment to a 64-bit boundary.
|
||||
*/
|
||||
struct MemoryNode
|
||||
{
|
||||
struct MinNode mn_MinNode;
|
||||
size_t mn_Size;
|
||||
|
||||
UBYTE mn_NeverFree;
|
||||
ULONG mn_AllocationSize;
|
||||
ULONG mn_Flags;
|
||||
|
||||
#ifdef __MEM_DEBUG
|
||||
UBYTE mn_AlreadyFree;
|
||||
UBYTE mn_Pad0[2];
|
||||
|
||||
void * mn_Allocation;
|
||||
size_t mn_AllocationSize;
|
||||
size_t mn_OriginalSize;
|
||||
|
||||
char * mn_FreeFile;
|
||||
int mn_FreeLine;
|
||||
@@ -172,16 +177,17 @@ struct MemoryNode
|
||||
char * mn_File;
|
||||
int mn_Line;
|
||||
|
||||
UBYTE mn_AlreadyFree;
|
||||
UBYTE mn_Pad1[7];
|
||||
#ifdef __USE_MEM_TREES
|
||||
struct MemoryNode * mn_Left;
|
||||
struct MemoryNode * mn_Right;
|
||||
struct MemoryNode * mn_Parent;
|
||||
|
||||
UBYTE mn_IsRed;
|
||||
UBYTE mn_Pad1[3];
|
||||
UBYTE mn_Pad2[3];
|
||||
#endif /* __USE_MEM_TREES */
|
||||
|
||||
#else
|
||||
UBYTE mn_Pad0[3];
|
||||
#endif /* __MEM_DEBUG */
|
||||
};
|
||||
|
||||
@@ -201,7 +207,7 @@ struct MemoryTree
|
||||
/* This keeps track of individual slabs. Each slab begins with this
|
||||
* header and is followed by the memory it manages. The size of that
|
||||
* memory "slab" is fixed and matches what is stored in
|
||||
* SlabData.sd_MaxSlabSize.
|
||||
* SlabData.sd_StandardSlabSize.
|
||||
*
|
||||
* Each slab manages allocations of a specific maximum size, e.g. 8, 16, 32,
|
||||
* 64, etc. bytes. Multiple slabs can exist which manage allocations of the same
|
||||
@@ -229,12 +235,28 @@ struct SlabNode
|
||||
/* How many chunks of this slab are currently in use? */
|
||||
ULONG sn_UseCount;
|
||||
|
||||
/* How many times was this slab reused instead of allocating
|
||||
* it from system memory?
|
||||
*/
|
||||
ULONG sn_NumReused;
|
||||
|
||||
/* This contains all the chunks of memory which are available
|
||||
* for allocation.
|
||||
*/
|
||||
struct MinList sn_FreeList;
|
||||
};
|
||||
|
||||
/* Memory allocations which are not part of a slab are
|
||||
* tracked using this data structure. This data structure
|
||||
* is supposed to be a multiple of 8 bytes in size.
|
||||
*/
|
||||
struct SlabSingleAllocation
|
||||
{
|
||||
struct MinNode ssa_MinNode;
|
||||
ULONG ssa_Size;
|
||||
ULONG ssa_Pad;
|
||||
};
|
||||
|
||||
/* This is the global bookkeeping information for managing
|
||||
* memory allocations from the slab data structure.
|
||||
*/
|
||||
@@ -244,15 +266,15 @@ struct SlabData
|
||||
* 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
|
||||
* which are 8 bytes in size, sd_Slabs[4] is for 16 byte
|
||||
* chunks, etc. The minimum chunk size is 8, which is why
|
||||
* lists 0..2 are not used. Currently, there is an upper limit
|
||||
* of 2^31 bytes per chunk, but you should not be using slab
|
||||
* chunks, etc. The minimum chunk size is 16, which is why
|
||||
* 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
|
||||
* chunks much larger than 4096 bytes.
|
||||
*/
|
||||
struct MinList sd_Slabs[31];
|
||||
struct MinList sd_Slabs[17];
|
||||
|
||||
/* Memory allocations which are larger than the limit
|
||||
* found in the sd_MaxSlabSize field are kept in this list.
|
||||
* found in the sd_StandardSlabSize field are kept in this list.
|
||||
* They are never associated with a slab.
|
||||
*/
|
||||
struct MinList sd_SingleAllocations;
|
||||
@@ -263,18 +285,20 @@ struct SlabData
|
||||
*/
|
||||
struct MinList sd_EmptySlabs;
|
||||
|
||||
/* This is the maximum size of a memory allocation which may
|
||||
/* This is the standard size of a memory allocation which may
|
||||
* be made from a slab that can accommodate it. This number
|
||||
* is initialized from the __slab_max_size global variable,
|
||||
* if > 0, and unless it already is a power of two, it will
|
||||
* be rounded up to the next largest power of two.
|
||||
*/
|
||||
size_t sd_MaxSlabSize;
|
||||
size_t sd_StandardSlabSize;
|
||||
|
||||
/* This field keeps track of how many entries there are in
|
||||
* the sd_SingleAllocations list.
|
||||
/* These fields keep track of how many entries there are in
|
||||
* the sd_SingleAllocations list, and how much memory these
|
||||
* allocations occupy.
|
||||
*/
|
||||
ULONG sd_NumSingleAllocations;
|
||||
size_t sd_NumSingleAllocations;
|
||||
size_t sd_TotalSingleAllocationSize;
|
||||
|
||||
/* If this is set to TRUE, then memory allocations will be
|
||||
* be managed through slabs.
|
||||
@@ -285,7 +309,8 @@ struct SlabData
|
||||
/****************************************************************************/
|
||||
|
||||
extern struct SlabData NOCOMMON __slab_data;
|
||||
extern ULONG NOCOMMON __slab_max_size;
|
||||
extern unsigned long NOCOMMON __slab_max_size;
|
||||
extern unsigned long NOCOMMON __slab_purge_threshold;
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
@@ -45,8 +45,8 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
extern void ASM _PROLOG(REG(a0,char *));
|
||||
extern void ASM _EPILOG(REG(a0,char *));
|
||||
extern void __asm _PROLOG(register __a0 char *);
|
||||
extern void __asm _EPILOG(register __a0 char *);
|
||||
|
||||
#if _PROFILE
|
||||
#define PROFILE_OFF() _PROLOG(0L)
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#ifndef _STDLIB_HEADERS_H
|
||||
#include "stdlib_headers.h"
|
||||
#endif /* _STDLIB_HEADERS_H */
|
||||
@@ -48,7 +50,7 @@
|
||||
/****************************************************************************/
|
||||
|
||||
__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;
|
||||
BOOL locked = FALSE;
|
||||
@@ -60,22 +62,24 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
||||
|
||||
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
|
||||
else if (size == 0)
|
||||
{
|
||||
D(("calling free(0x%08lx)",ptr));
|
||||
|
||||
__free(ptr,file,line);
|
||||
__free(ptr, file, line);
|
||||
}
|
||||
#endif /* UNIX_PATH_SEMANTICS */
|
||||
else
|
||||
{
|
||||
size_t new_allocation_size UNUSED;
|
||||
size_t old_allocation_size;
|
||||
struct MemoryNode * mn;
|
||||
BOOL reallocate;
|
||||
|
||||
@@ -89,16 +93,14 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
||||
|
||||
#ifdef __MEM_DEBUG
|
||||
{
|
||||
/* If we managed to find the memory allocation,
|
||||
reallocate it. */
|
||||
if(mn == NULL)
|
||||
/* Quit if we failed to find the memory allocation. */
|
||||
if (mn == NULL)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -108,76 +110,114 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
|
||||
if(mn == NULL || mn->mn_NeverFree)
|
||||
if (mn == NULL || FLAG_IS_SET(mn->mn_Flags, MNF_NEVER_FREE))
|
||||
{
|
||||
SHOWMSG("cannot free this chunk");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Don't do anything unless the size of the allocation
|
||||
has really changed. */
|
||||
assert( FLAG_IS_CLEAR(mn->mn_Flags, MNF_NEVER_FREE) );
|
||||
|
||||
old_allocation_size = mn->mn_AllocationSize;
|
||||
|
||||
/* If the memory debug option is enabled, just check if
|
||||
* requested allocation size has changed.
|
||||
*/
|
||||
#if defined(__MEM_DEBUG)
|
||||
{
|
||||
reallocate = (mn->mn_Size != size);
|
||||
reallocate = (mn->mn_OriginalSize != size);
|
||||
|
||||
new_allocation_size = (sizeof(*mn) + MALLOC_HEAD_SIZE + size + MALLOC_TAIL_SIZE + MEM_BLOCKMASK) & ~MEM_BLOCKMASK;
|
||||
}
|
||||
#else
|
||||
{
|
||||
size_t rounded_allocation_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;
|
||||
|
||||
/* Round the total allocation size to the operating system
|
||||
granularity. */
|
||||
rounded_allocation_size = __get_allocation_size(size);
|
||||
|
||||
assert( rounded_allocation_size >= size );
|
||||
|
||||
if(rounded_allocation_size > mn->mn_Size)
|
||||
if (new_allocation_size > old_allocation_size)
|
||||
{
|
||||
/* Allocation size should grow. */
|
||||
reallocate = TRUE;
|
||||
}
|
||||
else
|
||||
else if (new_allocation_size < old_allocation_size)
|
||||
{
|
||||
/* Optimization: If the block size shrinks by less than half the
|
||||
original allocation size, do not reallocate the
|
||||
block and do not copy over the contents of the old
|
||||
allocation. We also take into account that the
|
||||
actual size of the allocation is affected by a
|
||||
certain operating system imposed granularity. */
|
||||
reallocate = (rounded_allocation_size < mn->mn_Size && rounded_allocation_size <= mn->mn_Size / 2);
|
||||
block. */
|
||||
reallocate = (size <= old_allocation_size / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
reallocate = FALSE;
|
||||
}
|
||||
}
|
||||
#endif /* __MEM_DEBUG */
|
||||
|
||||
if(reallocate)
|
||||
if (reallocate)
|
||||
{
|
||||
void * new_ptr;
|
||||
|
||||
D(("realloc() size has changed; old=%ld, new=%ld",mn->mn_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
|
||||
attempt to replace the old. */
|
||||
new_ptr = __malloc(size,file,line);
|
||||
if(new_ptr == NULL)
|
||||
attempt to replace the old one. */
|
||||
new_ptr = __malloc(size, file, line);
|
||||
if (new_ptr == NULL)
|
||||
{
|
||||
SHOWMSG("could not reallocate memory");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Copy the contents of the old allocation to the new buffer. */
|
||||
if(size > mn->mn_Size)
|
||||
size = mn->mn_Size;
|
||||
/* With memory debugging enabled, the size of the allocation made
|
||||
* will use the requested and not the rounded size of the
|
||||
* 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
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
D(("size didn't actually change that much (%ld -> %ld); returning memory block as is.",mn->mn_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. */
|
||||
result = ptr;
|
||||
@@ -186,14 +226,14 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
||||
|
||||
out:
|
||||
|
||||
if(locked)
|
||||
if (locked)
|
||||
__memory_unlock();
|
||||
|
||||
if(result == NULL)
|
||||
if (result == NULL)
|
||||
SHOWMSG("ouch! realloc failed");
|
||||
|
||||
RETURN(result);
|
||||
return(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
788
library/stdlib_slab.c
Normal file → Executable file
788
library/stdlib_slab.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@@ -35,4 +35,4 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
ULONG NOCOMMON __slab_max_size;
|
||||
unsigned long __slab_max_size;
|
||||
|
||||
38
library/stdlib_slab_purge_threshold.c
Normal file
38
library/stdlib_slab_purge_threshold.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* :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_HEADERS_H
|
||||
#include "stdlib_headers.h"
|
||||
#endif /* _STDLIB_HEADERS_H */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
unsigned long __slab_purge_threshold;
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static const char * error_table[EILSEQ - EPERM + 1] =
|
||||
static const char * error_table[ENOTSUP - EPERM + 1] =
|
||||
{
|
||||
"Operation not permitted",
|
||||
"No such file or directory",
|
||||
@@ -127,7 +127,8 @@ static const char * error_table[EILSEQ - EPERM + 1] =
|
||||
"Identifier removed",
|
||||
"No message of the desired 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;
|
||||
size_t len;
|
||||
|
||||
if(number < EPERM || number > EILSEQ)
|
||||
if(number < EPERM || number > ENOTSUP)
|
||||
{
|
||||
__set_errno(EINVAL);
|
||||
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);
|
||||
}
|
||||
149
library/time_mktime.c
Normal file → Executable file
149
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
|
||||
*
|
||||
@@ -52,9 +52,10 @@ mktime(struct tm *tm)
|
||||
{
|
||||
DECLARE_UTILITYBASE();
|
||||
struct ClockData clock_data;
|
||||
ULONG seconds, delta;
|
||||
ULONG seconds;
|
||||
time_t result = (time_t)-1;
|
||||
int max_month_days;
|
||||
LONG combined_seconds;
|
||||
int month, year;
|
||||
|
||||
ENTER();
|
||||
|
||||
@@ -73,116 +74,63 @@ mktime(struct tm *tm)
|
||||
}
|
||||
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||
|
||||
/* The month must be valid. */
|
||||
if(tm->tm_mon < 0 || tm->tm_mon > 11)
|
||||
/* Normalize the year and month. */
|
||||
year = tm->tm_year + 1900;
|
||||
month = tm->tm_mon + 1;
|
||||
|
||||
if(month < 0 || month > 12)
|
||||
{
|
||||
SHOWVALUE(tm->tm_mon);
|
||||
SHOWMSG("invalid month");
|
||||
goto out;
|
||||
int y;
|
||||
|
||||
y = month / 12;
|
||||
|
||||
month -= y * 12;
|
||||
year += y;
|
||||
}
|
||||
|
||||
/* The day of the month must be valid. */
|
||||
if(tm->tm_mday < 1 || tm->tm_mday > 31)
|
||||
if(month < 1)
|
||||
{
|
||||
SHOWVALUE(tm->tm_mday);
|
||||
SHOWMSG("invalid day of month");
|
||||
goto out;
|
||||
month += 12;
|
||||
year -= 1;
|
||||
}
|
||||
|
||||
/* The year must be valid. */
|
||||
if(tm->tm_year < 78)
|
||||
/* The year must be valid. Amiga time begins with January 1st, 1978. */
|
||||
if(year < 1978)
|
||||
{
|
||||
SHOWVALUE(tm->tm_year);
|
||||
SHOWVALUE(year);
|
||||
SHOWMSG("invalid year");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Is this the month of February? */
|
||||
if(tm->tm_mon == 1)
|
||||
{
|
||||
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;
|
||||
/* Convert the first day of the month in the given year
|
||||
into the corresponding number of seconds. */
|
||||
memset(&clock_data, 0, sizeof(clock_data));
|
||||
|
||||
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();
|
||||
|
||||
@@ -193,10 +141,13 @@ mktime(struct tm *tm)
|
||||
|
||||
__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. */
|
||||
result = seconds + UNIX_TIME_OFFSET;
|
||||
|
||||
/* Finally, normalize the provided time and date information. */
|
||||
localtime_r(&result, tm);
|
||||
|
||||
out:
|
||||
|
||||
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. */
|
||||
}
|
||||
@@ -184,7 +184,6 @@ __getcwd(char * buffer,size_t buffer_size,const char *file,int line)
|
||||
if(__unix_path_semantics)
|
||||
{
|
||||
const char * path_name = buffer;
|
||||
size_t len;
|
||||
|
||||
if(__translate_amiga_to_unix_path_name(&path_name,&buffer_nti) != 0)
|
||||
goto out;
|
||||
|
||||
@@ -69,7 +69,7 @@ CLIB_DESTRUCTOR(unistd_exit)
|
||||
|
||||
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;
|
||||
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 buffer_nti;
|
||||
#endif /* UNIX_PATH_SEMANTICS */
|
||||
|
||||
D_S(struct bcpl_name, bname);
|
||||
const size_t name_size = sizeof(bname->name);
|
||||
|
||||
BPTR lock = ZERO;
|
||||
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();
|
||||
|
||||
@@ -70,12 +80,12 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
||||
|
||||
assert( path_name != NULL && buffer != NULL );
|
||||
|
||||
if(__check_abort_enabled)
|
||||
if (__check_abort_enabled)
|
||||
__check_abort();
|
||||
|
||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||
{
|
||||
if(path_name == NULL || buffer == NULL)
|
||||
if (path_name == NULL || buffer == NULL)
|
||||
{
|
||||
SHOWSTRING("invalid parameters");
|
||||
|
||||
@@ -87,9 +97,9 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
||||
|
||||
#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");
|
||||
|
||||
@@ -97,39 +107,119 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
||||
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;
|
||||
}
|
||||
}
|
||||
#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();
|
||||
lock = __lock((STRPTR)path_name,SHARED_LOCK,&target_length,buffer,(size_t)buffer_size);
|
||||
lock = Lock((STRPTR)path_part, SHARED_LOCK);
|
||||
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");
|
||||
|
||||
SetIoErr(ERROR_NO_FREE_STORE);
|
||||
goto out;
|
||||
}
|
||||
else if (target_length <= 0) /* No a soft-link. */
|
||||
|
||||
/* 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)
|
||||
{
|
||||
__set_errno(__translate_io_error_to_errno(IoErr()));
|
||||
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(__unix_path_semantics)
|
||||
if (__unix_path_semantics)
|
||||
{
|
||||
if(__translate_amiga_to_unix_path_name((char const **)&buffer,&buffer_nti) != 0)
|
||||
if (__translate_amiga_to_unix_path_name((char const **)&buffer, &buffer_nti) != 0)
|
||||
goto out;
|
||||
|
||||
__restore_path_name((char const **)&buffer,&buffer_nti);
|
||||
|
||||
strcpy(buffer,buffer_nti.substitute);
|
||||
strcpy(buffer, buffer_nti.substitute);
|
||||
}
|
||||
}
|
||||
#endif /* UNIX_PATH_SEMANTICS */
|
||||
@@ -137,13 +227,24 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
||||
result = strlen(buffer);
|
||||
|
||||
SHOWSTRING(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
PROFILE_OFF();
|
||||
|
||||
if (dvp != NULL)
|
||||
FreeDeviceProc(dvp);
|
||||
|
||||
UnLock(lock);
|
||||
|
||||
PROFILE_ON();
|
||||
|
||||
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
|
||||
*
|
||||
@@ -477,7 +477,10 @@ __translate_unix_to_amiga_path_name(char const ** name_ptr,struct name_translati
|
||||
for(i = j = 0 ; i < len ; i++)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
void
|
||||
int
|
||||
usleep(unsigned long microseconds)
|
||||
{
|
||||
ENTER();
|
||||
@@ -51,4 +51,6 @@ usleep(unsigned long microseconds)
|
||||
__time_delay(0,microseconds);
|
||||
|
||||
LEAVE();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ __wildcard_expand_init(void)
|
||||
}
|
||||
else if (rc != OK)
|
||||
{
|
||||
/* Some error occured. */
|
||||
/* Some error occurred. */
|
||||
error = EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define VERSION 1
|
||||
#define REVISION 207
|
||||
#define DATE "18.11.2016"
|
||||
#define VERS "unix.lib 1.207"
|
||||
#define VSTRING "unix.lib 1.207 (18.11.2016)\r\n"
|
||||
#define VERSTAG "\0$VER: unix.lib 1.207 (18.11.2016)"
|
||||
#define REVISION 215
|
||||
#define DATE "26.6.2017"
|
||||
#define VERS "unix.lib 1.215"
|
||||
#define VSTRING "unix.lib 1.215 (26.6.2017)\r\n"
|
||||
#define VERSTAG "\0$VER: unix.lib 1.215 (26.6.2017)"
|
||||
|
||||
@@ -1 +1 @@
|
||||
207
|
||||
215
|
||||
|
||||
@@ -37,9 +37,12 @@
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||
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 */
|
||||
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
|
||||
mbsinit(const mbstate_t *ps)
|
||||
{
|
||||
/* ZZZ unimplemented */
|
||||
return(0);
|
||||
return !ps || !*(unsigned *)ps;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
/****************************************************************************/
|
||||
|
||||
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 */
|
||||
return(0);
|
||||
|
||||
@@ -35,11 +35,13 @@
|
||||
#include "wchar_headers.h"
|
||||
#endif /* _WCHAR_HEADERS_H */
|
||||
|
||||
/* Implementation based on musl */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
wchar_t *
|
||||
wcscat(wchar_t *dest, const wchar_t *src)
|
||||
{
|
||||
/* ZZZ unimplemented */
|
||||
return(NULL);
|
||||
wcscpy(dest + wcslen(dest), src);
|
||||
return dest;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user