mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
Compare commits
65 Commits
master
...
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 |
@ -122,7 +122,7 @@ WARNINGS = \
|
|||||||
# -Wconversion -Wshadow
|
# -Wconversion -Wshadow
|
||||||
|
|
||||||
INCLUDES = -Iinclude -I. -Inetinclude
|
INCLUDES = -Iinclude -I. -Inetinclude
|
||||||
#OPTIONS = -fno-builtin -fno-common -DDEBUG
|
#OPTIONS = -fno-builtin -fno-common
|
||||||
OPTIONS = -fno-builtin -fno-common -DNDEBUG
|
OPTIONS = -fno-builtin -fno-common -DNDEBUG
|
||||||
#OPTIONS = -fno-builtin -fno-common -DNDEBUG -D__THREAD_SAFE
|
#OPTIONS = -fno-builtin -fno-common -DNDEBUG -D__THREAD_SAFE
|
||||||
#OPTIONS = -fno-builtin -fno-common -D__MEM_DEBUG
|
#OPTIONS = -fno-builtin -fno-common -D__MEM_DEBUG
|
||||||
@ -261,6 +261,7 @@ C_LIB = \
|
|||||||
stdio_iobhookentry.o \
|
stdio_iobhookentry.o \
|
||||||
stdio_lock.o \
|
stdio_lock.o \
|
||||||
stdio_locksemaphorename.o \
|
stdio_locksemaphorename.o \
|
||||||
|
stdio_long_path.o \
|
||||||
stdio_nostdio.o \
|
stdio_nostdio.o \
|
||||||
stdio_openiob.o \
|
stdio_openiob.o \
|
||||||
stdio_parent_of_fh.o \
|
stdio_parent_of_fh.o \
|
||||||
@ -449,7 +450,6 @@ C_LIB = \
|
|||||||
time_numbertostring.o \
|
time_numbertostring.o \
|
||||||
time_strftime.o \
|
time_strftime.o \
|
||||||
time_time.o \
|
time_time.o \
|
||||||
time_tzset.o \
|
|
||||||
time_weekday.o \
|
time_weekday.o \
|
||||||
uio_readv.o \
|
uio_readv.o \
|
||||||
uio_writev.o \
|
uio_writev.o \
|
||||||
@ -492,13 +492,13 @@ C_LIB = \
|
|||||||
UNIX_LIB = \
|
UNIX_LIB = \
|
||||||
unix.lib_rev.o \
|
unix.lib_rev.o \
|
||||||
dirent_closedir.o \
|
dirent_closedir.o \
|
||||||
dirent_rewinddir.o \
|
|
||||||
dirent_opendir.o \
|
dirent_opendir.o \
|
||||||
dirent_readdir.o \
|
dirent_readdir.o \
|
||||||
|
dirent_rewinddir.o \
|
||||||
fcntl_creat.o \
|
fcntl_creat.o \
|
||||||
fcntl_fcntl.o \
|
fcntl_fcntl.o \
|
||||||
fcntl_open.o \
|
|
||||||
fcntl_get_default_file.o \
|
fcntl_get_default_file.o \
|
||||||
|
fcntl_open.o \
|
||||||
getopt_getopt_long.o \
|
getopt_getopt_long.o \
|
||||||
mount_convertinfo.o \
|
mount_convertinfo.o \
|
||||||
mount_statfs.o \
|
mount_statfs.o \
|
||||||
@ -506,18 +506,19 @@ UNIX_LIB = \
|
|||||||
resource_setrlimit.o \
|
resource_setrlimit.o \
|
||||||
stat_chmod.o \
|
stat_chmod.o \
|
||||||
stat_fstat.o \
|
stat_fstat.o \
|
||||||
stat_lstat.o \
|
|
||||||
stat_lock.o \
|
stat_lock.o \
|
||||||
|
stat_lstat.o \
|
||||||
stat_mkdir.o \
|
stat_mkdir.o \
|
||||||
stat_rmdir.o \
|
stat_rmdir.o \
|
||||||
stat_stat.o \
|
stat_stat.o \
|
||||||
stdio_ctermid.o \
|
stdio_ctermid.o \
|
||||||
stdio_fdhookentry.o \
|
stdio_fdhookentry.o \
|
||||||
stdio_fflush.o \
|
stdio_fflush.o \
|
||||||
|
stdio_file_init.o \
|
||||||
stdio_fopen.o \
|
stdio_fopen.o \
|
||||||
stdio_init_exit.o \
|
stdio_init_exit.o \
|
||||||
stdio_file_init.o \
|
|
||||||
stdio_locksemaphorename.o \
|
stdio_locksemaphorename.o \
|
||||||
|
stdio_long_path.o \
|
||||||
stdio_openiob.o \
|
stdio_openiob.o \
|
||||||
stdio_popen.o \
|
stdio_popen.o \
|
||||||
stdio_record_locking.o \
|
stdio_record_locking.o \
|
||||||
@ -527,17 +528,28 @@ UNIX_LIB = \
|
|||||||
stdlib_alloca_cleanup.o \
|
stdlib_alloca_cleanup.o \
|
||||||
stdlib_alloca_trap.o \
|
stdlib_alloca_trap.o \
|
||||||
stdlib_arg.o \
|
stdlib_arg.o \
|
||||||
|
stdlib_calloc.o \
|
||||||
|
stdlib_decay_unused_slabs.o \
|
||||||
stdlib_expand_wildcard.o \
|
stdlib_expand_wildcard.o \
|
||||||
stdlib_expand_wildcard_check.o \
|
stdlib_expand_wildcard_check.o \
|
||||||
|
stdlib_free.o \
|
||||||
|
stdlib_free_unused_slabs.o \
|
||||||
stdlib_getmemstats.o \
|
stdlib_getmemstats.o \
|
||||||
|
stdlib_get_slab_allocations.o \
|
||||||
|
stdlib_get_slab_stats.o \
|
||||||
|
stdlib_get_slab_usage.o \
|
||||||
stdlib_main.o \
|
stdlib_main.o \
|
||||||
stdlib_main_stub.o \
|
stdlib_main_stub.o \
|
||||||
|
stdlib_malloc.o \
|
||||||
stdlib_mkdtemp.o \
|
stdlib_mkdtemp.o \
|
||||||
stdlib_mkstemp.o \
|
stdlib_mkstemp.o \
|
||||||
stdlib_mktemp.o \
|
stdlib_mktemp.o \
|
||||||
stdlib_malloc.o \
|
|
||||||
stdlib_realloc.o \
|
stdlib_realloc.o \
|
||||||
|
stdlib_red_black.o \
|
||||||
stdlib_resetmemstats.o \
|
stdlib_resetmemstats.o \
|
||||||
|
stdlib_slab.o \
|
||||||
|
stdlib_slab_max_size.o \
|
||||||
|
stdlib_slab_purge_threshold.o \
|
||||||
stdlib_system.o \
|
stdlib_system.o \
|
||||||
systeminfo_sysinfo.o \
|
systeminfo_sysinfo.o \
|
||||||
termios_cfgetispeed.o \
|
termios_cfgetispeed.o \
|
||||||
@ -941,6 +953,7 @@ AMIGA_LIB = \
|
|||||||
amiga_hotkey.o \
|
amiga_hotkey.o \
|
||||||
amiga_invertstring.o \
|
amiga_invertstring.o \
|
||||||
amiga_newlist.o \
|
amiga_newlist.o \
|
||||||
|
amiga_pools.o \
|
||||||
amiga_rangerand.o \
|
amiga_rangerand.o \
|
||||||
amiga_remtof.o \
|
amiga_remtof.o \
|
||||||
amiga_rexxvars.o \
|
amiga_rexxvars.o \
|
||||||
@ -1156,6 +1169,34 @@ $(LIBC_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h include/std
|
|||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_alloca.o : stdlib_alloca.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_calloc.o : stdlib_calloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_decay_unused_slabs.o : stdlib_decay_unused_slabs.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_free.o : stdlib_free.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_get_slab_allocations.o : stdlib_get_slab_allocations.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_get_slab_stats.o : stdlib_get_slab_stats.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_get_slab_usage.o : stdlib_get_slab_usage.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_malloc.o : stdlib_malloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_realloc.o : stdlib_realloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_slab.o : stdlib_slab.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBUNIX_OBJS)/stdlib_slab_purge_threshold.o : stdlib_slab_purge_threshold.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
# The -fbaserel32 option requires the CPU type to be 68020, too.
|
# The -fbaserel32 option requires the CPU type to be 68020, too.
|
||||||
ifneq (,$(findstring fbaserel32,$(CODE_FLAGS)))
|
ifneq (,$(findstring fbaserel32,$(CODE_FLAGS)))
|
||||||
LOCAL_CODE_FLAGS := $(CODE_FLAGS) $(CODE_TYPE)
|
LOCAL_CODE_FLAGS := $(CODE_FLAGS) $(CODE_TYPE)
|
||||||
|
|||||||
@ -97,7 +97,11 @@ include libm.gmk
|
|||||||
include libnet.gmk
|
include libnet.gmk
|
||||||
include libdebug.gmk
|
include libdebug.gmk
|
||||||
include libamiga.gmk
|
include libamiga.gmk
|
||||||
include libprofile.gmk
|
|
||||||
|
# Olaf (2019-08-22): Please note that "profile_profil.o" can no longer
|
||||||
|
# be built, presumably for lack of header files needed
|
||||||
|
# to build it properly.
|
||||||
|
#include libprofile.gmk
|
||||||
|
|
||||||
all-targets: \
|
all-targets: \
|
||||||
lib/crt0.o \
|
lib/crt0.o \
|
||||||
@ -164,7 +168,9 @@ cvs-tag:
|
|||||||
|
|
||||||
# General build rules for all object files and the individual libraries
|
# General build rules for all object files and the individual libraries
|
||||||
|
|
||||||
lib/crtbegin.o : CFLAGS += -fno-aggressive-loop-optimizations
|
#NO_AGGRESSIVE_LOOP_OPTIMIZATIONS := -fno-aggressive-loop-optimizations
|
||||||
|
|
||||||
|
lib/crtbegin.o : CFLAGS += $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
lib/crtbegin.o : crtbegin.c
|
lib/crtbegin.o : crtbegin.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@ -179,7 +185,7 @@ lib/small-data/%.o : AFLAGS += $(SMALLDATA)
|
|||||||
lib/small-data/%.o : %.S
|
lib/small-data/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
lib/small-data/crtbegin.o : CFLAGS += $(SMALLDATA) -fno-aggressive-loop-optimizations
|
lib/small-data/crtbegin.o : CFLAGS += $(SMALLDATA) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
lib/small-data/crtbegin.o : crtbegin.c
|
lib/small-data/crtbegin.o : crtbegin.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@ -191,7 +197,7 @@ lib/soft-float/%.o : AFLAGS += $(SOFTFLOAT)
|
|||||||
lib/soft-float/%.o : %.S
|
lib/soft-float/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
lib/soft-float/crtbegin.o : CFLAGS += $(SOFTFLOAT) -fno-aggressive-loop-optimizations
|
lib/soft-float/crtbegin.o : CFLAGS += $(SOFTFLOAT) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
lib/soft-float/crtbegin.o : crtbegin.c
|
lib/soft-float/crtbegin.o : crtbegin.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@ -203,7 +209,7 @@ lib/baserel/%.o : AFLAGS += $(BASEREL)
|
|||||||
lib/baserel/%.o : %.S
|
lib/baserel/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
lib/baserel/crtbegin.o : CFLAGS += $(BASEREL) -fno-aggressive-loop-optimizations
|
lib/baserel/crtbegin.o : CFLAGS += $(BASEREL) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
lib/baserel/crtbegin.o : crtbegin.c
|
lib/baserel/crtbegin.o : crtbegin.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@ -215,7 +221,7 @@ lib.threadsafe/%.o : AFLAGS += $(LARGEDATA) $(THREADSAFE)
|
|||||||
lib.threadsafe/%.o : %.S
|
lib.threadsafe/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
lib.threadsafe/crtbegin.o : CFLAGS += $(THREADSAFE) $(LARGEDATA) -fno-aggressive-loop-optimizations
|
lib.threadsafe/crtbegin.o : CFLAGS += $(THREADSAFE) $(LARGEDATA) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
lib.threadsafe/crtbegin.o : crtbegin.c
|
lib.threadsafe/crtbegin.o : crtbegin.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@ -227,7 +233,7 @@ lib.threadsafe/small-data/%.o : AFLAGS += $(SMALLDATA) $(THREADSAFE)
|
|||||||
lib.threadsafe/small-data/%.o : %.S
|
lib.threadsafe/small-data/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
lib.threadsafe/small-data/crtbegin.o : CFLAGS += $(THREADSAFE) $(SMALLDATA) -fno-aggressive-loop-optimizations
|
lib.threadsafe/small-data/crtbegin.o : CFLAGS += $(THREADSAFE) $(SMALLDATA) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
lib.threadsafe/small-data/crtbegin.o : crtbegin.c
|
lib.threadsafe/small-data/crtbegin.o : crtbegin.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@ -239,7 +245,7 @@ lib.threadsafe/soft-float/%.o : AFLAGS += $(SOFTFLOAT) $(THREADSAFE)
|
|||||||
lib.threadsafe/soft-float/%.o : %.S
|
lib.threadsafe/soft-float/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
lib.threadsafe/soft-float/crtbegin.o : CFLAGS += $(THREADSAFE) $(SOFTFLOAT) -fno-aggressive-loop-optimizations
|
lib.threadsafe/soft-float/crtbegin.o : CFLAGS += $(THREADSAFE) $(SOFTFLOAT) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
lib.threadsafe/soft-float/crtbegin.o : crtbegin.c
|
lib.threadsafe/soft-float/crtbegin.o : crtbegin.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
@ -251,7 +257,7 @@ lib.threadsafe/baserel/%.o : AFLAGS += $(BASEREL) $(THREADSAFE)
|
|||||||
lib.threadsafe/baserel/%.o : %.S
|
lib.threadsafe/baserel/%.o : %.S
|
||||||
@$(ASSEMBLE)
|
@$(ASSEMBLE)
|
||||||
|
|
||||||
lib.threadsafe/baserel/crtbegin.o : CFLAGS += $(THREADSAFE) $(BASEREL) -fno-aggressive-loop-optimizations
|
lib.threadsafe/baserel/crtbegin.o : CFLAGS += $(THREADSAFE) $(BASEREL) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
|
||||||
lib.threadsafe/baserel/crtbegin.o : crtbegin.c
|
lib.threadsafe/baserel/crtbegin.o : crtbegin.c
|
||||||
@$(COMPILE)
|
@$(COMPILE)
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 215
|
#define REVISION 216
|
||||||
#define DATE "26.6.2017"
|
#define DATE "10.7.2025"
|
||||||
#define VERS "amiga.lib 1.215"
|
#define VERS "amiga.lib 1.216"
|
||||||
#define VSTRING "amiga.lib 1.215 (26.6.2017)\r\n"
|
#define VSTRING "amiga.lib 1.216 (10.7.2025)\r\n"
|
||||||
#define VERSTAG "\0$VER: amiga.lib 1.215 (26.6.2017)"
|
#define VERSTAG "\0$VER: amiga.lib 1.216 (10.7.2025)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
215
|
216
|
||||||
|
|||||||
562
library/amiga_pools.c
Normal file
562
library/amiga_pools.c
Normal file
@ -0,0 +1,562 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2021 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <exec/memory.h>
|
||||||
|
#include <exec/alerts.h>
|
||||||
|
#include <exec/lists.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#include <proto/exec.h>
|
||||||
|
#include <clib/alib_protos.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* This signature identifies a large allocation on the list
|
||||||
|
* which contains both puddles and such large memory allocations.
|
||||||
|
*/
|
||||||
|
#define IS_LARGE_ALLOCATION 0
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* A private memory pool, as used by this implementation of the
|
||||||
|
* pool memory management functions.
|
||||||
|
*/
|
||||||
|
struct MemoryPool
|
||||||
|
{
|
||||||
|
struct MinList mp_PuddleMinList; /* Both puddles and large allocations
|
||||||
|
* are stored in this list. The puddles
|
||||||
|
* are stored near the head of the list
|
||||||
|
* and the large allocations are stored
|
||||||
|
* near the tail of the list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ULONG mp_MemoryFlags; /* Memory attributes for allocation,
|
||||||
|
* which may also include MEMF_CLEAR.
|
||||||
|
*/
|
||||||
|
ULONG mp_PuddleSize; /* Largest allocation which will fit
|
||||||
|
* into a single puddle.
|
||||||
|
*/
|
||||||
|
ULONG mp_PuddleSizeThreshold; /* Allocations which exceed this size
|
||||||
|
* will be allocated separately and not
|
||||||
|
* make use of the puddles.
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* The management data structure associated with a separate large memory
|
||||||
|
* allocation. This is distinct from the puddles.
|
||||||
|
*/
|
||||||
|
struct LargeAllocation
|
||||||
|
{
|
||||||
|
struct MinNode la_MinNode;
|
||||||
|
|
||||||
|
ULONG la_Signature; /* Must be set to IS_LARGE_ALLOCATION */
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* This combines a plain Node, a MemHeader and a LargeAllocation. They
|
||||||
|
* all overlap to some degree. The "puddle" is really a MemHeader from
|
||||||
|
* which the individual memory allocations are made.
|
||||||
|
*
|
||||||
|
* For reference, here is how the individual data structures look like.
|
||||||
|
* The 'struct MinNode' is used by the 'struct LargeAllocation' and you
|
||||||
|
* can see that the LargeAllocation.la_Signature overlaps the
|
||||||
|
* Node.ln_Type and Node.ln_Pri fields. The 'struct MemHeader' begins
|
||||||
|
* with a 'struct Node' and is initialized so that the Node.ln_Type and
|
||||||
|
* Node.ln_Pri are never zero. This is why LargeAllocation.la_Signature
|
||||||
|
* being zero is key to identifying large allocations which along with
|
||||||
|
* the MemHeaders share the same storage list.
|
||||||
|
*
|
||||||
|
* struct MinNode {
|
||||||
|
* struct MinNode * mln_Succ;
|
||||||
|
* struct MinNode * mln_Pred;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct LargeAllocation {
|
||||||
|
* struct MinNode la_MinNode;
|
||||||
|
* ULONG la_Signature;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct Node {
|
||||||
|
* struct Node * ln_Succ;
|
||||||
|
* struct Node * ln_Pred;
|
||||||
|
* UBYTE ln_Type;
|
||||||
|
* BYTE ln_Pri;
|
||||||
|
* char * ln_Name;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct MemHeader {
|
||||||
|
* struct Node mh_Node;
|
||||||
|
* UWORD mh_Attributes;
|
||||||
|
* struct MemChunk * mh_First;
|
||||||
|
* APTR mh_Lower;
|
||||||
|
* APTR mh_Upper;
|
||||||
|
* ULONG mh_Free;
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
union PuddleUnion
|
||||||
|
{
|
||||||
|
struct Node pu_Node;
|
||||||
|
struct MemHeader pu_MemHeader;
|
||||||
|
struct LargeAllocation pu_LargeAllocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Our local Kickstart 1.x compatible implementation of FreeVec(). */
|
||||||
|
static VOID free_vec(APTR allocation)
|
||||||
|
{
|
||||||
|
if (allocation != NULL)
|
||||||
|
{
|
||||||
|
ULONG * mem = allocation;
|
||||||
|
|
||||||
|
FreeMem(&mem[-1], mem[-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Our local Kickstart 1.x compatible implementation of AllocVec(). */
|
||||||
|
static APTR alloc_vec(ULONG size, ULONG flags)
|
||||||
|
{
|
||||||
|
ULONG * mem = NULL;
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
/* Note: no overflow testing is being performed! */
|
||||||
|
size += sizeof(*mem);
|
||||||
|
|
||||||
|
mem = AllocMem(size, flags);
|
||||||
|
if (mem != NULL)
|
||||||
|
(*mem++) = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
VOID LibDeletePool(APTR pool)
|
||||||
|
{
|
||||||
|
/* If possible, use the operating system implementation
|
||||||
|
* instead of this reimplementation.
|
||||||
|
*/
|
||||||
|
#if ! defined(__amigaos4__)
|
||||||
|
if (SysBase->LibNode.lib_Version >= 39)
|
||||||
|
{
|
||||||
|
DeletePool(pool);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* ! defined(__amigaos4__) */
|
||||||
|
|
||||||
|
if (pool != NULL)
|
||||||
|
{
|
||||||
|
struct MemoryPool * mp = pool;
|
||||||
|
struct MinNode * mln_next;
|
||||||
|
struct MinNode * mln;
|
||||||
|
|
||||||
|
for (mln = mp->mp_PuddleMinList.mlh_Head ;
|
||||||
|
mln->mln_Succ != NULL ;
|
||||||
|
mln = mln_next)
|
||||||
|
{
|
||||||
|
mln_next = mln->mln_Succ;
|
||||||
|
|
||||||
|
free_vec(mln);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeMem(mp, sizeof(*mp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Note: puddle size should not be 0 or every single memory allocation
|
||||||
|
* will result in an AllocVec() call.
|
||||||
|
*/
|
||||||
|
APTR LibCreatePool(
|
||||||
|
ULONG memory_flags,
|
||||||
|
ULONG puddle_size,
|
||||||
|
ULONG threshold_size)
|
||||||
|
{
|
||||||
|
struct MemoryPool * mp = NULL;
|
||||||
|
APTR result = NULL;
|
||||||
|
|
||||||
|
/* If possible, use the operating system implementation
|
||||||
|
* instead of this reimplementation.
|
||||||
|
*/
|
||||||
|
#if ! defined(__amigaos4__)
|
||||||
|
if (SysBase->LibNode.lib_Version >= 39)
|
||||||
|
{
|
||||||
|
return CreatePool(memory_flags, puddle_size, threshold_size);
|
||||||
|
}
|
||||||
|
#endif /* ! defined(__amigaos4__) */
|
||||||
|
|
||||||
|
/* The threshold size must be less than or equal
|
||||||
|
* to the puddle size.
|
||||||
|
*/
|
||||||
|
if (threshold_size > puddle_size)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Round up the puddle size to the size of a
|
||||||
|
* memory block, as managed by Allocate().
|
||||||
|
*
|
||||||
|
* Note: no overflow checking is performed!
|
||||||
|
*/
|
||||||
|
puddle_size = (puddle_size + MEM_BLOCKMASK) & ~MEM_BLOCKMASK;
|
||||||
|
|
||||||
|
mp = AllocMem(sizeof(*mp), MEMF_ANY);
|
||||||
|
if (mp == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
NewList((struct List *)&mp->mp_PuddleMinList);
|
||||||
|
|
||||||
|
mp->mp_MemoryFlags = memory_flags;
|
||||||
|
mp->mp_PuddleSize = puddle_size;
|
||||||
|
mp->mp_PuddleSizeThreshold = threshold_size;
|
||||||
|
|
||||||
|
result = mp;
|
||||||
|
mp = NULL;
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
if (mp != NULL)
|
||||||
|
LibDeletePool(mp);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Creates a new puddle from which memory allocations up to a certain size
|
||||||
|
* will be made. Returns the new puddle or NULL for failure.
|
||||||
|
*
|
||||||
|
* Note: No overflow testing is performed when allocating the puddle.
|
||||||
|
*/
|
||||||
|
static union PuddleUnion * create_new_puddle(struct MemoryPool * mp)
|
||||||
|
{
|
||||||
|
ULONG memory_flags = mp->mp_MemoryFlags;
|
||||||
|
ULONG puddle_size = mp->mp_PuddleSize;
|
||||||
|
union PuddleUnion * result = NULL;
|
||||||
|
union PuddleUnion * pu;
|
||||||
|
struct MemHeader * mh;
|
||||||
|
struct MemChunk * mc;
|
||||||
|
|
||||||
|
/* The extra sizeof(APTR) is needed for aligning the
|
||||||
|
* allocatable memory chunks within the memory header.
|
||||||
|
*
|
||||||
|
* Note: no overflow checking is performed!
|
||||||
|
*
|
||||||
|
* Also note that the original memory allocation flags are
|
||||||
|
* being used, which may include MEMF_CLEAR. This means that
|
||||||
|
* if MEMF_CLEAR is set, the initial allocation will be
|
||||||
|
* cleared and then the individual puddle allocations made
|
||||||
|
* through LibAllocPooled() will be cleared, too.
|
||||||
|
*/
|
||||||
|
pu = alloc_vec(sizeof(pu->pu_MemHeader) + sizeof(LONG) + puddle_size, memory_flags);
|
||||||
|
if (pu == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
mh = &pu->pu_MemHeader;
|
||||||
|
|
||||||
|
/* The first allocatable memory chunk follows the memory header
|
||||||
|
* and must be aligned to a 64 bit address. This happens to be
|
||||||
|
* the smallest allocatable memory unit (MEM_BLOCKSIZE == 8).
|
||||||
|
*/
|
||||||
|
mc = (struct MemChunk *)(((ULONG)&mh[1] + sizeof(LONG)) & ~MEM_BLOCKMASK);
|
||||||
|
|
||||||
|
mc->mc_Next = NULL;
|
||||||
|
mc->mc_Bytes = puddle_size;
|
||||||
|
|
||||||
|
/* Both ln_Type and ln_Pri must be non-zero! This allows them to
|
||||||
|
* be identified as small puddles as compared to the large puddles
|
||||||
|
* which have the la_Signature member set to IS_LARGE_ALLOCATION.
|
||||||
|
* The 'struct Node' which introduces the 'struct MemHeader'
|
||||||
|
* overlaps the 'struct LargeAllocation' in the Node.ln_Type/ln_Pri
|
||||||
|
* fields. This is why the test for la_Signature == IS_LARGE_ALLOCATION
|
||||||
|
* works.
|
||||||
|
*/
|
||||||
|
mh->mh_Node.ln_Type = NT_MEMORY;
|
||||||
|
mh->mh_Node.ln_Pri = mh->mh_Node.ln_Type;
|
||||||
|
|
||||||
|
mh->mh_Node.ln_Name = (char *)&"\0Pool"[1]; /* The memory name must be an odd address. */
|
||||||
|
mh->mh_Attributes = memory_flags;
|
||||||
|
mh->mh_First = mc;
|
||||||
|
mh->mh_Lower = mc;
|
||||||
|
mh->mh_Upper = &((BYTE *)mc)[puddle_size];
|
||||||
|
mh->mh_Free = puddle_size;
|
||||||
|
|
||||||
|
/* Puddles are always added at the head of the list. */
|
||||||
|
AddHead((struct List *)&mp->mp_PuddleMinList, &pu->pu_Node);
|
||||||
|
|
||||||
|
result = pu;
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Note: No overflow testing is performed when making a large allocation. */
|
||||||
|
APTR LibAllocPooled(APTR pool, ULONG mem_size)
|
||||||
|
{
|
||||||
|
struct MemoryPool * mp;
|
||||||
|
union PuddleUnion * pu;
|
||||||
|
APTR result = NULL;
|
||||||
|
|
||||||
|
/* If possible, use the operating system implementation
|
||||||
|
* instead of this reimplementation.
|
||||||
|
*/
|
||||||
|
#if ! defined(__amigaos4__)
|
||||||
|
if (SysBase->LibNode.lib_Version >= 39)
|
||||||
|
{
|
||||||
|
return AllocPooled(pool, mem_size);
|
||||||
|
}
|
||||||
|
#endif /* ! defined(__amigaos4__) */
|
||||||
|
|
||||||
|
/* No pool or no memory to allocate? */
|
||||||
|
if (pool == NULL || mem_size == 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
mp = pool;
|
||||||
|
|
||||||
|
/* Requested allocation size is still within the threshold limit? */
|
||||||
|
if (mem_size <= mp->mp_PuddleSizeThreshold)
|
||||||
|
{
|
||||||
|
/* Search for the first puddle from which memory may be
|
||||||
|
* allocated. If no such puddle exists, it will have
|
||||||
|
* to be created. Instead of puddles we might end up
|
||||||
|
* finding a large memory allocation instead. This is
|
||||||
|
* also an indication that a new puddle will have to
|
||||||
|
* be created.
|
||||||
|
*/
|
||||||
|
pu = (union PuddleUnion *)mp->mp_PuddleMinList.mlh_Head;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* We just reached the end of the puddle list or this
|
||||||
|
* is a large allocation? We can't use an existing puddle to
|
||||||
|
* allocate memory, so we have to make a new one.
|
||||||
|
*/
|
||||||
|
if (pu->pu_Node.ln_Succ == NULL || pu->pu_LargeAllocation.la_Signature == IS_LARGE_ALLOCATION)
|
||||||
|
{
|
||||||
|
/* We need to create another puddle, which is added to
|
||||||
|
* the head of the list. Then the search for allocatable
|
||||||
|
* memory in the puddle list will resume there.
|
||||||
|
*/
|
||||||
|
pu = create_new_puddle(mp);
|
||||||
|
if (pu == NULL)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to allocate memory from this puddle.*/
|
||||||
|
result = Allocate(&pu->pu_MemHeader, mem_size);
|
||||||
|
if (result != NULL)
|
||||||
|
{
|
||||||
|
/* If the allocation needs to be zeroed, clear
|
||||||
|
* the entire allocated memory which Allocate()
|
||||||
|
* returned. It's been rounded up to be a
|
||||||
|
* multiple of MEM_BLOCKSIZE.
|
||||||
|
*
|
||||||
|
* Note that the puddle will have been allocated
|
||||||
|
* with MEMF_CLEAR already, which does not render
|
||||||
|
* the following memset() call redundant, but
|
||||||
|
* making the initial puddle allocation use
|
||||||
|
* MEMF_CLEAR is definitely redundant.
|
||||||
|
*/
|
||||||
|
if ((mp->mp_MemoryFlags & MEMF_CLEAR) != 0)
|
||||||
|
memset(result, 0, (mem_size + MEM_BLOCKMASK) & ~MEM_BLOCKMASK);
|
||||||
|
|
||||||
|
/* And we're good. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try the next puddle on the list. */
|
||||||
|
pu = (union PuddleUnion *)pu->pu_Node.ln_Succ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* No, we need to allocate this memory chunk separately. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct LargeAllocation * la;
|
||||||
|
|
||||||
|
/* Note: no overflow checking is performed! */
|
||||||
|
pu = alloc_vec(sizeof(pu->pu_LargeAllocation) + mem_size, mp->mp_MemoryFlags);
|
||||||
|
if (pu == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* This identifies it as a separate large allocation. */
|
||||||
|
pu->pu_LargeAllocation.la_Signature = IS_LARGE_ALLOCATION;
|
||||||
|
|
||||||
|
/* The separate large allocations are stored near the end
|
||||||
|
* of the list. The puddles are always stored at the beginning
|
||||||
|
* of the list.
|
||||||
|
*/
|
||||||
|
AddTail((struct List *)&mp->mp_PuddleMinList, &pu->pu_Node);
|
||||||
|
|
||||||
|
la = &pu->pu_LargeAllocation;
|
||||||
|
|
||||||
|
result = &la[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Note: The size of the allocation to free must match
|
||||||
|
* exactly or memory will remain unfreed. Furthermore,
|
||||||
|
* the wrong allocation size may lead to general
|
||||||
|
* memory corruption.
|
||||||
|
*/
|
||||||
|
VOID LibFreePooled(APTR pool, APTR memory, ULONG size)
|
||||||
|
{
|
||||||
|
/* If possible, use the operating system implementation
|
||||||
|
* instead of this reimplementation.
|
||||||
|
*/
|
||||||
|
#if ! defined(__amigaos4__)
|
||||||
|
if (SysBase->LibNode.lib_Version >= 39)
|
||||||
|
{
|
||||||
|
FreePooled(pool, memory, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* ! defined(__amigaos4__) */
|
||||||
|
|
||||||
|
if (pool != NULL && memory != NULL)
|
||||||
|
{
|
||||||
|
struct MemoryPool * mp = pool;
|
||||||
|
|
||||||
|
/* This allocation was made from a puddle? */
|
||||||
|
if (size <= mp->mp_PuddleSizeThreshold)
|
||||||
|
{
|
||||||
|
union PuddleUnion * pu_deallocation = NULL;
|
||||||
|
union PuddleUnion * pu;
|
||||||
|
|
||||||
|
/* Try to find the puddle which contains this
|
||||||
|
* allocation.
|
||||||
|
*/
|
||||||
|
for (pu = (union PuddleUnion *)mp->mp_PuddleMinList.mlh_Head ;
|
||||||
|
pu->pu_Node.ln_Succ != NULL ;
|
||||||
|
pu = (union PuddleUnion *)pu->pu_Node.ln_Succ)
|
||||||
|
{
|
||||||
|
/* Did we reach the end of the puddle list? Then
|
||||||
|
* the given memory address and/or size may be
|
||||||
|
* invalid...
|
||||||
|
*/
|
||||||
|
if (pu->pu_LargeAllocation.la_Signature == IS_LARGE_ALLOCATION)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Is this the memory header which contains the
|
||||||
|
* memory allocation?
|
||||||
|
*/
|
||||||
|
if (pu->pu_MemHeader.mh_Lower <= memory && memory < pu->pu_MemHeader.mh_Upper)
|
||||||
|
{
|
||||||
|
/* Free the allocation and remember where it
|
||||||
|
* came from. We will make use of this below to
|
||||||
|
* free now unused puddles.
|
||||||
|
*/
|
||||||
|
Deallocate(&pu->pu_MemHeader, memory, size);
|
||||||
|
|
||||||
|
pu_deallocation = pu;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Did we succeed in releasing this memory allocation? */
|
||||||
|
if (pu_deallocation != NULL)
|
||||||
|
{
|
||||||
|
APTR upper;
|
||||||
|
|
||||||
|
/* The more frequently memory is freed from a
|
||||||
|
* specific puddle, the easier it should become
|
||||||
|
* to find it on the list again. We try to move it
|
||||||
|
* closer to the beginning of the list unless it
|
||||||
|
* is already at the head of the list.
|
||||||
|
*/
|
||||||
|
if (mp->mp_PuddleMinList.mlh_Head != (struct MinNode *)pu)
|
||||||
|
{
|
||||||
|
/* This puddle precedes the one from which we
|
||||||
|
* just released an allocation.
|
||||||
|
*/
|
||||||
|
struct Node * pred = pu->pu_Node.ln_Pred;
|
||||||
|
struct Node * before;
|
||||||
|
|
||||||
|
/* Put this puddle at the head of the list? */
|
||||||
|
if (pred == (struct Node *)mp->mp_PuddleMinList.mlh_Head)
|
||||||
|
before = NULL;
|
||||||
|
/* No, insert it in front of its predecessor. */
|
||||||
|
else
|
||||||
|
before = pred->ln_Pred;
|
||||||
|
|
||||||
|
Remove(&pu->pu_Node);
|
||||||
|
Insert((struct List *)&mp->mp_PuddleMinList, &pu->pu_Node, before);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Has this puddle been emptied? */
|
||||||
|
upper = &((BYTE *)pu->pu_MemHeader.mh_Lower)[pu->pu_MemHeader.mh_Free];
|
||||||
|
if (upper == pu->pu_MemHeader.mh_Upper)
|
||||||
|
{
|
||||||
|
/* Then we may remove and free it now. */
|
||||||
|
Remove(&pu->pu_Node);
|
||||||
|
|
||||||
|
free_vec(pu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Something's wrong :-( */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Alert(AN_BadFreeAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* No, this is a large allocation which must be freed as it is. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct LargeAllocation * la = &((struct LargeAllocation *)memory)[-1];
|
||||||
|
|
||||||
|
Remove((struct Node *)&la->la_MinNode);
|
||||||
|
|
||||||
|
free_vec(la);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 215
|
#define REVISION 217
|
||||||
#define DATE "26.6.2017"
|
#define DATE "10.7.2025"
|
||||||
#define VERS "c.lib 1.215"
|
#define VERS "c.lib 1.217"
|
||||||
#define VSTRING "c.lib 1.215 (26.6.2017)\r\n"
|
#define VSTRING "c.lib 1.217 (10.7.2025)\r\n"
|
||||||
#define VERSTAG "\0$VER: c.lib 1.215 (26.6.2017)"
|
#define VERSTAG "\0$VER: c.lib 1.217 (10.7.2025)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
215
|
217
|
||||||
|
|||||||
139
library/changes
139
library/changes
@ -1,6 +1,139 @@
|
|||||||
|
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)
|
c.lib 1.216 (xxx)
|
||||||
|
|
||||||
- Add some wchar and multbyte-string related functions to allow gcc
|
- Add some wchar and multibyte-string related functions to allow gcc
|
||||||
building a libstdc++ library with wide char support. For now, the
|
building a libstdc++ library with wide char support. For now, the
|
||||||
functions are mostly stub ones only. They can be implemented on
|
functions are mostly stub ones only. They can be implemented on
|
||||||
demand.
|
demand.
|
||||||
@ -177,7 +310,7 @@ c.lib 1.206 (24.4.2015)
|
|||||||
|
|
||||||
- Removed the remains of all the stack extension and stack overflow/underflow
|
- Removed the remains of all the stack extension and stack overflow/underflow
|
||||||
checking code. It never actually worked. The bit that does work is the stack
|
checking code. It never actually worked. The bit that does work is the stack
|
||||||
usage measurement code, plus the bit that sets up the the custom stack
|
usage measurement code, plus the bit that sets up the custom stack
|
||||||
according to local setting or by calling a query function.
|
according to local setting or by calling a query function.
|
||||||
|
|
||||||
|
|
||||||
@ -1355,7 +1488,7 @@ c.lib 1.187 (29.1.2005)
|
|||||||
adding/subtracting the local time zone.
|
adding/subtracting the local time zone.
|
||||||
|
|
||||||
- Changed the algorithm that calculates the number of days that have passed
|
- Changed the algorithm that calculates the number of days that have passed
|
||||||
so far as used by the the __convert_time() function and the conversion
|
so far as used by the __convert_time() function and the conversion
|
||||||
code in strftime().
|
code in strftime().
|
||||||
|
|
||||||
- Also changed the algorithm used by strftime() to produce the week numbers
|
- Also changed the algorithm used by strftime() to produce the week numbers
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: dirent_readdir.c,v 1.10 2006-09-25 14:51:15 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -79,9 +77,11 @@ readdir(DIR * directory_pointer)
|
|||||||
|
|
||||||
dh->dh_Position++;
|
dh->dh_Position++;
|
||||||
|
|
||||||
dh->dh_DirectoryEntry.d_ino = 0;
|
|
||||||
strcpy(dh->dh_DirectoryEntry.d_name,".");
|
strcpy(dh->dh_DirectoryEntry.d_name,".");
|
||||||
|
|
||||||
|
dh->dh_DirectoryEntry.d_ino = 0;
|
||||||
|
dh->dh_DirectoryEntry.d_type = DT_DIR;
|
||||||
|
|
||||||
result = &dh->dh_DirectoryEntry;
|
result = &dh->dh_DirectoryEntry;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -115,8 +115,9 @@ readdir(DIR * directory_pointer)
|
|||||||
assert( sizeof(dh->dh_DirectoryEntry.d_name) >= sizeof(fib->fib_FileName) );
|
assert( sizeof(dh->dh_DirectoryEntry.d_name) >= sizeof(fib->fib_FileName) );
|
||||||
|
|
||||||
strcpy(dh->dh_DirectoryEntry.d_name,fib->fib_FileName);
|
strcpy(dh->dh_DirectoryEntry.d_name,fib->fib_FileName);
|
||||||
|
|
||||||
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
|
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
|
||||||
|
dh->dh_DirectoryEntry.d_type = DT_DIR;
|
||||||
|
|
||||||
result = &dh->dh_DirectoryEntry;
|
result = &dh->dh_DirectoryEntry;
|
||||||
}
|
}
|
||||||
@ -147,10 +148,11 @@ readdir(DIR * directory_pointer)
|
|||||||
|
|
||||||
dh->dh_Position++;
|
dh->dh_Position++;
|
||||||
|
|
||||||
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
|
|
||||||
|
|
||||||
strcpy(dh->dh_DirectoryEntry.d_name,".");
|
strcpy(dh->dh_DirectoryEntry.d_name,".");
|
||||||
|
|
||||||
|
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
|
||||||
|
dh->dh_DirectoryEntry.d_type = DT_DIR;
|
||||||
|
|
||||||
result = &dh->dh_DirectoryEntry;
|
result = &dh->dh_DirectoryEntry;
|
||||||
}
|
}
|
||||||
else if (dh->dh_Position == 1)
|
else if (dh->dh_Position == 1)
|
||||||
@ -176,10 +178,11 @@ readdir(DIR * directory_pointer)
|
|||||||
|
|
||||||
SHOWMSG("returning ..");
|
SHOWMSG("returning ..");
|
||||||
|
|
||||||
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
|
|
||||||
|
|
||||||
strcpy(dh->dh_DirectoryEntry.d_name,"..");
|
strcpy(dh->dh_DirectoryEntry.d_name,"..");
|
||||||
|
|
||||||
|
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
|
||||||
|
dh->dh_DirectoryEntry.d_type = DT_DIR;
|
||||||
|
|
||||||
result = &dh->dh_DirectoryEntry;
|
result = &dh->dh_DirectoryEntry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,12 +195,23 @@ readdir(DIR * directory_pointer)
|
|||||||
|
|
||||||
if(ExNext(dh->dh_DirLock,&dh->dh_FileInfo))
|
if(ExNext(dh->dh_DirLock,&dh->dh_FileInfo))
|
||||||
{
|
{
|
||||||
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
|
int type;
|
||||||
|
|
||||||
assert( sizeof(dh->dh_DirectoryEntry.d_name) >= sizeof(dh->dh_FileInfo.fib_FileName) );
|
assert( sizeof(dh->dh_DirectoryEntry.d_name) >= sizeof(dh->dh_FileInfo.fib_FileName) );
|
||||||
|
|
||||||
strcpy(dh->dh_DirectoryEntry.d_name,dh->dh_FileInfo.fib_FileName);
|
strcpy(dh->dh_DirectoryEntry.d_name,dh->dh_FileInfo.fib_FileName);
|
||||||
|
|
||||||
|
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
|
||||||
|
|
||||||
|
if (dh->dh_FileInfo.fib_DirEntryType == ST_SOFTLINK)
|
||||||
|
type = DT_LNK;
|
||||||
|
else if (dh->dh_FileInfo.fib_DirEntryType < 0)
|
||||||
|
type = DT_REG;
|
||||||
|
else
|
||||||
|
type = DT_DIR;
|
||||||
|
|
||||||
|
dh->dh_DirectoryEntry.d_type = type;
|
||||||
|
|
||||||
result = &dh->dh_DirectoryEntry;
|
result = &dh->dh_DirectoryEntry;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: dirent.h,v 1.7 2006-01-08 12:06:14 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -71,12 +69,41 @@ typedef long DIR;
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* The POSIX requirements for the 'struct dirent' cover little more than
|
||||||
|
* the 'd_ino' and 'd_name' fields. Because it is useful, the 'd_type'
|
||||||
|
* field identifies the type of object in question. This was added with
|
||||||
|
* clib2 1.217 (10.7.2025), and you can find out if the 'd_type' field
|
||||||
|
* is available in the 'struct dirent' by checking if the
|
||||||
|
* _DIRENT_HAVE_D_TYPE macro is defined.
|
||||||
|
*/
|
||||||
struct dirent
|
struct dirent
|
||||||
{
|
{
|
||||||
ino_t d_ino;
|
ino_t d_ino;
|
||||||
char d_name[NAME_MAX+1];
|
char d_name[NAME_MAX+1];
|
||||||
|
int d_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define _DIRENT_HAVE_D_TYPE
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Note that the directory entry type is not a POSIX feature, but it will
|
||||||
|
* make life easier for porting code which expects the 'd_type' structure
|
||||||
|
* member in the 'struct dirent'.
|
||||||
|
*
|
||||||
|
* The following types are not all supported on the Amiga. For the time being,
|
||||||
|
* DT_DIR (directory), DT_REG (regular file) and DT_LNK (soft link) should make
|
||||||
|
* sense.
|
||||||
|
*/
|
||||||
|
#define DT_UNKNOWN 0
|
||||||
|
#define DT_FIFO 1
|
||||||
|
#define DT_CHR 2
|
||||||
|
#define DT_DIR 4
|
||||||
|
#define DT_BLK 6
|
||||||
|
#define DT_REG 8
|
||||||
|
#define DT_LNK 10
|
||||||
|
#define DT_SOCK 12
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
extern DIR * opendir(const char * path_name);
|
extern DIR * opendir(const char * path_name);
|
||||||
|
|||||||
@ -166,6 +166,8 @@ extern int errno;
|
|||||||
|
|
||||||
#define EILSEQ 85 /* Encoding error detected */
|
#define EILSEQ 85 /* Encoding error detected */
|
||||||
|
|
||||||
|
#define ENOTSUP 86 /* Not supported */
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: locale.h,v 1.5 2006-01-08 12:06:14 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -59,7 +57,10 @@ extern "C" {
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
typedef void *locale_t;
|
/* Forward declaration */
|
||||||
|
struct __locale_t;
|
||||||
|
|
||||||
|
typedef struct __locale_t *locale_t;
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
|||||||
@ -369,7 +369,7 @@ void __get_slab_allocations(__slab_allocation_callback callback);
|
|||||||
* You supply a function which will be called for each line of the JSON
|
* You supply a function which will be called for each line of the JSON
|
||||||
* data produced. You can store this data in a file, or in the clipboard,
|
* data produced. You can store this data in a file, or in the clipboard,
|
||||||
* for later use. Your function must return 0 if it wants to be called
|
* for later use. Your function must return 0 if it wants to be called
|
||||||
* again, or return -1 if it wants to stop (e.g. if an error occured
|
* again, or return -1 if it wants to stop (e.g. if an error occurred
|
||||||
* when writing the JSON data to disk). The same "user_data" pointer which
|
* when writing the JSON data to disk). The same "user_data" pointer which
|
||||||
* you pass to __get_slab_stats() will be passed to your callback function.
|
* you pass to __get_slab_stats() will be passed to your callback function.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -117,7 +117,7 @@ extern int readlink(const char * path_name, char * buffer, int buffer_size);
|
|||||||
extern int chdir(const char * path_name);
|
extern int chdir(const char * path_name);
|
||||||
extern int lockf(int file_descriptor, int function, off_t size);
|
extern int lockf(int file_descriptor, int function, off_t size);
|
||||||
extern unsigned int sleep(unsigned int seconds);
|
extern unsigned int sleep(unsigned int seconds);
|
||||||
extern void usleep(unsigned long microseconds);
|
extern int usleep(unsigned long microseconds);
|
||||||
extern int getopt(int argc, char * const argv[], const char *opts);
|
extern int getopt(int argc, char * const argv[], const char *opts);
|
||||||
extern pid_t getpid(void);
|
extern pid_t getpid(void);
|
||||||
extern char *realpath(const char *file_name, char *resolved_name);
|
extern char *realpath(const char *file_name, char *resolved_name);
|
||||||
|
|||||||
@ -46,6 +46,7 @@ AMIGA_LIB = \
|
|||||||
amiga_hotkey.o \
|
amiga_hotkey.o \
|
||||||
amiga_invertstring.o \
|
amiga_invertstring.o \
|
||||||
amiga_newlist.o \
|
amiga_newlist.o \
|
||||||
|
amiga_pools.o \
|
||||||
amiga_rangerand.o \
|
amiga_rangerand.o \
|
||||||
amiga_remtof.o \
|
amiga_remtof.o \
|
||||||
amiga_rexxvars.o \
|
amiga_rexxvars.o \
|
||||||
|
|||||||
@ -19,6 +19,10 @@ LIBS += \
|
|||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
# Olaf (2019-08-22): Please note that "profile_profil.o" can no longer
|
||||||
|
# be built, presumably for lack of header files needed
|
||||||
|
# to build it properly.
|
||||||
|
|
||||||
C_LIB := \
|
C_LIB := \
|
||||||
c.lib_rev.o \
|
c.lib_rev.o \
|
||||||
ctype_isalnum.o \
|
ctype_isalnum.o \
|
||||||
@ -66,7 +70,6 @@ C_LIB := \
|
|||||||
mount_convertinfo.o \
|
mount_convertinfo.o \
|
||||||
mount_fstatfs.o \
|
mount_fstatfs.o \
|
||||||
mount_statfs.o \
|
mount_statfs.o \
|
||||||
profile_profil.o \
|
|
||||||
signal_checkabort.o \
|
signal_checkabort.o \
|
||||||
signal_data.o \
|
signal_data.o \
|
||||||
signal_kill.o \
|
signal_kill.o \
|
||||||
|
|||||||
@ -22,13 +22,13 @@ LIBS += \
|
|||||||
UNIX_LIB := \
|
UNIX_LIB := \
|
||||||
unix.lib_rev.o \
|
unix.lib_rev.o \
|
||||||
dirent_closedir.o \
|
dirent_closedir.o \
|
||||||
dirent_rewinddir.o \
|
|
||||||
dirent_opendir.o \
|
dirent_opendir.o \
|
||||||
dirent_readdir.o \
|
dirent_readdir.o \
|
||||||
|
dirent_rewinddir.o \
|
||||||
fcntl_creat.o \
|
fcntl_creat.o \
|
||||||
fcntl_fcntl.o \
|
fcntl_fcntl.o \
|
||||||
fcntl_open.o \
|
|
||||||
fcntl_get_default_file.o \
|
fcntl_get_default_file.o \
|
||||||
|
fcntl_open.o \
|
||||||
getopt_getopt_long.o \
|
getopt_getopt_long.o \
|
||||||
mount_convertinfo.o \
|
mount_convertinfo.o \
|
||||||
mount_statfs.o \
|
mount_statfs.o \
|
||||||
@ -36,16 +36,16 @@ UNIX_LIB := \
|
|||||||
resource_setrlimit.o \
|
resource_setrlimit.o \
|
||||||
stat_chmod.o \
|
stat_chmod.o \
|
||||||
stat_fstat.o \
|
stat_fstat.o \
|
||||||
stat_lstat.o \
|
|
||||||
stat_lock.o \
|
stat_lock.o \
|
||||||
|
stat_lstat.o \
|
||||||
stat_mkdir.o \
|
stat_mkdir.o \
|
||||||
stat_rmdir.o \
|
stat_rmdir.o \
|
||||||
stat_stat.o \
|
stat_stat.o \
|
||||||
stdio_ctermid.o \
|
stdio_ctermid.o \
|
||||||
stdio_fdhookentry.o \
|
stdio_fdhookentry.o \
|
||||||
stdio_fflush.o \
|
stdio_fflush.o \
|
||||||
stdio_fopen.o \
|
|
||||||
stdio_file_init.o \
|
stdio_file_init.o \
|
||||||
|
stdio_fopen.o \
|
||||||
stdio_init_exit.o \
|
stdio_init_exit.o \
|
||||||
stdio_locksemaphorename.o \
|
stdio_locksemaphorename.o \
|
||||||
stdio_openiob.o \
|
stdio_openiob.o \
|
||||||
@ -60,15 +60,17 @@ UNIX_LIB := \
|
|||||||
stdlib_dlopen.o \
|
stdlib_dlopen.o \
|
||||||
stdlib_expand_wildcard.o \
|
stdlib_expand_wildcard.o \
|
||||||
stdlib_expand_wildcard_check.o \
|
stdlib_expand_wildcard_check.o \
|
||||||
|
stdlib_free.o \
|
||||||
stdlib_getmemstats.o \
|
stdlib_getmemstats.o \
|
||||||
stdlib_main.o \
|
stdlib_main.o \
|
||||||
stdlib_main_stub.o \
|
stdlib_main_stub.o \
|
||||||
|
stdlib_malloc.o \
|
||||||
stdlib_mkdtemp.o \
|
stdlib_mkdtemp.o \
|
||||||
stdlib_mkstemp.o \
|
stdlib_mkstemp.o \
|
||||||
stdlib_mktemp.o \
|
stdlib_mktemp.o \
|
||||||
stdlib_malloc.o \
|
|
||||||
stdlib_realloc.o \
|
stdlib_realloc.o \
|
||||||
stdlib_resetmemstats.o \
|
stdlib_resetmemstats.o \
|
||||||
|
stdlib_slab.o \
|
||||||
stdlib_system.o \
|
stdlib_system.o \
|
||||||
systeminfo_sysinfo.o \
|
systeminfo_sysinfo.o \
|
||||||
termios_cfgetispeed.o \
|
termios_cfgetispeed.o \
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: math_sqrt.c,v 1.9 2006-09-22 07:54:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -251,7 +249,8 @@ sqrt(double x)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = 0;
|
result = NAN;
|
||||||
|
|
||||||
__set_errno(EDOM);
|
__set_errno(EDOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: math_tgamma.c,v 1.3 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -54,13 +52,11 @@ double
|
|||||||
tgamma(double x)
|
tgamma(double x)
|
||||||
{
|
{
|
||||||
int gamma_sign;
|
int gamma_sign;
|
||||||
double y;
|
double y;
|
||||||
|
|
||||||
y = __lgamma(x,&gamma_sign);
|
y = __lgamma(x, &gamma_sign);
|
||||||
if (gamma_sign < 0)
|
|
||||||
y = -y;
|
|
||||||
|
|
||||||
return y;
|
return gamma_sign * exp(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: math_tgammaf.c,v 1.3 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
@ -56,11 +54,9 @@ tgammaf(float x)
|
|||||||
int gamma_sign;
|
int gamma_sign;
|
||||||
float y;
|
float y;
|
||||||
|
|
||||||
y = __lgammaf(x,&gamma_sign);
|
y = __lgammaf(x, &gamma_sign);
|
||||||
if (gamma_sign < 0)
|
|
||||||
y = -y;
|
|
||||||
|
|
||||||
return y;
|
return gamma_sign * expf(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
@ -71,7 +71,7 @@ raise(int sig)
|
|||||||
assert( SIGABRT <= sig && sig <= SIGTERM );
|
assert( SIGABRT <= sig && sig <= SIGTERM );
|
||||||
|
|
||||||
/* This has to be a well-known and supported signal. */
|
/* This has to be a well-known and supported signal. */
|
||||||
if(sig < SIGABRT || sig > SIGTERM)
|
if (sig < SIGABRT || sig > SIGTERM)
|
||||||
{
|
{
|
||||||
SHOWMSG("unknown signal number");
|
SHOWMSG("unknown signal number");
|
||||||
|
|
||||||
@ -80,48 +80,49 @@ raise(int sig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Can we deliver the signal? */
|
/* Can we deliver the signal? */
|
||||||
if(FLAG_IS_CLEAR(__signals_blocked, (1 << sig)) &&
|
if (FLAG_IS_CLEAR(__signals_blocked, (1 << sig)) &&
|
||||||
FLAG_IS_CLEAR(local_signals_blocked, (1 << sig)))
|
FLAG_IS_CLEAR(local_signals_blocked, (1 << sig)))
|
||||||
{
|
{
|
||||||
signal_handler_t handler;
|
signal_handler_t handler;
|
||||||
|
|
||||||
/* Which handler is installed for this signal? */
|
/* Which handler is installed for this signal? */
|
||||||
handler = __signal_handler_table[sig - SIGABRT];
|
handler = __signal_handler_table[sig - SIGABRT];
|
||||||
|
|
||||||
/* Should we ignore this signal? */
|
/* Should we handle this signal rather than ignoring it? */
|
||||||
if(handler != SIG_IGN)
|
if (handler != SIG_IGN)
|
||||||
{
|
{
|
||||||
/* Block delivery of this signal to prevent recursion. */
|
/* Block delivery of this signal to prevent recursion. */
|
||||||
SET_FLAG(local_signals_blocked,(1 << sig));
|
SET_FLAG(local_signals_blocked, (1 << sig));
|
||||||
|
|
||||||
/* The default behaviour is to drop into abort(), or do
|
/* The default behaviour is to drop into abort(), or do
|
||||||
something very much like it. */
|
* something very much like it.
|
||||||
if(handler == SIG_DFL)
|
*/
|
||||||
|
if (handler == SIG_DFL)
|
||||||
{
|
{
|
||||||
SHOWMSG("this is the default handler");
|
SHOWMSG("this is the default handler");
|
||||||
|
|
||||||
if(sig == SIGINT)
|
if (sig == SIGINT)
|
||||||
{
|
{
|
||||||
char break_string[80];
|
char break_string[80];
|
||||||
|
|
||||||
/* Turn off ^C checking for good. */
|
/* Turn off ^C checking for good. */
|
||||||
__check_abort_enabled = FALSE;
|
__check_abort_enabled = FALSE;
|
||||||
|
|
||||||
Fault(ERROR_BREAK,NULL,break_string,(LONG)sizeof(break_string));
|
Fault(ERROR_BREAK, NULL, break_string, (LONG)sizeof(break_string));
|
||||||
|
|
||||||
__print_termination_message(break_string);
|
__print_termination_message(break_string);
|
||||||
|
|
||||||
SHOWMSG("bye, bye...");
|
SHOWMSG("bye, bye...");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop straight into abort(), which might call signal()
|
/* Drop straight into __abort(), which will
|
||||||
again but is otherwise guaranteed to eventually
|
eventually land us in _exit(). Note that
|
||||||
land us in _exit(). */
|
abort() calls raise(SIGABRT). */
|
||||||
abort();
|
__abort();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SHOWMSG("calling the handler");
|
SHOWMSG("calling the signal handler");
|
||||||
|
|
||||||
(*handler)(sig);
|
(*handler)(sig);
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ raise(int sig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Unblock signal delivery again. */
|
/* Unblock signal delivery again. */
|
||||||
CLEAR_FLAG(local_signals_blocked,(1 << sig));
|
CLEAR_FLAG(local_signals_blocked, (1 << sig));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_fgets.c,v 1.6 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -46,6 +44,7 @@
|
|||||||
char *
|
char *
|
||||||
fgets(char *s,int n,FILE *stream)
|
fgets(char *s,int n,FILE *stream)
|
||||||
{
|
{
|
||||||
|
struct iob * file = (struct iob *)stream;
|
||||||
char * result = s;
|
char * result = s;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
@ -57,14 +56,14 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
|
|
||||||
assert( s != NULL && stream != NULL );
|
assert( s != NULL && stream != NULL );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
flockfile(stream);
|
flockfile(stream);
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(s == NULL || stream == NULL)
|
if (s == NULL || stream == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("invalid parameters");
|
SHOWMSG("invalid parameters");
|
||||||
|
|
||||||
@ -75,7 +74,7 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
}
|
}
|
||||||
#endif /* CHECK_FOR_NULL_POINTERS */
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||||
|
|
||||||
if(n <= 0)
|
if (n <= 0)
|
||||||
{
|
{
|
||||||
SHOWMSG("no work to be done");
|
SHOWMSG("no work to be done");
|
||||||
|
|
||||||
@ -86,7 +85,7 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
/* Take care of the checks and data structure changes that
|
/* Take care of the checks and data structure changes that
|
||||||
* need to be handled only once for this stream.
|
* need to be handled only once for this stream.
|
||||||
*/
|
*/
|
||||||
if(__fgetc_check(stream) < 0)
|
if (__fgetc_check(stream) < 0)
|
||||||
{
|
{
|
||||||
result = NULL;
|
result = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
@ -98,12 +97,83 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
/* One off for the terminating '\0'. */
|
/* One off for the terminating '\0'. */
|
||||||
n--;
|
n--;
|
||||||
|
|
||||||
while(n-- > 0)
|
assert( 0 <= file->iob_BufferReadBytes );
|
||||||
|
assert( file->iob_BufferReadBytes <= file->iob_BufferSize );
|
||||||
|
assert( file->iob_BufferPosition <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
while (n > 0)
|
||||||
{
|
{
|
||||||
c = __getc(stream);
|
/* If there is data in the buffer, try to copy it directly
|
||||||
if(c == EOF)
|
* into the string buffer. If there is a line feed in the
|
||||||
|
* buffer, too, try to conclude the read operation.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferPosition < file->iob_BufferReadBytes)
|
||||||
{
|
{
|
||||||
if(ferror(stream))
|
const unsigned char * buffer = &file->iob_Buffer[file->iob_BufferPosition];
|
||||||
|
size_t num_bytes_in_buffer;
|
||||||
|
const unsigned char * lf;
|
||||||
|
|
||||||
|
/* Copy only as much data as will fit into the string buffer. */
|
||||||
|
assert( file->iob_BufferReadBytes >= file->iob_BufferPosition );
|
||||||
|
|
||||||
|
num_bytes_in_buffer = file->iob_BufferReadBytes - file->iob_BufferPosition;
|
||||||
|
if (num_bytes_in_buffer > (size_t)n)
|
||||||
|
num_bytes_in_buffer = n;
|
||||||
|
|
||||||
|
/* Try to find a line feed character which could conclude
|
||||||
|
* the read operation if the remaining buffer data, including
|
||||||
|
* the line feed character, fit into the string buffer.
|
||||||
|
*/
|
||||||
|
lf = (unsigned char *)memchr(buffer, '\n', num_bytes_in_buffer);
|
||||||
|
if(lf != NULL)
|
||||||
|
{
|
||||||
|
size_t num_characters_in_line = lf + 1 - buffer;
|
||||||
|
|
||||||
|
/* Give the user a chance to abort what could otherwise
|
||||||
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
assert( num_characters_in_line <= num_bytes_in_buffer );
|
||||||
|
|
||||||
|
/* Copy the remainder of the read buffer into the
|
||||||
|
* string buffer, including the terminating line
|
||||||
|
* feed character.
|
||||||
|
*/
|
||||||
|
memmove(s, buffer, num_characters_in_line);
|
||||||
|
s += num_characters_in_line;
|
||||||
|
|
||||||
|
assert( file->iob_BufferPosition + num_characters_in_line <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferPosition += num_characters_in_line;
|
||||||
|
|
||||||
|
/* And that concludes the line read operation. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(s, buffer, num_bytes_in_buffer);
|
||||||
|
s += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
assert( file->iob_BufferPosition + num_bytes_in_buffer <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferPosition += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
/* Stop if the string buffer has been filled. */
|
||||||
|
assert( n >= num_bytes_in_buffer );
|
||||||
|
|
||||||
|
n -= num_bytes_in_buffer;
|
||||||
|
if (n == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the next buffered character; this will refill the read
|
||||||
|
* buffer, if necessary.
|
||||||
|
*/
|
||||||
|
c = __getc(stream);
|
||||||
|
if (c == EOF)
|
||||||
|
{
|
||||||
|
if (ferror(stream))
|
||||||
{
|
{
|
||||||
/* Just to be on the safe side. */
|
/* Just to be on the safe side. */
|
||||||
(*s) = '\0';
|
(*s) = '\0';
|
||||||
@ -113,8 +183,9 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that we return NULL if we really
|
/* Make sure that we return NULL if we really
|
||||||
didn't read anything at all */
|
* didn't read anything at all.
|
||||||
if(s == result)
|
*/
|
||||||
|
if (s == result)
|
||||||
result = NULL;
|
result = NULL;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -122,8 +193,11 @@ fgets(char *s,int n,FILE *stream)
|
|||||||
|
|
||||||
(*s++) = c;
|
(*s++) = c;
|
||||||
|
|
||||||
if(c == '\n')
|
if (c == '\n')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
assert( n > 0 );
|
||||||
|
n--;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*s) = '\0';
|
(*s) = '\0';
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_fputs.c,v 1.7 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -43,10 +41,12 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Both fputs() and puts() share this function. */
|
||||||
int
|
int
|
||||||
fputs(const char *s, FILE *stream)
|
__fputs(const char *s, int line_feed, FILE *stream)
|
||||||
{
|
{
|
||||||
struct iob * file = (struct iob *)stream;
|
struct iob * file = (struct iob *)stream;
|
||||||
|
size_t total_size;
|
||||||
int result = EOF;
|
int result = EOF;
|
||||||
int buffer_mode;
|
int buffer_mode;
|
||||||
int c;
|
int c;
|
||||||
@ -58,12 +58,12 @@ fputs(const char *s, FILE *stream)
|
|||||||
|
|
||||||
assert( s != NULL && stream != NULL );
|
assert( s != NULL && stream != NULL );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(s == NULL || stream == NULL)
|
if (s == NULL || stream == NULL)
|
||||||
{
|
{
|
||||||
__set_errno(EFAULT);
|
__set_errno(EFAULT);
|
||||||
goto out;
|
goto out;
|
||||||
@ -77,37 +77,261 @@ fputs(const char *s, FILE *stream)
|
|||||||
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
||||||
assert( file->iob_BufferSize > 0 );
|
assert( file->iob_BufferSize > 0 );
|
||||||
|
|
||||||
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
|
if (__fputc_check(stream) < 0)
|
||||||
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
|
|
||||||
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
|
||||||
|
|
||||||
if(__fputc_check(stream) < 0)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
while((c = (*s++)) != '\0')
|
assert( 0 <= file->iob_BufferWriteBytes );
|
||||||
|
assert( file->iob_BufferWriteBytes <= file->iob_BufferSize );
|
||||||
|
assert( file->iob_BufferPosition <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
/* We perform line buffering to improve readability of the
|
||||||
|
* buffered text if buffering was disabled and the output
|
||||||
|
* goes to an interactive stream.
|
||||||
|
*/
|
||||||
|
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
|
||||||
|
if (buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||||
{
|
{
|
||||||
if(__putc(c,stream,buffer_mode) == EOF)
|
struct fd * fd = __fd[file->iob_Descriptor];
|
||||||
goto out;
|
|
||||||
|
__fd_lock(fd);
|
||||||
|
|
||||||
|
if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE))
|
||||||
|
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
||||||
|
|
||||||
|
__fd_unlock(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
total_size = strlen(s);
|
||||||
|
if (total_size > 0)
|
||||||
|
{
|
||||||
|
if (buffer_mode == IOBF_BUFFER_MODE_LINE)
|
||||||
|
{
|
||||||
|
while (total_size > 0)
|
||||||
|
{
|
||||||
|
/* Is there still room in the write buffer to store
|
||||||
|
* more of the string?
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
|
||||||
|
size_t num_buffer_bytes;
|
||||||
|
const char * lf;
|
||||||
|
|
||||||
|
/* Give the user a chance to abort what could otherwise
|
||||||
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
/* Store only as many characters as will fit into the write buffer. */
|
||||||
|
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
|
||||||
|
if (total_size < num_buffer_bytes)
|
||||||
|
num_buffer_bytes = total_size;
|
||||||
|
|
||||||
|
/* Try to find a line feed in the string. If there is one,
|
||||||
|
* reduce the number of characters to write to the sequence
|
||||||
|
* which ends with the line feed character.
|
||||||
|
*/
|
||||||
|
lf = memchr(s, '\n', num_buffer_bytes);
|
||||||
|
if (lf != NULL)
|
||||||
|
{
|
||||||
|
assert( (size_t)(lf + 1 - s) <= num_buffer_bytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = lf + 1 - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( num_buffer_bytes > 0 );
|
||||||
|
|
||||||
|
memmove(buffer, s, num_buffer_bytes);
|
||||||
|
s += num_buffer_bytes;
|
||||||
|
|
||||||
|
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferWriteBytes += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Write the buffer to disk if it's full or contains a line feed. */
|
||||||
|
if ((lf != NULL || __iob_write_buffer_is_full(file)) && __flush_iob_write_buffer(file) < 0)
|
||||||
|
{
|
||||||
|
/* Abort with error. */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stop as soon as no further data needs to be written. */
|
||||||
|
assert( total_size >= num_buffer_bytes );
|
||||||
|
|
||||||
|
total_size -= num_buffer_bytes;
|
||||||
|
if (total_size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If there is again room in the output buffer,
|
||||||
|
* repeat this optimization.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (*s++);
|
||||||
|
|
||||||
|
if (__putc_line_buffered(c, (FILE *)file) == EOF)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
total_size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||||
|
{
|
||||||
|
ssize_t num_bytes_written;
|
||||||
|
|
||||||
|
/* We bypass the buffer entirely. */
|
||||||
|
num_bytes_written = write(file->iob_Descriptor, s, total_size);
|
||||||
|
if (num_bytes_written == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (total_size > 0)
|
||||||
|
{
|
||||||
|
/* If there is more data to be written than the write buffer will hold
|
||||||
|
* and the write buffer is empty anyway, then we'll bypass the write
|
||||||
|
* buffer entirely.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes == 0 && total_size >= (size_t)file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
ssize_t num_bytes_written;
|
||||||
|
|
||||||
|
/* We bypass the buffer entirely. */
|
||||||
|
num_bytes_written = write(file->iob_Descriptor, s, total_size);
|
||||||
|
if (num_bytes_written == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is there still room in the write buffer to store
|
||||||
|
* more of the string?
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
|
||||||
|
size_t num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Give the user a chance to abort what could otherwise
|
||||||
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
/* Store only as many characters as will fit into the write buffer. */
|
||||||
|
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
|
||||||
|
if (total_size < num_buffer_bytes)
|
||||||
|
num_buffer_bytes = total_size;
|
||||||
|
|
||||||
|
assert( num_buffer_bytes > 0 );
|
||||||
|
|
||||||
|
memmove(buffer, s, num_buffer_bytes);
|
||||||
|
s += num_buffer_bytes;
|
||||||
|
|
||||||
|
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferWriteBytes += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Write a full buffer to disk. */
|
||||||
|
if (__iob_write_buffer_is_full(file) && __flush_iob_write_buffer(file) < 0)
|
||||||
|
{
|
||||||
|
/* Abort with error. */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stop as soon as no further data needs to be written. */
|
||||||
|
assert( total_size >= num_buffer_bytes );
|
||||||
|
|
||||||
|
total_size -= num_buffer_bytes;
|
||||||
|
if (total_size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If there is again room in the output buffer,
|
||||||
|
* try this optimization again.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (*s++);
|
||||||
|
|
||||||
|
if (__putc_fully_buffered(c, (FILE *)file) == EOF)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
total_size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line_feed != 0 && __putc(line_feed, stream, buffer_mode) == EOF)
|
||||||
|
goto out;
|
||||||
|
|
||||||
result = OK;
|
result = OK;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
/* Note: if buffering is disabled for this stream, then we still
|
/* Note: if buffering is disabled for this stream, then we still
|
||||||
may have buffered data around, queued to be printed right now.
|
* may have buffered data around, queued to be printed right now.
|
||||||
This is intended to improve performance as it takes more effort
|
* This is intended to improve performance as it takes more effort
|
||||||
to write a single character to a file than to write a bunch. */
|
* to write a single character to a file than to write a bunch.
|
||||||
if(result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
*/
|
||||||
|
if (result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
||||||
{
|
{
|
||||||
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
|
if (__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
|
||||||
{
|
{
|
||||||
SHOWMSG("couldn't flush the write buffer");
|
SHOWMSG("couldn't flush the write buffer");
|
||||||
result = EOF;
|
result = EOF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
funlockfile(stream);
|
if (stream != NULL)
|
||||||
|
funlockfile(stream);
|
||||||
|
|
||||||
|
RETURN(result);
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
int
|
||||||
|
fputs(const char *s, FILE *stream)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
ENTER();
|
||||||
|
|
||||||
|
SHOWSTRING(s);
|
||||||
|
SHOWPOINTER(stream);
|
||||||
|
|
||||||
|
assert( s != NULL && stream != NULL );
|
||||||
|
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
|
{
|
||||||
|
if (s == NULL || stream == NULL)
|
||||||
|
{
|
||||||
|
__set_errno(EFAULT);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||||
|
|
||||||
|
result = __fputs(s, 0, stream);
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
return(result);
|
return(result);
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_fread.c,v 1.7 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -59,14 +57,14 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
assert( ptr != NULL && stream != NULL );
|
assert( ptr != NULL && stream != NULL );
|
||||||
assert( (int)element_size >= 0 && (int)count >= 0 );
|
assert( (int)element_size >= 0 && (int)count >= 0 );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
flockfile(stream);
|
flockfile(stream);
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(ptr == NULL || stream == NULL)
|
if (ptr == NULL || stream == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("invalid parameters");
|
SHOWMSG("invalid parameters");
|
||||||
|
|
||||||
@ -80,7 +78,7 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
||||||
assert( file->iob_BufferSize > 0 );
|
assert( file->iob_BufferSize > 0 );
|
||||||
|
|
||||||
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_IN_USE))
|
if (FLAG_IS_CLEAR(file->iob_Flags, IOBF_IN_USE))
|
||||||
{
|
{
|
||||||
SHOWMSG("this file is not even in use");
|
SHOWMSG("this file is not even in use");
|
||||||
|
|
||||||
@ -91,7 +89,7 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_READ))
|
if (FLAG_IS_CLEAR(file->iob_Flags, IOBF_READ))
|
||||||
{
|
{
|
||||||
SHOWMSG("this file is not read-enabled");
|
SHOWMSG("this file is not read-enabled");
|
||||||
|
|
||||||
@ -102,29 +100,114 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(element_size > 0 && count > 0)
|
/* So that we can tell error and 'end of file' conditions apart. */
|
||||||
|
clearerr(stream);
|
||||||
|
|
||||||
|
if (element_size > 0 && count > 0)
|
||||||
{
|
{
|
||||||
size_t total_bytes_read = 0;
|
size_t total_bytes_read = 0;
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
unsigned char * data = ptr;
|
unsigned char * data = ptr;
|
||||||
|
ssize_t num_bytes_read;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if(__fgetc_check((FILE *)file) < 0)
|
if (__fgetc_check((FILE *)file) < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
/* Check for overflow. */
|
||||||
total_size = element_size * count;
|
total_size = element_size * count;
|
||||||
|
if (element_size != (total_size / count))
|
||||||
|
goto out;
|
||||||
|
|
||||||
SHOWVALUE(total_size);
|
SHOWVALUE(total_size);
|
||||||
|
|
||||||
while(total_size-- > 0)
|
/* No buffering enabled? */
|
||||||
|
if ((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
||||||
{
|
{
|
||||||
c = __getc(file);
|
/* We bypass the buffer entirely. */
|
||||||
if(c == EOF)
|
num_bytes_read = read(file->iob_Descriptor, data, total_size);
|
||||||
break;
|
if (num_bytes_read == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags,IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
(*data++) = c;
|
if (num_bytes_read == 0)
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_EOF_REACHED);
|
||||||
|
|
||||||
total_bytes_read++;
|
total_bytes_read = num_bytes_read;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (total_size > 0)
|
||||||
|
{
|
||||||
|
/* If the read buffer is empty and there is more data to be
|
||||||
|
* read, we'll bypass the buffer entirely. Note that we try
|
||||||
|
* to read a complete full buffer worth's of data, not just
|
||||||
|
* a few bytes.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferReadBytes == 0 && total_size >= (size_t)file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
/* We bypass the buffer entirely. */
|
||||||
|
num_bytes_read = read(file->iob_Descriptor, data, total_size);
|
||||||
|
if (num_bytes_read == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_bytes_read == 0)
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_EOF_REACHED);
|
||||||
|
|
||||||
|
total_bytes_read += num_bytes_read;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there is still data in the read buffer, try to copy it
|
||||||
|
* directly into the output buffer.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferPosition < file->iob_BufferReadBytes)
|
||||||
|
{
|
||||||
|
const unsigned char * buffer = &file->iob_Buffer[file->iob_BufferPosition];
|
||||||
|
size_t num_bytes_in_buffer;
|
||||||
|
|
||||||
|
/* Copy as much data as will fit. */
|
||||||
|
assert( file->iob_BufferReadBytes >= file->iob_BufferPosition );
|
||||||
|
|
||||||
|
num_bytes_in_buffer = file->iob_BufferReadBytes - file->iob_BufferPosition;
|
||||||
|
if (total_size < num_bytes_in_buffer)
|
||||||
|
num_bytes_in_buffer = total_size;
|
||||||
|
|
||||||
|
assert( num_bytes_in_buffer > 0 );
|
||||||
|
|
||||||
|
memmove(data, buffer, num_bytes_in_buffer);
|
||||||
|
data += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
assert( file->iob_BufferPosition + num_bytes_in_buffer <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferPosition += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
total_bytes_read += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
/* Stop if the string buffer has been filled. */
|
||||||
|
assert( total_size >= num_bytes_in_buffer );
|
||||||
|
|
||||||
|
/* Are we finished yet? */
|
||||||
|
total_size -= num_bytes_in_buffer;
|
||||||
|
if (total_size == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the next byte and/or refill the read buffer. */
|
||||||
|
c = __getc(file);
|
||||||
|
if (c == EOF)
|
||||||
|
break;
|
||||||
|
|
||||||
|
(*data++) = c;
|
||||||
|
|
||||||
|
total_size--;
|
||||||
|
total_bytes_read++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SHOWVALUE(total_bytes_read);
|
SHOWVALUE(total_bytes_read);
|
||||||
@ -137,9 +220,6 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
SHOWVALUE(count);
|
SHOWVALUE(count);
|
||||||
|
|
||||||
SHOWMSG("either element size or count is zero");
|
SHOWMSG("either element size or count is zero");
|
||||||
|
|
||||||
/* Don't let this appear like an EOF or error. */
|
|
||||||
clearerr((FILE *)file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D(("total number of elements read = %ld",result));
|
D(("total number of elements read = %ld",result));
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_fwrite.c,v 1.12 2010-10-20 13:12:58 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -59,14 +57,14 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
assert( ptr != NULL && stream != NULL );
|
assert( ptr != NULL && stream != NULL );
|
||||||
assert( (int)element_size >= 0 && (int)count >= 0 );
|
assert( (int)element_size >= 0 && (int)count >= 0 );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
flockfile(stream);
|
flockfile(stream);
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(ptr == NULL || stream == NULL)
|
if (ptr == NULL || stream == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("invalid parameters");
|
SHOWMSG("invalid parameters");
|
||||||
|
|
||||||
@ -78,9 +76,8 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
|
|
||||||
assert( __is_valid_iob(file) );
|
assert( __is_valid_iob(file) );
|
||||||
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
||||||
assert( file->iob_BufferSize > 0 );
|
|
||||||
|
|
||||||
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_IN_USE))
|
if (FLAG_IS_CLEAR(file->iob_Flags,IOBF_IN_USE))
|
||||||
{
|
{
|
||||||
SHOWMSG("this file is not even in use");
|
SHOWMSG("this file is not even in use");
|
||||||
|
|
||||||
@ -91,7 +88,7 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_WRITE))
|
if (FLAG_IS_CLEAR(file->iob_Flags,IOBF_WRITE))
|
||||||
{
|
{
|
||||||
SHOWMSG("this stream is not write-enabled");
|
SHOWMSG("this stream is not write-enabled");
|
||||||
|
|
||||||
@ -102,69 +99,242 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(element_size > 0 && count > 0)
|
clearerr((FILE *)file);
|
||||||
|
|
||||||
|
if (element_size > 0 && count > 0)
|
||||||
{
|
{
|
||||||
const unsigned char * data = (unsigned char *)ptr;
|
const unsigned char * s = (unsigned char *)ptr;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
int buffer_mode;
|
int buffer_mode;
|
||||||
size_t total_bytes_written = 0;
|
size_t total_bytes_written = 0;
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
|
|
||||||
|
/* Check for overflow. */
|
||||||
total_size = element_size * count;
|
total_size = element_size * count;
|
||||||
|
if (element_size != (total_size / count))
|
||||||
if(__fputc_check((FILE *)file) < 0)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (__fputc_check((FILE *)file) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* If this is an unbuffered interactive stream, we will switch
|
||||||
|
* to line buffered mode in order to improve readability of
|
||||||
|
* the output.
|
||||||
|
*/
|
||||||
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
|
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
|
||||||
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
|
if (buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||||
{
|
{
|
||||||
struct fd * fd = __fd[file->iob_Descriptor];
|
struct fd * fd = __fd[file->iob_Descriptor];
|
||||||
|
|
||||||
__fd_lock(fd);
|
__fd_lock(fd);
|
||||||
|
|
||||||
if(FLAG_IS_SET(fd->fd_Flags,FDF_IS_INTERACTIVE))
|
if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE))
|
||||||
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
||||||
|
|
||||||
__fd_unlock(fd);
|
__fd_unlock(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(buffer_mode == IOBF_BUFFER_MODE_LINE)
|
if (buffer_mode == IOBF_BUFFER_MODE_LINE)
|
||||||
{
|
{
|
||||||
while(total_size-- > 0)
|
assert( file->iob_BufferSize > 0 );
|
||||||
|
|
||||||
|
while (total_size > 0)
|
||||||
{
|
{
|
||||||
c = (*data++);
|
/* Is there still room in the write buffer to store
|
||||||
|
* more of the data?
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
|
||||||
|
size_t num_buffer_bytes;
|
||||||
|
const unsigned char * lf;
|
||||||
|
|
||||||
if(__putc_line_buffered(c,(FILE *)file) == EOF)
|
/* Give the user a chance to abort what could otherwise
|
||||||
goto out;
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
/* Store only as many characters as will fit into the write buffer. */
|
||||||
|
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
|
||||||
|
if (total_size < num_buffer_bytes)
|
||||||
|
num_buffer_bytes = total_size;
|
||||||
|
|
||||||
|
/* Try to find a line feed in the string. If there is one,
|
||||||
|
* reduce the number of characters to write to the sequence
|
||||||
|
* which ends with the line feed character.
|
||||||
|
*/
|
||||||
|
lf = (unsigned char *)memchr(s, '\n', num_buffer_bytes);
|
||||||
|
if (lf != NULL)
|
||||||
|
{
|
||||||
|
assert( (size_t)(lf + 1 - s) <= num_buffer_bytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = lf + 1 - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( num_buffer_bytes > 0 );
|
||||||
|
|
||||||
|
memmove(buffer, s, num_buffer_bytes);
|
||||||
|
s += num_buffer_bytes;
|
||||||
|
|
||||||
|
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferWriteBytes += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Write the buffer to disk if the buffer is full
|
||||||
|
* or contains a line feed.
|
||||||
|
*/
|
||||||
|
if ((lf != NULL || __iob_write_buffer_is_full(file)) && __flush_iob_write_buffer(file) < 0)
|
||||||
|
{
|
||||||
|
/* Abort with error. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_written += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Stop as soon as no further data needs to be written. */
|
||||||
|
assert( total_size >= num_buffer_bytes );
|
||||||
|
|
||||||
|
total_size -= num_buffer_bytes;
|
||||||
|
if (total_size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If there is again room in the output buffer,
|
||||||
|
* repeat this optimization.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (*s++);
|
||||||
|
|
||||||
|
if (__putc_line_buffered(c, (FILE *)file) == EOF)
|
||||||
|
break;
|
||||||
|
|
||||||
|
total_size--;
|
||||||
total_bytes_written++;
|
total_bytes_written++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (buffer_mode == IOBF_BUFFER_MODE_NONE)
|
||||||
|
{
|
||||||
|
ssize_t num_bytes_written;
|
||||||
|
|
||||||
|
/* We bypass the buffer entirely. */
|
||||||
|
num_bytes_written = write(file->iob_Descriptor, s, total_size);
|
||||||
|
if (num_bytes_written == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_written = (size_t)num_bytes_written;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while(total_size-- > 0)
|
assert( file->iob_BufferSize > 0 );
|
||||||
|
|
||||||
|
while (total_size > 0)
|
||||||
{
|
{
|
||||||
c = (*data++);
|
/* If there is more data to be written than the write buffer will hold
|
||||||
|
* and the write buffer is empty anyway, then we'll bypass the write
|
||||||
|
* buffer entirely. Note that we try to store a complete full buffer
|
||||||
|
* worth's of data, not just a few bytes.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes == 0 && total_size >= (size_t)file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
ssize_t num_bytes_written;
|
||||||
|
|
||||||
if(__putc_fully_buffered(c,(FILE *)file) == EOF)
|
/* We bypass the buffer entirely. */
|
||||||
goto out;
|
num_bytes_written = write(file->iob_Descriptor, s, total_size);
|
||||||
|
if (num_bytes_written == -1)
|
||||||
|
{
|
||||||
|
SET_FLAG(file->iob_Flags, IOBF_ERROR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_written += num_bytes_written;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is there still room in the write buffer to store
|
||||||
|
* more of the data?
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
{
|
||||||
|
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
|
||||||
|
size_t num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Give the user a chance to abort what could otherwise
|
||||||
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
/* Store only as many bytes as will fit into the write buffer. */
|
||||||
|
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
|
||||||
|
|
||||||
|
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
|
||||||
|
if (total_size < num_buffer_bytes)
|
||||||
|
num_buffer_bytes = total_size;
|
||||||
|
|
||||||
|
assert( num_buffer_bytes > 0 );
|
||||||
|
|
||||||
|
memmove(buffer, s, num_buffer_bytes);
|
||||||
|
s += num_buffer_bytes;
|
||||||
|
|
||||||
|
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferWriteBytes += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Write a full buffer to disk. */
|
||||||
|
if (__iob_write_buffer_is_full(file) && __flush_iob_write_buffer(file) < 0)
|
||||||
|
{
|
||||||
|
/* Abort with error. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bytes_written += num_buffer_bytes;
|
||||||
|
|
||||||
|
/* Stop as soon as no further data needs to be written. */
|
||||||
|
assert( total_size >= num_buffer_bytes );
|
||||||
|
|
||||||
|
total_size -= num_buffer_bytes;
|
||||||
|
if (total_size == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If there is again room in the output buffer,
|
||||||
|
* try this optimization again.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = (*s++);
|
||||||
|
|
||||||
|
if (__putc_fully_buffered(c, (FILE *)file) == EOF)
|
||||||
|
break;
|
||||||
|
|
||||||
|
total_size--;
|
||||||
total_bytes_written++;
|
total_bytes_written++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
if ((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
||||||
{
|
{
|
||||||
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
|
if (__iob_write_buffer_is_valid(file))
|
||||||
goto out;
|
__flush_iob_write_buffer(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = total_bytes_written / element_size;
|
result = total_bytes_written / element_size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Don't let this appear like an EOF or error. */
|
SHOWVALUE(element_size);
|
||||||
clearerr((FILE *)file);
|
SHOWVALUE(count);
|
||||||
|
|
||||||
|
SHOWMSG("either element size or count is zero");
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_gets.c,v 1.6 2006-01-08 12:04:24 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -46,6 +44,8 @@
|
|||||||
char *
|
char *
|
||||||
gets(char *s)
|
gets(char *s)
|
||||||
{
|
{
|
||||||
|
FILE * stream = stdin;
|
||||||
|
struct iob * file = (struct iob *)stream;
|
||||||
char * result = s;
|
char * result = s;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
@ -53,16 +53,16 @@ gets(char *s)
|
|||||||
|
|
||||||
SHOWPOINTER(s);
|
SHOWPOINTER(s);
|
||||||
|
|
||||||
assert( s != NULL && stdin != NULL );
|
assert( s != NULL );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
flockfile(stdin);
|
flockfile(stream);
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(s == NULL || stdin == NULL)
|
if (s == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("invalid parameters");
|
SHOWMSG("invalid parameters");
|
||||||
|
|
||||||
@ -77,21 +77,84 @@ gets(char *s)
|
|||||||
/* Take care of the checks and data structure changes that
|
/* Take care of the checks and data structure changes that
|
||||||
* need to be handled only once for this stream.
|
* need to be handled only once for this stream.
|
||||||
*/
|
*/
|
||||||
if(__fgetc_check(stdin) < 0)
|
if (__fgetc_check(stream) < 0)
|
||||||
{
|
{
|
||||||
result = NULL;
|
result = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* So that we can tell error and 'end of file' conditions apart. */
|
/* So that we can tell error and 'end of file' conditions apart. */
|
||||||
clearerr(stdin);
|
clearerr(stream);
|
||||||
|
|
||||||
while(TRUE)
|
assert( 0 <= file->iob_BufferReadBytes );
|
||||||
|
assert( file->iob_BufferReadBytes <= file->iob_BufferSize );
|
||||||
|
assert( file->iob_BufferPosition <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
{
|
{
|
||||||
c = __getc(stdin);
|
/* If there is data in the buffer, try to copy it directly
|
||||||
if(c == EOF)
|
* into the string buffer. If there is a line feed in the
|
||||||
|
* buffer, too, try to conclude the read operation.
|
||||||
|
*/
|
||||||
|
if (file->iob_BufferPosition < file->iob_BufferReadBytes)
|
||||||
{
|
{
|
||||||
if(ferror(stdin))
|
size_t num_bytes_in_buffer = file->iob_BufferReadBytes - file->iob_BufferPosition;
|
||||||
|
const unsigned char * buffer = &file->iob_Buffer[file->iob_BufferPosition];
|
||||||
|
const unsigned char * lf;
|
||||||
|
|
||||||
|
assert( file->iob_BufferReadBytes >= file->iob_BufferPosition );
|
||||||
|
|
||||||
|
/* Try to find a line feed character which could conclude
|
||||||
|
* the read operation if the remaining buffer data, including
|
||||||
|
* the line feed character, fit into the string buffer.
|
||||||
|
*/
|
||||||
|
lf = (unsigned char *)memchr(buffer, '\n', num_bytes_in_buffer);
|
||||||
|
if (lf != NULL)
|
||||||
|
{
|
||||||
|
size_t num_characters_in_line = lf + 1 - buffer;
|
||||||
|
|
||||||
|
assert( num_characters_in_line <= num_bytes_in_buffer );
|
||||||
|
|
||||||
|
/* Give the user a chance to abort what could otherwise
|
||||||
|
* become an uninterrupted series of copying operations.
|
||||||
|
*/
|
||||||
|
if (__check_abort_enabled)
|
||||||
|
__check_abort();
|
||||||
|
|
||||||
|
/* Copy the remainder of the read buffer into the
|
||||||
|
* string buffer, omitting the terminating line
|
||||||
|
* feed character. This is the difference between
|
||||||
|
* gets() and fgets(): fgets() will keep the
|
||||||
|
* terminating line feed character, but gets()
|
||||||
|
* will drop it.
|
||||||
|
*/
|
||||||
|
assert( num_characters_in_line > 0 );
|
||||||
|
|
||||||
|
memmove(s, buffer, num_characters_in_line - 1);
|
||||||
|
s += num_characters_in_line - 1;
|
||||||
|
|
||||||
|
assert( file->iob_BufferPosition + num_characters_in_line <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferPosition += num_characters_in_line;
|
||||||
|
|
||||||
|
/* And that concludes the line read operation. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( num_bytes_in_buffer > 0 );
|
||||||
|
|
||||||
|
memmove(s, buffer, num_bytes_in_buffer);
|
||||||
|
s += num_bytes_in_buffer;
|
||||||
|
|
||||||
|
assert( file->iob_BufferPosition + num_bytes_in_buffer <= file->iob_BufferSize );
|
||||||
|
|
||||||
|
file->iob_BufferPosition += num_bytes_in_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = __getc(stream);
|
||||||
|
if (c == EOF)
|
||||||
|
{
|
||||||
|
if (ferror(stream))
|
||||||
{
|
{
|
||||||
/* Just to be on the safe side. */
|
/* Just to be on the safe side. */
|
||||||
(*s) = '\0';
|
(*s) = '\0';
|
||||||
@ -101,14 +164,15 @@ gets(char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that we return NULL if we really
|
/* Make sure that we return NULL if we really
|
||||||
didn't read anything at all */
|
* didn't read anything at all.
|
||||||
if(s == result)
|
*/
|
||||||
|
if (s == result)
|
||||||
result = NULL;
|
result = NULL;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c == '\n')
|
if (c == '\n')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
(*s++) = c;
|
(*s++) = c;
|
||||||
@ -120,7 +184,7 @@ gets(char *s)
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
funlockfile(stdin);
|
funlockfile(stream);
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
return(result);
|
return(result);
|
||||||
|
|||||||
581
library/stdio_long_path.c
Normal file
581
library/stdio_long_path.c
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2023 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __amigaos4__
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* We don't want the replacement functions to become active when buliding
|
||||||
|
* this file.
|
||||||
|
*/
|
||||||
|
#define __DISABLE_LONG_PATHS
|
||||||
|
|
||||||
|
#ifndef _STDIO_LONG_PATH_H
|
||||||
|
#include "stdio_long_path.h"
|
||||||
|
#endif /* _STDIO_LONG_PATH_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#include <proto/exec.h>
|
||||||
|
#include <proto/dos.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Split an AmigaDOS path name into a sequence of the individual path
|
||||||
|
* pieces. A path name may be empty, it may include a device name,
|
||||||
|
* a series of directory names or even "/" references to the
|
||||||
|
* parent directory and a file, directory or link name.
|
||||||
|
*
|
||||||
|
* split_path() is modeled on the SplitName() function in that it
|
||||||
|
* will copy each path piece into the supplied buffer, returning -1
|
||||||
|
* if the last piece has been copied. If -2 is returned, it means
|
||||||
|
* that the piece buffer is too short for the path piece to be
|
||||||
|
* copied.
|
||||||
|
*/
|
||||||
|
static LONG
|
||||||
|
split_path(CONST TEXT * path, TEXT * piece, LONG old_position, LONG size)
|
||||||
|
{
|
||||||
|
LONG length_copied = 0;
|
||||||
|
TEXT c;
|
||||||
|
|
||||||
|
/* The piece has to be NUL-terminated, which reduces the
|
||||||
|
* usable size of the piece buffer.
|
||||||
|
*/
|
||||||
|
size--;
|
||||||
|
|
||||||
|
/* Is the piece buffer too short? */
|
||||||
|
if (size <= 0)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
/* Is this not an empty string, which stands for the
|
||||||
|
* current directory?
|
||||||
|
*/
|
||||||
|
if (path[0] != '\0')
|
||||||
|
{
|
||||||
|
/* Adjust the starting position for scanning the path name,
|
||||||
|
* which simplifies the loop below.
|
||||||
|
*/
|
||||||
|
path += old_position;
|
||||||
|
|
||||||
|
while (size-- >= 0)
|
||||||
|
{
|
||||||
|
c = path[length_copied];
|
||||||
|
|
||||||
|
/* Was this the end of the path name? */
|
||||||
|
if (c == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
(*piece++) = c;
|
||||||
|
length_copied++;
|
||||||
|
|
||||||
|
/* Is this a device name separator, which may appear
|
||||||
|
* exactly once in a path name? Then we will have to
|
||||||
|
* keep it.
|
||||||
|
*/
|
||||||
|
if (c == ':' && old_position == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Is there a '/' at the end of this path piece? */
|
||||||
|
else if (c == '/')
|
||||||
|
{
|
||||||
|
/* Is this in fact a single '/' which represents a
|
||||||
|
* reference to the parent directory? Then we need
|
||||||
|
* to keep it, otherwise it will have to be removed.
|
||||||
|
*/
|
||||||
|
if (length_copied > 1)
|
||||||
|
{
|
||||||
|
/* Make sure that the trailing '/' will
|
||||||
|
* be removed from the piece.
|
||||||
|
*/
|
||||||
|
piece--;
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is the piece buffer too short? */
|
||||||
|
if (size < 0)
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure that the piece is NUL-terminated. */
|
||||||
|
(*piece) = '\0';
|
||||||
|
|
||||||
|
/* Is the separator character at the end of the path name,
|
||||||
|
* or is this an empty string (with path_length == 0)?
|
||||||
|
*/
|
||||||
|
if (path[length_copied] == '\0')
|
||||||
|
return -1; /* This is the last piece of the path name. */
|
||||||
|
|
||||||
|
/* Continue path processing at this position. */
|
||||||
|
return old_position + length_copied;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* If a path name exceeds 255 characters, break down the path into individual
|
||||||
|
* pieces, traveling to the end of the path and invoke a callback function
|
||||||
|
* with the current directory set and the name of the file/directory/link
|
||||||
|
* provided along with additional parameters needed to carry out a file
|
||||||
|
* system operation.
|
||||||
|
*
|
||||||
|
* For path names shorter than 256 characters, no extra work will be done
|
||||||
|
* and the callback function will be invoked directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef LONG (*callback_f)(CONST TEXT * name, LONG arg1, LONG arg2);
|
||||||
|
|
||||||
|
static void
|
||||||
|
long_path_workaround(
|
||||||
|
CONST TEXT * path_name, LONG arg1, LONG arg2,
|
||||||
|
LONG * result_ptr,
|
||||||
|
callback_f callback)
|
||||||
|
{
|
||||||
|
TEXT piece[256];
|
||||||
|
LONG path_name_len;
|
||||||
|
LONG len;
|
||||||
|
CONST TEXT * colon;
|
||||||
|
BPTR reference_dir = (BPTR)NULL;
|
||||||
|
BPTR old_current_dir = (BPTR)NULL;
|
||||||
|
LONG position = 0;
|
||||||
|
BPTR lock;
|
||||||
|
|
||||||
|
path_name_len = strlen(path_name);
|
||||||
|
|
||||||
|
/* Only go through with the extra effort to resolve the path
|
||||||
|
* if this job requires a file system and not a handler (such
|
||||||
|
* as "NIL:" or "CON:") and if the path name exceeds 255
|
||||||
|
* characters.
|
||||||
|
*/
|
||||||
|
if (path_name_len > 255 && IsFileSystem(path_name))
|
||||||
|
{
|
||||||
|
/* Does the path begin with a device name, or a reference
|
||||||
|
* to the root directory of a volume?
|
||||||
|
*/
|
||||||
|
colon = strchr(path_name, ':');
|
||||||
|
if (colon != NULL)
|
||||||
|
{
|
||||||
|
/* We need to copy the name of the device, which must
|
||||||
|
* not exceed 255 characters, including the colon
|
||||||
|
* character. Volume and device names should never
|
||||||
|
* exceed 30 characters, but accidents may still
|
||||||
|
* happen...
|
||||||
|
*/
|
||||||
|
len = (LONG)(colon - path_name) + 1;
|
||||||
|
if (len > 255)
|
||||||
|
{
|
||||||
|
SetIoErr(ERROR_LINE_TOO_LONG);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Obtain a shared lock on the device or root
|
||||||
|
* directory. We are using Lock() because it
|
||||||
|
* implies that the handler is a file system
|
||||||
|
* and not, for example, "NIL:" or "CON:".
|
||||||
|
*/
|
||||||
|
CopyMem(path_name, piece, len);
|
||||||
|
piece[len] = '\0';
|
||||||
|
|
||||||
|
reference_dir = Lock(piece, SHARED_LOCK);
|
||||||
|
if (reference_dir == (BPTR)NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* We took care of the device or root directory name. */
|
||||||
|
path_name += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the path name, one piece at a time, relative
|
||||||
|
* to a Lock on its parent directory. This repeats
|
||||||
|
* until the last piece of the path has been found.
|
||||||
|
* Each loop iteration will reuse the Lock of the
|
||||||
|
* previous iteration as the parent directory.
|
||||||
|
*/
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* Obtain the next piece of the path. */
|
||||||
|
position = split_path(path_name, piece, position, sizeof(piece));
|
||||||
|
|
||||||
|
/* Is the piece too long? */
|
||||||
|
if (position == -2)
|
||||||
|
{
|
||||||
|
SetIoErr(ERROR_LINE_TOO_LONG);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Access the next piece of the path relative to a
|
||||||
|
* specific directory? Otherwise, we use the current
|
||||||
|
* directory of the current Process. Because the current
|
||||||
|
* directory may be an exclusive lock we cannot
|
||||||
|
* conveniently fall back onto DupLock() or
|
||||||
|
* Lock("", SHARED_LOCK) instead.
|
||||||
|
*/
|
||||||
|
if (reference_dir != (BPTR)NULL)
|
||||||
|
old_current_dir = CurrentDir(reference_dir);
|
||||||
|
|
||||||
|
/* Unless this is the final piece of the path
|
||||||
|
* (split_path() will return -1), we will need to call
|
||||||
|
* Lock() and make use of shared locks.
|
||||||
|
*/
|
||||||
|
if (position != -1)
|
||||||
|
{
|
||||||
|
lock = Lock(piece, SHARED_LOCK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lock = (BPTR)NULL;
|
||||||
|
|
||||||
|
/* Time to do what we came here for. */
|
||||||
|
(*result_ptr) = (*callback)(piece, arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reference_dir != (BPTR)NULL)
|
||||||
|
CurrentDir(old_current_dir);
|
||||||
|
|
||||||
|
/* Stop as soon as we reach the end of the path or
|
||||||
|
* if the Lock could not be obtained.
|
||||||
|
*/
|
||||||
|
if (position == -1 || lock == (BPTR)NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Look at the next piece of the remaining path.
|
||||||
|
* Free the current reference directory Lock and
|
||||||
|
* replace it with the Lock obtained above.
|
||||||
|
*/
|
||||||
|
UnLock(reference_dir);
|
||||||
|
reference_dir = lock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*result_ptr) = (*callback)(path_name, arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
UnLock(reference_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
lock_callback(CONST TEXT * name, LONG type)
|
||||||
|
{
|
||||||
|
return Lock(name, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPTR
|
||||||
|
__new_lock(CONST TEXT * name, LONG type )
|
||||||
|
{
|
||||||
|
BPTR result = (BPTR)NULL;
|
||||||
|
|
||||||
|
long_path_workaround(name, type, 0, (LONG *)&result, (callback_f)lock_callback);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
set_owner_callback(CONST TEXT * name, LONG owner_info)
|
||||||
|
{
|
||||||
|
return SetOwner(name, owner_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_set_owner(CONST TEXT * name, LONG owner_info)
|
||||||
|
{
|
||||||
|
LONG success = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, owner_info, 0, &success, (callback_f)set_owner_callback);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
set_comment_callback(CONST TEXT * name, LONG comment)
|
||||||
|
{
|
||||||
|
return SetComment(name, (STRPTR)comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_set_comment(CONST TEXT * name, CONST TEXT * comment)
|
||||||
|
{
|
||||||
|
LONG success = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, (LONG)comment, 0, &success, (callback_f)set_comment_callback);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
set_protect_callback(CONST TEXT * name, LONG protect)
|
||||||
|
{
|
||||||
|
return SetProtection(name, protect);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_set_protection(CONST TEXT * name, LONG protect)
|
||||||
|
{
|
||||||
|
LONG success = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, protect, 0, &success, (callback_f)set_protect_callback);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
set_file_date_callback(CONST TEXT * name, LONG date)
|
||||||
|
{
|
||||||
|
return SetFileDate(name, (struct DateStamp *)date);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_set_file_date(CONST TEXT * name, CONST struct DateStamp * date)
|
||||||
|
{
|
||||||
|
LONG success = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, (LONG)date, 0, &success, (callback_f)set_file_date_callback);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
open_callback(CONST TEXT * name, LONG mode)
|
||||||
|
{
|
||||||
|
return Open(name, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPTR
|
||||||
|
__new_open(CONST TEXT * name, LONG mode)
|
||||||
|
{
|
||||||
|
BPTR file = (BPTR)NULL;
|
||||||
|
|
||||||
|
long_path_workaround(name, mode, 0, (LONG *)&file, (callback_f)open_callback);
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
delete_file_callback(CONST TEXT * name)
|
||||||
|
{
|
||||||
|
return DeleteFile(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_delete_file(CONST TEXT * name)
|
||||||
|
{
|
||||||
|
LONG successful = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, 0, 0, &successful, (callback_f)delete_file_callback);
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
create_dir_callback(CONST TEXT * name)
|
||||||
|
{
|
||||||
|
return CreateDir(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
BPTR
|
||||||
|
__new_create_dir(CONST TEXT * name)
|
||||||
|
{
|
||||||
|
BPTR lock = (BPTR)NULL;
|
||||||
|
|
||||||
|
long_path_workaround(name, 0, 0, (LONG *)&lock, (callback_f)create_dir_callback);
|
||||||
|
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
make_link_callback(CONST TEXT * name, LONG dest, LONG soft)
|
||||||
|
{
|
||||||
|
return MakeLink(name, dest, soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_make_link(CONST TEXT * name, LONG dest, LONG soft)
|
||||||
|
{
|
||||||
|
LONG success = FALSE;
|
||||||
|
|
||||||
|
long_path_workaround(name, dest, soft, (LONG *)&success, (callback_f)make_link_callback);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
struct rename_arg
|
||||||
|
{
|
||||||
|
BPTR dir_lock;
|
||||||
|
TEXT name[256+4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct rename_arg *
|
||||||
|
create_rename_arg(void)
|
||||||
|
{
|
||||||
|
struct rename_arg * arg;
|
||||||
|
|
||||||
|
arg = AllocMem(sizeof(*arg), MEMF_PUBLIC);
|
||||||
|
if (arg != NULL)
|
||||||
|
arg->dir_lock = (BPTR)NULL;
|
||||||
|
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_rename_arg(struct rename_arg * arg)
|
||||||
|
{
|
||||||
|
if (arg != NULL)
|
||||||
|
{
|
||||||
|
UnLock(arg->dir_lock);
|
||||||
|
FreeMem(arg, sizeof(*arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LONG
|
||||||
|
rename_callback(CONST TEXT * name, struct rename_arg * arg)
|
||||||
|
{
|
||||||
|
BOOL successful = FALSE;
|
||||||
|
LONG name_len;
|
||||||
|
BPTR old_lock;
|
||||||
|
|
||||||
|
old_lock = CurrentDir((BPTR)NULL);
|
||||||
|
CurrentDir(old_lock);
|
||||||
|
|
||||||
|
if (old_lock != (BPTR)NULL)
|
||||||
|
{
|
||||||
|
arg->dir_lock = DupLock(old_lock);
|
||||||
|
if (arg->dir_lock != (BPTR)NULL)
|
||||||
|
successful = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
successful = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (successful)
|
||||||
|
{
|
||||||
|
name_len = strlen(name);
|
||||||
|
if (name_len > 255)
|
||||||
|
name_len = 255;
|
||||||
|
|
||||||
|
arg->name[0] = name_len;
|
||||||
|
CopyMem(name, &arg->name[1], name_len);
|
||||||
|
arg->name[1+name_len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
__new_rename(CONST TEXT * oldName, CONST TEXT * newName)
|
||||||
|
{
|
||||||
|
struct rename_arg * from = NULL;
|
||||||
|
struct rename_arg * to = NULL;
|
||||||
|
struct MsgPort * filesys_port;
|
||||||
|
LONG successful = FALSE;
|
||||||
|
|
||||||
|
if (IsFileSystem(oldName) && IsFileSystem(newName) && (strlen(oldName) > 255 || strlen(newName) > 255))
|
||||||
|
{
|
||||||
|
from = create_rename_arg();
|
||||||
|
if (from == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
to = create_rename_arg();
|
||||||
|
if (to == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
long_path_workaround(oldName, (LONG)from, 0, (LONG *)&successful, (callback_f)rename_callback);
|
||||||
|
if (successful == FALSE)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
long_path_workaround(newName, (LONG)to, 0, (LONG *)&successful, (callback_f)rename_callback);
|
||||||
|
if (successful == FALSE)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (from->dir_lock == (BPTR)NULL && to->dir_lock == (BPTR)NULL)
|
||||||
|
{
|
||||||
|
filesys_port = GetFileSysTask();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (from->dir_lock == (BPTR)NULL || to->dir_lock == (BPTR)NULL ||
|
||||||
|
SameLock(from->dir_lock, to->dir_lock) == LOCK_DIFFERENT)
|
||||||
|
{
|
||||||
|
SetIoErr(ERROR_RENAME_ACROSS_DEVICES);
|
||||||
|
|
||||||
|
successful = FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
filesys_port = ((struct FileLock *)BADDR(from->dir_lock))->fl_Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
successful = DoPkt4(filesys_port, ACTION_RENAME_OBJECT,
|
||||||
|
from->dir_lock, MKBADDR(from->name),
|
||||||
|
to->dir_lock, MKBADDR(to->name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
successful = Rename(oldName, newName);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
delete_rename_arg(from);
|
||||||
|
delete_rename_arg(to);
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* __amigaos4__ */
|
||||||
168
library/stdio_long_path.h
Normal file
168
library/stdio_long_path.h
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2023 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDIO_LONG_PATH_H
|
||||||
|
#define _STDIO_LONG_PATH_H
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* This option enables support for long path names under Kickstart 2.04
|
||||||
|
* and beyond. Because this workaround is not needed for AmigaOS4, it will
|
||||||
|
* be ignored if you try to enable it.
|
||||||
|
*
|
||||||
|
* Caution: Enable this feature only here in the "stdio_headers.h" file,
|
||||||
|
* never as a compiler option. This is to make sure that all the
|
||||||
|
* source code which makes use of this feature is rebuilt when
|
||||||
|
* you change this file.
|
||||||
|
*/
|
||||||
|
/*#define __USE_LONG_PATHS*/
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __amigaos4__
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef PROTO_DOS_H
|
||||||
|
#include <proto/dos.h>
|
||||||
|
#endif /* PROTO_DOS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
extern BPTR __new_lock(CONST TEXT * name, LONG type );
|
||||||
|
extern LONG __new_set_owner(CONST TEXT * name, LONG owner_info);
|
||||||
|
extern LONG __new_set_comment(CONST TEXT * name, CONST TEXT * comment);
|
||||||
|
extern LONG __new_set_protection(CONST TEXT * name, LONG protect);
|
||||||
|
extern LONG __new_set_file_date(CONST TEXT * name, CONST struct DateStamp * date);
|
||||||
|
extern BPTR __new_open(CONST TEXT * name, LONG mode);
|
||||||
|
extern LONG __new_delete_file(CONST TEXT * name);
|
||||||
|
extern BPTR __new_create_dir(CONST TEXT * name);
|
||||||
|
extern LONG __new_make_link(CONST TEXT * name, LONG dest, LONG soft);
|
||||||
|
extern LONG __new_rename(CONST TEXT * oldName, CONST TEXT * newName);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* We don't want the replacement functions to become active when building
|
||||||
|
* the "stdio_long_path.c" file.
|
||||||
|
*/
|
||||||
|
#if ! defined(__DISABLE_LONG_PATHS) && defined(__USE_LONG_PATHS)
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(Lock)
|
||||||
|
#undef Lock
|
||||||
|
#endif /* Lock */
|
||||||
|
|
||||||
|
#define Lock(name, type) __new_lock((name), (type))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(SetOwner)
|
||||||
|
#undef SetOwner
|
||||||
|
#endif /* SetOwner */
|
||||||
|
|
||||||
|
#define SetOwner(name, owner_info) __new_set_owner((name), (owner_info))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(SetComment)
|
||||||
|
#undef SetComment
|
||||||
|
#endif /* SetComment */
|
||||||
|
|
||||||
|
#define SetComment(name, comment) __new_set_comment((name), (comment))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(SetProtection)
|
||||||
|
#undef SetProtection
|
||||||
|
#endif /* SetProtection */
|
||||||
|
|
||||||
|
#define SetProtection(name, protect) __new_set_protection((name), (protect))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(SetFileDate)
|
||||||
|
#undef SetFileDate
|
||||||
|
#endif /* SetFileDate */
|
||||||
|
|
||||||
|
#define SetFileDate(name, date) __new_set_file_date((name), (date))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(Open)
|
||||||
|
#undef Open
|
||||||
|
#endif /* Open */
|
||||||
|
|
||||||
|
#define Open(name, mode) __new_open((name), (mode))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(DeleteFile)
|
||||||
|
#undef DeleteFile
|
||||||
|
#endif /* DeleteFile */
|
||||||
|
|
||||||
|
#define DeleteFile(name) __new_delete_file(name)
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(CreateDir)
|
||||||
|
#undef CreateDir
|
||||||
|
#endif /* CreateDir */
|
||||||
|
|
||||||
|
#define CreateDir(name) __new_create_dir(name)
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(MakeLink)
|
||||||
|
#undef MakeLink
|
||||||
|
#endif /* MakeLink */
|
||||||
|
|
||||||
|
#define MakeLink(name, dest, soft) __new_make_link((name), (dest), (soft))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(Rename)
|
||||||
|
#undef Rename
|
||||||
|
#endif /* Rename */
|
||||||
|
|
||||||
|
#define Rename(oldName, newName) __new_rename((oldName), (newName))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* !__DISABLE_LONG_PATHS && __USE_LONG_PATHS */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* __amigaos4__ */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif /* _STDIO_LONG_PATH_H */
|
||||||
@ -162,6 +162,11 @@ extern int __fputc(int c,FILE *stream,int buffer_mode);
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* stdio_fputs.c */
|
||||||
|
extern int __fputs(const char *s, int line_feed, FILE *stream);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
/* stdio_sscanf_hook_entry.c */
|
/* stdio_sscanf_hook_entry.c */
|
||||||
extern int __sscanf_hook_entry(struct iob *string,struct file_action_message *fam);
|
extern int __sscanf_hook_entry(struct iob *string,struct file_action_message *fam);
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_puts.c,v 1.8 2006-01-08 12:04:25 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -46,10 +44,7 @@
|
|||||||
int
|
int
|
||||||
puts(const char *s)
|
puts(const char *s)
|
||||||
{
|
{
|
||||||
struct iob * file = (struct iob *)stdout;
|
|
||||||
int result = EOF;
|
int result = EOF;
|
||||||
int buffer_mode;
|
|
||||||
int c;
|
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
@ -57,11 +52,6 @@ puts(const char *s)
|
|||||||
|
|
||||||
assert( s != NULL );
|
assert( s != NULL );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
|
||||||
__check_abort();
|
|
||||||
|
|
||||||
flockfile(stdout);
|
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(s == NULL)
|
if(s == NULL)
|
||||||
@ -72,45 +62,13 @@ puts(const char *s)
|
|||||||
}
|
}
|
||||||
#endif /* CHECK_FOR_NULL_POINTERS */
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||||
|
|
||||||
assert( __is_valid_iob(file) );
|
if (__fputs(s, '\n', stdout) == EOF)
|
||||||
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
|
|
||||||
assert( file->iob_BufferSize > 0 );
|
|
||||||
|
|
||||||
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
|
|
||||||
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
|
|
||||||
buffer_mode = IOBF_BUFFER_MODE_LINE;
|
|
||||||
|
|
||||||
if(__fputc_check(stdout) < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
while((c = (*s++)) != '\0')
|
|
||||||
{
|
|
||||||
if(__putc(c,stdout,buffer_mode) == EOF)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(__putc('\n',stdout,buffer_mode) == EOF)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
result = OK;
|
result = OK;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
/* Note: if buffering is disabled for this stream, then we still
|
|
||||||
may have buffered data around, queued to be printed right now.
|
|
||||||
This is intended to improve performance as it takes more effort
|
|
||||||
to write a single character to a file than to write a bunch. */
|
|
||||||
if(result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
|
|
||||||
{
|
|
||||||
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
|
|
||||||
{
|
|
||||||
SHOWMSG("couldn't flush the write buffer");
|
|
||||||
result = EOF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
funlockfile(stdout);
|
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: stdio_setvbuf.c,v 1.11 2008-09-04 12:07:58 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -114,20 +112,28 @@ setvbuf(FILE *stream,char *buf,int bufmode,size_t size)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A buffer size of 0 bytes defaults to unbuffered operation. */
|
/* A buffer size of 0 bytes will cause the default buffer size to be used. */
|
||||||
if(size == 0)
|
if(size == 0)
|
||||||
bufmode = IOBF_BUFFER_MODE_NONE;
|
|
||||||
|
|
||||||
/* If a certain buffer size is requested but no buffer was provided,
|
|
||||||
allocate some memory for it. */
|
|
||||||
if(size > 0 && buf == NULL)
|
|
||||||
{
|
{
|
||||||
/* Allocate a little more memory than necessary. */
|
size = BUFSIZ;
|
||||||
new_buffer = malloc(size + (__cache_line_size-1));
|
buf = NULL;
|
||||||
if(new_buffer == NULL)
|
}
|
||||||
|
|
||||||
|
if(bufmode != IOBF_BUFFER_MODE_NONE)
|
||||||
|
{
|
||||||
|
/* If a certain buffer size is requested but no buffer was provided,
|
||||||
|
allocate some memory for it. */
|
||||||
|
if(size > 0 && buf == NULL)
|
||||||
{
|
{
|
||||||
__set_errno(ENOBUFS);
|
assert( size <= ((size + (__cache_line_size-1)) & ~(__cache_line_size-1)) );
|
||||||
goto out;
|
|
||||||
|
/* Allocate a little more memory than necessary. */
|
||||||
|
new_buffer = malloc(size + (__cache_line_size-1));
|
||||||
|
if(new_buffer == NULL)
|
||||||
|
{
|
||||||
|
__set_errno(ENOBUFS);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,15 +46,8 @@
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
abort(void)
|
__abort(void)
|
||||||
{
|
{
|
||||||
/* Try to call the signal handler that might be in charge of
|
|
||||||
handling cleanup operations, etc. */
|
|
||||||
raise(SIGABRT);
|
|
||||||
|
|
||||||
/* If the signal handler returns it means that we still have
|
|
||||||
to terminate the program. */
|
|
||||||
|
|
||||||
__check_abort_enabled = FALSE;
|
__check_abort_enabled = FALSE;
|
||||||
|
|
||||||
__print_termination_message(NULL);
|
__print_termination_message(NULL);
|
||||||
@ -63,3 +56,17 @@ abort(void)
|
|||||||
does not trigger the exit trap. */
|
does not trigger the exit trap. */
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
abort(void)
|
||||||
|
{
|
||||||
|
/* Try to call the signal handler that might be in charge of
|
||||||
|
handling cleanup operations, etc. */
|
||||||
|
raise(SIGABRT);
|
||||||
|
|
||||||
|
/* If the signal handler returns it means that we still have
|
||||||
|
to terminate the program. */
|
||||||
|
__abort();
|
||||||
|
}
|
||||||
|
|||||||
@ -69,11 +69,36 @@ struct MemoryContextNode
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* The default behaviour for alloca() failing is to
|
||||||
|
* terminate the program rather than let it stumble
|
||||||
|
* into a NULL-pointer reference.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
default_alloca_trap(void)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
CLIB_CONSTRUCTOR(alloca_init)
|
||||||
|
{
|
||||||
|
ENTER();
|
||||||
|
|
||||||
|
__alloca_trap = default_alloca_trap;
|
||||||
|
|
||||||
|
NewList((struct List *)&alloca_memory_list);
|
||||||
|
|
||||||
|
LEAVE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
CLIB_DESTRUCTOR(alloca_exit)
|
CLIB_DESTRUCTOR(alloca_exit)
|
||||||
{
|
{
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
/* Clean this up, too, just to be safe. */
|
/* This list should remain empty. */
|
||||||
NewList((struct List *)&alloca_memory_list);
|
NewList((struct List *)&alloca_memory_list);
|
||||||
|
|
||||||
LEAVE();
|
LEAVE();
|
||||||
@ -83,18 +108,18 @@ CLIB_DESTRUCTOR(alloca_exit)
|
|||||||
|
|
||||||
/* Cleans up after all alloca() allocations that have been made so far. */
|
/* Cleans up after all alloca() allocations that have been made so far. */
|
||||||
static void
|
static void
|
||||||
alloca_cleanup(const char * file,int line)
|
alloca_cleanup(const char * file, int line)
|
||||||
{
|
{
|
||||||
void * stack_pointer = __get_sp();
|
void * stack_pointer = __get_sp();
|
||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
/* Initialize this if it hasn't been taken care of yet. */
|
/* Initialize this if it hasn't been taken care of yet. */
|
||||||
if(alloca_memory_list.mlh_Head == NULL)
|
if (alloca_memory_list.mlh_Head == NULL)
|
||||||
NewList((struct List *)&alloca_memory_list);
|
NewList((struct List *)&alloca_memory_list);
|
||||||
|
|
||||||
/* Is this worth cleaning up? */
|
/* Is this worth cleaning up? */
|
||||||
if(NOT IsMinListEmpty(&alloca_memory_list))
|
if (NOT IsListEmpty((struct List *)&alloca_memory_list))
|
||||||
{
|
{
|
||||||
struct MemoryContextNode * mcn_prev;
|
struct MemoryContextNode * mcn_prev;
|
||||||
struct MemoryContextNode * mcn;
|
struct MemoryContextNode * mcn;
|
||||||
@ -106,21 +131,24 @@ alloca_cleanup(const char * file,int line)
|
|||||||
we move up from the end to the top of the list, the closer we get
|
we move up from the end to the top of the list, the closer we get
|
||||||
to the allocations made in the context of a stack frame near to
|
to the allocations made in the context of a stack frame near to
|
||||||
where were currently are. */
|
where were currently are. */
|
||||||
for(mcn = (struct MemoryContextNode *)alloca_memory_list.mlh_TailPred ;
|
for (mcn = (struct MemoryContextNode *)alloca_memory_list.mlh_TailPred ;
|
||||||
mcn->mcn_MinNode.mln_Pred != NULL && mcn->mcn_StackPointer < stack_pointer ;
|
mcn->mcn_MinNode.mln_Pred != NULL && mcn->mcn_StackPointer < stack_pointer ;
|
||||||
mcn = mcn_prev)
|
mcn = mcn_prev)
|
||||||
{
|
{
|
||||||
mcn_prev = (struct MemoryContextNode *)mcn->mcn_MinNode.mln_Pred;
|
mcn_prev = (struct MemoryContextNode *)mcn->mcn_MinNode.mln_Pred;
|
||||||
|
|
||||||
Remove((struct Node *)mcn);
|
Remove((struct Node *)mcn);
|
||||||
|
|
||||||
__free_memory(mcn->mcn_Memory,TRUE,file,line);
|
/* Note: force the memory to be freed because it
|
||||||
__free_memory(mcn,FALSE,file,line);
|
has gone out of scope. */
|
||||||
|
__free_memory(mcn->mcn_Memory, TRUE, file, line);
|
||||||
|
|
||||||
|
__free_memory(mcn, FALSE, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop the cleanup callback if there's nothing to be cleaned
|
/* Drop the cleanup callback if there's nothing to be cleaned
|
||||||
up any more. */
|
up any more. */
|
||||||
if(IsMinListEmpty(&alloca_memory_list))
|
if (IsListEmpty((struct List *)&alloca_memory_list))
|
||||||
__alloca_cleanup = NULL;
|
__alloca_cleanup = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +158,7 @@ alloca_cleanup(const char * file,int line)
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
__static void *
|
__static void *
|
||||||
__alloca(size_t size,const char * file,int line)
|
__alloca(size_t size, const char * file, int line)
|
||||||
{
|
{
|
||||||
void * stack_pointer = __get_sp();
|
void * stack_pointer = __get_sp();
|
||||||
struct MemoryContextNode * mcn;
|
struct MemoryContextNode * mcn;
|
||||||
@ -138,27 +166,23 @@ __alloca(size_t size,const char * file,int line)
|
|||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
/* Initialize this if it hasn't been taken care of yet. */
|
|
||||||
if(alloca_memory_list.mlh_Head == NULL)
|
|
||||||
NewList((struct List *)&alloca_memory_list);
|
|
||||||
|
|
||||||
__alloca_cleanup = alloca_cleanup;
|
__alloca_cleanup = alloca_cleanup;
|
||||||
(*__alloca_cleanup)(file,line);
|
(*__alloca_cleanup)(file, line);
|
||||||
|
|
||||||
mcn = __allocate_memory(sizeof(*mcn),FALSE,file,line);
|
mcn = __allocate_memory(sizeof(*mcn), FALSE, file, line);
|
||||||
if(mcn == NULL)
|
if (mcn == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("not enough memory");
|
SHOWMSG("not enough memory");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate memory which cannot be run through realloc() or free(). */
|
/* Allocate memory which cannot be run through realloc() or free(). */
|
||||||
mcn->mcn_Memory = __allocate_memory(size,TRUE,file,line);
|
mcn->mcn_Memory = __allocate_memory(size, TRUE, file, line);
|
||||||
if(mcn->mcn_Memory == NULL)
|
if (mcn->mcn_Memory == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("not enough memory");
|
SHOWMSG("not enough memory");
|
||||||
|
|
||||||
__free(mcn,file,line);
|
__free(mcn, file, line);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +190,7 @@ __alloca(size_t size,const char * file,int line)
|
|||||||
|
|
||||||
assert( alloca_memory_list.mlh_Head != NULL );
|
assert( alloca_memory_list.mlh_Head != NULL );
|
||||||
|
|
||||||
AddTail((struct List *)&alloca_memory_list,(struct Node *)mcn);
|
AddTail((struct List *)&alloca_memory_list, (struct Node *)mcn);
|
||||||
|
|
||||||
result = mcn->mcn_Memory;
|
result = mcn->mcn_Memory;
|
||||||
|
|
||||||
@ -176,10 +200,14 @@ __alloca(size_t size,const char * file,int line)
|
|||||||
|
|
||||||
/* If we are about to return NULL and a trap function is
|
/* If we are about to return NULL and a trap function is
|
||||||
provided, call it rather than returning NULL. */
|
provided, call it rather than returning NULL. */
|
||||||
if(result == NULL && __alloca_trap != NULL)
|
if (result == NULL && __alloca_trap != NULL)
|
||||||
(*__alloca_trap)();
|
{
|
||||||
|
__alloca_cleanup = NULL;
|
||||||
|
|
||||||
return(result);
|
(*__alloca_trap)();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@ -191,5 +219,5 @@ alloca(size_t size)
|
|||||||
|
|
||||||
result = __alloca(size,NULL,0);
|
result = __alloca(size,NULL,0);
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
47
library/stdlib_calloc.c
Normal file → Executable file
47
library/stdlib_calloc.c
Normal file → Executable file
@ -48,48 +48,51 @@
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
__static void *
|
__static void *
|
||||||
__calloc(size_t num_elements,size_t element_size,const char * file,int line)
|
__calloc(size_t num_elements, size_t element_size, const char * file UNUSED, int line UNUSED)
|
||||||
{
|
{
|
||||||
void * result = NULL;
|
void * result = NULL;
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
/*__check_memory_allocations(file,line);*/
|
__check_memory_allocations(file, line);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
/* This might overflow. */
|
/* Check for overflow. */
|
||||||
total_size = num_elements * element_size;
|
total_size = element_size * num_elements;
|
||||||
|
if (num_elements > 0 && element_size > 0 && element_size != (total_size / num_elements))
|
||||||
/* No arithmetic overflow? */
|
|
||||||
if(total_size >= num_elements)
|
|
||||||
{
|
|
||||||
result = __malloc(total_size,file,line);
|
|
||||||
if(result != NULL)
|
|
||||||
memset(result,0,total_size);
|
|
||||||
else
|
|
||||||
SHOWMSG("memory allocation failure");
|
|
||||||
}
|
|
||||||
/* Multiplying the number and size of elements overflows
|
|
||||||
* the size_t range.
|
|
||||||
*/
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
D(("calloc(num_elements=%ld, element_size=%ld) overflow"));
|
D(("calloc(num_elements=%ld, element_size=%ld) overflow"));
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(result);
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total_size > 0)
|
||||||
|
memset(result, 0, total_size);
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void *
|
void *
|
||||||
calloc(size_t num_elements,size_t element_size)
|
calloc(size_t num_elements, size_t element_size)
|
||||||
{
|
{
|
||||||
void * result;
|
void * result;
|
||||||
|
|
||||||
result = __calloc(num_elements,element_size,NULL,0);
|
result = __calloc(num_elements, element_size, NULL, 0);
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,18 +59,18 @@ get_hex_char(int n)
|
|||||||
{
|
{
|
||||||
char result;
|
char result;
|
||||||
|
|
||||||
if(0 <= n && n <= 9)
|
if (0 <= n && n <= 9)
|
||||||
result = n + '0';
|
result = n + '0';
|
||||||
else
|
else
|
||||||
result = n + 'A' - 10;
|
result = n + 'A' - 10;
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC VOID
|
STATIC VOID
|
||||||
int_to_hex(unsigned long v,char * buffer,int min_digits)
|
int_to_hex(unsigned long v, char * buffer, int min_digits)
|
||||||
{
|
{
|
||||||
int i,j,c;
|
int i, j, c;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
@ -81,12 +81,12 @@ int_to_hex(unsigned long v,char * buffer,int min_digits)
|
|||||||
|
|
||||||
buffer[i++] = get_hex_char(c);
|
buffer[i++] = get_hex_char(c);
|
||||||
}
|
}
|
||||||
while(v > 0);
|
while (v > 0);
|
||||||
|
|
||||||
while(i < min_digits)
|
while (i < min_digits)
|
||||||
buffer[i++] = '0';
|
buffer[i++] = '0';
|
||||||
|
|
||||||
for(j = 0 ; j < i / 2 ; j++)
|
for (j = 0 ; j < i / 2 ; j++)
|
||||||
{
|
{
|
||||||
c = buffer[i - 1 - j];
|
c = buffer[i - 1 - j];
|
||||||
buffer[i - 1 - j] = buffer[j];
|
buffer[i - 1 - j] = buffer[j];
|
||||||
@ -97,47 +97,47 @@ int_to_hex(unsigned long v,char * buffer,int min_digits)
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATIC VOID
|
STATIC VOID
|
||||||
dump_memory(unsigned char * m,int size,int ignore)
|
dump_memory(const unsigned char * m, int size, int ignore)
|
||||||
{
|
{
|
||||||
const int mod = 20;
|
const int mod = 20;
|
||||||
int position,i,c;
|
int position, i, c;
|
||||||
char buffer[120];
|
char buffer[120];
|
||||||
char hex[10];
|
char hex[10];
|
||||||
|
|
||||||
buffer[0] = '\0';
|
buffer[0] = '\0';
|
||||||
|
|
||||||
for(i = 0 ; i < size ; i++)
|
for (i = 0 ; i < size ; i++)
|
||||||
{
|
{
|
||||||
position = i % mod;
|
position = i % mod;
|
||||||
if(position == 0)
|
if (position == 0)
|
||||||
{
|
{
|
||||||
if(buffer[0] != '\0')
|
if (buffer[0] != '\0')
|
||||||
{
|
{
|
||||||
int len = sizeof(buffer)-1;
|
int len = sizeof(buffer)-1;
|
||||||
|
|
||||||
while(len > 0 && buffer[len-1] == ' ')
|
while (len > 0 && buffer[len-1] == ' ')
|
||||||
len--;
|
len--;
|
||||||
|
|
||||||
buffer[len] = '\0';
|
buffer[len] = '\0';
|
||||||
|
|
||||||
kprintf("[%s] %s\n",__program_name,buffer);
|
kprintf("[%s] %s\n", __program_name, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(buffer,' ',sizeof(buffer)-1);
|
memset(buffer, ' ', sizeof(buffer)-1);
|
||||||
|
|
||||||
int_to_hex((unsigned long)&m[i],hex,8);
|
int_to_hex((unsigned long)&m[i], hex, 8);
|
||||||
|
|
||||||
memmove(buffer,hex,8);
|
memmove(buffer, hex, 8);
|
||||||
hex[9] = ':';
|
hex[9] = ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m[i] != ignore)
|
if (m[i] != ignore)
|
||||||
{
|
{
|
||||||
buffer[10 + 2 * position + 0] = get_hex_char(m[i] >> 4);
|
buffer[10 + 2 * position + 0] = get_hex_char(m[i] >> 4);
|
||||||
buffer[10 + 2 * position + 1] = get_hex_char(m[i] & 15);
|
buffer[10 + 2 * position + 1] = get_hex_char(m[i] & 15);
|
||||||
|
|
||||||
c = m[i];
|
c = m[i];
|
||||||
if(c < ' ' || (c >= 127 && c <= 160))
|
if (c < ' ' || (127 <= c && c < 160))
|
||||||
c = '.';
|
c = '.';
|
||||||
|
|
||||||
buffer[10 + 2 * mod + 1 + position] = c;
|
buffer[10 + 2 * mod + 1 + position] = c;
|
||||||
@ -149,111 +149,111 @@ dump_memory(unsigned char * m,int size,int ignore)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(buffer[0] != '\0')
|
if (buffer[0] != '\0')
|
||||||
{
|
{
|
||||||
int len = sizeof(buffer)-1;
|
int len = sizeof(buffer)-1;
|
||||||
|
|
||||||
while(len > 0 && buffer[len-1] == ' ')
|
while (len > 0 && buffer[len-1] == ' ')
|
||||||
len--;
|
len--;
|
||||||
|
|
||||||
buffer[len] = '\0';
|
buffer[len] = '\0';
|
||||||
|
|
||||||
kprintf("[%s] %s\n",__program_name,buffer);
|
kprintf("[%s] %s\n", __program_name, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
STATIC VOID
|
STATIC VOID
|
||||||
check_memory_node(struct MemoryNode * mn,const char * file,int line)
|
check_memory_node(struct MemoryNode * mn, const char * file, int line)
|
||||||
{
|
{
|
||||||
ULONG size = GET_MN_SIZE(mn);
|
ULONG size = mn->mn_OriginalSize;
|
||||||
unsigned char * head = (unsigned char *)(mn + 1);
|
const unsigned char * head = (unsigned char *)&mn[1];
|
||||||
unsigned char * body = head + MALLOC_HEAD_SIZE;
|
const unsigned char * body = &head[MALLOC_HEAD_SIZE];
|
||||||
unsigned char * tail = body + size;
|
const unsigned char * tail = &body[size];
|
||||||
int max_head_damage = 0;
|
int max_head_damage = 0;
|
||||||
int max_tail_damage = 0;
|
int max_tail_damage = 0;
|
||||||
int max_body_damage = 0;
|
int max_body_damage = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 1 ; i <= MALLOC_HEAD_SIZE ; i++)
|
for (i = 1 ; i <= MALLOC_HEAD_SIZE ; i++)
|
||||||
{
|
{
|
||||||
if(head[MALLOC_HEAD_SIZE - i] != MALLOC_HEAD_FILL)
|
if (head[MALLOC_HEAD_SIZE - i] != MALLOC_HEAD_FILL)
|
||||||
max_head_damage = i;
|
max_head_damage = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(max_head_damage > 0)
|
if (max_head_damage > 0)
|
||||||
{
|
{
|
||||||
kprintf("[%s] ",__program_name);
|
kprintf("[%s] ", __program_name);
|
||||||
|
|
||||||
if(file != NULL)
|
if (file != NULL)
|
||||||
kprintf("%s:%ld:",file,line);
|
kprintf("%s:%ld:", file, line);
|
||||||
|
|
||||||
kprintf("At least %ld bytes were damaged in front of allocation 0x%08lx..0x%08lx, size = %ld",
|
kprintf("At least %ld bytes were damaged in front of allocation 0x%08lx..0x%08lx, size = %ld",
|
||||||
max_head_damage,
|
max_head_damage,
|
||||||
body,body + size - 1,size);
|
body, body + size - 1, size);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if (mn->mn_File != NULL)
|
||||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||||
|
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
|
|
||||||
dump_memory(head,MALLOC_HEAD_SIZE,MALLOC_HEAD_FILL);
|
dump_memory(head, MALLOC_HEAD_SIZE, MALLOC_HEAD_FILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0 ; i < MALLOC_TAIL_SIZE ; i++)
|
for (i = 0 ; i < MALLOC_TAIL_SIZE ; i++)
|
||||||
{
|
{
|
||||||
if(tail[i] != MALLOC_TAIL_FILL)
|
if (tail[i] != MALLOC_TAIL_FILL)
|
||||||
max_tail_damage = i+1;
|
max_tail_damage = i+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(max_tail_damage > 0)
|
if (max_tail_damage > 0)
|
||||||
{
|
{
|
||||||
kprintf("[%s] ",__program_name);
|
kprintf("[%s] ", __program_name);
|
||||||
|
|
||||||
if(file != NULL)
|
if (file != NULL)
|
||||||
kprintf("%s:%ld:",file,line);
|
kprintf("%s:%ld:", file, line);
|
||||||
|
|
||||||
kprintf("At least %ld bytes were damaged behind allocation 0x%08lx..0x%08lx, size = %ld (with damage = %ld)",
|
kprintf("At least %ld bytes were damaged behind allocation 0x%08lx..0x%08lx, size = %ld (with damage = %ld)",
|
||||||
max_tail_damage,
|
max_tail_damage,
|
||||||
body,body + size - 1,
|
body, body + size - 1,
|
||||||
size,size+max_tail_damage);
|
size, size + max_tail_damage);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if (mn->mn_File != NULL)
|
||||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||||
|
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
|
|
||||||
dump_memory(tail,MALLOC_TAIL_SIZE,MALLOC_TAIL_FILL);
|
dump_memory(tail, MALLOC_TAIL_SIZE, MALLOC_TAIL_FILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mn->mn_AlreadyFree)
|
if (mn->mn_AlreadyFree)
|
||||||
{
|
{
|
||||||
ULONG j;
|
ULONG j;
|
||||||
|
|
||||||
for(j = 0 ; j < size ; j++)
|
for (j = 0 ; j < size ; j++)
|
||||||
{
|
{
|
||||||
if(body[j] != MALLOC_FREE_FILL)
|
if (body[j] != MALLOC_FREE_FILL)
|
||||||
max_body_damage = j+1;
|
max_body_damage = j+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(max_body_damage > 0)
|
if (max_body_damage > 0)
|
||||||
{
|
{
|
||||||
kprintf("[%s] ",__program_name);
|
kprintf("[%s] ", __program_name);
|
||||||
|
|
||||||
if(file != NULL)
|
if (file != NULL)
|
||||||
kprintf("%s:%ld:",file,line);
|
kprintf("%s:%ld:", file, line);
|
||||||
|
|
||||||
kprintf("At least %ld bytes were damaged in freed allocation 0x%08lx..0x%08lx, size = %ld",
|
kprintf("At least %ld bytes were damaged in freed allocation 0x%08lx..0x%08lx, size = %ld",
|
||||||
max_body_damage,
|
max_body_damage,
|
||||||
body,body + size - 1,size);
|
body, body + size - 1, size);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if (mn->mn_File != NULL)
|
||||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||||
|
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
|
|
||||||
dump_memory(body,size,MALLOC_FREE_FILL);
|
dump_memory(body, size, MALLOC_FREE_FILL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,17 +261,17 @@ check_memory_node(struct MemoryNode * mn,const char * file,int line)
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
__check_memory_allocations(const char * file,int line)
|
__check_memory_allocations(const char * file, int line)
|
||||||
{
|
{
|
||||||
struct MemoryNode * mn;
|
struct MemoryNode * mn;
|
||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
for(mn = (struct MemoryNode *)__memory_list.mlh_Head ;
|
for (mn = (struct MemoryNode *)__memory_list.mlh_Head ;
|
||||||
mn->mn_MinNode.mln_Succ != NULL ;
|
mn->mn_MinNode.mln_Succ != NULL ;
|
||||||
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
|
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
|
||||||
{
|
{
|
||||||
check_memory_node(mn,file,line);
|
check_memory_node(mn, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
__memory_unlock();
|
__memory_unlock();
|
||||||
@ -290,7 +290,7 @@ __find_memory_node(void * address)
|
|||||||
|
|
||||||
#if defined(__USE_MEM_TREES)
|
#if defined(__USE_MEM_TREES)
|
||||||
{
|
{
|
||||||
result = __red_black_tree_find(&__memory_tree,address);
|
result = __red_black_tree_find(&__memory_tree, address);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
@ -298,11 +298,11 @@ __find_memory_node(void * address)
|
|||||||
|
|
||||||
result = NULL;
|
result = NULL;
|
||||||
|
|
||||||
for(mn = (struct MemoryNode *)__memory_list.mlh_Head ;
|
for (mn = (struct MemoryNode *)__memory_list.mlh_Head ;
|
||||||
mn->mn_MinNode.mln_Succ != NULL ;
|
mn->mn_MinNode.mln_Succ != NULL ;
|
||||||
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
|
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
|
||||||
{
|
{
|
||||||
if(address == mn->mn_Allocation)
|
if (address == mn->mn_Allocation)
|
||||||
{
|
{
|
||||||
result = mn;
|
result = mn;
|
||||||
break;
|
break;
|
||||||
@ -331,7 +331,7 @@ __find_memory_node(void * address)
|
|||||||
|
|
||||||
result = &((struct MemoryNode *)address)[-1];
|
result = &((struct MemoryNode *)address)[-1];
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@ -349,96 +349,84 @@ remove_and_free_memory_node(struct MemoryNode * mn)
|
|||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
|
allocation_size = mn->mn_AllocationSize;
|
||||||
|
|
||||||
#if defined(__MEM_DEBUG)
|
#if defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
Remove((struct Node *)mn);
|
Remove((struct Node *)mn);
|
||||||
|
|
||||||
#if defined(__USE_MEM_TREES)
|
#if defined(__USE_MEM_TREES)
|
||||||
{
|
{
|
||||||
__red_black_tree_remove(&__memory_tree,mn);
|
__red_black_tree_remove(&__memory_tree, mn);
|
||||||
}
|
}
|
||||||
#endif /* __USE_MEM_TREES */
|
#endif /* __USE_MEM_TREES */
|
||||||
|
|
||||||
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + GET_MN_SIZE(mn) + MALLOC_TAIL_SIZE;
|
memset(mn, MALLOC_FREE_FILL, allocation_size);
|
||||||
|
|
||||||
assert( allocation_size == mn->mn_AllocationSize );
|
|
||||||
|
|
||||||
memset(mn,MALLOC_FREE_FILL,allocation_size);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
allocation_size = sizeof(*mn) + GET_MN_SIZE(mn);
|
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
#if defined(__USE_SLAB_ALLOCATOR)
|
#if defined(__USE_SLAB_ALLOCATOR)
|
||||||
{
|
{
|
||||||
/* Are we using the slab allocator? */
|
/* Are we using the slab allocator? */
|
||||||
if(__slab_data.sd_InUse)
|
if (__slab_data.sd_InUse)
|
||||||
{
|
{
|
||||||
__slab_free(mn,allocation_size);
|
/* No need to remove the memory node because it was never
|
||||||
|
* added or has already been removed if the memory debugging
|
||||||
|
* option is in effect.
|
||||||
|
*/
|
||||||
|
__slab_free(mn, allocation_size);
|
||||||
}
|
}
|
||||||
|
/* Are we using the memory pool? */
|
||||||
|
else if (__memory_pool != NULL)
|
||||||
|
{
|
||||||
|
/* No need to remove the memory node because it was never
|
||||||
|
* added or has already been removed if the memory debugging
|
||||||
|
* option is in effect.
|
||||||
|
*/
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreePooled(__memory_pool, mn, allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
/* So we have to do this the hard way... */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(__memory_pool != NULL)
|
#if NOT defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
PROFILE_OFF();
|
Remove((struct Node *)mn);
|
||||||
FreePooled(__memory_pool,mn,allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
}
|
||||||
else
|
#endif /* __MEM_DEBUG */
|
||||||
{
|
|
||||||
#if defined(__MEM_DEBUG)
|
|
||||||
{
|
|
||||||
PROFILE_OFF();
|
|
||||||
FreeMem(mn,allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
struct MinNode * mln = (struct MinNode *)mn;
|
|
||||||
|
|
||||||
mln--;
|
PROFILE_OFF();
|
||||||
|
FreeMem(mn, allocation_size);
|
||||||
Remove((struct Node *)mln);
|
PROFILE_ON();
|
||||||
|
|
||||||
PROFILE_OFF();
|
|
||||||
FreeMem(mln,sizeof(*mln) + allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
#endif /* __MEM_DEBUG */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
if(__memory_pool != NULL)
|
if (__memory_pool != NULL)
|
||||||
{
|
{
|
||||||
|
/* No need to remove the memory node because it was never
|
||||||
|
* added or has already been removed if the memory debugging
|
||||||
|
* option is in effect.
|
||||||
|
*/
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
FreePooled(__memory_pool,mn,allocation_size);
|
FreePooled(__memory_pool, mn, allocation_size);
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if defined(__MEM_DEBUG)
|
#if NOT defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
PROFILE_OFF();
|
Remove((struct Node *)mn);
|
||||||
FreeMem(mn,allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
struct MinNode * mln = (struct MinNode *)mn;
|
|
||||||
|
|
||||||
mln--;
|
|
||||||
|
|
||||||
Remove((struct Node *)mln);
|
|
||||||
|
|
||||||
PROFILE_OFF();
|
|
||||||
FreeMem(mln,sizeof(*mln) + allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
|
/* No need to remove the memory node because the memory
|
||||||
|
* debugging option is in effect.
|
||||||
|
*/
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreeMem(mn, allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __USE_SLAB_ALLOCATOR */
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
@ -452,37 +440,35 @@ remove_and_free_memory_node(struct MemoryNode * mn)
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
__free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED line)
|
__free_memory_node(struct MemoryNode * mn, const char * UNUSED file, int UNUSED line)
|
||||||
{
|
{
|
||||||
assert(mn != NULL);
|
assert(mn != NULL);
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
ULONG size = GET_MN_SIZE(mn);
|
check_memory_node(mn, file, line);
|
||||||
|
|
||||||
check_memory_node(mn,file,line);
|
if (NOT mn->mn_AlreadyFree)
|
||||||
|
|
||||||
if(NOT mn->mn_AlreadyFree)
|
|
||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name,size,mn->mn_Allocation);
|
kprintf("[%s] - %10ld 0x%08lx [",__program_name, mn->mn_OriginalSize, mn->mn_Allocation);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if (mn->mn_File != NULL)
|
||||||
kprintf("allocated at %s:%ld, ",mn->mn_File,mn->mn_Line);
|
kprintf("allocated at %s:%ld, ", mn->mn_File, mn->mn_Line);
|
||||||
|
|
||||||
kprintf("freed at %s:%ld]\n",file,line);
|
kprintf("freed at %s:%ld]\n", file, line);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
if(__never_free)
|
if (__never_free)
|
||||||
{
|
{
|
||||||
mn->mn_AlreadyFree = TRUE;
|
mn->mn_AlreadyFree = TRUE;
|
||||||
|
|
||||||
mn->mn_FreeFile = (char *)file;
|
mn->mn_FreeFile = (char *)file;
|
||||||
mn->mn_FreeLine = line;
|
mn->mn_FreeLine = line;
|
||||||
|
|
||||||
memset(mn->mn_Allocation,MALLOC_FREE_FILL,size);
|
memset(&mn[1], MALLOC_FREE_FILL, MALLOC_HEAD_SIZE + mn->mn_OriginalSize + MALLOC_TAIL_SIZE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -493,19 +479,19 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
|
|||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name,size,mn->mn_Allocation);
|
kprintf("[%s] - %10ld 0x%08lx [", __program_name, mn->mn_AllocationSize, mn);
|
||||||
|
|
||||||
kprintf("FAILED]\n");
|
kprintf("FAILED]\n");
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
kprintf("[%s] %s:%ld:Allocation at address 0x%08lx, size %ld",
|
kprintf("[%s] %s:%ld:Allocation at address 0x%08lx, size %ld",
|
||||||
__program_name,file,line,mn->mn_Allocation,size);
|
__program_name, file, line, mn->mn_Allocation, mn->mn_OriginalSize);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if (mn->mn_File != NULL)
|
||||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
|
||||||
|
|
||||||
kprintf(", has already been freed at %s:%ld.\n",mn->mn_FreeFile,mn->mn_FreeLine);
|
kprintf(", has already been freed at %s:%ld.\n", mn->mn_FreeFile, mn->mn_FreeLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -518,7 +504,7 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
__free_memory(void * ptr,BOOL force,const char * file,int line)
|
__free_memory(void * ptr, BOOL force, const char * file, int line)
|
||||||
{
|
{
|
||||||
struct MemoryNode * mn;
|
struct MemoryNode * mn;
|
||||||
|
|
||||||
@ -529,7 +515,7 @@ __free_memory(void * ptr,BOOL force,const char * file,int line)
|
|||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
/*if((rand() % 16) == 0)
|
/*if ((rand() % 16) == 0)
|
||||||
__check_memory_allocations(file,line);*/
|
__check_memory_allocations(file,line);*/
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
@ -538,34 +524,37 @@ __free_memory(void * ptr,BOOL force,const char * file,int line)
|
|||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
if(mn != NULL)
|
if (mn != NULL)
|
||||||
{
|
{
|
||||||
if(force || FLAG_IS_CLEAR(mn->mn_Size, MN_SIZE_NEVERFREE))
|
if (force || FLAG_IS_CLEAR(mn->mn_Flags, MNF_NEVER_FREE))
|
||||||
__free_memory_node(mn,file,line);
|
__free_memory_node(mn, file, line);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name,0,ptr);
|
kprintf("[%s] - %10ld 0x%08lx [", __program_name, 0, ptr);
|
||||||
|
|
||||||
kprintf("FAILED]\n");
|
kprintf("FAILED]\n");
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
kprintf("[%s] %s:%ld:Address for free(0x%08lx) not known.\n",__program_name,file,line,ptr);
|
kprintf("[%s] %s:%ld:Address for free(0x%08lx) not known.\n", __program_name, file, line, ptr);
|
||||||
|
|
||||||
D(("memory allocation at 0x%08lx could not be freed",ptr));
|
D(("memory allocation at 0x%08lx could not be freed", ptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
assert( mn != NULL );
|
assert( mn != NULL );
|
||||||
|
|
||||||
SHOWVALUE(mn->mn_Size);
|
if (FLAG_IS_SET(mn->mn_Flags, MNF_NEVER_FREE))
|
||||||
|
D(("mn->mn_AllocationSize=%ld (0x%08lx), not to be freed", mn->mn_AllocationSize, mn->mn_AllocationSize));
|
||||||
|
else
|
||||||
|
D(("mn->mn_AllocationSize=%ld (0x%08lx)", mn->mn_AllocationSize, mn->mn_AllocationSize));
|
||||||
|
|
||||||
if(mn != NULL && (force || FLAG_IS_CLEAR(mn->mn_Size, MN_SIZE_NEVERFREE)))
|
if (mn != NULL && (force || FLAG_IS_CLEAR(mn->mn_Flags, MNF_NEVER_FREE)))
|
||||||
__free_memory_node(mn,file,line);
|
__free_memory_node(mn, file, line);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
}
|
}
|
||||||
@ -578,13 +567,13 @@ __free(void * ptr,const char * file,int line)
|
|||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
/* Try to get rid of now unused memory. */
|
/* Try to get rid of now unused memory. */
|
||||||
if(__alloca_cleanup != NULL)
|
if (__alloca_cleanup != NULL)
|
||||||
(*__alloca_cleanup)(file,line);
|
(*__alloca_cleanup)(file, line);
|
||||||
|
|
||||||
__memory_unlock();
|
__memory_unlock();
|
||||||
|
|
||||||
if(ptr != NULL)
|
if (ptr != NULL)
|
||||||
__free_memory(ptr,FALSE,file,line);
|
__free_memory(ptr, FALSE, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@ -592,5 +581,5 @@ __free(void * ptr,const char * file,int line)
|
|||||||
void
|
void
|
||||||
free(void * ptr)
|
free(void * ptr)
|
||||||
{
|
{
|
||||||
__free(ptr,NULL,0);
|
__free(ptr, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
26
library/stdlib_get_slab_usage.c
Normal file → Executable file
26
library/stdlib_get_slab_usage.c
Normal file → Executable file
@ -44,14 +44,14 @@
|
|||||||
void
|
void
|
||||||
__get_slab_usage(__slab_usage_callback callback)
|
__get_slab_usage(__slab_usage_callback callback)
|
||||||
{
|
{
|
||||||
if(__slab_data.sd_InUse)
|
if (__slab_data.sd_InUse)
|
||||||
{
|
{
|
||||||
struct __slab_usage_information sui;
|
struct __slab_usage_information sui;
|
||||||
const struct SlabNode * sn;
|
const struct SlabNode * sn;
|
||||||
BOOL stop;
|
BOOL stop;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memset(&sui,0,sizeof(sui));
|
memset(&sui, 0, sizeof(sui));
|
||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
@ -59,11 +59,11 @@ __get_slab_usage(__slab_usage_callback callback)
|
|||||||
sui.sui_num_single_allocations = __slab_data.sd_NumSingleAllocations;
|
sui.sui_num_single_allocations = __slab_data.sd_NumSingleAllocations;
|
||||||
sui.sui_total_single_allocation_size = __slab_data.sd_TotalSingleAllocationSize;
|
sui.sui_total_single_allocation_size = __slab_data.sd_TotalSingleAllocationSize;
|
||||||
|
|
||||||
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
for (i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||||
{
|
{
|
||||||
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
for (sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||||
sn->sn_MinNode.mln_Succ != NULL ;
|
sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||||
{
|
{
|
||||||
if (sn->sn_UseCount == 0)
|
if (sn->sn_UseCount == 0)
|
||||||
sui.sui_num_empty_slabs++;
|
sui.sui_num_empty_slabs++;
|
||||||
@ -76,13 +76,15 @@ __get_slab_usage(__slab_usage_callback callback)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sui.sui_num_slabs > 0)
|
if (sui.sui_num_slabs > 0)
|
||||||
{
|
{
|
||||||
for(i = 0, stop = FALSE ; NOT stop && i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
for (i = 0, stop = FALSE ;
|
||||||
|
stop == FALSE && i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ;
|
||||||
|
i++)
|
||||||
{
|
{
|
||||||
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
for (sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||||
sn->sn_MinNode.mln_Succ != NULL ;
|
sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||||
{
|
{
|
||||||
sui.sui_chunk_size = sn->sn_ChunkSize;
|
sui.sui_chunk_size = sn->sn_ChunkSize;
|
||||||
sui.sui_num_chunks = sn->sn_Count;
|
sui.sui_num_chunks = sn->sn_Count;
|
||||||
@ -91,7 +93,7 @@ __get_slab_usage(__slab_usage_callback callback)
|
|||||||
|
|
||||||
sui.sui_slab_index++;
|
sui.sui_slab_index++;
|
||||||
|
|
||||||
if((*callback)(&sui) != 0)
|
if ((*callback)(&sui) != 0)
|
||||||
{
|
{
|
||||||
stop = TRUE;
|
stop = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -189,6 +189,10 @@ extern BOOL NOCOMMON __lib_startup;
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
extern int __addition_overflows(ULONG x, ULONG y);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
extern void NOCOMMON (*__alloca_trap)(void);
|
extern void NOCOMMON (*__alloca_trap)(void);
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
unsigned long NOCOMMON __maximum_memory_allocated;
|
unsigned long NOCOMMON __maximum_memory_allocated;
|
||||||
unsigned long NOCOMMON __current_memory_allocated;
|
unsigned long NOCOMMON __current_memory_allocated;
|
||||||
|
|
||||||
unsigned long NOCOMMON __maximum_num_memory_chunks_allocated;
|
unsigned long NOCOMMON __maximum_num_memory_chunks_allocated;
|
||||||
unsigned long NOCOMMON __current_num_memory_chunks_allocated;
|
unsigned long NOCOMMON __current_num_memory_chunks_allocated;
|
||||||
|
|
||||||
@ -74,36 +75,59 @@ struct MinList NOCOMMON __memory_list;
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void *
|
/* Check if the sum of two unsigned 32-bit integers will be larger than what
|
||||||
__allocate_memory(size_t size,BOOL never_free,const char *debug_file_name UNUSED,int debug_line_number UNUSED)
|
* an unsigned 32-bit integer can hold and return the overflow. This
|
||||||
|
* algorithm comes from Henry S. Warren's book "Hacker's delight".
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
__addition_overflows(ULONG x, ULONG y)
|
||||||
{
|
{
|
||||||
struct MemoryNode * mn;
|
ULONG z;
|
||||||
|
|
||||||
|
assert( sizeof(x) == 4 );
|
||||||
|
assert( sizeof(y) == 4 );
|
||||||
|
|
||||||
|
z = (x & y) | ((x | y) & ~(x + y));
|
||||||
|
|
||||||
|
return ((LONG)z) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void *
|
||||||
|
__allocate_memory(
|
||||||
|
size_t size,
|
||||||
|
BOOL never_free,
|
||||||
|
const char * debug_file_name UNUSED,
|
||||||
|
int debug_line_number UNUSED)
|
||||||
|
{
|
||||||
|
struct MemoryNode * mn UNUSED;
|
||||||
size_t allocation_size;
|
size_t allocation_size;
|
||||||
void * result = NULL;
|
void * result = NULL;
|
||||||
|
size_t original_size UNUSED;
|
||||||
|
|
||||||
#if defined(UNIX_PATH_SEMANTICS)
|
#if defined(UNIX_PATH_SEMANTICS)
|
||||||
size_t original_size;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
original_size = size;
|
original_size = size;
|
||||||
|
|
||||||
/* The libunix.a flavour accepts zero length memory allocations
|
/* The libunix.a flavour of malloc() accepts zero-length
|
||||||
and quietly turns them into a pointer sized allocations. */
|
memory allocations and quietly turns these into
|
||||||
if(size == 0)
|
pointer-sized allocations. */
|
||||||
size = sizeof(char *);
|
if (size == 0)
|
||||||
|
size = sizeof(BYTE *);
|
||||||
}
|
}
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
/* Zero length allocations are by default rejected. */
|
/* Zero length allocations are by default rejected. */
|
||||||
if(size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
__set_errno(EINVAL);
|
__set_errno(EINVAL);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(__free_memory_threshold > 0 && AvailMem(MEMF_ANY|MEMF_LARGEST) < __free_memory_threshold)
|
if (__free_memory_threshold > 0 && AvailMem(MEMF_ANY|MEMF_LARGEST) < __free_memory_threshold)
|
||||||
{
|
{
|
||||||
SHOWMSG("not enough free memory available to safely proceed with allocation");
|
SHOWMSG("not enough free memory available to safely proceed with allocation");
|
||||||
goto out;
|
goto out;
|
||||||
@ -115,172 +139,140 @@ __allocate_memory(size_t size,BOOL never_free,const char *debug_file_name UNUSED
|
|||||||
assert( MALLOC_TAIL_SIZE > 0 && (MALLOC_TAIL_SIZE % 4) == 0 );
|
assert( MALLOC_TAIL_SIZE > 0 && (MALLOC_TAIL_SIZE % 4) == 0 );
|
||||||
assert( (sizeof(*mn) % 4) == 0 );
|
assert( (sizeof(*mn) % 4) == 0 );
|
||||||
|
|
||||||
|
if (__addition_overflows(sizeof(*mn) + MALLOC_HEAD_SIZE + MALLOC_TAIL_SIZE, size))
|
||||||
|
{
|
||||||
|
SHOWMSG("integer overflow");
|
||||||
|
|
||||||
|
__set_errno(ENOMEM);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + size + MALLOC_TAIL_SIZE;
|
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + size + MALLOC_TAIL_SIZE;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
/* Round up allocation to a multiple of 32 bits. */
|
if (__addition_overflows(sizeof(*mn), size))
|
||||||
if((size & 3) != 0)
|
{
|
||||||
size += 4 - (size & 3);
|
SHOWMSG("integer overflow");
|
||||||
|
|
||||||
|
__set_errno(ENOMEM);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
allocation_size = sizeof(*mn) + size;
|
allocation_size = sizeof(*mn) + size;
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
/* Integer overflow has occured? */
|
/* Round up allocation to a multiple of 8 bytes. */
|
||||||
if(size == 0 || allocation_size < size)
|
if ((allocation_size % MEM_BLOCKSIZE) > 0)
|
||||||
{
|
{
|
||||||
__set_errno(ENOMEM);
|
size_t padding;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We reuse the MemoryNode.mn_Size field to mark
|
padding = MEM_BLOCKSIZE - (allocation_size % MEM_BLOCKSIZE);
|
||||||
* allocations are not suitable for use with
|
|
||||||
* free() and realloc(). This limits allocation
|
if (__addition_overflows(padding, allocation_size))
|
||||||
* sizes to a little less than 2 GBytes.
|
{
|
||||||
*/
|
SHOWMSG("integer overflow");
|
||||||
if(allocation_size & MN_SIZE_NEVERFREE)
|
|
||||||
{
|
__set_errno(ENOMEM);
|
||||||
__set_errno(ENOMEM);
|
goto out;
|
||||||
goto out;
|
}
|
||||||
|
|
||||||
|
allocation_size += padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__USE_SLAB_ALLOCATOR)
|
#if defined(__USE_SLAB_ALLOCATOR)
|
||||||
{
|
{
|
||||||
/* Are we using the slab allocator? */
|
/* Are we using the slab allocator? */
|
||||||
if(__slab_data.sd_InUse)
|
if (__slab_data.sd_InUse)
|
||||||
{
|
{
|
||||||
mn = __slab_allocate(allocation_size);
|
mn = __slab_allocate(allocation_size);
|
||||||
|
|
||||||
|
SHOWPOINTER(mn);
|
||||||
|
|
||||||
|
assert( (((ULONG)mn) & MEM_BLOCKMASK) == 0 );
|
||||||
|
assert( (((ULONG)&mn[1]) & MEM_BLOCKMASK) == 0 );
|
||||||
}
|
}
|
||||||
|
/* Are we using the memory pool? */
|
||||||
|
else if (__memory_pool != NULL)
|
||||||
|
{
|
||||||
|
PROFILE_OFF();
|
||||||
|
mn = AllocPooled(__memory_pool, allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
/* Then we'll have to do it the hard way... */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (__memory_pool != NULL)
|
PROFILE_OFF();
|
||||||
{
|
mn = AllocMem(allocation_size, MEMF_ANY);
|
||||||
PROFILE_OFF();
|
PROFILE_ON();
|
||||||
mn = AllocPooled(__memory_pool,allocation_size);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef __MEM_DEBUG
|
|
||||||
{
|
|
||||||
PROFILE_OFF();
|
|
||||||
mn = AllocMem(allocation_size,MEMF_ANY);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
struct MinNode * mln;
|
|
||||||
|
|
||||||
PROFILE_OFF();
|
|
||||||
mln = AllocMem(sizeof(*mln) + allocation_size,MEMF_ANY);
|
|
||||||
PROFILE_ON();
|
|
||||||
|
|
||||||
if(mln != NULL)
|
|
||||||
{
|
|
||||||
AddTail((struct List *)&__memory_list,(struct Node *)mln);
|
|
||||||
|
|
||||||
mn = (struct MemoryNode *)&mln[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mn = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* __MEM_DEBUG */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
if(__memory_pool != NULL)
|
if (__memory_pool != NULL)
|
||||||
{
|
{
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
mn = AllocPooled(__memory_pool,allocation_size);
|
mn = AllocPooled(__memory_pool, allocation_size);
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG
|
PROFILE_OFF();
|
||||||
{
|
mn = AllocMem(allocation_size, MEMF_ANY);
|
||||||
PROFILE_OFF();
|
PROFILE_ON();
|
||||||
mn = AllocMem(allocation_size,MEMF_ANY);
|
|
||||||
PROFILE_ON();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
struct MinNode * mln;
|
|
||||||
|
|
||||||
PROFILE_OFF();
|
|
||||||
mln = AllocMem(sizeof(*mln) + allocation_size,MEMF_ANY);
|
|
||||||
PROFILE_ON();
|
|
||||||
|
|
||||||
if(mln != NULL)
|
|
||||||
{
|
|
||||||
AddTail((struct List *)&__memory_list,(struct Node *)mln);
|
|
||||||
|
|
||||||
mn = (struct MemoryNode *)&mln[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mn = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* __MEM_DEBUG */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __USE_SLAB_ALLOCATOR */
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
|
|
||||||
if(mn == NULL)
|
if (mn == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("not enough memory");
|
SHOWMSG("not enough memory");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
mn->mn_Size = size;
|
mn->mn_AllocationSize = allocation_size;
|
||||||
|
mn->mn_Flags = never_free ? MNF_NEVER_FREE : 0;
|
||||||
if(never_free)
|
|
||||||
SET_FLAG(mn->mn_Size, MN_SIZE_NEVERFREE);
|
|
||||||
|
|
||||||
__current_memory_allocated += allocation_size;
|
__current_memory_allocated += allocation_size;
|
||||||
if(__maximum_memory_allocated < __current_memory_allocated)
|
if (__maximum_memory_allocated < __current_memory_allocated)
|
||||||
__maximum_memory_allocated = __current_memory_allocated;
|
__maximum_memory_allocated = __current_memory_allocated;
|
||||||
|
|
||||||
__current_num_memory_chunks_allocated++;
|
__current_num_memory_chunks_allocated++;
|
||||||
if(__maximum_num_memory_chunks_allocated < __current_num_memory_chunks_allocated)
|
if (__maximum_num_memory_chunks_allocated < __current_num_memory_chunks_allocated)
|
||||||
__maximum_num_memory_chunks_allocated = __current_num_memory_chunks_allocated;
|
__maximum_num_memory_chunks_allocated = __current_num_memory_chunks_allocated;
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
char * head = (char *)(mn + 1);
|
BYTE * head = (BYTE *)&mn[1];
|
||||||
char * body = head + MALLOC_HEAD_SIZE;
|
BYTE * body = &head[MALLOC_HEAD_SIZE];
|
||||||
char * tail = body + size;
|
BYTE * tail = &body[size];
|
||||||
|
|
||||||
AddTail((struct List *)&__memory_list,(struct Node *)mn);
|
|
||||||
|
|
||||||
mn->mn_AlreadyFree = FALSE;
|
mn->mn_AlreadyFree = FALSE;
|
||||||
mn->mn_Allocation = body;
|
mn->mn_Allocation = body;
|
||||||
mn->mn_AllocationSize = allocation_size;
|
mn->mn_OriginalSize = size;
|
||||||
mn->mn_File = (char *)debug_file_name;
|
mn->mn_File = (char *)debug_file_name;
|
||||||
mn->mn_Line = debug_line_number;
|
mn->mn_Line = debug_line_number;
|
||||||
mn->mn_FreeFile = NULL;
|
mn->mn_FreeFile = NULL;
|
||||||
mn->mn_FreeLine = 0;
|
mn->mn_FreeLine = 0;
|
||||||
|
|
||||||
memset(head,MALLOC_HEAD_FILL,MALLOC_HEAD_SIZE);
|
memset(head, MALLOC_HEAD_FILL, MALLOC_HEAD_SIZE);
|
||||||
memset(body,MALLOC_NEW_FILL,size);
|
memset(body, MALLOC_NEW_FILL, size);
|
||||||
memset(tail,MALLOC_TAIL_FILL,MALLOC_TAIL_SIZE);
|
memset(tail, MALLOC_TAIL_FILL, MALLOC_TAIL_SIZE);
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
kprintf("[%s] + %10ld 0x%08lx [",__program_name,size,body);
|
kprintf("[%s] + %10ld 0x%08lx [", __program_name, size, body);
|
||||||
|
|
||||||
kprintf("allocated at %s:%ld]\n",debug_file_name,debug_line_number);
|
kprintf("allocated at %s:%ld]\n", debug_file_name, debug_line_number);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
|
AddTail((struct List *)&__memory_list,(struct Node *)mn);
|
||||||
|
|
||||||
#ifdef __USE_MEM_TREES
|
#ifdef __USE_MEM_TREES
|
||||||
{
|
{
|
||||||
__red_black_tree_insert(&__memory_tree,mn);
|
__red_black_tree_insert(&__memory_tree, mn);
|
||||||
}
|
}
|
||||||
#endif /* __USE_MEM_TREES */
|
#endif /* __USE_MEM_TREES */
|
||||||
|
|
||||||
@ -288,6 +280,22 @@ __allocate_memory(size_t size,BOOL never_free,const char *debug_file_name UNUSED
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
|
#if defined(__USE_SLAB_ALLOCATOR)
|
||||||
|
{
|
||||||
|
/* If we are using neither the slab allocator nor
|
||||||
|
* the memory pool, then the allocation will have
|
||||||
|
* to be freed later, the hard way.
|
||||||
|
*/
|
||||||
|
if (__slab_data.sd_InUse == FALSE && __memory_pool == NULL)
|
||||||
|
AddTail((struct List *)&__memory_list, (struct Node *)mn);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
if (__memory_pool == NULL)
|
||||||
|
AddTail((struct List *)&__memory_list, (struct Node *)mn);
|
||||||
|
}
|
||||||
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
|
|
||||||
result = &mn[1];
|
result = &mn[1];
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
@ -295,57 +303,57 @@ __allocate_memory(size_t size,BOOL never_free,const char *debug_file_name UNUSED
|
|||||||
#if defined(UNIX_PATH_SEMANTICS)
|
#if defined(UNIX_PATH_SEMANTICS)
|
||||||
{
|
{
|
||||||
/* Set the zero length allocation contents to NULL. */
|
/* Set the zero length allocation contents to NULL. */
|
||||||
if(original_size == 0)
|
if (original_size == 0 && size >= sizeof(BYTE *))
|
||||||
*(char **)result = NULL;
|
*(BYTE **)result = NULL;
|
||||||
}
|
}
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
|
|
||||||
assert( (((ULONG)result) & 3) == 0 );
|
assert( (((ULONG)result) & MEM_BLOCKMASK) == 0 );
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
if(result == NULL)
|
if (result == NULL)
|
||||||
{
|
{
|
||||||
kprintf("[%s] + %10ld 0x%08lx [",__program_name,size,NULL);
|
kprintf("[%s] + %10ld 0x%08lx [", __program_name, size, NULL);
|
||||||
|
|
||||||
kprintf("FAILED: allocated at %s:%ld]\n",debug_file_name,debug_line_number);
|
kprintf("FAILED: allocated at %s:%ld]\n", debug_file_name, debug_line_number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
__memory_unlock();
|
__memory_unlock();
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
__static void *
|
__static void *
|
||||||
__malloc(size_t size,const char * file,int line)
|
__malloc(size_t size, const char * file, int line)
|
||||||
{
|
{
|
||||||
void * result = NULL;
|
void * result = NULL;
|
||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
/* Try to get rid of now unused memory. */
|
/* Try to get rid of now unused memory. */
|
||||||
if(__alloca_cleanup != NULL)
|
if (__alloca_cleanup != NULL)
|
||||||
(*__alloca_cleanup)(file,line);
|
(*__alloca_cleanup)(file, line);
|
||||||
|
|
||||||
__memory_unlock();
|
__memory_unlock();
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
/*if((rand() % 16) == 0)
|
/*if ((rand() % 16) == 0)
|
||||||
__check_memory_allocations(file,line);*/
|
__check_memory_allocations(file,line);*/
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
/* Allocate memory which can be put through realloc() and free(). */
|
/* Allocate memory which can be put through realloc() and free(). */
|
||||||
result = __allocate_memory(size,FALSE,file,line);
|
result = __allocate_memory(size, FALSE, file, line);
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@ -355,7 +363,7 @@ malloc(size_t size)
|
|||||||
{
|
{
|
||||||
void * result;
|
void * result;
|
||||||
|
|
||||||
result = __malloc(size,NULL,0);
|
result = __malloc(size, NULL, 0);
|
||||||
|
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
@ -375,7 +383,7 @@ __memory_lock(void)
|
|||||||
{
|
{
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
|
|
||||||
if(memory_semaphore != NULL)
|
if (memory_semaphore != NULL)
|
||||||
ObtainSemaphore(memory_semaphore);
|
ObtainSemaphore(memory_semaphore);
|
||||||
|
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
@ -388,7 +396,7 @@ __memory_unlock(void)
|
|||||||
{
|
{
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
|
|
||||||
if(memory_semaphore != NULL)
|
if (memory_semaphore != NULL)
|
||||||
ReleaseSemaphore(memory_semaphore);
|
ReleaseSemaphore(memory_semaphore);
|
||||||
|
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
@ -404,30 +412,34 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
|
|||||||
{
|
{
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
|
/* Make sure that freeing any memory does not also
|
||||||
|
* trigger the alloca cleanup operations. Otherwise,
|
||||||
|
* the data structures used by alloca() to track
|
||||||
|
* the scope in which allocated memory remains
|
||||||
|
* valid and should not be freed just yet may be
|
||||||
|
* freed, corrupting them.
|
||||||
|
*/
|
||||||
|
__alloca_cleanup = NULL;
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
kprintf("[%s] %ld bytes still allocated upon exit, maximum of %ld bytes allocated at a time.\n",
|
kprintf("[%s] %ld bytes still allocated upon exit, maximum of %ld bytes allocated at a time.\n",
|
||||||
__program_name,__current_memory_allocated,__maximum_memory_allocated);
|
__program_name, __current_memory_allocated, __maximum_memory_allocated);
|
||||||
|
|
||||||
kprintf("[%s] %ld chunks of memory still allocated upon exit, maximum of %ld chunks allocated at a time.\n",
|
kprintf("[%s] %ld chunks of memory still allocated upon exit, maximum of %ld chunks allocated at a time.\n",
|
||||||
__program_name,__current_num_memory_chunks_allocated,__maximum_num_memory_chunks_allocated);
|
__program_name, __current_num_memory_chunks_allocated, __maximum_num_memory_chunks_allocated);
|
||||||
|
|
||||||
__check_memory_allocations(__FILE__,__LINE__);
|
__check_memory_allocations(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
/* Make sure that those memory nodes which were
|
||||||
|
* intended not to be freed will get freed this
|
||||||
|
* time around.
|
||||||
|
*/
|
||||||
__never_free = FALSE;
|
__never_free = FALSE;
|
||||||
|
|
||||||
if(__memory_list.mlh_Head != NULL)
|
|
||||||
{
|
|
||||||
while(NOT IsMinListEmpty(&__memory_list))
|
|
||||||
{
|
|
||||||
((struct MemoryNode *)__memory_list.mlh_Head)->mn_AlreadyFree = FALSE;
|
|
||||||
|
|
||||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__USE_MEM_TREES)
|
#if defined(__USE_MEM_TREES)
|
||||||
{
|
{
|
||||||
|
/* This must remain empty. */
|
||||||
__initialize_red_black_tree(&__memory_tree);
|
__initialize_red_black_tree(&__memory_tree);
|
||||||
}
|
}
|
||||||
#endif /* __USE_MEM_TREES */
|
#endif /* __USE_MEM_TREES */
|
||||||
@ -439,39 +451,36 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
|
|||||||
/* Is the slab memory allocator enabled? */
|
/* Is the slab memory allocator enabled? */
|
||||||
if (__slab_data.sd_InUse)
|
if (__slab_data.sd_InUse)
|
||||||
{
|
{
|
||||||
|
/* Just release the memory. */
|
||||||
__slab_exit();
|
__slab_exit();
|
||||||
}
|
}
|
||||||
else
|
/* Is the memory pool in use? */
|
||||||
|
else if (__memory_pool != NULL)
|
||||||
{
|
{
|
||||||
if (__memory_pool != NULL)
|
/* Just release the memory. */
|
||||||
|
DeletePool(__memory_pool);
|
||||||
|
__memory_pool = NULL;
|
||||||
|
}
|
||||||
|
/* Do we have to release every single allocation? */
|
||||||
|
else if (__memory_list.mlh_Head != NULL)
|
||||||
|
{
|
||||||
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
NewList((struct List *)&__memory_list);
|
while (NOT IsMinListEmpty(&__memory_list))
|
||||||
|
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, __FILE__, __LINE__);
|
||||||
DeletePool(__memory_pool);
|
|
||||||
__memory_pool = NULL;
|
|
||||||
}
|
}
|
||||||
else if (__memory_list.mlh_Head != NULL)
|
#else
|
||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG
|
while (NOT IsMinListEmpty(&__memory_list))
|
||||||
{
|
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, NULL, 0);
|
||||||
while(NOT IsMinListEmpty(&__memory_list))
|
|
||||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
while(NOT IsMinListEmpty(&__memory_list))
|
|
||||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,NULL,0);
|
|
||||||
}
|
|
||||||
#endif /* __MEM_DEBUG */
|
|
||||||
}
|
}
|
||||||
|
#endif /* __MEM_DEBUG */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
if (__memory_pool != NULL)
|
if (__memory_pool != NULL)
|
||||||
{
|
{
|
||||||
NewList((struct List *)&__memory_list);
|
|
||||||
|
|
||||||
DeletePool(__memory_pool);
|
DeletePool(__memory_pool);
|
||||||
__memory_pool = NULL;
|
__memory_pool = NULL;
|
||||||
}
|
}
|
||||||
@ -479,19 +488,22 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
|
|||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
while(NOT IsMinListEmpty(&__memory_list))
|
while (NOT IsMinListEmpty(&__memory_list))
|
||||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
|
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, __FILE__, __LINE__);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
while(NOT IsMinListEmpty(&__memory_list))
|
while (NOT IsMinListEmpty(&__memory_list))
|
||||||
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,NULL,0);
|
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, NULL, 0);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __USE_SLAB_ALLOCATOR */
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
|
|
||||||
|
/* The list of memory allocations must remain empty. */
|
||||||
|
NewList((struct List *)&__memory_list);
|
||||||
|
|
||||||
#if defined(__THREAD_SAFE)
|
#if defined(__THREAD_SAFE)
|
||||||
{
|
{
|
||||||
__delete_semaphore(memory_semaphore);
|
__delete_semaphore(memory_semaphore);
|
||||||
@ -510,13 +522,7 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
#if defined(__THREAD_SAFE)
|
NewList((struct List *)&__memory_list);
|
||||||
{
|
|
||||||
memory_semaphore = __create_semaphore();
|
|
||||||
if(memory_semaphore == NULL)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
#endif /* __THREAD_SAFE */
|
|
||||||
|
|
||||||
#if defined(__USE_MEM_TREES) && defined(__MEM_DEBUG)
|
#if defined(__USE_MEM_TREES) && defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
@ -524,27 +530,38 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
}
|
}
|
||||||
#endif /* __USE_MEM_TREES && __MEM_DEBUG */
|
#endif /* __USE_MEM_TREES && __MEM_DEBUG */
|
||||||
|
|
||||||
NewList((struct List *)&__memory_list);
|
#if defined(__THREAD_SAFE)
|
||||||
|
{
|
||||||
|
memory_semaphore = __create_semaphore();
|
||||||
|
if (memory_semaphore == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("could not create memory semaphore");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* __THREAD_SAFE */
|
||||||
|
|
||||||
#if defined(__USE_SLAB_ALLOCATOR)
|
#ifdef __USE_SLAB_ALLOCATOR
|
||||||
{
|
{
|
||||||
/* ZZZ this is just for the purpose of testing */
|
/* ZZZ this is just for the purpose of testing */
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
{
|
{
|
||||||
TEXT slab_size_var[20];
|
TEXT slab_size_var[20];
|
||||||
|
|
||||||
if(GetVar("SLAB_SIZE", slab_size_var, sizeof(slab_size_var), 0) > 0)
|
if (GetVar("SLAB_SIZE", slab_size_var, sizeof(slab_size_var), 0) > 0)
|
||||||
{
|
{
|
||||||
LONG value;
|
LONG value = 0;
|
||||||
|
|
||||||
if(StrToLong(slab_size_var,&value) > 0 && value > 0)
|
if (StrToLong(slab_size_var, &value) > 0 && value > 0)
|
||||||
__slab_max_size = (size_t)value;
|
__slab_max_size = (size_t)value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SHOWVALUE(__slab_max_size);
|
||||||
|
|
||||||
/* Enable the slab memory allocator? */
|
/* Enable the slab memory allocator? */
|
||||||
if(__slab_max_size > 0)
|
if (__slab_max_size > 0)
|
||||||
{
|
{
|
||||||
__slab_init(__slab_max_size);
|
__slab_init(__slab_max_size);
|
||||||
}
|
}
|
||||||
@ -552,15 +569,27 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
{
|
{
|
||||||
#if defined(__amigaos4__)
|
#if defined(__amigaos4__)
|
||||||
{
|
{
|
||||||
__memory_pool = CreatePool(MEMF_PRIVATE,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
|
__memory_pool = CreatePool(MEMF_PRIVATE, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
|
||||||
|
if (__memory_pool == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("could not create memory pool");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
/* There is no support for memory pools in the operating system
|
/* There is no support for memory pools in the operating system
|
||||||
* prior to Kickstart 3.0 (V39).
|
* prior to Kickstart 3.0 (V39).
|
||||||
*/
|
*/
|
||||||
if(((struct Library *)SysBase)->lib_Version >= 39)
|
if (((struct Library *)SysBase)->lib_Version >= 39)
|
||||||
__memory_pool = CreatePool(MEMF_ANY,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
|
{
|
||||||
|
__memory_pool = CreatePool(MEMF_ANY, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
|
||||||
|
if (__memory_pool == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("could not create memory pool");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* __amigaos4__ */
|
#endif /* __amigaos4__ */
|
||||||
}
|
}
|
||||||
@ -569,19 +598,31 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
{
|
{
|
||||||
#if defined(__amigaos4__)
|
#if defined(__amigaos4__)
|
||||||
{
|
{
|
||||||
__memory_pool = CreatePool(MEMF_PRIVATE,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
|
__memory_pool = CreatePool(MEMF_PRIVATE, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
|
||||||
|
if (__memory_pool == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("could not create memory pool");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
/* There is no support for memory pools in the operating system
|
/* There is no support for memory pools in the operating system
|
||||||
* prior to Kickstart 3.0 (V39).
|
* prior to Kickstart 3.0 (V39).
|
||||||
*/
|
*/
|
||||||
if(((struct Library *)SysBase)->lib_Version >= 39)
|
if (((struct Library *)SysBase)->lib_Version >= 39)
|
||||||
__memory_pool = CreatePool(MEMF_ANY,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
|
{
|
||||||
|
__memory_pool = CreatePool(MEMF_ANY, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
|
||||||
|
if (__memory_pool == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("could not create memory pool");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* __amigaos4__ */
|
#endif /* __amigaos4__ */
|
||||||
}
|
}
|
||||||
#endif /* __USE_SLAB_ALLOCATOR) */
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
|
|
||||||
success = TRUE;
|
success = TRUE;
|
||||||
|
|
||||||
@ -590,7 +631,7 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
SHOWVALUE(success);
|
SHOWVALUE(success);
|
||||||
LEAVE();
|
LEAVE();
|
||||||
|
|
||||||
if(success)
|
if (success)
|
||||||
CONSTRUCTOR_SUCCEED();
|
CONSTRUCTOR_SUCCEED();
|
||||||
else
|
else
|
||||||
CONSTRUCTOR_FAIL();
|
CONSTRUCTOR_FAIL();
|
||||||
|
|||||||
36
library/stdlib_memory.h
Normal file → Executable file
36
library/stdlib_memory.h
Normal file → Executable file
@ -63,7 +63,7 @@
|
|||||||
/*
|
/*
|
||||||
* Uncomment this to enable the slab allocator.
|
* Uncomment this to enable the slab allocator.
|
||||||
*/
|
*/
|
||||||
#define __USE_SLAB_ALLOCATOR
|
/*#define __USE_SLAB_ALLOCATOR*/
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
@ -150,27 +150,26 @@ extern char * __getcwd(char * buffer,size_t buffer_size,const char *file,int lin
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
/* If this flag is set in mn_Size, then this memory allocation
|
/* If this flag is set in mn_Flags, then this memory allocation
|
||||||
* cannot be released with free() or used with realloc(). This
|
* cannot be released with free() or used with realloc(). This
|
||||||
* flag is set by alloca().
|
* flag is set by alloca().
|
||||||
*/
|
*/
|
||||||
#define MN_SIZE_NEVERFREE (0x80000000UL)
|
#define MNF_NEVER_FREE (1UL << 0)
|
||||||
|
|
||||||
/* This obtains the allocation size from a memory node, ignoring
|
/* Memory allocations are remembered by this tracking data structure.
|
||||||
* the "never free" flag altogether.
|
* Its size is always a multiple of 8 bytes, which provides memory
|
||||||
|
* address alignment to a 64-bit boundary.
|
||||||
*/
|
*/
|
||||||
#define GET_MN_SIZE(mn) ((mn)->mn_Size & ~MN_SIZE_NEVERFREE)
|
|
||||||
|
|
||||||
struct MemoryNode
|
struct MemoryNode
|
||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG
|
|
||||||
struct MinNode mn_MinNode;
|
struct MinNode mn_MinNode;
|
||||||
|
|
||||||
UBYTE mn_AlreadyFree;
|
ULONG mn_AllocationSize;
|
||||||
UBYTE mn_Pad0[3];
|
ULONG mn_Flags;
|
||||||
|
|
||||||
|
#ifdef __MEM_DEBUG
|
||||||
void * mn_Allocation;
|
void * mn_Allocation;
|
||||||
size_t mn_AllocationSize;
|
size_t mn_OriginalSize;
|
||||||
|
|
||||||
char * mn_FreeFile;
|
char * mn_FreeFile;
|
||||||
int mn_FreeLine;
|
int mn_FreeLine;
|
||||||
@ -178,17 +177,18 @@ struct MemoryNode
|
|||||||
char * mn_File;
|
char * mn_File;
|
||||||
int mn_Line;
|
int mn_Line;
|
||||||
|
|
||||||
|
UBYTE mn_AlreadyFree;
|
||||||
|
UBYTE mn_Pad1[7];
|
||||||
#ifdef __USE_MEM_TREES
|
#ifdef __USE_MEM_TREES
|
||||||
struct MemoryNode * mn_Left;
|
struct MemoryNode * mn_Left;
|
||||||
struct MemoryNode * mn_Right;
|
struct MemoryNode * mn_Right;
|
||||||
struct MemoryNode * mn_Parent;
|
struct MemoryNode * mn_Parent;
|
||||||
|
|
||||||
UBYTE mn_IsRed;
|
UBYTE mn_IsRed;
|
||||||
UBYTE mn_Pad1[3];
|
UBYTE mn_Pad2[3];
|
||||||
#endif /* __USE_MEM_TREES */
|
#endif /* __USE_MEM_TREES */
|
||||||
|
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
ULONG mn_Size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __USE_MEM_TREES
|
#ifdef __USE_MEM_TREES
|
||||||
@ -247,12 +247,14 @@ struct SlabNode
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Memory allocations which are not part of a slab are
|
/* Memory allocations which are not part of a slab are
|
||||||
* tracked using this data structure.
|
* tracked using this data structure. This data structure
|
||||||
|
* is supposed to be a multiple of 8 bytes in size.
|
||||||
*/
|
*/
|
||||||
struct SlabSingleAllocation
|
struct SlabSingleAllocation
|
||||||
{
|
{
|
||||||
struct MinNode ssa_MinNode;
|
struct MinNode ssa_MinNode;
|
||||||
ULONG ssa_Size;
|
ULONG ssa_Size;
|
||||||
|
ULONG ssa_Pad;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is the global bookkeeping information for managing
|
/* This is the global bookkeeping information for managing
|
||||||
@ -264,8 +266,8 @@ struct SlabData
|
|||||||
* which are a power of 2 bytes in size, e.g. 8, 16, 32,
|
* which are a power of 2 bytes in size, e.g. 8, 16, 32,
|
||||||
* 64, 128 bytes. Hence, sd_Slabs[3] keeps track of the slabs
|
* 64, 128 bytes. Hence, sd_Slabs[3] keeps track of the slabs
|
||||||
* which are 8 bytes in size, sd_Slabs[4] is for 16 byte
|
* which are 8 bytes in size, sd_Slabs[4] is for 16 byte
|
||||||
* chunks, etc. The minimum chunk size is 8, which is why
|
* chunks, etc. The minimum chunk size is 16, which is why
|
||||||
* lists 0..2 are not used. Currently, there is an upper limit
|
* lists 0..3 are not used. Currently, there is an upper limit
|
||||||
* of 2^17 bytes per chunk, but you should not be using slab
|
* of 2^17 bytes per chunk, but you should not be using slab
|
||||||
* chunks much larger than 4096 bytes.
|
* chunks much larger than 4096 bytes.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -50,7 +50,7 @@
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
__static void *
|
__static void *
|
||||||
__realloc(void *ptr,size_t size,const char * file,int line)
|
__realloc(void *ptr, size_t size, const char * file, int line)
|
||||||
{
|
{
|
||||||
void * result = NULL;
|
void * result = NULL;
|
||||||
BOOL locked = FALSE;
|
BOOL locked = FALSE;
|
||||||
@ -62,23 +62,24 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
|
|
||||||
assert( (int)size >= 0 );
|
assert( (int)size >= 0 );
|
||||||
|
|
||||||
if(ptr == NULL)
|
if (ptr == NULL)
|
||||||
{
|
{
|
||||||
D(("calling malloc(%ld)",size));
|
D(("calling malloc(%ld)", size));
|
||||||
|
|
||||||
result = __malloc(size,file,line);
|
result = __malloc(size, file, line);
|
||||||
}
|
}
|
||||||
#ifndef UNIX_PATH_SEMANTICS
|
#ifndef UNIX_PATH_SEMANTICS
|
||||||
else if (size == 0)
|
else if (size == 0)
|
||||||
{
|
{
|
||||||
D(("calling free(0x%08lx)",ptr));
|
D(("calling free(0x%08lx)",ptr));
|
||||||
|
|
||||||
__free(ptr,file,line);
|
__free(ptr, file, line);
|
||||||
}
|
}
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t old_size;
|
size_t new_allocation_size UNUSED;
|
||||||
|
size_t old_allocation_size;
|
||||||
struct MemoryNode * mn;
|
struct MemoryNode * mn;
|
||||||
BOOL reallocate;
|
BOOL reallocate;
|
||||||
|
|
||||||
@ -92,16 +93,14 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
/* If we managed to find the memory allocation,
|
/* Quit if we failed to find the memory allocation. */
|
||||||
reallocate it. */
|
if (mn == NULL)
|
||||||
if(mn == NULL)
|
|
||||||
{
|
{
|
||||||
SHOWMSG("allocation not found");
|
SHOWMSG("allocation not found");
|
||||||
|
|
||||||
kprintf("[%s] %s:%ld:Address for realloc(0x%08lx,%ld) not known.\n",__program_name,file,line,ptr,size);
|
kprintf("[%s] %s:%ld:Address for realloc(0x%08lx,%ld) not known.\n",
|
||||||
|
__program_name, file, line, ptr, size);
|
||||||
|
|
||||||
/* Apparently, the address did not qualify for
|
|
||||||
reallocation. */
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,70 +110,114 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
if(mn == NULL || FLAG_IS_SET(mn->mn_Size, MN_SIZE_NEVERFREE))
|
if (mn == NULL || FLAG_IS_SET(mn->mn_Flags, MNF_NEVER_FREE))
|
||||||
{
|
{
|
||||||
SHOWMSG("cannot free this chunk");
|
SHOWMSG("cannot free this chunk");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_size = GET_MN_SIZE(mn);
|
assert( FLAG_IS_CLEAR(mn->mn_Flags, MNF_NEVER_FREE) );
|
||||||
|
|
||||||
/* Don't do anything unless the size of the allocation
|
old_allocation_size = mn->mn_AllocationSize;
|
||||||
has really changed. */
|
|
||||||
|
/* If the memory debug option is enabled, just check if
|
||||||
|
* requested allocation size has changed.
|
||||||
|
*/
|
||||||
#if defined(__MEM_DEBUG)
|
#if defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
reallocate = (old_size != size);
|
reallocate = (mn->mn_OriginalSize != size);
|
||||||
|
|
||||||
|
new_allocation_size = (sizeof(*mn) + MALLOC_HEAD_SIZE + size + MALLOC_TAIL_SIZE + MEM_BLOCKMASK) & ~MEM_BLOCKMASK;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
if(size > old_size)
|
/* The actual size of the allocation is affected by the
|
||||||
|
granularity and minimum allocation size used by the
|
||||||
|
operating system. */
|
||||||
|
new_allocation_size = (sizeof(*mn) + size + MEM_BLOCKMASK) & ~MEM_BLOCKMASK;
|
||||||
|
|
||||||
|
if (new_allocation_size > old_allocation_size)
|
||||||
{
|
{
|
||||||
/* Allocation size should grow. */
|
/* Allocation size should grow. */
|
||||||
reallocate = TRUE;
|
reallocate = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else if (new_allocation_size < old_allocation_size)
|
||||||
{
|
{
|
||||||
/* Optimization: If the block size shrinks by less than half the
|
/* Optimization: If the block size shrinks by less than half the
|
||||||
original allocation size, do not reallocate the
|
original allocation size, do not reallocate the
|
||||||
block and do not copy over the contents of the old
|
block. */
|
||||||
allocation. We also take into account that the
|
reallocate = (size <= old_allocation_size / 2);
|
||||||
actual size of the allocation is affected by a
|
}
|
||||||
certain operating system imposed granularity. */
|
else
|
||||||
reallocate = (size < old_size && size <= old_size / 2);
|
{
|
||||||
|
reallocate = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
if(reallocate)
|
if (reallocate)
|
||||||
{
|
{
|
||||||
void * new_ptr;
|
void * new_ptr;
|
||||||
|
|
||||||
D(("realloc() size has changed; old=%ld, new=%ld",old_size,size));
|
D(("realloc() allocation size has changed; old=%ld, new=%ld", old_allocation_size, new_allocation_size));
|
||||||
|
|
||||||
/* We allocate the new memory chunk before we
|
/* We allocate the new memory chunk before we
|
||||||
attempt to replace the old. */
|
attempt to replace the old one. */
|
||||||
new_ptr = __malloc(size,file,line);
|
new_ptr = __malloc(size, file, line);
|
||||||
if(new_ptr == NULL)
|
if (new_ptr == NULL)
|
||||||
{
|
{
|
||||||
SHOWMSG("could not reallocate memory");
|
SHOWMSG("could not reallocate memory");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the contents of the old allocation to the new buffer. */
|
/* With memory debugging enabled, the size of the allocation made
|
||||||
if(size > old_size)
|
* will use the requested and not the rounded size of the
|
||||||
size = old_size;
|
* allocation, which can be shorter. We need to deal with this.
|
||||||
|
*/
|
||||||
|
#if defined(__MEM_DEBUG)
|
||||||
|
{
|
||||||
|
struct MemoryNode * new_mn;
|
||||||
|
|
||||||
memmove(new_ptr,ptr,size);
|
new_mn = __find_memory_node(new_ptr);
|
||||||
|
if (new_mn == NULL)
|
||||||
|
{
|
||||||
|
free(new_ptr);
|
||||||
|
|
||||||
|
SHOWMSG("Could not find memory node for new allocation");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure that if the new allocation size is smaller than
|
||||||
|
* the old allocation, we only copy as much data as will fit
|
||||||
|
* into the new allocation.
|
||||||
|
*/
|
||||||
|
if (size > new_mn->mn_OriginalSize)
|
||||||
|
size = new_mn->mn_OriginalSize;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
/* We assume that the total size of the allocation will
|
||||||
|
* include padding. The requested size does not include
|
||||||
|
* the memory node, of course, which is why it is added
|
||||||
|
* here.
|
||||||
|
*/
|
||||||
|
if (size + sizeof(*mn) > old_allocation_size)
|
||||||
|
size = old_allocation_size - sizeof(*mn);
|
||||||
|
}
|
||||||
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
|
memmove(new_ptr, ptr, size);
|
||||||
|
|
||||||
/* Free the old allocation. Since we already know which memory
|
/* Free the old allocation. Since we already know which memory
|
||||||
node is associated with it, we don't call __free() here. */
|
node is associated with it, we don't call __free() here. */
|
||||||
__free_memory_node(mn,file,line);
|
__free_memory_node(mn, file, line);
|
||||||
|
|
||||||
result = new_ptr;
|
result = new_ptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
D(("size didn't actually change that much (%ld -> %ld); returning memory block as is.",old_size,size));
|
D(("size didn't actually change that much (%ld -> %ld); returning memory block as is.",
|
||||||
|
old_allocation_size, new_allocation_size));
|
||||||
|
|
||||||
/* No change in size. */
|
/* No change in size. */
|
||||||
result = ptr;
|
result = ptr;
|
||||||
@ -183,14 +226,14 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
if(locked)
|
if (locked)
|
||||||
__memory_unlock();
|
__memory_unlock();
|
||||||
|
|
||||||
if(result == NULL)
|
if (result == NULL)
|
||||||
SHOWMSG("ouch! realloc failed");
|
SHOWMSG("ouch! realloc failed");
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|||||||
1144
library/stdlib_slab.c
Normal file → Executable file
1144
library/stdlib_slab.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
static const char * error_table[EILSEQ - EPERM + 1] =
|
static const char * error_table[ENOTSUP - EPERM + 1] =
|
||||||
{
|
{
|
||||||
"Operation not permitted",
|
"Operation not permitted",
|
||||||
"No such file or directory",
|
"No such file or directory",
|
||||||
@ -127,7 +127,8 @@ static const char * error_table[EILSEQ - EPERM + 1] =
|
|||||||
"Identifier removed",
|
"Identifier removed",
|
||||||
"No message of the desired type.",
|
"No message of the desired type.",
|
||||||
"Value too large to be stored in data type.",
|
"Value too large to be stored in data type.",
|
||||||
"Encoding error detected"
|
"Encoding error detected",
|
||||||
|
"Not supported"
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@ -139,7 +140,7 @@ strerror_r(int number,char * buffer,size_t buffer_size)
|
|||||||
const char * str;
|
const char * str;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if(number < EPERM || number > EILSEQ)
|
if(number < EPERM || number > ENOTSUP)
|
||||||
{
|
{
|
||||||
__set_errno(EINVAL);
|
__set_errno(EINVAL);
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
151
library/time_mktime.c
Normal file → Executable file
151
library/time_mktime.c
Normal file → Executable file
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Id: time_mktime.c,v 1.10 2006-01-08 12:04:27 obarthel Exp $
|
* $Id: time_mktime.c,v 1.11 2015-06-26 11:22:00 obarthel Exp $
|
||||||
*
|
*
|
||||||
* :ts=4
|
* :ts=4
|
||||||
*
|
*
|
||||||
@ -52,9 +52,10 @@ mktime(struct tm *tm)
|
|||||||
{
|
{
|
||||||
DECLARE_UTILITYBASE();
|
DECLARE_UTILITYBASE();
|
||||||
struct ClockData clock_data;
|
struct ClockData clock_data;
|
||||||
ULONG seconds, delta;
|
ULONG seconds;
|
||||||
time_t result = (time_t)-1;
|
time_t result = (time_t)-1;
|
||||||
int max_month_days;
|
LONG combined_seconds;
|
||||||
|
int month, year;
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
@ -73,116 +74,63 @@ mktime(struct tm *tm)
|
|||||||
}
|
}
|
||||||
#endif /* CHECK_FOR_NULL_POINTERS */
|
#endif /* CHECK_FOR_NULL_POINTERS */
|
||||||
|
|
||||||
/* The month must be valid. */
|
/* Normalize the year and month. */
|
||||||
if(tm->tm_mon < 0 || tm->tm_mon > 11)
|
year = tm->tm_year + 1900;
|
||||||
|
month = tm->tm_mon + 1;
|
||||||
|
|
||||||
|
if(month < 0 || month > 12)
|
||||||
{
|
{
|
||||||
SHOWVALUE(tm->tm_mon);
|
int y;
|
||||||
SHOWMSG("invalid month");
|
|
||||||
goto out;
|
y = month / 12;
|
||||||
|
|
||||||
|
month -= y * 12;
|
||||||
|
year += y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The day of the month must be valid. */
|
if(month < 1)
|
||||||
if(tm->tm_mday < 1 || tm->tm_mday > 31)
|
|
||||||
{
|
{
|
||||||
SHOWVALUE(tm->tm_mday);
|
month += 12;
|
||||||
SHOWMSG("invalid day of month");
|
year -= 1;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The year must be valid. */
|
/* The year must be valid. Amiga time begins with January 1st, 1978. */
|
||||||
if(tm->tm_year < 78)
|
if(year < 1978)
|
||||||
{
|
{
|
||||||
SHOWVALUE(tm->tm_year);
|
SHOWVALUE(year);
|
||||||
SHOWMSG("invalid year");
|
SHOWMSG("invalid year");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is this the month of February? */
|
/* Convert the first day of the month in the given year
|
||||||
if(tm->tm_mon == 1)
|
into the corresponding number of seconds. */
|
||||||
{
|
memset(&clock_data, 0, sizeof(clock_data));
|
||||||
int year;
|
|
||||||
|
|
||||||
/* We need to have the full year number for the
|
|
||||||
leap year calculation below. */
|
|
||||||
year = tm->tm_year + 1900;
|
|
||||||
|
|
||||||
/* Now for the famous leap year calculation rules... In
|
|
||||||
the given year, how many days are there in the month
|
|
||||||
of February? */
|
|
||||||
if((year % 4) != 0)
|
|
||||||
max_month_days = 28;
|
|
||||||
else if ((year % 400) == 0)
|
|
||||||
max_month_days = 29;
|
|
||||||
else if ((year % 100) == 0)
|
|
||||||
max_month_days = 28;
|
|
||||||
else
|
|
||||||
max_month_days = 29;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static const char days_per_month[12] =
|
|
||||||
{
|
|
||||||
31, 0,31,
|
|
||||||
30,31,30,
|
|
||||||
31,31,30,
|
|
||||||
31,30,31
|
|
||||||
};
|
|
||||||
|
|
||||||
max_month_days = days_per_month[tm->tm_mon];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The day of the month must be valid. */
|
|
||||||
if(tm->tm_mday < 0 || tm->tm_mday > max_month_days)
|
|
||||||
{
|
|
||||||
SHOWVALUE(tm->tm_mday);
|
|
||||||
SHOWMSG("invalid day of month");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The hour must be valid. */
|
|
||||||
if(tm->tm_hour < 0 || tm->tm_hour > 23)
|
|
||||||
{
|
|
||||||
SHOWVALUE(tm->tm_hour);
|
|
||||||
SHOWMSG("invalid hour");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The minute must be valid. */
|
|
||||||
if(tm->tm_min < 0 || tm->tm_min > 59)
|
|
||||||
{
|
|
||||||
SHOWVALUE(tm->tm_min);
|
|
||||||
SHOWMSG("invalid minute");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Note: the number of seconds can be larger than 59
|
|
||||||
in order to account for leap seconds. */
|
|
||||||
if(tm->tm_sec < 0 || tm->tm_sec > 60)
|
|
||||||
{
|
|
||||||
SHOWVALUE(tm->tm_sec);
|
|
||||||
SHOWMSG("invalid seconds");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
clock_data.sec = (tm->tm_sec > 59) ? 59 : tm->tm_sec;
|
|
||||||
clock_data.min = tm->tm_min;
|
|
||||||
clock_data.hour = tm->tm_hour;
|
|
||||||
clock_data.mday = tm->tm_mday;
|
|
||||||
clock_data.month = tm->tm_mon + 1;
|
|
||||||
clock_data.year = tm->tm_year + 1900;
|
|
||||||
|
|
||||||
seconds = Date2Amiga(&clock_data) + (tm->tm_sec - 59);
|
|
||||||
|
|
||||||
/* The AmigaOS "epoch" starts with January 1st, 1978, which was
|
|
||||||
a Sunday. */
|
|
||||||
tm->tm_wday = (seconds / (24 * 60 * 60)) % 7;
|
|
||||||
|
|
||||||
clock_data.mday = 1;
|
clock_data.mday = 1;
|
||||||
clock_data.month = 1;
|
clock_data.month = month;
|
||||||
|
clock_data.year = year;
|
||||||
|
|
||||||
delta = Date2Amiga(&clock_data);
|
seconds = Date2Amiga(&clock_data);
|
||||||
|
|
||||||
tm->tm_yday = (seconds - delta) / (24 * 60 * 60);
|
/* Put the combined number of seconds involved together,
|
||||||
|
covering the seconds/minutes/hours of the day as well
|
||||||
|
as the number of days of the month. This will be added
|
||||||
|
to the number of seconds for the date. */
|
||||||
|
combined_seconds = tm->tm_sec + 60 * (tm->tm_min + 60 * (tm->tm_hour + 24 * (tm->tm_mday-1)));
|
||||||
|
|
||||||
|
/* If the combined number of seconds is negative, adding it
|
||||||
|
* to the number of seconds for the date should not produce
|
||||||
|
* a negative value.
|
||||||
|
*/
|
||||||
|
if(combined_seconds < 0 && seconds < (ULONG)(-combined_seconds))
|
||||||
|
{
|
||||||
|
SHOWVALUE(seconds);
|
||||||
|
SHOWVALUE(combined_seconds);
|
||||||
|
SHOWMSG("invalid combined number of seconds");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
seconds += combined_seconds;
|
||||||
|
|
||||||
__locale_lock();
|
__locale_lock();
|
||||||
|
|
||||||
@ -193,10 +141,13 @@ mktime(struct tm *tm)
|
|||||||
|
|
||||||
__locale_unlock();
|
__locale_unlock();
|
||||||
|
|
||||||
/* Finally, adjust for the difference between the Unix and the
|
/* Adjust for the difference between the Unix and the
|
||||||
AmigaOS epochs, which differ by 8 years. */
|
AmigaOS epochs, which differ by 8 years. */
|
||||||
result = seconds + UNIX_TIME_OFFSET;
|
result = seconds + UNIX_TIME_OFFSET;
|
||||||
|
|
||||||
|
/* Finally, normalize the provided time and date information. */
|
||||||
|
localtime_r(&result, tm);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
|
|||||||
@ -58,9 +58,19 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
|||||||
struct name_translation_info path_name_nti;
|
struct name_translation_info path_name_nti;
|
||||||
struct name_translation_info buffer_nti;
|
struct name_translation_info buffer_nti;
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
|
|
||||||
|
D_S(struct bcpl_name, bname);
|
||||||
|
const size_t name_size = sizeof(bname->name);
|
||||||
|
|
||||||
BPTR lock = ZERO;
|
BPTR lock = ZERO;
|
||||||
int result = ERROR;
|
int result = ERROR;
|
||||||
int target_length = -1;
|
struct DevProc *dvp = NULL;
|
||||||
|
char * new_name = NULL;
|
||||||
|
char * path_part;
|
||||||
|
size_t name_len;
|
||||||
|
size_t new_name_size;
|
||||||
|
LONG readlink_result;
|
||||||
|
LONG error;
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
@ -70,12 +80,12 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
|||||||
|
|
||||||
assert( path_name != NULL && buffer != NULL );
|
assert( path_name != NULL && buffer != NULL );
|
||||||
|
|
||||||
if(__check_abort_enabled)
|
if (__check_abort_enabled)
|
||||||
__check_abort();
|
__check_abort();
|
||||||
|
|
||||||
#if defined(CHECK_FOR_NULL_POINTERS)
|
#if defined(CHECK_FOR_NULL_POINTERS)
|
||||||
{
|
{
|
||||||
if(path_name == NULL || buffer == NULL)
|
if (path_name == NULL || buffer == NULL)
|
||||||
{
|
{
|
||||||
SHOWSTRING("invalid parameters");
|
SHOWSTRING("invalid parameters");
|
||||||
|
|
||||||
@ -87,9 +97,9 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
|||||||
|
|
||||||
#if defined(UNIX_PATH_SEMANTICS)
|
#if defined(UNIX_PATH_SEMANTICS)
|
||||||
{
|
{
|
||||||
if(__unix_path_semantics)
|
if (__unix_path_semantics)
|
||||||
{
|
{
|
||||||
if(path_name[0] == '\0')
|
if (path_name[0] == '\0')
|
||||||
{
|
{
|
||||||
SHOWMSG("no name given");
|
SHOWMSG("no name given");
|
||||||
|
|
||||||
@ -97,53 +107,144 @@ readlink(const char * path_name, char * buffer, int buffer_size)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(__translate_unix_to_amiga_path_name(&path_name,&path_name_nti) != 0)
|
if (__translate_unix_to_amiga_path_name(&path_name, &path_name_nti) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
|
|
||||||
D(("trying to get a lock on '%s'",path_name));
|
name_len = strlen(path_name);
|
||||||
|
if (name_len >= name_size)
|
||||||
|
{
|
||||||
|
SHOWMSG("name too long");
|
||||||
|
|
||||||
|
SetIoErr(ERROR_LINE_TOO_LONG);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the name into a BCPL string. */
|
||||||
|
bname->name[0] = name_len;
|
||||||
|
memcpy(&bname->name[1], path_name, name_len);
|
||||||
|
|
||||||
|
/* Get a handle on the device, volume or assignment name in the path. */
|
||||||
|
dvp = GetDeviceProc((STRPTR)path_name, dvp);
|
||||||
|
if (dvp == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("dvp == NULL");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to obtain a lock on the object. It should be a link and not
|
||||||
|
* a file or directory.
|
||||||
|
*/
|
||||||
|
lock = DoPkt(dvp->dvp_Port, ACTION_LOCATE_OBJECT, dvp->dvp_Lock, MKBADDR(bname), SHARED_LOCK, 0, 0);
|
||||||
|
if (lock != ZERO)
|
||||||
|
{
|
||||||
|
SHOWMSG("lock != ZERO");
|
||||||
|
|
||||||
|
SetIoErr(ERROR_OBJECT_WRONG_TYPE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = IoErr();
|
||||||
|
|
||||||
|
if (error != ERROR_IS_SOFT_LINK)
|
||||||
|
{
|
||||||
|
SHOWMSG("not a soft link");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We only need the leading path name. */
|
||||||
|
name_len = ((BYTE *)PathPart(path_name)) - (BYTE *)path_name;
|
||||||
|
|
||||||
|
path_part = malloc(name_len+1);
|
||||||
|
if (path_part == NULL)
|
||||||
|
{
|
||||||
|
SHOWMSG("path_part too long");
|
||||||
|
|
||||||
|
SetIoErr(ERROR_NO_FREE_STORE);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(path_part, path_name, name_len);
|
||||||
|
path_part[name_len] = '\0';
|
||||||
|
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
lock = __lock((STRPTR)path_name,SHARED_LOCK,&target_length,buffer,(size_t)buffer_size);
|
lock = Lock((STRPTR)path_part, SHARED_LOCK);
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
|
|
||||||
if(lock != ZERO)
|
new_name_size = name_size+1;
|
||||||
|
|
||||||
|
/* Provide as much buffer space as possible. */
|
||||||
|
if (buffer_size > 0 && (size_t)buffer_size > new_name_size)
|
||||||
|
new_name_size = buffer_size;
|
||||||
|
|
||||||
|
/* For soft link resolution we need a temporary buffer to
|
||||||
|
let the file system store the resolved path name in. */
|
||||||
|
new_name = malloc(new_name_size);
|
||||||
|
if (new_name == NULL)
|
||||||
{
|
{
|
||||||
__set_errno(EINVAL);
|
SHOWMSG("new_name too long");
|
||||||
goto out;
|
|
||||||
}
|
SetIoErr(ERROR_NO_FREE_STORE);
|
||||||
else if (target_length <= 0) /* No a soft-link. */
|
|
||||||
{
|
|
||||||
__set_errno(__translate_io_error_to_errno(IoErr()));
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(UNIX_PATH_SEMANTICS)
|
/* Now ask the file system to resolve the entire path. */
|
||||||
|
readlink_result = ReadLink(dvp->dvp_Port, lock, (STRPTR)FilePart(path_name), (STRPTR)new_name, (LONG)new_name_size);
|
||||||
|
if (readlink_result < 0)
|
||||||
{
|
{
|
||||||
if(__unix_path_semantics)
|
SHOWMSG("ReadLink");
|
||||||
|
|
||||||
|
/* This will return either -1 (resolution error) or -2
|
||||||
|
(buffer too small). We regard both as trouble. */
|
||||||
|
SetIoErr(ERROR_INVALID_COMPONENT_NAME);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( result > 0 );
|
||||||
|
|
||||||
|
/* If the caller supplied a buffer, copy as much of the name
|
||||||
|
as possible into it. */
|
||||||
|
if (buffer != NULL && buffer_size > 0)
|
||||||
|
{
|
||||||
|
strlcpy(buffer, new_name, buffer_size);
|
||||||
|
|
||||||
|
#if defined(UNIX_PATH_SEMANTICS)
|
||||||
{
|
{
|
||||||
if(__translate_amiga_to_unix_path_name((char const **)&buffer,&buffer_nti) != 0)
|
if (__unix_path_semantics)
|
||||||
goto out;
|
{
|
||||||
|
if (__translate_amiga_to_unix_path_name((char const **)&buffer, &buffer_nti) != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
__restore_path_name((char const **)&buffer,&buffer_nti);
|
__restore_path_name((char const **)&buffer,&buffer_nti);
|
||||||
|
|
||||||
strcpy(buffer,buffer_nti.substitute);
|
strcpy(buffer, buffer_nti.substitute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
|
|
||||||
|
result = strlen(buffer);
|
||||||
|
|
||||||
|
SHOWSTRING(buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
}
|
}
|
||||||
#endif /* UNIX_PATH_SEMANTICS */
|
|
||||||
|
|
||||||
result = strlen(buffer);
|
|
||||||
|
|
||||||
SHOWSTRING(buffer);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
PROFILE_OFF();
|
PROFILE_OFF();
|
||||||
|
|
||||||
|
if (dvp != NULL)
|
||||||
|
FreeDeviceProc(dvp);
|
||||||
|
|
||||||
UnLock(lock);
|
UnLock(lock);
|
||||||
|
|
||||||
PROFILE_ON();
|
PROFILE_ON();
|
||||||
|
|
||||||
RETURN(result);
|
RETURN(result);
|
||||||
return(result);
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
void
|
int
|
||||||
usleep(unsigned long microseconds)
|
usleep(unsigned long microseconds)
|
||||||
{
|
{
|
||||||
ENTER();
|
ENTER();
|
||||||
@ -51,4 +51,6 @@ usleep(unsigned long microseconds)
|
|||||||
__time_delay(0,microseconds);
|
__time_delay(0,microseconds);
|
||||||
|
|
||||||
LEAVE();
|
LEAVE();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -334,7 +334,7 @@ __wildcard_expand_init(void)
|
|||||||
}
|
}
|
||||||
else if (rc != OK)
|
else if (rc != OK)
|
||||||
{
|
{
|
||||||
/* Some error occured. */
|
/* Some error occurred. */
|
||||||
error = EIO;
|
error = EIO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user