1
0
mirror of https://github.com/adtools/clib2.git synced 2025-12-08 14:59:05 +00:00

129 Commits

Author SHA1 Message Date
obarthel
14c53db07c Typo corrections and small changes to the implementation documentation 2025-07-17 11:49:12 +02:00
obarthel
c56fb088ef The new "d_type" field of the "struct dirent" is available if the _DIRENT_HAVE_D_TYPE macro is defined 2025-07-17 11:48:29 +02:00
Olaf Barthel
fe363c5403 The dependencies for the stdio_long_path.c file need more work 2025-07-14 13:47:52 +02:00
Olaf Barthel
9f1a9ae92e The readlink() function now uses DOS packet I/O instead of trusting Lock() to do the right thing 2025-07-14 13:33:02 +02:00
Olaf Barthel
d9b2c0f38f Added the header file dependency for the long path handling which makes it build on demand 2025-07-14 13:31:14 +02:00
Olaf Barthel
165232d694 The long path handling code works much better if you actually check it in 2025-07-14 13:29:06 +02:00
obarthel
7a4966e670 Documentation now covers the most recent handful of changes
Details matter: the locale_t definition uses an incomplete structure definition, not an anonymous structure.
2025-07-13 10:59:51 +02:00
obarthel
dfa3c412d9 The definition of 'locale_t' is now based upon a pointer to an "anonymous" structure
Thanks go to sacredbanana for the fix.
2025-07-12 12:30:59 +02:00
obarthel
f49877920e sqrt() now returns NAN, rather than 0, if the argument is < 0
Thanks go to sodero for providing the fix.
2025-07-12 12:26:34 +02:00
obarthel
2704ff880f Implemented the fixes for the tgamma() and tgammaf() functions
Thanks go to sodero for providing the fixes.
2025-07-12 12:25:42 +02:00
obarthel
8378274572 Added support for the "d_type" member of the "dirent" structure.
If the '_DIRENT_HAVE_D_TYPE' macro is defined after "#include <dirent.h>" has been used successfully, it means that the "dirent" structure features the "d_type" member. The directory entry type values were adapted from 4.4BSD-Lite2, but not all of these are used.
2025-07-12 12:17:12 +02:00
obarthel
0e637e9663 usleep() now correctly returns 0, with the function prototype to match
This addresses issue #4  by· capehill opened on Jul 30, 2017
2025-07-12 10:15:59 +02:00
Olaf Barthel
a1f85a9c7f First preparations for a future clib2 release 2025-07-10 14:21:30 +02:00
Olaf Barthel
76d5b5874e Very minor documentation cleanup 2025-07-10 13:17:30 +02:00
Olaf Barthel
51f88950eb Copied the changes which introduced ENOTSUP to <errno.h> and the related strerror_r() function. 2025-07-08 14:27:43 +02:00
Olaf Barthel
f9d1222bd7 Fix for wrong address alignment rounding
The original V39/V40 amiga.lib puddle creation code did not round up, it rounded off.
2023-10-11 09:15:28 +02:00
obarthel
d37909e409 Documented why bypassing the read/write buffer is only attempted if there is at least a full buffer worth of data to be read or written. 2023-09-14 09:52:21 +02:00
obarthel
f5631d8bda The inner loop of the read operation already fills the buffer as far as it can go. No need to drop into "continue;". 2023-09-11 17:36:32 +02:00
obarthel
9a9ae7d6fd The SIGABRT handler can no longer invoke abort() recursively. 2023-09-10 11:45:38 +02:00
obarthel
64ab8643b5 The size of a slab entry is now calculated inside a single local function, rather than calculated differently in different parts of stdlib_slab.c. This change made it easier to simplify the implementation. 2023-09-10 11:17:00 +02:00
obarthel
f7fd63acb4 Indentation fix. 2023-09-10 11:15:25 +02:00
obarthel
8bd7403ae3 The 'struct MemoryNode' is now so larger than the smallest usable allocation size is now 16 bytes. 2023-09-10 11:15:15 +02:00
obarthel
5efacb1a2b Fix for unnecessary compiler warnings. 2023-09-10 11:14:32 +02:00
obarthel
7207c96a6f Made the slab allocator work with libunix.a again. 2023-09-09 18:36:09 +02:00
obarthel
21bc996705 Fixed to make use of the aligned slab address when verifying that the slab node is present in the slab. The requested slab size is now properly rounded up to a power of 2 and will always be limited to a valid range. 2023-09-09 18:35:31 +02:00
obarthel
438fd5bbd2 Fixed the MemoryNode padding, which was short of a 32 bit word. 2023-09-09 18:33:38 +02:00
obarthel
101846e423 If the memory management system constructor fails, it now prints some diagnostic debug output. 2023-09-09 18:32:50 +02:00
obarthel
fba7f7da9b Small type corrections. 2023-09-09 12:55:13 +02:00
obarthel
115099698a Added an assertion to verify that the first free chunk on the slab's list is really always available. 2023-09-09 12:55:01 +02:00
obarthel
4f3d0c981c If the memory debug option is active, realloc() can no longer damage the trailing guard area. 2023-09-09 12:54:16 +02:00
obarthel
96af3a1165 Reformatted, so that it might be a bit more readable. 2023-09-08 17:20:51 +02:00
obarthel
6cabff4bbb Added the missing semicolon; 2023-09-08 17:20:16 +02:00
obarthel
71708e84ce The memory debugging code now places the the damage detection areas which bracket the allocation area so that the originally requested allocation size is used, not the rounded-up size. Debug output in memory node checking no longer counts the non-breaking space character as unprintable. 2023-09-08 16:11:01 +02:00
obarthel
3d70b18c23 Simplified how the slab allocator, the memory pool or AllocMem() are being used. Added robust integer overflow detection. Allocation sizes are now padded to a multiple of MEM_BLOCKSIZE. Repaired how the plain AllocMem() allocations are managed. alloca() cleanup is disabled during the stdlib_memory_exit destructor's work. The stdlib_memory_init constructor is more robust and now insists that exec.library V39+ uses memory pools. 2023-09-08 16:08:45 +02:00
obarthel
842acf2eaa Updated to properly use the MemoryNode changes. 2023-09-08 16:05:29 +02:00
obarthel
b9463f442b Added notes on calloc() being safe to use under certain circumstances if the number of elements or the element size happens to be 0. In effect, malloc() will decide what is going to happen. 2023-09-08 16:04:53 +02:00
obarthel
7ceeb4f8ed If alloca() would end up returning a NULL pointer, it now invokes the default alloca trap function, which calls abort(). You can override this, if you need to. 2023-09-08 16:03:47 +02:00
obarthel
fc8051f724 Modifed the MemoryNode so that its size will always be a multiple of MEM_BLOCKSIZE. The SlabSingleAllocation is now always a multiple of MEM_BLOCKSIZE, too. Tracking whether a MemoryNode is not supposed to be freed is now accomplished through dedicated flag instead of repurposing the allocation size field. 2023-09-08 16:02:37 +02:00
obarthel
64ba9b5389 Added the __addition_overflows() function prototype, which is used by code which checks for unsigned 32 bit integer sums exceeding the range of an unsigned 32 bit integer. 2023-09-08 16:00:38 +02:00
obarthel
1286b86f07 Added more robust integer overflow detection. Slab memory is now allocated so that its address starts on a MEM_BLOCKSIZE boundary. 2023-09-08 15:59:19 +02:00
obarthel
8101b43fc5 Tpyo correction 2023-09-08 15:52:06 +02:00
obarthel
efaffd9182 Typo corection 2023-09-08 15:51:13 +02:00
Olaf Barthel
6197531c90 Added integer overflow checking for the element_size and count parameters. 2023-09-06 13:28:48 +02:00
Olaf Barthel
b94937ff38 Fixed the bug which broke both fgets() and gets(): copying data from the FILE buffer failed to bump the destination string pointer. Also added an abort check in order to avoid turning the memcpy() operation into an uninterruptable sequence. 2023-09-06 13:27:45 +02:00
Olaf Barthel
2cb54d48a9 Added the common function which both fputs() and puts() share now. 2023-09-06 13:24:45 +02:00
Olaf Barthel
a7389454bb fputs() and puts() now share the same common code. Added abort checks in order to avoid turning the memcpy() operations into an uninterruptable sequence. 2023-09-06 13:24:15 +02:00
Olaf Barthel
45d118101a Added assertion test for the buffer alignment padding size. 2023-09-06 13:22:07 +02:00
Olaf Barthel
e4a703000a Reactivated memory debugging features. Added more robust integer overflow checking. 2023-09-06 13:21:13 +02:00
Olaf Barthel
8a4a75e721 Optionally, the slab allocator can be built to deliver 64-bit aligned allocations by default. Also, the slab allocator is no longer enabled at build time. 2023-09-06 13:20:10 +02:00
obarthel
4cb621d24d Added documentation on side-effects caused by using MEMF_CLEAR 2022-03-30 09:33:25 +02:00
obarthel
ff5826c54e Small changes to the code documentation
The memory pools store puddles near head of the allocation list and the large allocations near the tail of the list.

Some hints added to point to side-effects which might apply to memory allocation operations.
2021-12-23 13:08:08 +01:00
obarthel
b7ce13cbf8 Changed the internal data structures for slab allocations to yield 64-bit-aligned memory allocations. This can be tuned with the __MEM_ALLOCATIONS_64_BIT_ALIGNED preprocessor symbol. 2021-09-27 11:03:08 +02:00
obarthel
e71249a15b Removed the profile_profile.o file from the library to be be built. Added a comment explaining why this was necessary. 2021-09-27 11:00:54 +02:00
obarthel
19323ec218 The aggressive loop optimization option can be disabled/enabled as needed through a variable. 2021-09-27 11:00:20 +02:00
obarthel
cc8b81e7cc Added a 'C' implementation for the memory pools functions
Data structures and behaviour should follow the original (well, "original and bug-fixed") implementation.
2021-06-22 15:15:29 +02:00
obarthel
a7efdabefc Rewritten to handle date ranges better which lie outside the expected time of day, day of month and month.
The 'struct tm' is now properly updated to reflect the time and date information which comes out of the number of seconds calculated.

A bug reported by Andreas Falkenhahn is resolved which had the effect of distorting the number of seconds calculated.
2020-07-06 12:01:35 +02:00
Olaf Barthel
57774795af Typo correction. 2020-02-27 12:15:30 +01:00
Olaf Barthel
9d99542299 Fix for indentation error. 2020-02-27 12:15:17 +01:00
obarthel
e02089e28a Better handling of unbuffered mode for interactive streams
If the stream is unbuffered and turns out to be an interactive stream (e.g. stderr) then output will be made to follow the rules of line buffering to yield better readability of the output. Similar code exists with fputs(), for example.
2019-08-24 14:05:09 +02:00
obarthel
2bcfec3e60 Optimizations for better write performance.
fwrite() now tries to fill the write buffer as far is possible and will only resort to using the __putc() macros when necessary. This should improve write performance by quite a bit.

If the write buffer happens to be empty and the number of bytes to write is at least as large as the write buffer, then fwrite() will directly call write(). This should improve write performance, too.

If the file is in unbuffered mode, fwrite() now always calls write(), bypassing the write buffer altogether.
2019-08-24 14:03:34 +02:00
obarthel
4a01746be2 Optimizations for better write performance.
fputs() now works almost exactly like fwrite(), except that it's dealing with a NUL-terminated string.
2019-08-24 14:00:03 +02:00
obarthel
914ef57844 Changed how size=0 plays out
Setting the buffer size to 0 had the effect of switching the buffering mode. This is a bad idea since it wasn't actually called for: this is what the 'bufmode' parameter is intended for. What happens now is that the default buffer size is used (BUFSIZ), which sort of follows what the BSD libc did: a zero buffer size delayed the allocation of a buffer until the first read/write access occured.
2019-08-24 13:58:04 +02:00
obarthel
089ae11181 Improvements for better read performance.
gets() now tries to copy as much data from the read buffer as possible, and will fall back onto using the __getc() macro only if necessary. This should improve performance on long lines, or crash faster if the read buffer happens to be too short. This is probably wasted on gets(), but you never know...
2019-08-24 13:55:31 +02:00
obarthel
ae13cd77fc Optimizations for better read performance.
If the buffer mode is set to "no buffering" then fread() will always bypass the buffer and call read() instead.

If there is enough data waiting to be read from the buffer, fread() will now copy it directly, refilling the buffer as needed.

If the read buffer happens to be empty, buffering is enabled for the stream, and the number of bytes to read is at least as large as the buffer size,  then fread() will directly call read(), which should improve performance significantly.
2019-08-24 13:53:48 +02:00
obarthel
3f21e90fca Optimizations for better read performance
fgets() now copies as much data from the read buffer as possible, falling back onto the __getc() macro only as a last resort. This should help greatly when reading long lines since the overhead of calling __getc() goes away.
2019-08-24 13:50:41 +02:00
Olaf Barthel
5f14118d73 Fix for translation bug, which would make "a/../b" into "a./b". Contributed by Thomas Frieden - thank you very much! 2018-12-05 13:31:43 +01:00
Sebastian Bauer
b874ff71de Add wcscoll() dummy. 2018-04-22 11:21:24 +02:00
Sebastian Bauer
397013922c Use IsMinListEmpty() for MinList rather than IsListEmpty().
This removes the warnings about breaking the strict-aliasing rules.
2018-04-10 23:20:20 +02:00
Sebastian Bauer
85c36839d5 Create the proper directoy for MAKELIB. 2018-04-10 23:19:13 +02:00
Sebastian Bauer
196d37b28a Compile with -nostdlib, rather than -mcrt=clib2.
We are actually building the clib2 here.
2018-04-10 23:18:30 +02:00
Sebastian Bauer
e8086be768 Disable -Wunused-label.
There are a lot of unused lables, depending on the actual
compiling mode.
2018-04-10 23:17:08 +02:00
Sebastian Bauer
82dd474e3b Disable -Wbad-function-cast. It produces a lot of useless warnings. 2018-04-09 23:24:56 +02:00
Sebastian Bauer
58f36203b1 Fix cast to function pointer. 2018-04-09 23:24:07 +02:00
Sebastian Bauer
425f899302 Merge pull request #7 from sba1/wchar-fixes
Wchar fixes
2018-03-31 09:37:50 +02:00
Sebastian Bauer
febe89c61b Update changelog. 2018-03-30 22:17:41 +02:00
Sebastian Bauer
3e50be491b Include stdint.h for WCHAR_MAX to avoid redundant definitions. 2018-03-30 21:42:12 +02:00
Sebastian Bauer
dfc7f310d6 Don't define wchar_t in C++ as it is a bultin-type there. 2018-03-30 21:35:06 +02:00
Sebastian Bauer
a6a9352a00 Compile wchar_wscoll.c. 2018-03-30 21:21:31 +02:00
Sebastian Bauer
eb1d784c0d Provide stub for mbrtowc(). 2018-03-30 21:21:11 +02:00
Sebastian Bauer
d1092099d0 Provide some more wide char functions. 2018-03-29 20:59:02 +02:00
Sebastian Bauer
bc621bed9c Disable the LOG_COMMAND.
Piping will have the consequence that the exit status of the first command
will not be considered. As this is the compiling command in our case, make
will not exit with an error code even if the compiling failed.

While there are shell-specific solutions, disabling LOG_COMMAND seems to
be the most general solution.
2018-03-29 20:57:32 +02:00
Sebastian Bauer
60eebbe732 Implement wcscat(). 2018-03-28 21:23:13 +02:00
Sebastian Bauer
345995000a Implement some more of the iswXXX() functions. 2018-03-28 21:16:14 +02:00
Sebastian Bauer
ef18bf5f3e Fix vswprintf() prototype. 2018-03-28 18:47:24 +02:00
Sebastian Bauer
6f3b3b6d28 Implement few wide char functions. 2018-03-28 17:09:18 +02:00
Sebastian Bauer
846eebc66c Fix mbtowc() to and compile it. 2018-03-28 17:08:42 +02:00
Sebastian Bauer
75d47ccdad Build all existing wchar and wctype functions. 2018-03-27 20:03:45 +02:00
Sebastian Bauer
456123fe7f Add dummy wctob(). 2018-03-27 20:02:54 +02:00
Sebastian Bauer
5733c99ba1 Fix wcspbrk() definition to match the prototype. 2018-03-27 20:00:28 +02:00
Sebastian Bauer
391e7e39ad Add wcscoll() prototype. 2018-03-27 19:59:54 +02:00
Sebastian Bauer
f5f0e17e78 Define ISO 99 multibyte functions also in C++ context. 2018-03-27 19:59:23 +02:00
Sebastian Bauer
f6f0082a0e Include sys/clib2_stdc.h for restrict. 2018-03-27 19:56:45 +02:00
obarthel
c84b1fc1ff Tiny fixes 2018-02-18 13:58:25 +01:00
obarthel
e35307a7e3 Ignore linker map files, too. 2018-02-17 13:45:21 +01:00
Henning Nielsen Lund
911114c286 add an unimplemented tzset().
ctime_r() and localtime_r() are already using the localtime, so no need to do anything.
http://pubs.opengroup.org/onlinepubs/9699919799/functions/tzset.html

Signed-off-by: Henning Nielsen Lund <hnl_dk@amigaos.dk>
2017-08-27 13:30:12 +02:00
Henning Nielsen Lund
9e998ca108 should have been sys/clib2_stdc.h 2017-08-15 21:53:49 +02:00
Henning Nielsen Lund
99695dec0b we use restrict
Signed-off-by: Henning Nielsen Lund <hnl_dk@amigaos.dk>
2017-08-15 21:45:33 +02:00
Henning Nielsen Lund
0ec7094877 Code depending on statfs or fstatfs do both depend on sys/mount.h and sys/param.h where we only had sys/mount.h
Signed-off-by: Henning Nielsen Lund <hnl_dk@amigaos.dk>
2017-08-15 21:26:45 +02:00
Henning Nielsen Lund
a471e73adf add timespec declaration 2017-08-05 17:28:39 +02:00
Henning Nielsen Lund
c76bf8e20b add strnlen() 2017-08-01 21:28:07 +02:00
Henning Nielsen Lund
309bbd8c8c Add a few extra wide-character prototypes and the missing typedef locale_t 2017-08-01 21:26:59 +02:00
Henning Nielsen Lund
d6e5769bc5 using restrict, so restrict to c99 2017-08-01 14:52:45 +02:00
Henning Nielsen Lund
976b6ae7e1 Change the mbrlen declaration to equal ISO C.
http://pubs.opengroup.org/onlinepubs/9699919799/functions/mbrlen.html

Signed-off-by: Henning Nielsen Lund <hnl_dk@amigaos.dk>
2017-08-01 13:55:11 +02:00
obarthel
8af96cb6cb Merge branch 'master' of https://github.com/adtools/clib2 2017-07-08 18:10:45 +02:00
obarthel
febe690623 This got lost last year
The missing calloc() overflow test never made it to the CVS or git repositories :-(
2017-07-08 18:10:28 +02:00
Jens Maus
e36ebff16e Merge pull request #3 from adtools/gcc5-fixes
Fixes for compiling with GCC 5.4.0 on AmigaOS 4.1
2017-06-28 08:55:21 +02:00
Steven Solie
6a1fd36b3a Revision bump. 2017-06-28 06:35:31 +02:00
Steven Solie
feebeb6751 GCC 5 changes 2017-06-28 06:34:57 +02:00
obarthel
1b2c798467 Fixed calloc() and getopt_long()
Added integer overflow test to calloc().

Tiny change in getopt_long() so that the value pointed to by the "longindex" parameter is always initialized to an invalid index position (that being -1), instead of 0. The value of 0 can break some shell commands, most notably GNU wget.
2017-05-01 18:06:23 +02:00
Jens Maus
053a61fc4b Create LICENSE 2016-12-05 14:41:06 +01:00
obarthel
4c54ee3f2d Version bump 2016-12-04 11:14:17 +01:00
obarthel
f491e38b38 Added code to temporarily disable profiling 2016-12-04 11:14:00 +01:00
obarthel
734ce4c1a9 Added code to temporarily disable profiling 2016-12-04 11:13:37 +01:00
obarthel
ce345df9da Hide warnings for deprecated functions 2016-12-04 11:13:00 +01:00
obarthel
5e0fa78d61 Only builds with GCC now 2016-12-04 11:12:42 +01:00
obarthel
bc3e19abe5 Only uses MEMF_PRIVATE on OS4 now 2016-12-04 11:12:32 +01:00
obarthel
29e02775fb Cleaned up the build rules, added missing files 2016-12-04 11:11:53 +01:00
obarthel
5cb27db203 Slab allocator is exercised much more 2016-12-04 11:11:28 +01:00
obarthel
4fc1b13945 Added a rogue malloc/free pair 2016-12-04 11:11:05 +01:00
obarthel
8beaabac4f Removed unused local variable 2016-12-04 11:10:46 +01:00
obarthel
271572ed56 Fixed so that it builds correctly with SAS/C again 2016-12-04 11:10:33 +01:00
obarthel
e0feef8932 Moved __CXV54 into sas_cxv.asm
sas_cxv54.asm is no longer needed.
2016-12-04 11:10:13 +01:00
obarthel
07259ed7eb This is needed when building with math=ieee option 2016-12-04 11:09:24 +01:00
obarthel
3203fcf96a Removed unused result variable 2016-12-04 11:08:54 +01:00
obarthel
bfba44bf83 Rewritten to use setjmp()/longjmp()
Also contains new code which prints the number of times a slab was reused.
2016-12-04 11:08:41 +01:00
obarthel
35434bdedc Updated to build correctly with SAS/C again 2016-12-04 11:07:40 +01:00
obarthel
17ba18c731 Added code which temporarily disables profiling 2016-12-04 11:06:50 +01:00
obarthel
78a8c7655e Added __decay_unused_slabs() 2016-12-04 11:05:50 +01:00
obarthel
184a127860 Added stdlib_decay_unused_slabs() 2016-12-04 11:05:30 +01:00
125 changed files with 6005 additions and 2431 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
*.a
/library/compiler.log
/library/netinclude
*.map

29
LICENSE Normal file
View File

@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2016, Olaf Barthel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -122,7 +122,7 @@ WARNINGS = \
# -Wconversion -Wshadow
INCLUDES = -Iinclude -I. -Inetinclude
#OPTIONS = -fno-builtin -fno-common -DDEBUG
#OPTIONS = -fno-builtin -fno-common
OPTIONS = -fno-builtin -fno-common -DNDEBUG
#OPTIONS = -fno-builtin -fno-common -DNDEBUG -D__THREAD_SAFE
#OPTIONS = -fno-builtin -fno-common -D__MEM_DEBUG
@@ -261,6 +261,7 @@ C_LIB = \
stdio_iobhookentry.o \
stdio_lock.o \
stdio_locksemaphorename.o \
stdio_long_path.o \
stdio_nostdio.o \
stdio_openiob.o \
stdio_parent_of_fh.o \
@@ -327,6 +328,7 @@ C_LIB = \
stdlib_exit.o \
stdlib_free.o \
stdlib_free_unused_slabs.o \
stdlib_decay_unused_slabs.o \
stdlib_getdefstacksize.o \
stdlib_getenv.o \
stdlib_getmemstats.o \
@@ -490,13 +492,13 @@ C_LIB = \
UNIX_LIB = \
unix.lib_rev.o \
dirent_closedir.o \
dirent_rewinddir.o \
dirent_opendir.o \
dirent_readdir.o \
dirent_rewinddir.o \
fcntl_creat.o \
fcntl_fcntl.o \
fcntl_open.o \
fcntl_get_default_file.o \
fcntl_open.o \
getopt_getopt_long.o \
mount_convertinfo.o \
mount_statfs.o \
@@ -504,18 +506,19 @@ UNIX_LIB = \
resource_setrlimit.o \
stat_chmod.o \
stat_fstat.o \
stat_lstat.o \
stat_lock.o \
stat_lstat.o \
stat_mkdir.o \
stat_rmdir.o \
stat_stat.o \
stdio_ctermid.o \
stdio_fdhookentry.o \
stdio_fflush.o \
stdio_file_init.o \
stdio_fopen.o \
stdio_init_exit.o \
stdio_file_init.o \
stdio_locksemaphorename.o \
stdio_long_path.o \
stdio_openiob.o \
stdio_popen.o \
stdio_record_locking.o \
@@ -525,17 +528,28 @@ UNIX_LIB = \
stdlib_alloca_cleanup.o \
stdlib_alloca_trap.o \
stdlib_arg.o \
stdlib_calloc.o \
stdlib_decay_unused_slabs.o \
stdlib_expand_wildcard.o \
stdlib_expand_wildcard_check.o \
stdlib_free.o \
stdlib_free_unused_slabs.o \
stdlib_getmemstats.o \
stdlib_get_slab_allocations.o \
stdlib_get_slab_stats.o \
stdlib_get_slab_usage.o \
stdlib_main.o \
stdlib_main_stub.o \
stdlib_malloc.o \
stdlib_mkdtemp.o \
stdlib_mkstemp.o \
stdlib_mktemp.o \
stdlib_malloc.o \
stdlib_realloc.o \
stdlib_red_black.o \
stdlib_resetmemstats.o \
stdlib_slab.o \
stdlib_slab_max_size.o \
stdlib_slab_purge_threshold.o \
stdlib_system.o \
systeminfo_sysinfo.o \
termios_cfgetispeed.o \
@@ -939,6 +953,7 @@ AMIGA_LIB = \
amiga_hotkey.o \
amiga_invertstring.o \
amiga_newlist.o \
amiga_pools.o \
amiga_rangerand.o \
amiga_remtof.o \
amiga_rexxvars.o \
@@ -1142,6 +1157,8 @@ $(LIBC_OBJS)/stdlib_get_slab_stats.o : stdlib_get_slab_stats.c stdlib_memory.h i
$(LIBC_OBJS)/stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h include/stdlib.h
$(LIBC_OBJS)/stdlib_decay_unused_slabs.o : stdlib_decay_unused_slabs.c stdlib_memory.h include/stdlib.h
$(LIBC_OBJS)/stdlib_get_slab_usage.o : stdlib_get_slab_usage.c stdlib_memory.h include/stdlib.h
$(LIBC_OBJS)/stdlib_get_slab_allocations.o : stdlib_get_slab_allocations.c stdlib_memory.h include/stdlib.h
@@ -1152,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.
ifneq (,$(findstring fbaserel32,$(CODE_FLAGS)))
LOCAL_CODE_FLAGS := $(CODE_FLAGS) $(CODE_TYPE)

View File

@@ -29,7 +29,11 @@ RANLIB := ppc-amigaos-ranlib
COPY := cp -p
DELETE := rm -rf
MAKEDIR := mkdir -p
LOG_COMMAND := 2>&1 | tee -a compiler.log
# Enabling the LOG_COMMAND has the consequence that a rule will not
# fail on an error because only the exit status from the tee command
# will be considered
#LOG_COMMAND := 2>&1 | tee -a compiler.log
LOG_COMMAND :=
# You may need to request a specific compiler version in order to
# build the baserel versions of the library. At this time of
# writing (2008-11-06) GCC 4.0.4 and below support the -mbaserel
@@ -54,12 +58,13 @@ LOG_COMMAND := 2>&1 | tee -a compiler.log
WARNINGS := \
-Wall -W -Wpointer-arith -Wsign-compare -Wmissing-prototypes \
-Wundef -Wbad-function-cast -Wmissing-declarations -Wunused -Wwrite-strings
-Wundef -Wmissing-declarations -Wunused -Wwrite-strings \
-Wno-deprecated-declarations -Wno-unused-label \
# -Wconversion -Wshadow
# -Wconversion -Wshadow -Wbad-function-cast
INCLUDES := -Iinclude -I. -I$(SDK_INCLUDE)
OPTIONS := -DUSE_64_BIT_INTS -D__USE_INLINE__ -Wa,-mregnames -fno-common -std=gnu99 -mcrt=clib2
OPTIONS := -DUSE_64_BIT_INTS -D__USE_INLINE__ -Wa,-mregnames -fno-builtin -fno-common -std=c99 -nostdlib
OPTIMIZE := -DNDEBUG -O3
#DEBUG := -ggdb
@@ -92,7 +97,11 @@ include libm.gmk
include libnet.gmk
include libdebug.gmk
include libamiga.gmk
include libprofile.gmk
# Olaf (2019-08-22): Please note that "profile_profil.o" can no longer
# be built, presumably for lack of header files needed
# to build it properly.
#include libprofile.gmk
all-targets: \
lib/crt0.o \
@@ -159,6 +168,12 @@ cvs-tag:
# General build rules for all object files and the individual libraries
#NO_AGGRESSIVE_LOOP_OPTIMIZATIONS := -fno-aggressive-loop-optimizations
lib/crtbegin.o : CFLAGS += $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
lib/crtbegin.o : crtbegin.c
@$(COMPILE)
lib/%.o : AFLAGS += $(LARGEDATA)
lib/%.o : %.S
@$(ASSEMBLE)
@@ -170,6 +185,11 @@ lib/small-data/%.o : AFLAGS += $(SMALLDATA)
lib/small-data/%.o : %.S
@$(ASSEMBLE)
lib/small-data/crtbegin.o : CFLAGS += $(SMALLDATA) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
lib/small-data/crtbegin.o : crtbegin.c
@$(COMPILE)
lib/small-data/%.o : CFLAGS += $(SMALLDATA)
lib/small-data/%.o : %.c
@$(COMPILE)
@@ -177,6 +197,11 @@ lib/soft-float/%.o : AFLAGS += $(SOFTFLOAT)
lib/soft-float/%.o : %.S
@$(ASSEMBLE)
lib/soft-float/crtbegin.o : CFLAGS += $(SOFTFLOAT) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
lib/soft-float/crtbegin.o : crtbegin.c
@$(COMPILE)
lib/soft-float/%.o : CFLAGS += $(SOFTFLOAT)
lib/soft-float/%.o : %.c
@$(COMPILE)
@@ -184,6 +209,11 @@ lib/baserel/%.o : AFLAGS += $(BASEREL)
lib/baserel/%.o : %.S
@$(ASSEMBLE)
lib/baserel/crtbegin.o : CFLAGS += $(BASEREL) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
lib/baserel/crtbegin.o : crtbegin.c
@$(COMPILE)
lib/baserel/%.o : CFLAGS += $(BASEREL)
lib/baserel/%.o : %.c
@$(COMPILE)
@@ -191,6 +221,11 @@ lib.threadsafe/%.o : AFLAGS += $(LARGEDATA) $(THREADSAFE)
lib.threadsafe/%.o : %.S
@$(ASSEMBLE)
lib.threadsafe/crtbegin.o : CFLAGS += $(THREADSAFE) $(LARGEDATA) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
lib.threadsafe/crtbegin.o : crtbegin.c
@$(COMPILE)
lib.threadsafe/%.o : CFLAGS += $(THREADSAFE) $(LARGEDATA)
lib.threadsafe/%.o : %.c
@$(COMPILE)
@@ -198,6 +233,11 @@ lib.threadsafe/small-data/%.o : AFLAGS += $(SMALLDATA) $(THREADSAFE)
lib.threadsafe/small-data/%.o : %.S
@$(ASSEMBLE)
lib.threadsafe/small-data/crtbegin.o : CFLAGS += $(THREADSAFE) $(SMALLDATA) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
lib.threadsafe/small-data/crtbegin.o : crtbegin.c
@$(COMPILE)
lib.threadsafe/small-data/%.o : CFLAGS += $(THREADSAFE) $(SMALLDATA)
lib.threadsafe/small-data/%.o : %.c
@$(COMPILE)
@@ -205,6 +245,11 @@ lib.threadsafe/soft-float/%.o : AFLAGS += $(SOFTFLOAT) $(THREADSAFE)
lib.threadsafe/soft-float/%.o : %.S
@$(ASSEMBLE)
lib.threadsafe/soft-float/crtbegin.o : CFLAGS += $(THREADSAFE) $(SOFTFLOAT) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
lib.threadsafe/soft-float/crtbegin.o : crtbegin.c
@$(COMPILE)
lib.threadsafe/soft-float/%.o : CFLAGS += $(THREADSAFE) $(SOFTFLOAT)
lib.threadsafe/soft-float/%.o : %.c
@$(COMPILE)
@@ -212,6 +257,11 @@ lib.threadsafe/baserel/%.o : AFLAGS += $(BASEREL) $(THREADSAFE)
lib.threadsafe/baserel/%.o : %.S
@$(ASSEMBLE)
lib.threadsafe/baserel/crtbegin.o : CFLAGS += $(THREADSAFE) $(BASEREL) $(NO_AGGRESSIVE_LOOP_OPTIMIZATIONS)
lib.threadsafe/baserel/crtbegin.o : crtbegin.c
@$(COMPILE)
lib.threadsafe/baserel/%.o : CFLAGS += $(THREADSAFE) $(BASEREL)
lib.threadsafe/baserel/%.o : %.c
@$(COMPILE)
@@ -230,7 +280,7 @@ $(CC) $(AFLAGS) -o $@ -c $< $(LOG_COMMAND)
endef
define MAKELIB
-$(MAKEDIR) $@
-$(MAKEDIR) $(@D)
$(DELETE) $@
echo "Making $@"
$(AR) $@ $^ $(LOG_COMMAND)

View File

@@ -1,6 +1,6 @@
#define VERSION 1
#define REVISION 212
#define DATE "27.11.2016"
#define VERS "amiga.lib 1.212"
#define VSTRING "amiga.lib 1.212 (27.11.2016)\r\n"
#define VERSTAG "\0$VER: amiga.lib 1.212 (27.11.2016)"
#define REVISION 216
#define DATE "10.7.2025"
#define VERS "amiga.lib 1.216"
#define VSTRING "amiga.lib 1.216 (10.7.2025)\r\n"
#define VERSTAG "\0$VER: amiga.lib 1.216 (10.7.2025)"

View File

@@ -1 +1 @@
212
216

View File

@@ -79,6 +79,8 @@ DoTimer(struct timeval *tv,LONG unit,LONG command)
struct MsgPort * mp;
LONG error;
PROFILE_OFF();
assert( tv != NULL );
#if defined(__amigaos4__)
@@ -129,14 +131,10 @@ DoTimer(struct timeval *tv,LONG unit,LONG command)
tr->tr_time.tv_secs = tv->tv_secs;
tr->tr_time.tv_micro = tv->tv_micro;
PROFILE_OFF();
SetSignal(0,(1UL << mp->mp_SigBit));
error = DoIO((struct IORequest *)tr);
PROFILE_ON();
tv->tv_secs = tr->tr_time.tv_secs;
tv->tv_micro = tr->tr_time.tv_micro;
@@ -161,5 +159,7 @@ DoTimer(struct timeval *tv,LONG unit,LONG command)
}
#endif /* __amigaos4__ */
PROFILE_ON();
return(error);
}

562
library/amiga_pools.c Normal file
View 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);
}
}
}

View File

@@ -262,9 +262,8 @@ STATIC VOID
_SetValue(struct Environment * env,struct NexxStr * value,struct Node * symbol_table_node)
{
STATIC CONST UWORD code[] = { 0x4EAE,0xFFAC,0x4E75 }; /* jsr -84(a6) ; rts */
struct Node * result;
result = (struct Node *)EmulateTags(code,
EmulateTags(code,
ET_RegisterA0,env,
ET_RegisterA1,value,
ET_RegisterD0,symbol_table_node,

View File

@@ -1,6 +1,6 @@
#define VERSION 1
#define REVISION 212
#define DATE "27.11.2016"
#define VERS "c.lib 1.212"
#define VSTRING "c.lib 1.212 (27.11.2016)\r\n"
#define VERSTAG "\0$VER: c.lib 1.212 (27.11.2016)"
#define REVISION 217
#define DATE "10.7.2025"
#define VERS "c.lib 1.217"
#define VSTRING "c.lib 1.217 (10.7.2025)\r\n"
#define VERSTAG "\0$VER: c.lib 1.217 (10.7.2025)"

View File

@@ -1 +1 @@
212
217

View File

@@ -1,3 +1,197 @@
c.lib 1.217 (10.7.2025)
- Added support for handling path names that exceed 255 characters in
the AmigaOS 2.x/3.x build. This feature works by replacing calls to the
CreateDir(), DeleteFile(), Lock(), MakeLink(), Open(), Rename(),
SetComment(), SetFileDate(), SetOwner() and SetProtection() functions
with a call to a front-end which breaks down long path names into
the individual path components. This is a compile-time option which
is enabled through the "library/stdio_long_path.h" header file.
Note that this feature is by default disabled for AmigaOS 4 because
its dos.library already transparently performs the long path
processing.
- The raise() function no longer directly calls abort() because that
function in turn would have invoked raise(SIGABRT), triggering an
infinite loop. Instead, raise() now invokes the __abort() function
which abort() would have called via raise(SIGABRT).
- fgets() no longer leverages the __getc() macro, which in the
original implementation added excessive overhead for even small
read operations. Instead, fgets() now focuses on copying data
stored in the FILE read buffer, transferring the buffered data
in bulk, if possible. The same kind of changes are present in
the gets() function.
- fputs() and puts() no longer leverage the __putc() macro. As with
the fgets() implementation, the focus is now on enabling bulk
data transfer, eliminating the __putc() macro overhead. For line
buffered output, both fputs() and puts() will check if the text
ends with a line feed and, if so, will output everything up to
and including the line feed. If enabled, Ctrl+C checking will
occur for every single line written.
- fread() and fwrite() no longer leverage the __getc() and
__putc() macros. Their focus is on enabling bulk data transfer
instead.
- The setvbuf() function now correctly sets the buffer size to the
value of BUFSIZ if a buffer size of 0 is specified. Previously,
setvbuf() would have disabled buffering for the FILE instead (this
was a bug).
Failure to allocate a buffer of the specified non-zero size is
now caught and results in the setvbuf() function to indicate
failure, setting the errno variable to ENOBUFS.
- The alloca() library function (which is a built-in function for
gcc, for example) now calls abort() rather than returning NULL.
- Changed the numeric overflow check which the calloc() function
uses, simplifying it.
- The memory management debugging code in stdlib_free.c is no longer
reusing the allocation size value to indicate that an allocation
should never be freed. This indication is now stored in a separate
flags field.
- The memory debugging code in malloc() now checks if the combined
size of the management data structures and front/back padding
stay within the bounds of a 32 bit integer.
The list of memory nodes to be freed is now initialized first.
Previously, the list would be left uninitialized if the attempt to
allocate memory for memory arbitration semaphore had failed.
- The realloc() function now obtains the original size of the
allocation from a dedicated field of the data structure which
precedes the allocation, whose purpose is to track the
allocation until it is freed. Previously, obtaining the relevant
allocation size information was encapsulated by a "clever"
macro.
With memory debugging enabled, the stored allocation size no
longer says how much memory, padding included, is being used.
Instead, the requested allocation size is stored unchanged, with
the total allocation size derived from this number. The idea is
to make it harder to mistake the original allocation size for
the padded one and vice versa.
- The use of the optional slab allocator now has to be deliberately
enabled in the "library/stdlib_memory.h" header file.
- The minimum size of an allocation managed by the optional slab
allocator is now 16 bytes instead of 8 because the management
data structure for each allocation now includes a flags field.
- The minimum size of a slab is now 4096 bytes.
- The optional slab allocator now checks for integer overflows when
processing allocation requests, taking into account the size of
the actual allocation, including padding. The task of figuring
out how much padding is needed now rests in a function which
calculates the total overhead.
- The usleep() function now correctly returns 0 and the function
prototype reflects this, too. Thanks go to capehill who raised
this issue.
- The "struct dirent" which is used by the readdir() function now
features a "d_type" member which indicates the kind of directory
entry the respective entry represents. For the time being,
the type can be one of DT_DIR (directory, or hard link to a
directory), DT_REG (file, or hard link to a file) or DT_LINK (soft
link). How do you know if the "d_type" member is available?
Check if the _DIRENT_HAVE_D_TYPE macro is defined. If it is, then
you can make use of the "d_type" member.
- Implemented the fixes for the tgamma() and tgammaf() functions
which were prompted by sodero. Thank you very much!
- The sqrt() function now returns a plain NAN if the function
parameter is < 0. Thanks go to sodero for providing the fix.
- The definition of "locale_t" is now based upon an incomplete
structure, with locale_t being a pointer to it. This change was
was provided by sacredbanana. Thank you very much!
amiga.lib 1.216 (10.7.2025)
- Added a 'C' implementation of the pools.lib functions which were
merged with the Kickstart/Workbench 3.0 era amiga.lib. This
implementation provides the LibDeletePool(), LibCreatePool(),
LibAllocPooled() and LibFreePooled() functions which had not
been available before in clib2.
Please note that these functions are largely obsolete and only
helpful for code which must run on Kickstart 2.04. The current
implementation performs no error checking for integer overflows,
just like the original pools.lib implementation.
c.lib 1.216 (xxx)
- Add some wchar and multibyte-string related functions to allow gcc
building a libstdc++ library with wide char support. For now, the
functions are mostly stub ones only. They can be implemented on
demand.
c.lib 1.215 (26.6.2017)
- Added -fno-aggressive-loop-optimizations option when building crtbegin.c
to work around constructor/destructor hack with GCC 5.4.0 on AmigaOS 4.
- Added -fno-builtin option to fix conflicts with builtin memset()
with GCC 5.4.0 on AmigaOS 4.
c.lib 1.214 (27.4.2017)
- Added integer overflow test to calloc().
- Tiny change in getopt_long() so that the value pointed to by longindex
is always initialized to an invalid index position (that being -1),
instead of 0. The value of 0 can break some shell commands, most notably
GNU wget.
c.lib 1.213 (4.12.2016)
- Added the __decay_unused_slabs() function which brings all currently
empty slabs which are still protected from reuse closer to getting
reused or released.
- The slab-test program now exercises the memory allocation functions
to a greater degree. Memory is allocated in random chunk sizes,
the allocations are resized (to other random chunk sizes),
33% of all allocations are randomly freed, empty slabs readied for
reuse then discarded. The output in JSON format now shows a bit
more information as to what is being done.
- Rewrote __get_slab_stats() to use setjmp() and longjmp() in the
print() callback invocation.
- __get_slab_stats() now reports how many times a slab was reused
after having stuck around in the "empty slab" list.
- Changing the slab size through an environment variable is now
a feature of the debug build.
- Small changes to allow the library to be built with SAS/C again.
This includes adding code to disable/re-enable profiling,
fixing "stdlib_profile.h" and updating the smakefiles.
- Still not sure what it does, but _CXV45 now sits along with _CX25
and _CX35 in "sas_cxv.asm". "sas_cxv54.asm" is not needed any
more.
- Found the last use of MEMF_PRIVATE which should have been compiled
only for the OS4 version.
c.lib 1.212 (27.11.2016)
- Unused slabs which get recycled are no longer reinitialized from
@@ -116,7 +310,7 @@ c.lib 1.206 (24.4.2015)
- Removed the remains of all the stack extension and stack overflow/underflow
checking code. It never actually worked. The bit that does work is the stack
usage measurement code, plus the bit that sets up the the custom stack
usage measurement code, plus the bit that sets up the custom stack
according to local setting or by calling a query function.
@@ -1294,7 +1488,7 @@ c.lib 1.187 (29.1.2005)
adding/subtracting the local time zone.
- Changed the algorithm that calculates the number of days that have passed
so far as used by the the __convert_time() function and the conversion
so far as used by the __convert_time() function and the conversion
code in strftime().
- Also changed the algorithm used by strftime() to produce the week numbers

View File

@@ -1,5 +1,5 @@
/*
* $Id: crtbegin.c,v 1.13 2010-08-21 11:37:03 obarthel Exp $
* crtbegin.c
*
* :ts=4
*
@@ -48,7 +48,12 @@
* Dummy constructor and destructor array. The linker script will put these at the
* very beginning of section ".ctors" and ".dtors". crtend.o contains a similar entry
* with a NULL pointer entry and is put at the end of the sections. This way, the init
* code can find the global constructor/destructor pointers
* code can find the global constructor/destructor pointers.
*
* WARNING:
* This hack does not work correctly with GCC 5 and higher. The optimizer
* will see a one element array and act appropriately. The current workaround
* is to use -fno-aggressive-loop-optimizations when compiling this file.
*/
static void (*__CTOR_LIST__[1]) (void) __attribute__(( used, section(".ctors"), aligned(sizeof(void (*)(void))) ));
static void (*__DTOR_LIST__[1]) (void) __attribute__(( used, section(".dtors"), aligned(sizeof(void (*)(void))) ));

View File

@@ -1,6 +1,6 @@
#define VERSION 1
#define REVISION 212
#define DATE "27.11.2016"
#define VERS "debug.lib 1.212"
#define VSTRING "debug.lib 1.212 (27.11.2016)\r\n"
#define VERSTAG "\0$VER: debug.lib 1.212 (27.11.2016)"
#define REVISION 215
#define DATE "26.6.2017"
#define VERS "debug.lib 1.215"
#define VSTRING "debug.lib 1.215 (26.6.2017)\r\n"
#define VERSTAG "\0$VER: debug.lib 1.215 (26.6.2017)"

View File

@@ -1 +1 @@
212
215

View File

@@ -125,7 +125,7 @@ CLIB_DESTRUCTOR(dirent_exit)
if(__directory_list.mlh_Head != NULL)
{
while(NOT IsListEmpty((struct List *)&__directory_list))
while(NOT IsMinListEmpty(&__directory_list))
closedir((DIR *)__directory_list.mlh_Head);
}

View File

@@ -196,7 +196,7 @@ opendir(const char * path_name)
UnLockDosList(LDF_VOLUMES|LDF_READ);
/* Bail out if we cannot present anything. */
if(IsListEmpty((struct List *)&dh->dh_VolumeList))
if(IsMinListEmpty(&dh->dh_VolumeList))
{
__set_errno(ENOMEM);
goto out;

View File

@@ -1,10 +1,8 @@
/*
* $Id: dirent_readdir.c,v 1.10 2006-09-25 14:51:15 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -79,9 +77,11 @@ readdir(DIR * directory_pointer)
dh->dh_Position++;
dh->dh_DirectoryEntry.d_ino = 0;
strcpy(dh->dh_DirectoryEntry.d_name,".");
dh->dh_DirectoryEntry.d_ino = 0;
dh->dh_DirectoryEntry.d_type = DT_DIR;
result = &dh->dh_DirectoryEntry;
}
else
@@ -93,7 +93,7 @@ readdir(DIR * directory_pointer)
assert( (((ULONG)name) & 3) == 0 );
if(dh->dh_VolumeNode == NULL && NOT IsListEmpty((struct List *)&dh->dh_VolumeList))
if(dh->dh_VolumeNode == NULL && NOT IsMinListEmpty(&dh->dh_VolumeList))
dh->dh_VolumeNode = (struct Node *)dh->dh_VolumeList.mlh_Head;
strcpy(name,"\1:"); /* BSTR for ":" */
@@ -115,8 +115,9 @@ readdir(DIR * directory_pointer)
assert( sizeof(dh->dh_DirectoryEntry.d_name) >= sizeof(fib->fib_FileName) );
strcpy(dh->dh_DirectoryEntry.d_name,fib->fib_FileName);
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
dh->dh_DirectoryEntry.d_type = DT_DIR;
result = &dh->dh_DirectoryEntry;
}
@@ -147,10 +148,11 @@ readdir(DIR * directory_pointer)
dh->dh_Position++;
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
strcpy(dh->dh_DirectoryEntry.d_name,".");
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
dh->dh_DirectoryEntry.d_type = DT_DIR;
result = &dh->dh_DirectoryEntry;
}
else if (dh->dh_Position == 1)
@@ -176,10 +178,11 @@ readdir(DIR * directory_pointer)
SHOWMSG("returning ..");
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
strcpy(dh->dh_DirectoryEntry.d_name,"..");
dh->dh_DirectoryEntry.d_ino = fib->fib_DiskKey;
dh->dh_DirectoryEntry.d_type = DT_DIR;
result = &dh->dh_DirectoryEntry;
}
}
@@ -192,12 +195,23 @@ readdir(DIR * directory_pointer)
if(ExNext(dh->dh_DirLock,&dh->dh_FileInfo))
{
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
int type;
assert( sizeof(dh->dh_DirectoryEntry.d_name) >= sizeof(dh->dh_FileInfo.fib_FileName) );
strcpy(dh->dh_DirectoryEntry.d_name,dh->dh_FileInfo.fib_FileName);
dh->dh_DirectoryEntry.d_ino = dh->dh_FileInfo.fib_DiskKey;
if (dh->dh_FileInfo.fib_DirEntryType == ST_SOFTLINK)
type = DT_LNK;
else if (dh->dh_FileInfo.fib_DirEntryType < 0)
type = DT_REG;
else
type = DT_DIR;
dh->dh_DirectoryEntry.d_type = type;
result = &dh->dh_DirectoryEntry;
}
else

View File

@@ -296,7 +296,7 @@ static int getopt_long_internal(int argc, const char **argv, const char *optstri
optp = strchr(optstring, c);
/* We never find a long option in a compound option */
*longindex = 0;
*longindex = -1;
/* Check if it's legal */
if (c == ':' || (optp == NULL))

View File

@@ -1,10 +1,8 @@
/*
* $Id: dirent.h,v 1.7 2006-01-08 12:06:14 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -71,12 +69,41 @@ typedef long DIR;
/****************************************************************************/
/* The POSIX requirements for the 'struct dirent' cover little more than
* the 'd_ino' and 'd_name' fields. Because it is useful, the 'd_type'
* field identifies the type of object in question. This was added with
* clib2 1.217 (10.7.2025), and you can find out if the 'd_type' field
* is available in the 'struct dirent' by checking if the
* _DIRENT_HAVE_D_TYPE macro is defined.
*/
struct dirent
{
ino_t d_ino;
char d_name[NAME_MAX+1];
int d_type;
};
#define _DIRENT_HAVE_D_TYPE
/****************************************************************************/
/* Note that the directory entry type is not a POSIX feature, but it will
* make life easier for porting code which expects the 'd_type' structure
* member in the 'struct dirent'.
*
* The following types are not all supported on the Amiga. For the time being,
* DT_DIR (directory), DT_REG (regular file) and DT_LNK (soft link) should make
* sense.
*/
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
/****************************************************************************/
extern DIR * opendir(const char * path_name);

View File

@@ -359,7 +359,7 @@ extern unsigned int (* __get_default_stack_size)(void);
/*
* This library falls back onto locale.library to perform string collation
* in strcoll(), character conversion in toupper() and various other
* functions. This may not your intention. To restrict the library to use
* functions. This may not be your intention. To restrict the library to use
* only the "C" language locale, declare the following variable in your
* code and set it to FALSE, so that it overrides the default settings.
* The variable value is checked during program startup and, if set to

View File

@@ -166,6 +166,8 @@ extern int errno;
#define EILSEQ 85 /* Encoding error detected */
#define ENOTSUP 86 /* Not supported */
/****************************************************************************/
#ifdef __cplusplus

View File

@@ -1,10 +1,8 @@
/*
* $Id: locale.h,v 1.5 2006-01-08 12:06:14 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -59,6 +57,13 @@ extern "C" {
/****************************************************************************/
/* Forward declaration */
struct __locale_t;
typedef struct __locale_t *locale_t;
/****************************************************************************/
struct lconv
{
char * decimal_point; /* Decimal point character (non-monetary). */

View File

@@ -61,7 +61,11 @@ extern "C" {
typedef int ptrdiff_t;
typedef unsigned int size_t;
/* wchar_t is a built-in type in C++ */
#ifndef __cplusplus
typedef unsigned short wchar_t;
#endif
/****************************************************************************/

View File

@@ -47,6 +47,10 @@
#include <stddef.h>
#endif /* _STDDEF_H */
#ifndef _SYS_CLIB2_STDC_H
#include <sys/clib2_stdc.h>
#endif /* _SYS_CLIB2_STDC_H */
/****************************************************************************/
#ifdef __cplusplus
@@ -201,6 +205,21 @@ extern void __free_unused_slabs(void);
/****************************************************************************/
/*
* You can accelerate the reuse of currently unused slabs by calling
* the __decay_unused_slabs() function. Each call decrements the decay
* counter until it reaches 0, at which point an unused slab can be
* reused instead of allocating a new slab. Also, at 0 unused slabs
* will be freed by the allocator.
*
* Please note that this function works within the context of the memory
* allocation system and is not safe to call from interrupt code. It may
* break a Forbid() or Disable() condition.
*/
extern void __decay_unused_slabs(void);
/****************************************************************************/
/*
* You can obtain runtime statistics about the slab allocator by
* invoking the __get_slab_usage() function which in turn invokes
@@ -350,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
* data produced. You can store this data in a file, or in the clipboard,
* for later use. Your function must return 0 if it wants to be called
* again, or return -1 if it wants to stop (e.g. if an error 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
* you pass to __get_slab_stats() will be passed to your callback function.
*
@@ -432,6 +451,11 @@ extern lldiv_t lldiv(long long n,long long d);
/****************************************************************************/
extern int mbtowc(wchar_t *restrict pwc, const char *restrict s, size_t n);
extern int wctomb(char *s, wchar_t wchar);
/****************************************************************************/
#endif /* __GNUC__ || (__STDC_VERSION__ && __STDC_VERSION__ >= 199901L) */
/****************************************************************************/

View File

@@ -62,6 +62,7 @@ extern int strcmp(const char *s1, const char * s2);
extern int strncmp(const char *s1, const char *s2, size_t n);
extern char *strcpy(char *dest, const char *src);
extern char *strncpy(char *dest, const char *src, size_t n);
extern size_t strnlen(const char *s, size_t maxlen);
extern size_t strlen(const char *s);
extern char *strchr(const char *s, int c);
extern char *strrchr(const char *s, int c);

View File

@@ -0,0 +1,73 @@
/*
* $Id: $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2017 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of Olaf Barthel nor the names of contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************
*
* Documentation and source code for this library, and the most recent library
* build are available from <https://github.com/adtools/clib2>.
*
*****************************************************************************
*/
#ifndef _SYS_PARAM_H
#define _SYS_PARAM_H
/****************************************************************************/
/* The following is not part of the ISO 'C' (1994) standard. */
/****************************************************************************/
#ifndef _UNISTD_H
#include <unistd.h>
#endif /* _UNISTD_H */
/****************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/****************************************************************************/
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
/****************************************************************************/
#ifdef __cplusplus
}
#endif /* __cplusplus */
/****************************************************************************/
#endif /* _SYS_MOUNT_H */

View File

@@ -106,10 +106,24 @@ extern size_t strftime(char *s, size_t maxsize, const char *format,
/****************************************************************************/
/* Timespec declaration */
struct timespec
{
time_t tv_secs;
long tv_nsec;
};
#ifndef tv_sec
#define tv_sec tv_secs
#endif /* tv_sec */
/****************************************************************************/
extern char * asctime_r(const struct tm *tm,char * buffer);
extern char * ctime_r(const time_t *tptr,char * buffer);
extern struct tm * gmtime_r(const time_t *t,struct tm * tm_ptr);
extern struct tm * localtime_r(const time_t *t,struct tm * tm_ptr);
extern void tzset(void);
/****************************************************************************/

View File

@@ -117,7 +117,7 @@ extern int readlink(const char * path_name, char * buffer, int buffer_size);
extern int chdir(const char * path_name);
extern int lockf(int file_descriptor, int function, off_t size);
extern unsigned int sleep(unsigned int seconds);
extern void usleep(unsigned long microseconds);
extern int usleep(unsigned long microseconds);
extern int getopt(int argc, char * const argv[], const char *opts);
extern pid_t getpid(void);
extern char *realpath(const char *file_name, char *resolved_name);

View File

@@ -43,6 +43,10 @@
/****************************************************************************/
#ifndef _SYS_CLIB2_STDC_H
#include <sys/clib2_stdc.h>
#endif /* _SYS_CLIB2_STDC_H */
#ifndef _STDDEF_H
#include <stddef.h>
#endif /* _STDDEF_H */
@@ -59,6 +63,14 @@
#include <time.h>
#endif /* _TIME_H */
#ifndef _LOCALE_H
#include <locale.h>
#endif /* _LOCALE_H */
#ifndef _STDINT_H
#include <stdint.h>
#endif
/****************************************************************************/
#ifdef __cplusplus
@@ -68,8 +80,6 @@ extern "C" {
/****************************************************************************/
#define WEOF (-1)
#define WCHAR_MAX 65535
#define WCHAR_MIN 0
/****************************************************************************/
@@ -81,7 +91,6 @@ typedef long mbstate_t;
extern wint_t btowc(int c);
extern int wctob(wint_t c);
extern int mbsinit(const mbstate_t *ps);
extern size_t mbrlen(wchar_t *pwc, const char * s, size_t n, mbstate_t *ps);
extern size_t wcrtomb(char *s, wchar_t wc, mbstate_t *ps);
extern size_t mbsrtowcs(wchar_t *pwcs, const char **src, size_t n, mbstate_t *ps);
extern size_t wcsrtombs(char *s, const wchar_t **src, size_t n, mbstate_t *ps);
@@ -161,7 +170,7 @@ extern int swprintf(wchar_t *s, const wchar_t *format, ...);
extern int vfwprintf(FILE *stream,const wchar_t *format,va_list arg);
extern int vwprintf(const wchar_t *format,va_list arg);
extern int vswprintf(char *s, const wchar_t *format,va_list arg);
extern int vswprintf(wchar_t *s, size_t maxlen, const wchar_t *format, va_list arg);
/****************************************************************************/
@@ -174,16 +183,24 @@ extern size_t wcsftime(wchar_t *s, size_t maxsize, const wchar_t *format, const
/****************************************************************************/
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || defined(__cplusplus)
extern size_t mbrlen(const char *restrict s, size_t n, mbstate_t *restrict ps);
extern size_t mbrtowc(wchar_t *restrict pwc, const char *restrict s, size_t n, mbstate_t *restrict ps);
extern int mbsinit(const mbstate_t *ps);
extern size_t mbsnrtowcs(wchar_t *restrict dst, const char **restrict src, size_t nmc, size_t len, mbstate_t *restrict ps);
extern size_t mbsrtowcs(wchar_t *restrict dst, const char **restrict src, size_t len, mbstate_t *restrict ps);
extern size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict ps);
extern int wcscoll(const wchar_t *ws1, const wchar_t *ws2);
extern int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t loc);
extern size_t wcscspn(const wchar_t *s, const wchar_t *c);
extern size_t wcsnrtombs(char *restrict dst, const wchar_t **restrict src, size_t nwc, size_t len, mbstate_t *restrict ps);
extern wchar_t * wcsrchr(const wchar_t *ws, wchar_t wc);
extern size_t wcsrtombs(char *restrict dst, const wchar_t **restrict src, size_t len, mbstate_t *restrict ps);
extern long long wcstoll(const wchar_t *str, wchar_t **ptr, int base);
extern unsigned long long wcstoull(const wchar_t *str, wchar_t **ptr, int base);
extern size_t mbrtowc_l(wchar_t *restrict pwc, const char *restrict s, size_t n, mbstate_t *restrict ps, locale_t loc);
extern int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t loc);
extern size_t wcscspn(const wchar_t *ws1, const wchar_t *ws2);
extern wchar_t * wcsrchr(const wchar_t *ws, wchar_t wc);
#endif /* __STDC_VERSION__ && __STDC_VERSION__ >= 199901L */
/****************************************************************************/

View File

@@ -46,6 +46,7 @@ AMIGA_LIB = \
amiga_hotkey.o \
amiga_invertstring.o \
amiga_newlist.o \
amiga_pools.o \
amiga_rangerand.o \
amiga_remtof.o \
amiga_rexxvars.o \

View File

@@ -19,6 +19,10 @@ LIBS += \
##############################################################################
# Olaf (2019-08-22): Please note that "profile_profil.o" can no longer
# be built, presumably for lack of header files needed
# to build it properly.
C_LIB := \
c.lib_rev.o \
ctype_isalnum.o \
@@ -66,7 +70,6 @@ C_LIB := \
mount_convertinfo.o \
mount_fstatfs.o \
mount_statfs.o \
profile_profil.o \
signal_checkabort.o \
signal_data.o \
signal_kill.o \
@@ -212,6 +215,7 @@ C_LIB := \
stdlib_dosbase.o \
stdlib_exit.o \
stdlib_free.o \
stdlib_decay_unused_slabs.o \
stdlib_free_unused_slabs.o \
stdlib_getdefstacksize.o \
stdlib_getenv.o \
@@ -233,6 +237,7 @@ C_LIB := \
stdlib_main_stub.o \
stdlib_malloc.o \
stdlib_math.o \
stdlib_mbtowc.o \
stdlib_mkdtemp.o \
stdlib_mkstemp.o \
stdlib_mktemp.o \
@@ -309,6 +314,7 @@ C_LIB := \
string_strncat.o \
string_strncmp.o \
string_strncpy.o \
string_strnlen.o \
string_strpbrk.o \
string_strrchr.o \
string_strspn.o \
@@ -335,6 +341,7 @@ C_LIB := \
time_numbertostring.o \
time_strftime.o \
time_time.o \
time_tzset.o \
time_weekday.o \
uio_readv.o \
uio_writev.o \
@@ -371,7 +378,79 @@ C_LIB := \
unistd_unlink.o \
unistd_usleep.o \
utime_utime.o \
utsname_uname.o
utsname_uname.o \
wchar_btowc.o \
wchar_fgetwc.o \
wchar_fgetws.o \
wchar_fputwc.o \
wchar_fputws.o \
wchar_fwide.o \
wchar_fwprintf.o \
wchar_fwscanf.o \
wchar_getwc.o \
wchar_getwchar.o \
wchar_mbrlen.o \
wchar_mbrtowc.o \
wchar_mbsinit.o \
wchar_mbsrtowcs.o \
wchar_putwc.o \
wchar_putwchar.o \
wchar_swprintf.o \
wchar_swscanf.o \
wchar_ungetwc.o \
wchar_vfwprintf.o \
wchar_vswprintf.o \
wchar_vwprintf.o \
wchar_wcrtomb.o \
wchar_wcscat.o \
wchar_wcschr.o \
wchar_wcscmp.o \
wchar_wcscoll.o \
wchar_wcscpy.o \
wchar_wcscspn.o \
wchar_wcsftime.o \
wchar_wcslen.o \
wchar_wcsncat.o \
wchar_wcsncmp.o \
wchar_wcsncpy.o \
wchar_wscoll.o \
wchar_wcspbrk.o \
wchar_wcsrtombs.o \
wchar_wcsspn.o \
wchar_wcstod.o \
wchar_wcstok.o \
wchar_wcstol.o \
wchar_wcstoll.o \
wchar_wcstoul.o \
wchar_wcstoull.o \
wchar_wcsxfrm.o \
wchar_wctob.o \
wchar_wmemchr.o \
wchar_wmemcmp.o \
wchar_wmemcpy.o \
wchar_wmemmove.o \
wchar_wmemset.o \
wchar_wprintf.o \
wchar_wscanf.o \
wchar_wscoll.o \
wctype_iswalnum.o \
wctype_iswalpha.o \
wctype_iswblank.o \
wctype_iswcntrl.o \
wctype_iswctype.o \
wctype_iswdigit.o \
wctype_iswgraph.o \
wctype_iswlower.o \
wctype_iswprint.o \
wctype_iswpunc.o \
wctype_iswspace.o \
wctype_iswupper.o \
wctype_iswxdigit.o \
wctype_towctrans.o \
wctype_towlower.o \
wctype_towupper.o \
wctype_wctrans.o \
wctype_wctype.o
##############################################################################

View File

@@ -22,13 +22,13 @@ LIBS += \
UNIX_LIB := \
unix.lib_rev.o \
dirent_closedir.o \
dirent_rewinddir.o \
dirent_opendir.o \
dirent_readdir.o \
dirent_rewinddir.o \
fcntl_creat.o \
fcntl_fcntl.o \
fcntl_open.o \
fcntl_get_default_file.o \
fcntl_open.o \
getopt_getopt_long.o \
mount_convertinfo.o \
mount_statfs.o \
@@ -36,16 +36,16 @@ UNIX_LIB := \
resource_setrlimit.o \
stat_chmod.o \
stat_fstat.o \
stat_lstat.o \
stat_lock.o \
stat_lstat.o \
stat_mkdir.o \
stat_rmdir.o \
stat_stat.o \
stdio_ctermid.o \
stdio_fdhookentry.o \
stdio_fflush.o \
stdio_fopen.o \
stdio_file_init.o \
stdio_fopen.o \
stdio_init_exit.o \
stdio_locksemaphorename.o \
stdio_openiob.o \
@@ -60,15 +60,17 @@ UNIX_LIB := \
stdlib_dlopen.o \
stdlib_expand_wildcard.o \
stdlib_expand_wildcard_check.o \
stdlib_free.o \
stdlib_getmemstats.o \
stdlib_main.o \
stdlib_main_stub.o \
stdlib_malloc.o \
stdlib_mkdtemp.o \
stdlib_mkstemp.o \
stdlib_mktemp.o \
stdlib_malloc.o \
stdlib_realloc.o \
stdlib_resetmemstats.o \
stdlib_slab.o \
stdlib_system.o \
systeminfo_sysinfo.o \
termios_cfgetispeed.o \

View File

@@ -1,6 +1,6 @@
#define VERSION 1
#define REVISION 212
#define DATE "27.11.2016"
#define VERS "m.lib 1.212"
#define VSTRING "m.lib 1.212 (27.11.2016)\r\n"
#define VERSTAG "\0$VER: m.lib 1.212 (27.11.2016)"
#define REVISION 215
#define DATE "26.6.2017"
#define VERS "m.lib 1.215"
#define VSTRING "m.lib 1.215 (26.6.2017)\r\n"
#define VERSTAG "\0$VER: m.lib 1.215 (26.6.2017)"

View File

@@ -1 +1 @@
212
215

View File

@@ -1,6 +1,6 @@
#define VERSION 1
#define REVISION 212
#define DATE "27.11.2016"
#define VERS "m881.lib 1.212"
#define VSTRING "m881.lib 1.212 (27.11.2016)\r\n"
#define VERSTAG "\0$VER: m881.lib 1.212 (27.11.2016)"
#define REVISION 214
#define DATE "27.4.2017"
#define VERS "m881.lib 1.214"
#define VSTRING "m881.lib 1.214 (27.4.2017)\r\n"
#define VERSTAG "\0$VER: m881.lib 1.214 (27.4.2017)"

View File

@@ -1 +1 @@
212
214

View File

@@ -93,6 +93,13 @@
/****************************************************************************/
#ifndef IsMinListEmpty
#define IsMinListEmpty(ml) \
((struct MinList *)((ml)->mlh_TailPred) == (struct MinList *)(ml))
#endif
/****************************************************************************/
#ifndef AMIGA_COMPILER_H
#ifdef __SASC

View File

@@ -1,10 +1,8 @@
/*
* $Id: math_sqrt.c,v 1.9 2006-09-22 07:54:24 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -251,7 +249,8 @@ sqrt(double x)
}
else
{
result = 0;
result = NAN;
__set_errno(EDOM);
}

View File

@@ -1,10 +1,8 @@
/*
* $Id: math_tgamma.c,v 1.3 2006-01-08 12:04:24 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2025 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,13 +52,11 @@ double
tgamma(double x)
{
int gamma_sign;
double y;
double y;
y = __lgamma(x,&gamma_sign);
if (gamma_sign < 0)
y = -y;
y = __lgamma(x, &gamma_sign);
return y;
return gamma_sign * exp(y);
}
/****************************************************************************/

View File

@@ -1,6 +1,4 @@
/*
* $Id: math_tgammaf.c,v 1.3 2006-01-08 12:04:24 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
@@ -56,11 +54,9 @@ tgammaf(float x)
int gamma_sign;
float y;
y = __lgammaf(x,&gamma_sign);
if (gamma_sign < 0)
y = -y;
y = __lgammaf(x, &gamma_sign);
return y;
return gamma_sign * expf(y);
}
/****************************************************************************/

View File

@@ -1,6 +1,6 @@
#define VERSION 1
#define REVISION 212
#define DATE "27.11.2016"
#define VERS "net.lib 1.212"
#define VSTRING "net.lib 1.212 (27.11.2016)\r\n"
#define VERSTAG "\0$VER: net.lib 1.212 (27.11.2016)"
#define REVISION 215
#define DATE "26.6.2017"
#define VERS "net.lib 1.215"
#define VSTRING "net.lib 1.215 (26.6.2017)\r\n"
#define VERSTAG "\0$VER: net.lib 1.215 (26.6.2017)"

View File

@@ -1 +1 @@
212
215

View File

@@ -136,7 +136,7 @@ profil(unsigned short *buffer, size_t bufSize, size_t offset, unsigned int scale
ProfileData.CounterStart = GetCounterStart();
/* Set interrupt vector */
CounterInt.is_Code = (void (*)())CounterIntFn;
CounterInt.is_Code = (void (*)(void))CounterIntFn;
CounterInt.is_Data = &ProfileData;
IPM->SetInterruptVector(1, &CounterInt);

View File

@@ -37,6 +37,7 @@
xdef __CXV25
xdef __CXV35
xdef __CXV45
xdef __CXNRM5
xdef __CXTAB5
@@ -74,6 +75,43 @@ L44: MOVE.W D0,D1
MOVEM.L (SP)+,D2-D5/A1
RTS
__CXV45:
MOVE.L D0,D1
SWAP D1
AND.W #$7FFF,D1
CMP.W #$80,D1
BLT .1
CMP.W #$7F80,D1
BGE .3
ASR.L #3,D0
AND.L #$8FFFFFFF,D0
ADD.L #$38000000,D0
SWAP D1
AND.L #7,D1
ROR.L #3,D1
.2 RTS
.1 TST.L D1
BEQ.S .2
MOVEM.L D2-D5,-(SP)
SWAP D0
MOVE.W D0,D4
AND.W #$8000,D4
MOVE.W #$39D0,D5
MOVEQ #0,D0
SWAP D1
JSR __CXNRM5(PC)
MOVEM.L (SP)+,D2-D5
RTS
.3 ASR.L #3,D0
OR.L #$7FF00000,D0
SWAP D1
AND.L #7,D1
ROR.L #3,D1
RTS
__CXNRM5:
CMP.L #$20,D0

106
library/sas_cxv52.asm Normal file
View File

@@ -0,0 +1,106 @@
*
* :ts=8
*
* Adapted from reassembled SAS/C runtime library code.
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of Olaf Barthel nor the names of contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
xdef __CXV52
xdef __CXV53
xref __CXFERR
section text,code
__CXV52:
MOVEM.L D2/D3,-(SP)
MOVEQ #-1,D3
MOVE.L D0,D2
BPL.W lab04A
CMPI.L #$BFF00000,D0
BCS.W lab07A
MOVEM.L D0/D1/A0/A1,-(SP)
PEA (2).L
JSR __CXFERR
ADDQ.W #4,SP
MOVEM.L (SP)+,D0/D1/A0/A1
BRA.W lab07A
__CXV53:
MOVEM.L D2/D3,-(SP)
MOVE.L #$7FFFFFFF,D3
MOVE.L D0,D2
BPL.W lab04A
ADDQ.L #1,D3
EOR.L D3,D0
lab04A: SWAP D0
MOVE.W D0,D2
ANDI.W #$7FF0,D2
EOR.W D2,D0
SUBI.W #$3FF0,D2
BLT.W lab07A
EORI.W #$10,D0
SWAP D0
ASR.W #4,D2
SUBI.W #$14,D2
BGT.W lab09A
NEG.W D2
LSR.L D2,D0
TST.L D2
BMI.W lab0B2
BRA.W lab0B4
lab07A: MOVEQ #0,D0
BRA.W lab0B4
lab080: MOVEM.L D0/D1/A0/A1,-(SP)
PEA (2).L
JSR __CXFERR
ADDQ.W #4,SP
MOVEM.L (SP)+,D0/D1/A0/A1
MOVE.L D3,D0
BRA.W lab0B4
lab09A: CMPI.W #11,D2
BGT.B lab080
EOR.L D1,D0
ROL.L D2,D0
LSL.L D2,D1
EOR.L D1,D0
CMP.L D3,D0
BHI.B lab080
TST.L D2
BPL.W lab0B4
lab0B2: NEG.L D0
lab0B4: MOVEM.L (SP)+,D2/D3
RTS
end

View File

@@ -1,6 +1,4 @@
*
* $Id: sas_cxv54.asm,v 1.1.1.1 2004-07-26 16:31:04 obarthel Exp $
*
* :ts=8
*
* Adapted from reassembled SAS/C runtime library code.
@@ -38,7 +36,8 @@
xdef __CXV54
xref __CXFERR
__CXV54
__CXV54:
MOVEM.L A0/A1,-(SP)
MOVE.L D4,A0
SWAP D0
@@ -47,11 +46,11 @@ __CXV54
EOR.W D4,D0
SUB.W #$3800,D0
CMP.W #$10,D0
BLT lbC000098
BLT lab098
CMP.W #$FEF,D0
BLT lbC000102
BLT lab102
CMP.W #$47F0,D0
BLT lbC000058
BLT lab058
SWAP D0
LSL.L #3,D0
ROL.L #3,D1
@@ -59,17 +58,16 @@ __CXV54
EOR.L D1,D0
SWAP D0
OR.W #$7F80,D0
BRA lbC000112
BRA lab112
lbC000058
CMP.W #$FF0,D0
BGE lbC000074
lab058: CMP.W #$FF0,D0
BGE lab074
CMP.L #$FFFF0FEF,D0
BNE lbC000102
BNE lab102
CMP.L #$F0000000,D1
BCS lbC000102
lbC000074
MOVEM.L D0/D1/A0/A1,-(SP)
BCS lab102
lab074: MOVEM.L D0/D1/A0/A1,-(SP)
PEA 2.L
JSR __CXFERR
ADDQ.W #4,SP
@@ -78,63 +76,56 @@ lbC000074
EOR.W D4,D0
SWAP D0
MOVEQ #0,D1
BRA lbC000116
BRA lab116
lbC000098
CMP.W #$FE90,D0
BGE lbC0000C4
lab098: CMP.W #$FE90,D0
BGE lab0C4
ADD.W #$3800,D0
OR.L D1,D0
BEQ lbC000112
BEQ lab112
MOVEM.L D0/D1/A0/A1,-(SP)
PEA 1.L
JSR __CXFERR
ADDQ.W #4,SP
MOVEM.L (SP)+,D0/D1/A0/A1
MOVEQ #0,D0
BRA lbC000112
BRA lab112
lbC0000C4
MOVE.L D5,A1
lab0C4: MOVE.L D5,A1
MOVE.W D0,D5
AND.W #15,D0
EOR.W #$10,D0
SWAP D0
ASR.W #4,D5
ADDQ.W #2,D5
BGE lbC0000E6
BGE lab0E6
NEG.W D5
LSR.L D5,D0
MOVEQ #0,D5
ADDX.L D5,D0
BRA lbC0000F6
BRA lab0F6
lbC0000E6
CLR.W D1
lab0E6: CLR.W D1
LSL.L D5,D0
ADDQ.W #1,D5
ROXL.L D5,D1
AND.L #15,D1
ADDX.L D1,D0
lbC0000F6
MOVE.L A1,D5
lab0F6: MOVE.L A1,D5
SWAP D0
EOR.W D4,D0
SWAP D0
BRA lbC000116
BRA lab116
lbC000102
SWAP D0
lab102: SWAP D0
LSL.L #3,D0
ROXL.L #4,D1
AND.L #7,D1
ADDX.L D1,D0
SWAP D0
lbC000112
EOR.W D4,D0
lab112: EOR.W D4,D0
SWAP D0
lbC000116
MOVE.L A0,D4
lab116: MOVE.L A0,D4
MOVEM.L (SP)+,A0/A1
RTS

View File

@@ -71,7 +71,7 @@ raise(int sig)
assert( SIGABRT <= sig && sig <= SIGTERM );
/* This has to be a well-known and supported signal. */
if(sig < SIGABRT || sig > SIGTERM)
if (sig < SIGABRT || sig > SIGTERM)
{
SHOWMSG("unknown signal number");
@@ -80,48 +80,49 @@ raise(int sig)
}
/* Can we deliver the signal? */
if(FLAG_IS_CLEAR(__signals_blocked, (1 << sig)) &&
FLAG_IS_CLEAR(local_signals_blocked, (1 << sig)))
if (FLAG_IS_CLEAR(__signals_blocked, (1 << sig)) &&
FLAG_IS_CLEAR(local_signals_blocked, (1 << sig)))
{
signal_handler_t handler;
/* Which handler is installed for this signal? */
handler = __signal_handler_table[sig - SIGABRT];
/* Should we ignore this signal? */
if(handler != SIG_IGN)
/* Should we handle this signal rather than ignoring it? */
if (handler != SIG_IGN)
{
/* Block delivery of this signal to prevent recursion. */
SET_FLAG(local_signals_blocked,(1 << sig));
SET_FLAG(local_signals_blocked, (1 << sig));
/* The default behaviour is to drop into abort(), or do
something very much like it. */
if(handler == SIG_DFL)
* something very much like it.
*/
if (handler == SIG_DFL)
{
SHOWMSG("this is the default handler");
if(sig == SIGINT)
if (sig == SIGINT)
{
char break_string[80];
/* Turn off ^C checking for good. */
__check_abort_enabled = FALSE;
Fault(ERROR_BREAK,NULL,break_string,(LONG)sizeof(break_string));
Fault(ERROR_BREAK, NULL, break_string, (LONG)sizeof(break_string));
__print_termination_message(break_string);
SHOWMSG("bye, bye...");
}
/* Drop straight into abort(), which might call signal()
again but is otherwise guaranteed to eventually
land us in _exit(). */
abort();
/* Drop straight into __abort(), which will
eventually land us in _exit(). Note that
abort() calls raise(SIGABRT). */
__abort();
}
else
else
{
SHOWMSG("calling the handler");
SHOWMSG("calling the signal handler");
(*handler)(sig);
@@ -129,7 +130,7 @@ raise(int sig)
}
/* Unblock signal delivery again. */
CLEAR_FLAG(local_signals_blocked,(1 << sig));
CLEAR_FLAG(local_signals_blocked, (1 << sig));
}
}
else

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,8 @@
/*
* $Id: stdio_fgets.c,v 1.6 2006-01-08 12:04:24 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,6 +44,7 @@
char *
fgets(char *s,int n,FILE *stream)
{
struct iob * file = (struct iob *)stream;
char * result = s;
int c;
@@ -57,14 +56,14 @@ fgets(char *s,int n,FILE *stream)
assert( s != NULL && stream != NULL );
if(__check_abort_enabled)
if (__check_abort_enabled)
__check_abort();
flockfile(stream);
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(s == NULL || stream == NULL)
if (s == NULL || stream == NULL)
{
SHOWMSG("invalid parameters");
@@ -75,7 +74,7 @@ fgets(char *s,int n,FILE *stream)
}
#endif /* CHECK_FOR_NULL_POINTERS */
if(n <= 0)
if (n <= 0)
{
SHOWMSG("no work to be done");
@@ -86,7 +85,7 @@ fgets(char *s,int n,FILE *stream)
/* Take care of the checks and data structure changes that
* need to be handled only once for this stream.
*/
if(__fgetc_check(stream) < 0)
if (__fgetc_check(stream) < 0)
{
result = NULL;
goto out;
@@ -98,12 +97,83 @@ fgets(char *s,int n,FILE *stream)
/* One off for the terminating '\0'. */
n--;
while(n-- > 0)
assert( 0 <= file->iob_BufferReadBytes );
assert( file->iob_BufferReadBytes <= file->iob_BufferSize );
assert( file->iob_BufferPosition <= file->iob_BufferSize );
while (n > 0)
{
c = __getc(stream);
if(c == EOF)
/* If there is data in the buffer, try to copy it directly
* into the string buffer. If there is a line feed in the
* buffer, too, try to conclude the read operation.
*/
if (file->iob_BufferPosition < file->iob_BufferReadBytes)
{
if(ferror(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. */
(*s) = '\0';
@@ -113,8 +183,9 @@ fgets(char *s,int n,FILE *stream)
}
/* Make sure that we return NULL if we really
didn't read anything at all */
if(s == result)
* didn't read anything at all.
*/
if (s == result)
result = NULL;
break;
@@ -122,8 +193,11 @@ fgets(char *s,int n,FILE *stream)
(*s++) = c;
if(c == '\n')
if (c == '\n')
break;
assert( n > 0 );
n--;
}
(*s) = '\0';

View File

@@ -1,10 +1,8 @@
/*
* $Id: stdio_fputs.c,v 1.7 2006-01-08 12:04:24 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,10 +41,12 @@
/****************************************************************************/
/* Both fputs() and puts() share this function. */
int
fputs(const char *s, FILE *stream)
__fputs(const char *s, int line_feed, FILE *stream)
{
struct iob * file = (struct iob *)stream;
size_t total_size;
int result = EOF;
int buffer_mode;
int c;
@@ -58,12 +58,12 @@ fputs(const char *s, FILE *stream)
assert( s != NULL && stream != NULL );
if(__check_abort_enabled)
if (__check_abort_enabled)
__check_abort();
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(s == NULL || stream == NULL)
if (s == NULL || stream == NULL)
{
__set_errno(EFAULT);
goto out;
@@ -77,37 +77,261 @@ fputs(const char *s, FILE *stream)
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(stream) < 0)
if (__fputc_check(stream) < 0)
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)
goto out;
struct fd * fd = __fd[file->iob_Descriptor];
__fd_lock(fd);
if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE))
buffer_mode = IOBF_BUFFER_MODE_LINE;
__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;
out:
/* Note: if buffering is disabled for this stream, then we still
may have buffered data around, queued to be printed right now.
This is intended to improve performance as it takes more effort
to write a single character to a file than to write a bunch. */
if(result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
* may have buffered data around, queued to be printed right now.
* This is intended to improve performance as it takes more effort
* to write a single character to a file than to write a bunch.
*/
if (result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
{
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
if (__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
{
SHOWMSG("couldn't flush the write buffer");
result = EOF;
}
}
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);

View File

@@ -1,10 +1,8 @@
/*
* $Id: stdio_fread.c,v 1.7 2006-01-08 12:04:24 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -59,14 +57,14 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
assert( ptr != NULL && stream != NULL );
assert( (int)element_size >= 0 && (int)count >= 0 );
if(__check_abort_enabled)
if (__check_abort_enabled)
__check_abort();
flockfile(stream);
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(ptr == NULL || stream == NULL)
if (ptr == NULL || stream == NULL)
{
SHOWMSG("invalid parameters");
@@ -80,7 +78,7 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
assert( file->iob_BufferSize > 0 );
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_IN_USE))
if (FLAG_IS_CLEAR(file->iob_Flags, IOBF_IN_USE))
{
SHOWMSG("this file is not even in use");
@@ -91,7 +89,7 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
goto out;
}
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_READ))
if (FLAG_IS_CLEAR(file->iob_Flags, IOBF_READ))
{
SHOWMSG("this file is not read-enabled");
@@ -102,29 +100,114 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
goto out;
}
if(element_size > 0 && count > 0)
/* So that we can tell error and 'end of file' conditions apart. */
clearerr(stream);
if (element_size > 0 && count > 0)
{
size_t total_bytes_read = 0;
size_t total_size;
unsigned char * data = ptr;
ssize_t num_bytes_read;
int c;
if(__fgetc_check((FILE *)file) < 0)
if (__fgetc_check((FILE *)file) < 0)
goto out;
/* Check for overflow. */
total_size = element_size * count;
if (element_size != (total_size / count))
goto out;
SHOWVALUE(total_size);
while(total_size-- > 0)
/* No buffering enabled? */
if ((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
{
c = __getc(file);
if(c == EOF)
break;
/* 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;
}
(*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);
@@ -137,9 +220,6 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
SHOWVALUE(count);
SHOWMSG("either element size or count is zero");
/* Don't let this appear like an EOF or error. */
clearerr((FILE *)file);
}
D(("total number of elements read = %ld",result));

View File

@@ -1,10 +1,8 @@
/*
* $Id: stdio_fwrite.c,v 1.12 2010-10-20 13:12:58 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -59,14 +57,14 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
assert( ptr != NULL && stream != NULL );
assert( (int)element_size >= 0 && (int)count >= 0 );
if(__check_abort_enabled)
if (__check_abort_enabled)
__check_abort();
flockfile(stream);
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(ptr == NULL || stream == NULL)
if (ptr == NULL || stream == NULL)
{
SHOWMSG("invalid parameters");
@@ -78,9 +76,8 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
assert( __is_valid_iob(file) );
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
assert( file->iob_BufferSize > 0 );
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_IN_USE))
if (FLAG_IS_CLEAR(file->iob_Flags,IOBF_IN_USE))
{
SHOWMSG("this file is not even in use");
@@ -91,7 +88,7 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
goto out;
}
if(FLAG_IS_CLEAR(file->iob_Flags,IOBF_WRITE))
if (FLAG_IS_CLEAR(file->iob_Flags,IOBF_WRITE))
{
SHOWMSG("this stream is not write-enabled");
@@ -102,69 +99,242 @@ fwrite(const void *ptr,size_t element_size,size_t count,FILE *stream)
goto out;
}
if(element_size > 0 && count > 0)
clearerr((FILE *)file);
if (element_size > 0 && count > 0)
{
const unsigned char * data = (unsigned char *)ptr;
const unsigned char * s = (unsigned char *)ptr;
unsigned char c;
int buffer_mode;
size_t total_bytes_written = 0;
size_t total_size;
/* Check for overflow. */
total_size = element_size * count;
if(__fputc_check((FILE *)file) < 0)
if (element_size != (total_size / count))
goto out;
if (__fputc_check((FILE *)file) < 0)
goto out;
/* If this is an unbuffered interactive stream, we will switch
* to line buffered mode in order to improve readability of
* the output.
*/
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
if (buffer_mode == IOBF_BUFFER_MODE_NONE)
{
struct fd * fd = __fd[file->iob_Descriptor];
__fd_lock(fd);
if(FLAG_IS_SET(fd->fd_Flags,FDF_IS_INTERACTIVE))
if (FLAG_IS_SET(fd->fd_Flags, FDF_IS_INTERACTIVE))
buffer_mode = IOBF_BUFFER_MODE_LINE;
__fd_unlock(fd);
}
if(buffer_mode == IOBF_BUFFER_MODE_LINE)
if (buffer_mode == IOBF_BUFFER_MODE_LINE)
{
while(total_size-- > 0)
assert( file->iob_BufferSize > 0 );
while (total_size > 0)
{
c = (*data++);
/* Is there still room in the write buffer to store
* more of the data?
*/
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
{
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
size_t num_buffer_bytes;
const unsigned char * lf;
if(__putc_line_buffered(c,(FILE *)file) == EOF)
goto out;
/* Give the user a chance to abort what could otherwise
* become an uninterrupted series of copying operations.
*/
if (__check_abort_enabled)
__check_abort();
/* Store only as many characters as will fit into the write buffer. */
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
if (total_size < num_buffer_bytes)
num_buffer_bytes = total_size;
/* Try to find a line feed in the string. If there is one,
* reduce the number of characters to write to the sequence
* which ends with the line feed character.
*/
lf = (unsigned char *)memchr(s, '\n', num_buffer_bytes);
if (lf != NULL)
{
assert( (size_t)(lf + 1 - s) <= num_buffer_bytes );
num_buffer_bytes = lf + 1 - s;
}
assert( num_buffer_bytes > 0 );
memmove(buffer, s, num_buffer_bytes);
s += num_buffer_bytes;
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
file->iob_BufferWriteBytes += num_buffer_bytes;
/* Write the buffer to disk if the buffer is full
* or contains a line feed.
*/
if ((lf != NULL || __iob_write_buffer_is_full(file)) && __flush_iob_write_buffer(file) < 0)
{
/* Abort with error. */
break;
}
total_bytes_written += num_buffer_bytes;
/* Stop as soon as no further data needs to be written. */
assert( total_size >= num_buffer_bytes );
total_size -= num_buffer_bytes;
if (total_size == 0)
break;
/* If there is again room in the output buffer,
* repeat this optimization.
*/
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
continue;
}
c = (*s++);
if (__putc_line_buffered(c, (FILE *)file) == EOF)
break;
total_size--;
total_bytes_written++;
}
}
else if (buffer_mode == IOBF_BUFFER_MODE_NONE)
{
ssize_t num_bytes_written;
/* We bypass the buffer entirely. */
num_bytes_written = write(file->iob_Descriptor, s, total_size);
if (num_bytes_written == -1)
{
SET_FLAG(file->iob_Flags, IOBF_ERROR);
goto out;
}
total_bytes_written = (size_t)num_bytes_written;
}
else
{
while(total_size-- > 0)
assert( file->iob_BufferSize > 0 );
while (total_size > 0)
{
c = (*data++);
/* If there is more data to be written than the write buffer will hold
* and the write buffer is empty anyway, then we'll bypass the write
* buffer entirely. Note that we try to store a complete full buffer
* worth's of data, not just a few bytes.
*/
if (file->iob_BufferWriteBytes == 0 && total_size >= (size_t)file->iob_BufferSize)
{
ssize_t num_bytes_written;
if(__putc_fully_buffered(c,(FILE *)file) == EOF)
goto out;
/* We bypass the buffer entirely. */
num_bytes_written = write(file->iob_Descriptor, s, total_size);
if (num_bytes_written == -1)
{
SET_FLAG(file->iob_Flags, IOBF_ERROR);
goto out;
}
total_bytes_written += num_bytes_written;
break;
}
/* Is there still room in the write buffer to store
* more of the data?
*/
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
{
unsigned char * buffer = &file->iob_Buffer[file->iob_BufferWriteBytes];
size_t num_buffer_bytes;
/* Give the user a chance to abort what could otherwise
* become an uninterrupted series of copying operations.
*/
if (__check_abort_enabled)
__check_abort();
/* Store only as many bytes as will fit into the write buffer. */
assert( file->iob_BufferSize >= file->iob_BufferWriteBytes );
num_buffer_bytes = file->iob_BufferSize - file->iob_BufferWriteBytes;
if (total_size < num_buffer_bytes)
num_buffer_bytes = total_size;
assert( num_buffer_bytes > 0 );
memmove(buffer, s, num_buffer_bytes);
s += num_buffer_bytes;
assert( file->iob_BufferWriteBytes + num_buffer_bytes <= file->iob_BufferSize );
file->iob_BufferWriteBytes += num_buffer_bytes;
/* Write a full buffer to disk. */
if (__iob_write_buffer_is_full(file) && __flush_iob_write_buffer(file) < 0)
{
/* Abort with error. */
break;
}
total_bytes_written += num_buffer_bytes;
/* Stop as soon as no further data needs to be written. */
assert( total_size >= num_buffer_bytes );
total_size -= num_buffer_bytes;
if (total_size == 0)
break;
/* If there is again room in the output buffer,
* try this optimization again.
*/
if (file->iob_BufferWriteBytes < file->iob_BufferSize)
continue;
}
c = (*s++);
if (__putc_fully_buffered(c, (FILE *)file) == EOF)
break;
total_size--;
total_bytes_written++;
}
}
if((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
if ((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
{
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
goto out;
if (__iob_write_buffer_is_valid(file))
__flush_iob_write_buffer(file);
}
result = total_bytes_written / element_size;
}
else
{
/* Don't let this appear like an EOF or error. */
clearerr((FILE *)file);
SHOWVALUE(element_size);
SHOWVALUE(count);
SHOWMSG("either element size or count is zero");
}
out:

View File

@@ -1,10 +1,8 @@
/*
* $Id: stdio_gets.c,v 1.6 2006-01-08 12:04:24 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,6 +44,8 @@
char *
gets(char *s)
{
FILE * stream = stdin;
struct iob * file = (struct iob *)stream;
char * result = s;
int c;
@@ -53,16 +53,16 @@ gets(char *s)
SHOWPOINTER(s);
assert( s != NULL && stdin != NULL );
assert( s != NULL );
if(__check_abort_enabled)
if (__check_abort_enabled)
__check_abort();
flockfile(stdin);
flockfile(stream);
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(s == NULL || stdin == NULL)
if (s == NULL)
{
SHOWMSG("invalid parameters");
@@ -77,21 +77,84 @@ gets(char *s)
/* Take care of the checks and data structure changes that
* need to be handled only once for this stream.
*/
if(__fgetc_check(stdin) < 0)
if (__fgetc_check(stream) < 0)
{
result = NULL;
goto out;
}
/* So that we can tell error and 'end of file' conditions apart. */
clearerr(stdin);
clearerr(stream);
while(TRUE)
assert( 0 <= file->iob_BufferReadBytes );
assert( file->iob_BufferReadBytes <= file->iob_BufferSize );
assert( file->iob_BufferPosition <= file->iob_BufferSize );
while (TRUE)
{
c = __getc(stdin);
if(c == EOF)
/* If there is data in the buffer, try to copy it directly
* into the string buffer. If there is a line feed in the
* buffer, too, try to conclude the read operation.
*/
if (file->iob_BufferPosition < file->iob_BufferReadBytes)
{
if(ferror(stdin))
size_t num_bytes_in_buffer = file->iob_BufferReadBytes - file->iob_BufferPosition;
const unsigned char * buffer = &file->iob_Buffer[file->iob_BufferPosition];
const unsigned char * lf;
assert( file->iob_BufferReadBytes >= file->iob_BufferPosition );
/* Try to find a line feed character which could conclude
* the read operation if the remaining buffer data, including
* the line feed character, fit into the string buffer.
*/
lf = (unsigned char *)memchr(buffer, '\n', num_bytes_in_buffer);
if (lf != NULL)
{
size_t num_characters_in_line = lf + 1 - buffer;
assert( num_characters_in_line <= num_bytes_in_buffer );
/* Give the user a chance to abort what could otherwise
* become an uninterrupted series of copying operations.
*/
if (__check_abort_enabled)
__check_abort();
/* Copy the remainder of the read buffer into the
* string buffer, omitting the terminating line
* feed character. This is the difference between
* gets() and fgets(): fgets() will keep the
* terminating line feed character, but gets()
* will drop it.
*/
assert( num_characters_in_line > 0 );
memmove(s, buffer, num_characters_in_line - 1);
s += num_characters_in_line - 1;
assert( file->iob_BufferPosition + num_characters_in_line <= file->iob_BufferSize );
file->iob_BufferPosition += num_characters_in_line;
/* And that concludes the line read operation. */
break;
}
assert( num_bytes_in_buffer > 0 );
memmove(s, buffer, num_bytes_in_buffer);
s += num_bytes_in_buffer;
assert( file->iob_BufferPosition + num_bytes_in_buffer <= file->iob_BufferSize );
file->iob_BufferPosition += num_bytes_in_buffer;
}
c = __getc(stream);
if (c == EOF)
{
if (ferror(stream))
{
/* Just to be on the safe side. */
(*s) = '\0';
@@ -101,14 +164,15 @@ gets(char *s)
}
/* Make sure that we return NULL if we really
didn't read anything at all */
if(s == result)
* didn't read anything at all.
*/
if (s == result)
result = NULL;
break;
}
if(c == '\n')
if (c == '\n')
break;
(*s++) = c;
@@ -120,7 +184,7 @@ gets(char *s)
out:
funlockfile(stdin);
funlockfile(stream);
RETURN(result);
return(result);

581
library/stdio_long_path.c Normal file
View 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
View 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 */

View File

@@ -162,6 +162,11 @@ extern int __fputc(int c,FILE *stream,int buffer_mode);
/****************************************************************************/
/* stdio_fputs.c */
extern int __fputs(const char *s, int line_feed, FILE *stream);
/****************************************************************************/
/* stdio_sscanf_hook_entry.c */
extern int __sscanf_hook_entry(struct iob *string,struct file_action_message *fam);

View File

@@ -1,10 +1,8 @@
/*
* $Id: stdio_puts.c,v 1.8 2006-01-08 12:04:25 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,10 +44,7 @@
int
puts(const char *s)
{
struct iob * file = (struct iob *)stdout;
int result = EOF;
int buffer_mode;
int c;
ENTER();
@@ -57,11 +52,6 @@ puts(const char *s)
assert( s != NULL );
if(__check_abort_enabled)
__check_abort();
flockfile(stdout);
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(s == NULL)
@@ -72,45 +62,13 @@ puts(const char *s)
}
#endif /* CHECK_FOR_NULL_POINTERS */
assert( __is_valid_iob(file) );
assert( FLAG_IS_SET(file->iob_Flags,IOBF_IN_USE) );
assert( file->iob_BufferSize > 0 );
buffer_mode = (file->iob_Flags & IOBF_BUFFER_MODE);
if(buffer_mode == IOBF_BUFFER_MODE_NONE)
buffer_mode = IOBF_BUFFER_MODE_LINE;
if(__fputc_check(stdout) < 0)
goto out;
while((c = (*s++)) != '\0')
{
if(__putc(c,stdout,buffer_mode) == EOF)
goto out;
}
if(__putc('\n',stdout,buffer_mode) == EOF)
if (__fputs(s, '\n', stdout) == EOF)
goto out;
result = OK;
out:
/* Note: if buffering is disabled for this stream, then we still
may have buffered data around, queued to be printed right now.
This is intended to improve performance as it takes more effort
to write a single character to a file than to write a bunch. */
if(result == 0 && (file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
{
if(__iob_write_buffer_is_valid(file) && __flush_iob_write_buffer(file) < 0)
{
SHOWMSG("couldn't flush the write buffer");
result = EOF;
}
}
funlockfile(stdout);
RETURN(result);
return(result);
}

View File

@@ -327,7 +327,7 @@ remove_locked_region_node(struct FileLockSemaphore * fls,struct fd * fd,LONG sta
/* Check if there are any locked regions left.
* If not, mark the entire file as unlocked.
*/
if(IsListEmpty((struct List *)&which_lock->fln_LockedRegionList))
if(IsMinListEmpty(&which_lock->fln_LockedRegionList))
{
SHOWMSG("no more regions are locked; removing the file lock node");
@@ -705,7 +705,7 @@ cleanup_locked_records(struct fd * fd)
}
}
if(IsListEmpty((struct List *)&which_lock->fln_LockedRegionList))
if(IsMinListEmpty(&which_lock->fln_LockedRegionList))
{
SHOWMSG("no more regions are locked; removing the file lock node");

View File

@@ -1,10 +1,8 @@
/*
* $Id: stdio_setvbuf.c,v 1.11 2008-09-04 12:07:58 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -114,20 +112,28 @@ setvbuf(FILE *stream,char *buf,int bufmode,size_t size)
goto out;
}
/* A buffer size of 0 bytes defaults to unbuffered operation. */
/* A buffer size of 0 bytes will cause the default buffer size to be used. */
if(size == 0)
bufmode = IOBF_BUFFER_MODE_NONE;
/* 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. */
new_buffer = malloc(size + (__cache_line_size-1));
if(new_buffer == NULL)
size = BUFSIZ;
buf = NULL;
}
if(bufmode != IOBF_BUFFER_MODE_NONE)
{
/* If a certain buffer size is requested but no buffer was provided,
allocate some memory for it. */
if(size > 0 && buf == NULL)
{
__set_errno(ENOBUFS);
goto out;
assert( size <= ((size + (__cache_line_size-1)) & ~(__cache_line_size-1)) );
/* Allocate a little more memory than necessary. */
new_buffer = malloc(size + (__cache_line_size-1));
if(new_buffer == NULL)
{
__set_errno(ENOBUFS);
goto out;
}
}
}

View File

@@ -46,15 +46,8 @@
/****************************************************************************/
void
abort(void)
__abort(void)
{
/* Try to call the signal handler that might be in charge of
handling cleanup operations, etc. */
raise(SIGABRT);
/* If the signal handler returns it means that we still have
to terminate the program. */
__check_abort_enabled = FALSE;
__print_termination_message(NULL);
@@ -63,3 +56,17 @@ abort(void)
does not trigger the exit trap. */
_exit(EXIT_FAILURE);
}
/****************************************************************************/
void
abort(void)
{
/* Try to call the signal handler that might be in charge of
handling cleanup operations, etc. */
raise(SIGABRT);
/* If the signal handler returns it means that we still have
to terminate the program. */
__abort();
}

View File

@@ -69,11 +69,36 @@ struct MemoryContextNode
/****************************************************************************/
/* The default behaviour for alloca() failing is to
* terminate the program rather than let it stumble
* into a NULL-pointer reference.
*/
static void
default_alloca_trap(void)
{
abort();
}
/****************************************************************************/
CLIB_CONSTRUCTOR(alloca_init)
{
ENTER();
__alloca_trap = default_alloca_trap;
NewList((struct List *)&alloca_memory_list);
LEAVE();
}
/****************************************************************************/
CLIB_DESTRUCTOR(alloca_exit)
{
ENTER();
/* Clean this up, too, just to be safe. */
/* This list should remain empty. */
NewList((struct List *)&alloca_memory_list);
LEAVE();
@@ -83,18 +108,18 @@ CLIB_DESTRUCTOR(alloca_exit)
/* Cleans up after all alloca() allocations that have been made so far. */
static void
alloca_cleanup(const char * file,int line)
alloca_cleanup(const char * file, int line)
{
void * stack_pointer = __get_sp();
__memory_lock();
/* Initialize this if it hasn't been taken care of yet. */
if(alloca_memory_list.mlh_Head == NULL)
if (alloca_memory_list.mlh_Head == NULL)
NewList((struct List *)&alloca_memory_list);
/* Is this worth cleaning up? */
if(NOT IsListEmpty((struct List *)&alloca_memory_list))
if (NOT IsListEmpty((struct List *)&alloca_memory_list))
{
struct MemoryContextNode * mcn_prev;
struct MemoryContextNode * mcn;
@@ -106,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
to the allocations made in the context of a stack frame near to
where were currently are. */
for(mcn = (struct MemoryContextNode *)alloca_memory_list.mlh_TailPred ;
mcn->mcn_MinNode.mln_Pred != NULL && mcn->mcn_StackPointer < stack_pointer ;
mcn = mcn_prev)
for (mcn = (struct MemoryContextNode *)alloca_memory_list.mlh_TailPred ;
mcn->mcn_MinNode.mln_Pred != NULL && mcn->mcn_StackPointer < stack_pointer ;
mcn = mcn_prev)
{
mcn_prev = (struct MemoryContextNode *)mcn->mcn_MinNode.mln_Pred;
Remove((struct Node *)mcn);
__free_memory(mcn->mcn_Memory,TRUE,file,line);
__free_memory(mcn,FALSE,file,line);
/* Note: force the memory to be freed because it
has gone out of scope. */
__free_memory(mcn->mcn_Memory, TRUE, file, line);
__free_memory(mcn, FALSE, file, line);
}
/* Drop the cleanup callback if there's nothing to be cleaned
up any more. */
if(IsListEmpty((struct List *)&alloca_memory_list))
if (IsListEmpty((struct List *)&alloca_memory_list))
__alloca_cleanup = NULL;
}
@@ -130,7 +158,7 @@ alloca_cleanup(const char * file,int line)
/****************************************************************************/
__static void *
__alloca(size_t size,const char * file,int line)
__alloca(size_t size, const char * file, int line)
{
void * stack_pointer = __get_sp();
struct MemoryContextNode * mcn;
@@ -138,27 +166,23 @@ __alloca(size_t size,const char * file,int line)
__memory_lock();
/* Initialize this if it hasn't been taken care of yet. */
if(alloca_memory_list.mlh_Head == NULL)
NewList((struct List *)&alloca_memory_list);
__alloca_cleanup = alloca_cleanup;
(*__alloca_cleanup)(file,line);
(*__alloca_cleanup)(file, line);
mcn = __allocate_memory(sizeof(*mcn),FALSE,file,line);
if(mcn == NULL)
mcn = __allocate_memory(sizeof(*mcn), FALSE, file, line);
if (mcn == NULL)
{
SHOWMSG("not enough memory");
goto out;
}
/* Allocate memory which cannot be run through realloc() or free(). */
mcn->mcn_Memory = __allocate_memory(size,TRUE,file,line);
if(mcn->mcn_Memory == NULL)
mcn->mcn_Memory = __allocate_memory(size, TRUE, file, line);
if (mcn->mcn_Memory == NULL)
{
SHOWMSG("not enough memory");
__free(mcn,file,line);
__free(mcn, file, line);
goto out;
}
@@ -166,7 +190,7 @@ __alloca(size_t size,const char * file,int line)
assert( alloca_memory_list.mlh_Head != NULL );
AddTail((struct List *)&alloca_memory_list,(struct Node *)mcn);
AddTail((struct List *)&alloca_memory_list, (struct Node *)mcn);
result = mcn->mcn_Memory;
@@ -176,10 +200,14 @@ __alloca(size_t size,const char * file,int line)
/* If we are about to return NULL and a trap function is
provided, call it rather than returning NULL. */
if(result == NULL && __alloca_trap != NULL)
(*__alloca_trap)();
if (result == NULL && __alloca_trap != NULL)
{
__alloca_cleanup = NULL;
return(result);
(*__alloca_trap)();
}
return result;
}
/****************************************************************************/
@@ -191,5 +219,5 @@ alloca(size_t size)
result = __alloca(size,NULL,0);
return(result);
return result;
}

37
library/stdlib_calloc.c Normal file → Executable file
View File

@@ -48,36 +48,51 @@
/****************************************************************************/
__static void *
__calloc(size_t num_elements,size_t element_size,const char * file,int line)
__calloc(size_t num_elements, size_t element_size, const char * file UNUSED, int line UNUSED)
{
void * result = NULL;
size_t total_size;
#ifdef __MEM_DEBUG
{
/*__check_memory_allocations(file,line);*/
__check_memory_allocations(file, line);
}
#endif /* __MEM_DEBUG */
total_size = num_elements * element_size;
/* Check for overflow. */
total_size = element_size * num_elements;
if (num_elements > 0 && element_size > 0 && element_size != (total_size / num_elements))
{
D(("calloc(num_elements=%ld, element_size=%ld) overflow"));
goto out;
}
result = __malloc(total_size,file,line);
if(result != NULL)
memset(result,0,total_size);
else
/* Note: malloc(0) may allocate memory and will also
* initialize its contents to zero.
*/
result = __malloc(total_size, file, line);
if (result == NULL)
{
SHOWMSG("memory allocation failure");
goto out;
}
return(result);
if (total_size > 0)
memset(result, 0, total_size);
out:
return result;
}
/****************************************************************************/
void *
calloc(size_t num_elements,size_t element_size)
calloc(size_t num_elements, size_t element_size)
{
void * result;
result = __calloc(num_elements,element_size,NULL,0);
result = __calloc(num_elements, element_size, NULL, 0);
return(result);
return result;
}

View File

@@ -0,0 +1,75 @@
/*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of Olaf Barthel nor the names of contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _STDLIB_HEADERS_H
#include "stdlib_headers.h"
#endif /* _STDLIB_HEADERS_H */
/****************************************************************************/
#ifndef _STDLIB_MEMORY_H
#include "stdlib_memory.h"
#endif /* _STDLIB_MEMORY_H */
/****************************************************************************/
/* Look at all currently unused slabs, decrementing the decay
* counter which prevents them from being reused.
*/
void
__decay_unused_slabs(void)
{
if(__slab_data.sd_InUse)
{
struct MinNode * free_node;
struct MinNode * free_node_next;
struct SlabNode * sn;
__memory_lock();
for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ;
free_node->mln_Succ != NULL ;
free_node = free_node_next)
{
free_node_next = (struct MinNode *)free_node->mln_Succ;
/* free_node points to SlabNode.sn_EmptyLink, which
* directly follows the SlabNode.sn_MinNode.
*/
sn = (struct SlabNode *)&free_node[-1];
if(sn->sn_EmptyDecay > 0)
sn->sn_EmptyDecay--;
}
__memory_unlock();
}
}

View File

@@ -59,18 +59,18 @@ get_hex_char(int n)
{
char result;
if(0 <= n && n <= 9)
if (0 <= n && n <= 9)
result = n + '0';
else
result = n + 'A' - 10;
return(result);
return result;
}
STATIC VOID
int_to_hex(unsigned long v,char * buffer,int min_digits)
int_to_hex(unsigned long v, char * buffer, int min_digits)
{
int i,j,c;
int i, j, c;
i = 0;
@@ -81,12 +81,12 @@ int_to_hex(unsigned long v,char * buffer,int min_digits)
buffer[i++] = get_hex_char(c);
}
while(v > 0);
while (v > 0);
while(i < min_digits)
while (i < min_digits)
buffer[i++] = '0';
for(j = 0 ; j < i / 2 ; j++)
for (j = 0 ; j < i / 2 ; j++)
{
c = buffer[i - 1 - j];
buffer[i - 1 - j] = buffer[j];
@@ -97,47 +97,47 @@ int_to_hex(unsigned long v,char * buffer,int min_digits)
}
STATIC VOID
dump_memory(unsigned char * m,int size,int ignore)
dump_memory(const unsigned char * m, int size, int ignore)
{
const int mod = 20;
int position,i,c;
int position, i, c;
char buffer[120];
char hex[10];
buffer[0] = '\0';
for(i = 0 ; i < size ; i++)
for (i = 0 ; i < size ; i++)
{
position = i % mod;
if(position == 0)
if (position == 0)
{
if(buffer[0] != '\0')
if (buffer[0] != '\0')
{
int len = sizeof(buffer)-1;
while(len > 0 && buffer[len-1] == ' ')
while (len > 0 && buffer[len-1] == ' ')
len--;
buffer[len] = '\0';
kprintf("[%s] %s\n",__program_name,buffer);
kprintf("[%s] %s\n", __program_name, buffer);
}
memset(buffer,' ',sizeof(buffer)-1);
memset(buffer, ' ', sizeof(buffer)-1);
int_to_hex((unsigned long)&m[i],hex,8);
int_to_hex((unsigned long)&m[i], hex, 8);
memmove(buffer,hex,8);
memmove(buffer, hex, 8);
hex[9] = ':';
}
if(m[i] != ignore)
if (m[i] != ignore)
{
buffer[10 + 2 * position + 0] = get_hex_char(m[i] >> 4);
buffer[10 + 2 * position + 1] = get_hex_char(m[i] & 15);
c = m[i];
if(c < ' ' || (c >= 127 && c <= 160))
if (c < ' ' || (127 <= c && c < 160))
c = '.';
buffer[10 + 2 * mod + 1 + position] = c;
@@ -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;
while(len > 0 && buffer[len-1] == ' ')
while (len > 0 && buffer[len-1] == ' ')
len--;
buffer[len] = '\0';
kprintf("[%s] %s\n",__program_name,buffer);
kprintf("[%s] %s\n", __program_name, buffer);
}
}
/****************************************************************************/
STATIC VOID
check_memory_node(struct MemoryNode * mn,const char * file,int line)
check_memory_node(struct MemoryNode * mn, const char * file, int line)
{
ULONG size = GET_MN_SIZE(mn);
unsigned char * head = (unsigned char *)(mn + 1);
unsigned char * body = head + MALLOC_HEAD_SIZE;
unsigned char * tail = body + size;
ULONG size = mn->mn_OriginalSize;
const unsigned char * head = (unsigned char *)&mn[1];
const unsigned char * body = &head[MALLOC_HEAD_SIZE];
const unsigned char * tail = &body[size];
int max_head_damage = 0;
int max_tail_damage = 0;
int max_body_damage = 0;
int i;
for(i = 1 ; i <= MALLOC_HEAD_SIZE ; i++)
for (i = 1 ; i <= MALLOC_HEAD_SIZE ; i++)
{
if(head[MALLOC_HEAD_SIZE - i] != MALLOC_HEAD_FILL)
if (head[MALLOC_HEAD_SIZE - i] != MALLOC_HEAD_FILL)
max_head_damage = i;
}
if(max_head_damage > 0)
if (max_head_damage > 0)
{
kprintf("[%s] ",__program_name);
kprintf("[%s] ", __program_name);
if(file != NULL)
kprintf("%s:%ld:",file,line);
if (file != NULL)
kprintf("%s:%ld:", file, line);
kprintf("At least %ld bytes were damaged in front of allocation 0x%08lx..0x%08lx, size = %ld",
max_head_damage,
body,body + size - 1,size);
body, body + size - 1, size);
if(mn->mn_File != NULL)
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
if (mn->mn_File != NULL)
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
kprintf("\n");
dump_memory(head,MALLOC_HEAD_SIZE,MALLOC_HEAD_FILL);
dump_memory(head, MALLOC_HEAD_SIZE, MALLOC_HEAD_FILL);
}
for(i = 0 ; i < MALLOC_TAIL_SIZE ; i++)
for (i = 0 ; i < MALLOC_TAIL_SIZE ; i++)
{
if(tail[i] != MALLOC_TAIL_FILL)
if (tail[i] != MALLOC_TAIL_FILL)
max_tail_damage = i+1;
}
if(max_tail_damage > 0)
if (max_tail_damage > 0)
{
kprintf("[%s] ",__program_name);
kprintf("[%s] ", __program_name);
if(file != NULL)
kprintf("%s:%ld:",file,line);
if (file != NULL)
kprintf("%s:%ld:", file, line);
kprintf("At least %ld bytes were damaged behind allocation 0x%08lx..0x%08lx, size = %ld (with damage = %ld)",
max_tail_damage,
body,body + size - 1,
size,size+max_tail_damage);
body, body + size - 1,
size, size + max_tail_damage);
if(mn->mn_File != NULL)
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
if (mn->mn_File != NULL)
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
kprintf("\n");
dump_memory(tail,MALLOC_TAIL_SIZE,MALLOC_TAIL_FILL);
dump_memory(tail, MALLOC_TAIL_SIZE, MALLOC_TAIL_FILL);
}
if(mn->mn_AlreadyFree)
if (mn->mn_AlreadyFree)
{
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;
}
if(max_body_damage > 0)
if (max_body_damage > 0)
{
kprintf("[%s] ",__program_name);
kprintf("[%s] ", __program_name);
if(file != NULL)
kprintf("%s:%ld:",file,line);
if (file != NULL)
kprintf("%s:%ld:", file, line);
kprintf("At least %ld bytes were damaged in freed allocation 0x%08lx..0x%08lx, size = %ld",
max_body_damage,
body,body + size - 1,size);
body, body + size - 1, size);
if(mn->mn_File != NULL)
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
if (mn->mn_File != NULL)
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
kprintf("\n");
dump_memory(body,size,MALLOC_FREE_FILL);
dump_memory(body, size, MALLOC_FREE_FILL);
}
}
}
@@ -261,17 +261,17 @@ check_memory_node(struct MemoryNode * mn,const char * file,int line)
/****************************************************************************/
void
__check_memory_allocations(const char * file,int line)
__check_memory_allocations(const char * file, int line)
{
struct MemoryNode * mn;
__memory_lock();
for(mn = (struct MemoryNode *)__memory_list.mlh_Head ;
mn->mn_MinNode.mln_Succ != NULL ;
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
for (mn = (struct MemoryNode *)__memory_list.mlh_Head ;
mn->mn_MinNode.mln_Succ != NULL ;
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
{
check_memory_node(mn,file,line);
check_memory_node(mn, file, line);
}
__memory_unlock();
@@ -290,7 +290,7 @@ __find_memory_node(void * address)
#if defined(__USE_MEM_TREES)
{
result = __red_black_tree_find(&__memory_tree,address);
result = __red_black_tree_find(&__memory_tree, address);
}
#else
{
@@ -298,11 +298,11 @@ __find_memory_node(void * address)
result = NULL;
for(mn = (struct MemoryNode *)__memory_list.mlh_Head ;
mn->mn_MinNode.mln_Succ != NULL ;
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
for (mn = (struct MemoryNode *)__memory_list.mlh_Head ;
mn->mn_MinNode.mln_Succ != NULL ;
mn = (struct MemoryNode *)mn->mn_MinNode.mln_Succ)
{
if(address == mn->mn_Allocation)
if (address == mn->mn_Allocation)
{
result = mn;
break;
@@ -331,7 +331,7 @@ __find_memory_node(void * address)
result = &((struct MemoryNode *)address)[-1];
return(result);
return result;
}
/****************************************************************************/
@@ -349,25 +349,19 @@ remove_and_free_memory_node(struct MemoryNode * mn)
__memory_lock();
allocation_size = mn->mn_AllocationSize;
#if defined(__MEM_DEBUG)
{
Remove((struct Node *)mn);
#if defined(__USE_MEM_TREES)
{
__red_black_tree_remove(&__memory_tree,mn);
__red_black_tree_remove(&__memory_tree, mn);
}
#endif /* __USE_MEM_TREES */
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + GET_MN_SIZE(mn) + MALLOC_TAIL_SIZE;
assert( allocation_size == mn->mn_AllocationSize );
memset(mn,MALLOC_FREE_FILL,allocation_size);
}
#else
{
allocation_size = sizeof(*mn) + GET_MN_SIZE(mn);
memset(mn, MALLOC_FREE_FILL, allocation_size);
}
#endif /* __MEM_DEBUG */
@@ -376,54 +370,63 @@ remove_and_free_memory_node(struct MemoryNode * mn)
/* Are we using the slab allocator? */
if (__slab_data.sd_InUse)
{
__slab_free(mn,allocation_size);
/* No need to remove the memory node because it was never
* added or has already been removed if the memory debugging
* option is in effect.
*/
__slab_free(mn, allocation_size);
}
/* Are we using the memory pool? */
else if (__memory_pool != NULL)
{
FreePooled(__memory_pool,mn,allocation_size);
/* No need to remove the memory node because it was never
* added or has already been removed if the memory debugging
* option is in effect.
*/
PROFILE_OFF();
FreePooled(__memory_pool, mn, allocation_size);
PROFILE_ON();
}
/* So we have to do this the hard way... */
else
{
#if defined(__MEM_DEBUG)
#if NOT defined(__MEM_DEBUG)
{
FreeMem(mn,allocation_size);
}
#else
{
struct MinNode * mln = (struct MinNode *)mn;
mln--;
Remove((struct Node *)mln);
FreeMem(mln,sizeof(*mln) + allocation_size);
Remove((struct Node *)mn);
}
#endif /* __MEM_DEBUG */
PROFILE_OFF();
FreeMem(mn, allocation_size);
PROFILE_ON();
}
}
#else
{
if (__memory_pool != NULL)
{
FreePooled(__memory_pool,mn,allocation_size);
/* No need to remove the memory node because it was never
* added or has already been removed if the memory debugging
* option is in effect.
*/
PROFILE_OFF();
FreePooled(__memory_pool, mn, allocation_size);
PROFILE_ON();
}
else
{
#if defined(__MEM_DEBUG)
#if NOT defined(__MEM_DEBUG)
{
FreeMem(mn,allocation_size);
}
#else
{
struct MinNode * mln = (struct MinNode *)mn;
mln--;
Remove((struct Node *)mln);
FreeMem(mln,sizeof(*mln) + allocation_size);
Remove((struct Node *)mn);
}
#endif /* __MEM_DEBUG */
/* No need to remove the memory node because the memory
* debugging option is in effect.
*/
PROFILE_OFF();
FreeMem(mn, allocation_size);
PROFILE_ON();
}
}
#endif /* __USE_SLAB_ALLOCATOR */
@@ -437,37 +440,35 @@ remove_and_free_memory_node(struct MemoryNode * mn)
/****************************************************************************/
void
__free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED line)
__free_memory_node(struct MemoryNode * mn, const char * UNUSED file, int UNUSED line)
{
assert(mn != NULL);
#ifdef __MEM_DEBUG
{
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
{
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)
kprintf("allocated at %s:%ld, ",mn->mn_File,mn->mn_Line);
if (mn->mn_File != NULL)
kprintf("allocated at %s:%ld, ", mn->mn_File, mn->mn_Line);
kprintf("freed at %s:%ld]\n",file,line);
kprintf("freed at %s:%ld]\n", file, line);
}
#endif /* __MEM_DEBUG_LOG */
if(__never_free)
if (__never_free)
{
mn->mn_AlreadyFree = TRUE;
mn->mn_FreeFile = (char *)file;
mn->mn_FreeFile = (char *)file;
mn->mn_FreeLine = line;
memset(mn->mn_Allocation,MALLOC_FREE_FILL,size);
memset(&mn[1], MALLOC_FREE_FILL, MALLOC_HEAD_SIZE + mn->mn_OriginalSize + MALLOC_TAIL_SIZE);
}
else
{
@@ -478,19 +479,19 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
{
#ifdef __MEM_DEBUG_LOG
{
kprintf("[%s] - %10ld 0x%08lx [",__program_name,size,mn->mn_Allocation);
kprintf("[%s] - %10ld 0x%08lx [", __program_name, mn->mn_AllocationSize, mn);
kprintf("FAILED]\n");
}
#endif /* __MEM_DEBUG_LOG */
kprintf("[%s] %s:%ld:Allocation at address 0x%08lx, size %ld",
__program_name,file,line,mn->mn_Allocation,size);
__program_name, file, line, mn->mn_Allocation, mn->mn_OriginalSize);
if(mn->mn_File != NULL)
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
if (mn->mn_File != NULL)
kprintf(", allocated at %s:%ld", mn->mn_File, mn->mn_Line);
kprintf(", has already been freed at %s:%ld.\n",mn->mn_FreeFile,mn->mn_FreeLine);
kprintf(", has already been freed at %s:%ld.\n", mn->mn_FreeFile, mn->mn_FreeLine);
}
}
#else
@@ -503,7 +504,7 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
/****************************************************************************/
VOID
__free_memory(void * ptr,BOOL force,const char * file,int line)
__free_memory(void * ptr, BOOL force, const char * file, int line)
{
struct MemoryNode * mn;
@@ -514,7 +515,7 @@ __free_memory(void * ptr,BOOL force,const char * file,int line)
#ifdef __MEM_DEBUG
{
/*if((rand() % 16) == 0)
/*if ((rand() % 16) == 0)
__check_memory_allocations(file,line);*/
}
#endif /* __MEM_DEBUG */
@@ -523,34 +524,37 @@ __free_memory(void * ptr,BOOL force,const char * file,int line)
#ifdef __MEM_DEBUG
{
if(mn != NULL)
if (mn != NULL)
{
if(force || FLAG_IS_CLEAR(mn->mn_Size, MN_SIZE_NEVERFREE))
__free_memory_node(mn,file,line);
if (force || FLAG_IS_CLEAR(mn->mn_Flags, MNF_NEVER_FREE))
__free_memory_node(mn, file, line);
}
else
{
#ifdef __MEM_DEBUG_LOG
{
kprintf("[%s] - %10ld 0x%08lx [",__program_name,0,ptr);
kprintf("[%s] - %10ld 0x%08lx [", __program_name, 0, ptr);
kprintf("FAILED]\n");
}
#endif /* __MEM_DEBUG_LOG */
kprintf("[%s] %s:%ld:Address for free(0x%08lx) not known.\n",__program_name,file,line,ptr);
kprintf("[%s] %s:%ld:Address for free(0x%08lx) not known.\n", __program_name, file, line, ptr);
D(("memory allocation at 0x%08lx could not be freed",ptr));
D(("memory allocation at 0x%08lx could not be freed", ptr));
}
}
#else
{
assert( mn != NULL );
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)))
__free_memory_node(mn,file,line);
if (mn != NULL && (force || FLAG_IS_CLEAR(mn->mn_Flags, MNF_NEVER_FREE)))
__free_memory_node(mn, file, line);
}
#endif /* __MEM_DEBUG */
}
@@ -563,13 +567,13 @@ __free(void * ptr,const char * file,int line)
__memory_lock();
/* Try to get rid of now unused memory. */
if(__alloca_cleanup != NULL)
(*__alloca_cleanup)(file,line);
if (__alloca_cleanup != NULL)
(*__alloca_cleanup)(file, line);
__memory_unlock();
if(ptr != NULL)
__free_memory(ptr,FALSE,file,line);
if (ptr != NULL)
__free_memory(ptr, FALSE, file, line);
}
/****************************************************************************/
@@ -577,5 +581,5 @@ __free(void * ptr,const char * file,int line)
void
free(void * ptr)
{
__free(ptr,NULL,0);
__free(ptr, NULL, 0);
}

View File

@@ -72,7 +72,9 @@ __free_unused_slabs(void)
/* Unlink from list of slabs of the same size. */
Remove((struct Node *)sn);
PROFILE_OFF();
FreeVec(sn);
PROFILE_ON();
}
__memory_unlock();

View File

@@ -41,9 +41,13 @@
/****************************************************************************/
#include <setjmp.h>
/****************************************************************************/
struct context
{
int status;
jmp_buf abort_buf;
void * user_data;
__slab_status_callback callback;
char * buffer;
@@ -54,23 +58,21 @@ struct context
static void print(struct context * ct, const char * format, ...)
{
if(ct->status == 0)
{
va_list args;
int len;
va_list args;
int len;
va_start(args,format);
len = vsnprintf(ct->buffer, ct->buffer_size, format, args);
va_end(args);
va_start(args,format);
len = vsnprintf(ct->buffer, ct->buffer_size, format, args);
va_end(args);
/* This shouldn't happen: the buffer ought to be large enough
* to hold every single line.
*/
if(len >= (int)ct->buffer_size)
len = strlen(ct->buffer);
/* This shouldn't happen: the buffer ought to be large enough
* to hold every single line.
*/
if(len >= (int)ct->buffer_size)
len = strlen(ct->buffer);
ct->status = (*ct->callback)(ct->user_data, ct->buffer, len);
}
if((*ct->callback)(ct->user_data, ct->buffer, len) != 0)
longjmp(ct->abort_buf,-1);
}
/****************************************************************************/
@@ -83,11 +85,11 @@ __get_slab_stats(void * user_data, __slab_status_callback callback)
static int times_checked = 1;
const struct SlabNode * sn;
size_t num_empty_slabs = 0;
size_t num_full_slabs = 0;
size_t num_slabs = 0;
size_t slab_allocation_size = 0;
size_t total_slab_allocation_size = 0;
volatile size_t num_empty_slabs = 0;
volatile size_t num_full_slabs = 0;
volatile size_t num_slabs = 0;
volatile size_t slab_allocation_size = 0;
volatile size_t total_slab_allocation_size = 0;
struct context ct;
char line[1024];
char time_buffer[40];
@@ -104,96 +106,100 @@ __get_slab_stats(void * user_data, __slab_status_callback callback)
__memory_lock();
now = time(NULL);
localtime_r(&now, &when);
strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", &when);
print(&ct,"{\n");
print(&ct,"\t\"when\": \"%s\",\n", time_buffer);
print(&ct,"\t\"times_checked\": %d,\n", times_checked++);
print(&ct,"\t\"slab_size\": %zu,\n", __slab_data.sd_StandardSlabSize);
print(&ct,"\t\"num_single_allocations\": %zu,\n", __slab_data.sd_NumSingleAllocations);
print(&ct,"\t\"total_single_allocation_size\": %zu,\n", __slab_data.sd_TotalSingleAllocationSize);
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
if(setjmp(ct.abort_buf) == 0)
{
const struct SlabSingleAllocation * ssa;
now = time(NULL);
localtime_r(&now, &when);
print(&ct,"\t\"single_allocations\": [\n");
strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", &when);
for(ssa = (struct SlabSingleAllocation *)__slab_data.sd_SingleAllocations.mlh_Head ;
ssa->ssa_MinNode.mln_Succ != NULL && ct.status == 0 ;
ssa = (struct SlabSingleAllocation *)ssa->ssa_MinNode.mln_Succ)
print(&ct,"{\n");
print(&ct,"\t\"when\": \"%s\",\n", time_buffer);
print(&ct,"\t\"times_checked\": %d,\n", times_checked++);
print(&ct,"\t\"slab_size\": %zu,\n", __slab_data.sd_StandardSlabSize);
print(&ct,"\t\"num_single_allocations\": %zu,\n", __slab_data.sd_NumSingleAllocations);
print(&ct,"\t\"total_single_allocation_size\": %zu,\n", __slab_data.sd_TotalSingleAllocationSize);
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
{
print(&ct,"\t\t{ \"size\": %lu, \"total_size\": %lu }%s\n",
ssa->ssa_Size - sizeof(*ssa), ssa->ssa_Size,
ssa->ssa_MinNode.mln_Succ->mln_Succ != NULL ? "," : "");
const struct SlabSingleAllocation * ssa;
print(&ct,"\t\"single_allocations\": [\n");
for(ssa = (struct SlabSingleAllocation *)__slab_data.sd_SingleAllocations.mlh_Head ;
ssa->ssa_MinNode.mln_Succ != NULL ;
ssa = (struct SlabSingleAllocation *)ssa->ssa_MinNode.mln_Succ)
{
print(&ct,"\t\t{ \"size\": %lu, \"total_size\": %lu }%s\n",
ssa->ssa_Size - sizeof(*ssa), ssa->ssa_Size,
ssa->ssa_MinNode.mln_Succ->mln_Succ != NULL ? "," : "");
}
print(&ct,"\t],\n");
}
else
{
print(&ct,"\t\"single_allocations\": [],\n");
}
print(&ct,"\t],\n");
}
else
{
print(&ct,"\t\"single_allocations\": [],\n");
}
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
{
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
sn->sn_MinNode.mln_Succ != NULL ;
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
{
if (sn->sn_UseCount == 0)
num_empty_slabs++;
else if (sn->sn_UseCount == sn->sn_Count)
num_full_slabs++;
num_slabs++;
slab_allocation_size += sn->sn_ChunkSize * sn->sn_UseCount;
total_slab_allocation_size += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
}
}
print(&ct,"\t\"num_slabs\": %zu,\n", num_slabs);
print(&ct,"\t\"num_empty_slabs\": %zu,\n", num_empty_slabs);
print(&ct,"\t\"num_full_slabs\": %zu,\n", num_full_slabs);
print(&ct,"\t\"slab_allocation_size\": %zu,\n", slab_allocation_size);
print(&ct,"\t\"total_slab_allocation_size\": %zu,\n", total_slab_allocation_size);
if(num_slabs > 0)
{
const char * eol = "";
print(&ct,"\t\"slabs\": [\n");
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) && ct.status == 0 ; i++)
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
{
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
sn->sn_MinNode.mln_Succ != NULL && ct.status == 0 ;
sn->sn_MinNode.mln_Succ != NULL ;
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
{
print(&ct,"%s\t\t{ \"size\": %lu, \"chunks\": %lu, \"chunks_in_use\": %lu, \"times_reused\": %lu }",
eol,
sn->sn_ChunkSize,
sn->sn_Count,
sn->sn_UseCount,
sn->sn_NumReused);
if (sn->sn_UseCount == 0)
num_empty_slabs++;
else if (sn->sn_UseCount == sn->sn_Count)
num_full_slabs++;
eol = ",\n";
num_slabs++;
slab_allocation_size += sn->sn_ChunkSize * sn->sn_UseCount;
total_slab_allocation_size += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
}
}
print(&ct,"\n\t]\n");
}
else
{
print(&ct,"\t\"slabs\": []\n");
}
print(&ct,"\t\"num_slabs\": %zu,\n", num_slabs);
print(&ct,"\t\"num_empty_slabs\": %zu,\n", num_empty_slabs);
print(&ct,"\t\"num_full_slabs\": %zu,\n", num_full_slabs);
print(&ct,"\t\"slab_allocation_size\": %zu,\n", slab_allocation_size);
print(&ct,"\t\"total_slab_allocation_size\": %zu,\n", total_slab_allocation_size);
print(&ct,"}\n");
if(num_slabs > 0)
{
const char * eol = "";
print(&ct,"\t\"slabs\": [\n");
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
{
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
sn->sn_MinNode.mln_Succ != NULL ;
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
{
print(&ct,"%s\t\t{ \"size\": %lu, \"chunks\": %lu, \"chunks_in_use\": %lu, \"times_reused\": %lu, \"empty_decay\": %lu }",
eol,
sn->sn_ChunkSize,
sn->sn_Count,
sn->sn_UseCount,
sn->sn_NumReused,
sn->sn_EmptyDecay);
eol = ",\n";
}
}
print(&ct,"\n\t]\n");
}
else
{
print(&ct,"\t\"slabs\": []\n");
}
print(&ct,"}\n");
}
__memory_unlock();
}

26
library/stdlib_get_slab_usage.c Normal file → Executable file
View File

@@ -44,14 +44,14 @@
void
__get_slab_usage(__slab_usage_callback callback)
{
if(__slab_data.sd_InUse)
if (__slab_data.sd_InUse)
{
struct __slab_usage_information sui;
const struct SlabNode * sn;
BOOL stop;
int i;
memset(&sui,0,sizeof(sui));
memset(&sui, 0, sizeof(sui));
__memory_lock();
@@ -59,11 +59,11 @@ __get_slab_usage(__slab_usage_callback callback)
sui.sui_num_single_allocations = __slab_data.sd_NumSingleAllocations;
sui.sui_total_single_allocation_size = __slab_data.sd_TotalSingleAllocationSize;
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
for (i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
{
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
sn->sn_MinNode.mln_Succ != NULL ;
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
for (sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
sn->sn_MinNode.mln_Succ != NULL ;
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
{
if (sn->sn_UseCount == 0)
sui.sui_num_empty_slabs++;
@@ -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 ;
sn->sn_MinNode.mln_Succ != NULL ;
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
for (sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
sn->sn_MinNode.mln_Succ != NULL ;
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
{
sui.sui_chunk_size = sn->sn_ChunkSize;
sui.sui_num_chunks = sn->sn_Count;
@@ -91,7 +93,7 @@ __get_slab_usage(__slab_usage_callback callback)
sui.sui_slab_index++;
if((*callback)(&sui) != 0)
if ((*callback)(&sui) != 0)
{
stop = TRUE;
break;

View File

@@ -189,6 +189,10 @@ extern BOOL NOCOMMON __lib_startup;
/****************************************************************************/
extern int __addition_overflows(ULONG x, ULONG y);
/****************************************************************************/
extern void NOCOMMON (*__alloca_trap)(void);
/****************************************************************************/

View File

@@ -37,6 +37,10 @@
/****************************************************************************/
#if defined(__GNUC__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
/****************************************************************************/
lldiv_t
lldiv(long long n,long long d)
{
@@ -49,3 +53,7 @@ lldiv(long long n,long long d)
return(result);
}
/****************************************************************************/
#endif

View File

@@ -117,9 +117,20 @@ call_main(void)
struct Process * this_process = (struct Process *)FindTask(NULL);
UBYTE * arg_str = GetArgStr();
size_t arg_str_len = strlen(arg_str);
UBYTE * arg_str_copy = AllocVec(arg_str_len+1,MEMF_PRIVATE);
UBYTE * arg_str_copy;
UBYTE current_dir_name[256];
#if defined(__amigaos4__)
{
arg_str_copy = AllocVec(arg_str_len+1,MEMF_PRIVATE);
}
#else
{
arg_str_copy = AllocVec(arg_str_len+1,MEMF_ANY);
}
#endif /* __amigaos4__ */
if(arg_str_copy != NULL && NameFromLock(this_process->pr_CurrentDir,current_dir_name,sizeof(current_dir_name)))
{
strcpy(arg_str_copy,arg_str);

View File

@@ -58,6 +58,7 @@
unsigned long NOCOMMON __maximum_memory_allocated;
unsigned long NOCOMMON __current_memory_allocated;
unsigned long NOCOMMON __maximum_num_memory_chunks_allocated;
unsigned long NOCOMMON __current_num_memory_chunks_allocated;
@@ -74,35 +75,59 @@ struct MinList NOCOMMON __memory_list;
/****************************************************************************/
void *
__allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_name,int UNUSED debug_line_number)
/* Check if the sum of two unsigned 32-bit integers will be larger than what
* an unsigned 32-bit integer can hold and return the overflow. This
* algorithm comes from Henry S. Warren's book "Hacker's delight".
*/
int
__addition_overflows(ULONG x, ULONG y)
{
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;
void * result = NULL;
size_t original_size;
size_t original_size UNUSED;
#if defined(UNIX_PATH_SEMANTICS)
{
original_size = size;
/* The libunix.a flavour accepts zero length memory allocations
and quietly turns them into a pointer sized allocations. */
if(size == 0)
size = sizeof(char *);
/* The libunix.a flavour of malloc() accepts zero-length
memory allocations and quietly turns these into
pointer-sized allocations. */
if (size == 0)
size = sizeof(BYTE *);
}
#endif /* UNIX_PATH_SEMANTICS */
__memory_lock();
/* Zero length allocations are by default rejected. */
if(size == 0)
if (size == 0)
{
__set_errno(EINVAL);
goto out;
}
if(__free_memory_threshold > 0 && AvailMem(MEMF_ANY|MEMF_LARGEST) < __free_memory_threshold)
if (__free_memory_threshold > 0 && AvailMem(MEMF_ANY|MEMF_LARGEST) < __free_memory_threshold)
{
SHOWMSG("not enough free memory available to safely proceed with allocation");
goto out;
@@ -114,34 +139,46 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam
assert( MALLOC_TAIL_SIZE > 0 && (MALLOC_TAIL_SIZE % 4) == 0 );
assert( (sizeof(*mn) % 4) == 0 );
if (__addition_overflows(sizeof(*mn) + MALLOC_HEAD_SIZE + MALLOC_TAIL_SIZE, size))
{
SHOWMSG("integer overflow");
__set_errno(ENOMEM);
goto out;
}
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + size + MALLOC_TAIL_SIZE;
}
#else
{
/* Round up allocation to a multiple of 32 bits. */
if((size & 3) != 0)
size += 4 - (size & 3);
if (__addition_overflows(sizeof(*mn), size))
{
SHOWMSG("integer overflow");
__set_errno(ENOMEM);
goto out;
}
allocation_size = sizeof(*mn) + size;
}
#endif /* __MEM_DEBUG */
/* Integer overflow has occured? */
if(size == 0 || allocation_size < size)
/* Round up allocation to a multiple of 8 bytes. */
if ((allocation_size % MEM_BLOCKSIZE) > 0)
{
__set_errno(ENOMEM);
goto out;
}
size_t padding;
/* We reuse the MemoryNode.mn_Size field to mark
* allocations are not suitable for use with
* free() and realloc(). This limits allocation
* sizes to a little less than 2 GBytes.
*/
if(allocation_size & MN_SIZE_NEVERFREE)
{
__set_errno(ENOMEM);
goto out;
padding = MEM_BLOCKSIZE - (allocation_size % MEM_BLOCKSIZE);
if (__addition_overflows(padding, allocation_size))
{
SHOWMSG("integer overflow");
__set_errno(ENOMEM);
goto out;
}
allocation_size += padding;
}
#if defined(__USE_SLAB_ALLOCATOR)
@@ -150,119 +187,92 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam
if (__slab_data.sd_InUse)
{
mn = __slab_allocate(allocation_size);
SHOWPOINTER(mn);
assert( (((ULONG)mn) & MEM_BLOCKMASK) == 0 );
assert( (((ULONG)&mn[1]) & MEM_BLOCKMASK) == 0 );
}
/* Are we using the memory pool? */
else if (__memory_pool != NULL)
{
mn = AllocPooled(__memory_pool,allocation_size);
PROFILE_OFF();
mn = AllocPooled(__memory_pool, allocation_size);
PROFILE_ON();
}
/* Then we'll have to do it the hard way... */
else
{
#ifdef __MEM_DEBUG
{
mn = AllocMem(allocation_size,MEMF_ANY);
}
#else
{
struct MinNode * mln;
mln = AllocMem(sizeof(*mln) + allocation_size,MEMF_ANY);
if(mln != NULL)
{
AddTail((struct List *)&__memory_list,(struct Node *)mln);
mn = (struct MemoryNode *)&mln[1];
}
else
{
mn = NULL;
}
}
#endif /* __MEM_DEBUG */
PROFILE_OFF();
mn = AllocMem(allocation_size, MEMF_ANY);
PROFILE_ON();
}
}
#else
{
if(__memory_pool != NULL)
if (__memory_pool != NULL)
{
mn = AllocPooled(__memory_pool,allocation_size);
PROFILE_OFF();
mn = AllocPooled(__memory_pool, allocation_size);
PROFILE_ON();
}
else
{
#ifdef __MEM_DEBUG
{
mn = AllocMem(allocation_size,MEMF_ANY);
}
#else
{
struct MinNode * mln;
mln = AllocMem(sizeof(*mln) + allocation_size,MEMF_ANY);
if(mln != NULL)
{
AddTail((struct List *)&__memory_list,(struct Node *)mln);
mn = (struct MemoryNode *)&mln[1];
}
else
{
mn = NULL;
}
}
#endif /* __MEM_DEBUG */
PROFILE_OFF();
mn = AllocMem(allocation_size, MEMF_ANY);
PROFILE_ON();
}
}
#endif /* __USE_SLAB_ALLOCATOR */
if(mn == NULL)
if (mn == NULL)
{
SHOWMSG("not enough memory");
goto out;
}
mn->mn_Size = size;
if(never_free)
SET_FLAG(mn->mn_Size, MN_SIZE_NEVERFREE);
mn->mn_AllocationSize = allocation_size;
mn->mn_Flags = never_free ? MNF_NEVER_FREE : 0;
__current_memory_allocated += allocation_size;
if(__maximum_memory_allocated < __current_memory_allocated)
if (__maximum_memory_allocated < __current_memory_allocated)
__maximum_memory_allocated = __current_memory_allocated;
__current_num_memory_chunks_allocated++;
if(__maximum_num_memory_chunks_allocated < __current_num_memory_chunks_allocated)
if (__maximum_num_memory_chunks_allocated < __current_num_memory_chunks_allocated)
__maximum_num_memory_chunks_allocated = __current_num_memory_chunks_allocated;
#ifdef __MEM_DEBUG
{
char * head = (char *)(mn + 1);
char * body = head + MALLOC_HEAD_SIZE;
char * tail = body + size;
AddTail((struct List *)&__memory_list,(struct Node *)mn);
BYTE * head = (BYTE *)&mn[1];
BYTE * body = &head[MALLOC_HEAD_SIZE];
BYTE * tail = &body[size];
mn->mn_AlreadyFree = FALSE;
mn->mn_Allocation = body;
mn->mn_AllocationSize = allocation_size;
mn->mn_OriginalSize = size;
mn->mn_File = (char *)debug_file_name;
mn->mn_Line = debug_line_number;
mn->mn_FreeFile = NULL;
mn->mn_FreeLine = 0;
memset(head,MALLOC_HEAD_FILL,MALLOC_HEAD_SIZE);
memset(body,MALLOC_NEW_FILL,size);
memset(tail,MALLOC_TAIL_FILL,MALLOC_TAIL_SIZE);
memset(head, MALLOC_HEAD_FILL, MALLOC_HEAD_SIZE);
memset(body, MALLOC_NEW_FILL, size);
memset(tail, MALLOC_TAIL_FILL, MALLOC_TAIL_SIZE);
#ifdef __MEM_DEBUG_LOG
{
kprintf("[%s] + %10ld 0x%08lx [",__program_name,size,body);
kprintf("[%s] + %10ld 0x%08lx [", __program_name, size, body);
kprintf("allocated at %s:%ld]\n",debug_file_name,debug_line_number);
kprintf("allocated at %s:%ld]\n", debug_file_name, debug_line_number);
}
#endif /* __MEM_DEBUG_LOG */
AddTail((struct List *)&__memory_list,(struct Node *)mn);
#ifdef __USE_MEM_TREES
{
__red_black_tree_insert(&__memory_tree,mn);
__red_black_tree_insert(&__memory_tree, mn);
}
#endif /* __USE_MEM_TREES */
@@ -270,6 +280,22 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam
}
#else
{
#if defined(__USE_SLAB_ALLOCATOR)
{
/* If we are using neither the slab allocator nor
* the memory pool, then the allocation will have
* to be freed later, the hard way.
*/
if (__slab_data.sd_InUse == FALSE && __memory_pool == NULL)
AddTail((struct List *)&__memory_list, (struct Node *)mn);
}
#else
{
if (__memory_pool == NULL)
AddTail((struct List *)&__memory_list, (struct Node *)mn);
}
#endif /* __USE_SLAB_ALLOCATOR */
result = &mn[1];
}
#endif /* __MEM_DEBUG */
@@ -277,57 +303,57 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_nam
#if defined(UNIX_PATH_SEMANTICS)
{
/* Set the zero length allocation contents to NULL. */
if(original_size == 0)
*(char **)result = NULL;
if (original_size == 0 && size >= sizeof(BYTE *))
*(BYTE **)result = NULL;
}
#endif /* UNIX_PATH_SEMANTICS */
assert( (((ULONG)result) & 3) == 0 );
assert( (((ULONG)result) & MEM_BLOCKMASK) == 0 );
out:
#ifdef __MEM_DEBUG_LOG
{
if(result == NULL)
if (result == NULL)
{
kprintf("[%s] + %10ld 0x%08lx [",__program_name,size,NULL);
kprintf("[%s] + %10ld 0x%08lx [", __program_name, size, NULL);
kprintf("FAILED: allocated at %s:%ld]\n",debug_file_name,debug_line_number);
kprintf("FAILED: allocated at %s:%ld]\n", debug_file_name, debug_line_number);
}
}
#endif /* __MEM_DEBUG_LOG */
__memory_unlock();
return(result);
return result;
}
/****************************************************************************/
__static void *
__malloc(size_t size,const char * file,int line)
__malloc(size_t size, const char * file, int line)
{
void * result = NULL;
__memory_lock();
/* Try to get rid of now unused memory. */
if(__alloca_cleanup != NULL)
(*__alloca_cleanup)(file,line);
if (__alloca_cleanup != NULL)
(*__alloca_cleanup)(file, line);
__memory_unlock();
#ifdef __MEM_DEBUG
{
/*if((rand() % 16) == 0)
/*if ((rand() % 16) == 0)
__check_memory_allocations(file,line);*/
}
#endif /* __MEM_DEBUG */
/* Allocate memory which can be put through realloc() and free(). */
result = __allocate_memory(size,FALSE,file,line);
result = __allocate_memory(size, FALSE, file, line);
return(result);
return result;
}
/****************************************************************************/
@@ -337,7 +363,7 @@ malloc(size_t size)
{
void * result;
result = __malloc(size,NULL,0);
result = __malloc(size, NULL, 0);
return(result);
}
@@ -355,8 +381,12 @@ static struct SignalSemaphore * memory_semaphore;
void
__memory_lock(void)
{
if(memory_semaphore != NULL)
PROFILE_OFF();
if (memory_semaphore != NULL)
ObtainSemaphore(memory_semaphore);
PROFILE_ON();
}
/****************************************************************************/
@@ -364,8 +394,12 @@ __memory_lock(void)
void
__memory_unlock(void)
{
if(memory_semaphore != NULL)
PROFILE_OFF();
if (memory_semaphore != NULL)
ReleaseSemaphore(memory_semaphore);
PROFILE_ON();
}
/****************************************************************************/
@@ -378,30 +412,34 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
{
ENTER();
/* Make sure that freeing any memory does not also
* trigger the alloca cleanup operations. Otherwise,
* the data structures used by alloca() to track
* the scope in which allocated memory remains
* valid and should not be freed just yet may be
* freed, corrupting them.
*/
__alloca_cleanup = NULL;
#ifdef __MEM_DEBUG
{
kprintf("[%s] %ld bytes still allocated upon exit, maximum of %ld bytes allocated at a time.\n",
__program_name,__current_memory_allocated,__maximum_memory_allocated);
__program_name, __current_memory_allocated, __maximum_memory_allocated);
kprintf("[%s] %ld chunks of memory still allocated upon exit, maximum of %ld chunks allocated at a time.\n",
__program_name,__current_num_memory_chunks_allocated,__maximum_num_memory_chunks_allocated);
__program_name, __current_num_memory_chunks_allocated, __maximum_num_memory_chunks_allocated);
__check_memory_allocations(__FILE__,__LINE__);
__check_memory_allocations(__FILE__, __LINE__);
/* Make sure that those memory nodes which were
* intended not to be freed will get freed this
* time around.
*/
__never_free = FALSE;
if(__memory_list.mlh_Head != NULL)
{
while(NOT IsListEmpty((struct List *)&__memory_list))
{
((struct MemoryNode *)__memory_list.mlh_Head)->mn_AlreadyFree = FALSE;
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
}
}
#if defined(__USE_MEM_TREES)
{
/* This must remain empty. */
__initialize_red_black_tree(&__memory_tree);
}
#endif /* __USE_MEM_TREES */
@@ -413,39 +451,36 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
/* Is the slab memory allocator enabled? */
if (__slab_data.sd_InUse)
{
/* Just release the memory. */
__slab_exit();
}
else
/* Is the memory pool in use? */
else if (__memory_pool != NULL)
{
if (__memory_pool != NULL)
/* 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);
DeletePool(__memory_pool);
__memory_pool = NULL;
while (NOT IsMinListEmpty(&__memory_list))
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, __FILE__, __LINE__);
}
else if (__memory_list.mlh_Head != NULL)
#else
{
#ifdef __MEM_DEBUG
{
while(NOT IsListEmpty((struct List *)&__memory_list))
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
}
#else
{
while(NOT IsListEmpty((struct List *)&__memory_list))
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,NULL,0);
}
#endif /* __MEM_DEBUG */
while (NOT IsMinListEmpty(&__memory_list))
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, NULL, 0);
}
#endif /* __MEM_DEBUG */
}
}
#else
{
if (__memory_pool != NULL)
{
NewList((struct List *)&__memory_list);
DeletePool(__memory_pool);
__memory_pool = NULL;
}
@@ -453,19 +488,22 @@ STDLIB_DESTRUCTOR(stdlib_memory_exit)
{
#ifdef __MEM_DEBUG
{
while(NOT IsListEmpty((struct List *)&__memory_list))
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,__FILE__,__LINE__);
while (NOT IsMinListEmpty(&__memory_list))
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, __FILE__, __LINE__);
}
#else
{
while(NOT IsListEmpty((struct List *)&__memory_list))
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head,NULL,0);
while (NOT IsMinListEmpty(&__memory_list))
__free_memory_node((struct MemoryNode *)__memory_list.mlh_Head, NULL, 0);
}
#endif /* __MEM_DEBUG */
}
}
#endif /* __USE_SLAB_ALLOCATOR */
/* The list of memory allocations must remain empty. */
NewList((struct List *)&__memory_list);
#if defined(__THREAD_SAFE)
{
__delete_semaphore(memory_semaphore);
@@ -484,13 +522,7 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
ENTER();
#if defined(__THREAD_SAFE)
{
memory_semaphore = __create_semaphore();
if(memory_semaphore == NULL)
goto out;
}
#endif /* __THREAD_SAFE */
NewList((struct List *)&__memory_list);
#if defined(__USE_MEM_TREES) && defined(__MEM_DEBUG)
{
@@ -498,27 +530,38 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
}
#endif /* __USE_MEM_TREES && __MEM_DEBUG */
NewList((struct List *)&__memory_list);
#if defined(__THREAD_SAFE)
{
memory_semaphore = __create_semaphore();
if (memory_semaphore == NULL)
{
SHOWMSG("could not create memory semaphore");
goto out;
}
}
#endif /* __THREAD_SAFE */
#if defined(__USE_SLAB_ALLOCATOR)
#ifdef __USE_SLAB_ALLOCATOR
{
/* ZZZ this is just for the purpose of testing */
#if 1
#if DEBUG
{
TEXT slab_size_var[20];
if(GetVar("SLAB_SIZE", slab_size_var, sizeof(slab_size_var), 0) > 0)
if (GetVar("SLAB_SIZE", slab_size_var, sizeof(slab_size_var), 0) > 0)
{
LONG value;
LONG value = 0;
if(StrToLong(slab_size_var,&value) > 0 && value > 0)
if (StrToLong(slab_size_var, &value) > 0 && value > 0)
__slab_max_size = (size_t)value;
}
}
#endif
SHOWVALUE(__slab_max_size);
/* Enable the slab memory allocator? */
if(__slab_max_size > 0)
if (__slab_max_size > 0)
{
__slab_init(__slab_max_size);
}
@@ -526,15 +569,27 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
{
#if defined(__amigaos4__)
{
__memory_pool = CreatePool(MEMF_PRIVATE,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
__memory_pool = CreatePool(MEMF_PRIVATE, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
if (__memory_pool == NULL)
{
SHOWMSG("could not create memory pool");
goto out;
}
}
#else
{
/* There is no support for memory pools in the operating system
* prior to Kickstart 3.0 (V39).
*/
if(((struct Library *)SysBase)->lib_Version >= 39)
__memory_pool = CreatePool(MEMF_ANY,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
if (((struct Library *)SysBase)->lib_Version >= 39)
{
__memory_pool = CreatePool(MEMF_ANY, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
if (__memory_pool == NULL)
{
SHOWMSG("could not create memory pool");
goto out;
}
}
}
#endif /* __amigaos4__ */
}
@@ -543,19 +598,31 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
{
#if defined(__amigaos4__)
{
__memory_pool = CreatePool(MEMF_PRIVATE,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
__memory_pool = CreatePool(MEMF_PRIVATE, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
if (__memory_pool == NULL)
{
SHOWMSG("could not create memory pool");
goto out;
}
}
#else
{
/* There is no support for memory pools in the operating system
* prior to Kickstart 3.0 (V39).
*/
if(((struct Library *)SysBase)->lib_Version >= 39)
__memory_pool = CreatePool(MEMF_ANY,(ULONG)__default_pool_size,(ULONG)__default_puddle_size);
if (((struct Library *)SysBase)->lib_Version >= 39)
{
__memory_pool = CreatePool(MEMF_ANY, (ULONG)__default_pool_size, (ULONG)__default_puddle_size);
if (__memory_pool == NULL)
{
SHOWMSG("could not create memory pool");
goto out;
}
}
}
#endif /* __amigaos4__ */
}
#endif /* __USE_SLAB_ALLOCATOR) */
#endif /* __USE_SLAB_ALLOCATOR */
success = TRUE;
@@ -564,7 +631,7 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
SHOWVALUE(success);
LEAVE();
if(success)
if (success)
CONSTRUCTOR_SUCCEED();
else
CONSTRUCTOR_FAIL();

View File

@@ -37,9 +37,13 @@
/****************************************************************************/
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
int
mbtowc(wchar_t *pwc, const char *s, size_t n)
mbtowc(wchar_t *restrict pwc, const char *restrict s, size_t n)
{
/* ZZZ unimplemented */
return(-1);
errno = EILSEQ;
return -1;
}
#endif

36
library/stdlib_memory.h Normal file → Executable file
View File

@@ -63,7 +63,7 @@
/*
* 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
* 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
* the "never free" flag altogether.
/* Memory allocations are remembered by this tracking data structure.
* Its size is always a multiple of 8 bytes, which provides memory
* address alignment to a 64-bit boundary.
*/
#define GET_MN_SIZE(mn) ((mn)->mn_Size & ~MN_SIZE_NEVERFREE)
struct MemoryNode
{
#ifdef __MEM_DEBUG
struct MinNode mn_MinNode;
UBYTE mn_AlreadyFree;
UBYTE mn_Pad0[3];
ULONG mn_AllocationSize;
ULONG mn_Flags;
#ifdef __MEM_DEBUG
void * mn_Allocation;
size_t mn_AllocationSize;
size_t mn_OriginalSize;
char * mn_FreeFile;
int mn_FreeLine;
@@ -178,17 +177,18 @@ struct MemoryNode
char * mn_File;
int mn_Line;
UBYTE mn_AlreadyFree;
UBYTE mn_Pad1[7];
#ifdef __USE_MEM_TREES
struct MemoryNode * mn_Left;
struct MemoryNode * mn_Right;
struct MemoryNode * mn_Parent;
UBYTE mn_IsRed;
UBYTE mn_Pad1[3];
UBYTE mn_Pad2[3];
#endif /* __USE_MEM_TREES */
#endif /* __MEM_DEBUG */
ULONG mn_Size;
};
#ifdef __USE_MEM_TREES
@@ -247,12 +247,14 @@ struct SlabNode
};
/* 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 MinNode ssa_MinNode;
ULONG ssa_Size;
ULONG ssa_Pad;
};
/* 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,
* 64, 128 bytes. Hence, sd_Slabs[3] keeps track of the slabs
* which are 8 bytes in size, sd_Slabs[4] is for 16 byte
* chunks, etc. The minimum chunk size is 8, which is why
* lists 0..2 are not used. Currently, there is an upper limit
* chunks, etc. The minimum chunk size is 16, which is why
* lists 0..3 are not used. Currently, there is an upper limit
* of 2^17 bytes per chunk, but you should not be using slab
* chunks much larger than 4096 bytes.
*/

View File

@@ -45,8 +45,8 @@
/****************************************************************************/
extern void ASM _PROLOG(REG(a0,char *));
extern void ASM _EPILOG(REG(a0,char *));
extern void __asm _PROLOG(register __a0 char *);
extern void __asm _EPILOG(register __a0 char *);
#if _PROFILE
#define PROFILE_OFF() _PROLOG(0L)

View File

@@ -50,7 +50,7 @@
/****************************************************************************/
__static void *
__realloc(void *ptr,size_t size,const char * file,int line)
__realloc(void *ptr, size_t size, const char * file, int line)
{
void * result = NULL;
BOOL locked = FALSE;
@@ -62,23 +62,24 @@ __realloc(void *ptr,size_t size,const char * file,int line)
assert( (int)size >= 0 );
if(ptr == NULL)
if (ptr == NULL)
{
D(("calling malloc(%ld)",size));
D(("calling malloc(%ld)", size));
result = __malloc(size,file,line);
result = __malloc(size, file, line);
}
#ifndef UNIX_PATH_SEMANTICS
else if (size == 0)
{
D(("calling free(0x%08lx)",ptr));
__free(ptr,file,line);
__free(ptr, file, line);
}
#endif /* UNIX_PATH_SEMANTICS */
else
{
size_t old_size;
size_t new_allocation_size UNUSED;
size_t old_allocation_size;
struct MemoryNode * mn;
BOOL reallocate;
@@ -92,16 +93,14 @@ __realloc(void *ptr,size_t size,const char * file,int line)
#ifdef __MEM_DEBUG
{
/* If we managed to find the memory allocation,
reallocate it. */
if(mn == NULL)
/* Quit if we failed to find the memory allocation. */
if (mn == NULL)
{
SHOWMSG("allocation not found");
kprintf("[%s] %s:%ld:Address for realloc(0x%08lx,%ld) not known.\n",__program_name,file,line,ptr,size);
kprintf("[%s] %s:%ld:Address for realloc(0x%08lx,%ld) not known.\n",
__program_name, file, line, ptr, size);
/* Apparently, the address did not qualify for
reallocation. */
goto out;
}
}
@@ -111,70 +110,114 @@ __realloc(void *ptr,size_t size,const char * file,int line)
}
#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");
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
has really changed. */
old_allocation_size = mn->mn_AllocationSize;
/* If the memory debug option is enabled, just check if
* requested allocation size has changed.
*/
#if defined(__MEM_DEBUG)
{
reallocate = (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
{
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. */
reallocate = TRUE;
}
else
else if (new_allocation_size < old_allocation_size)
{
/* Optimization: If the block size shrinks by less than half the
original allocation size, do not reallocate the
block and do not copy over the contents of the old
allocation. We also take into account that the
actual size of the allocation is affected by a
certain operating system imposed granularity. */
reallocate = (size < old_size && size <= old_size / 2);
block. */
reallocate = (size <= old_allocation_size / 2);
}
else
{
reallocate = FALSE;
}
}
#endif /* __MEM_DEBUG */
if(reallocate)
if (reallocate)
{
void * new_ptr;
D(("realloc() size has changed; old=%ld, new=%ld",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
attempt to replace the old. */
new_ptr = __malloc(size,file,line);
if(new_ptr == NULL)
attempt to replace the old one. */
new_ptr = __malloc(size, file, line);
if (new_ptr == NULL)
{
SHOWMSG("could not reallocate memory");
goto out;
}
/* Copy the contents of the old allocation to the new buffer. */
if(size > old_size)
size = old_size;
/* With memory debugging enabled, the size of the allocation made
* will use the requested and not the rounded size of the
* allocation, which can be shorter. We need to deal with this.
*/
#if defined(__MEM_DEBUG)
{
struct MemoryNode * new_mn;
memmove(new_ptr,ptr,size);
new_mn = __find_memory_node(new_ptr);
if (new_mn == NULL)
{
free(new_ptr);
SHOWMSG("Could not find memory node for new allocation");
goto out;
}
/* Make sure that if the new allocation size is smaller than
* the old allocation, we only copy as much data as will fit
* into the new allocation.
*/
if (size > new_mn->mn_OriginalSize)
size = new_mn->mn_OriginalSize;
}
#else
{
/* We assume that the total size of the allocation will
* include padding. The requested size does not include
* the memory node, of course, which is why it is added
* here.
*/
if (size + sizeof(*mn) > old_allocation_size)
size = old_allocation_size - sizeof(*mn);
}
#endif /* __MEM_DEBUG */
memmove(new_ptr, ptr, size);
/* Free the old allocation. Since we already know which memory
node is associated with it, we don't call __free() here. */
__free_memory_node(mn,file,line);
__free_memory_node(mn, file, line);
result = new_ptr;
}
else
{
D(("size didn't actually change that much (%ld -> %ld); returning memory block as is.",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. */
result = ptr;
@@ -183,14 +226,14 @@ __realloc(void *ptr,size_t size,const char * file,int line)
out:
if(locked)
if (locked)
__memory_unlock();
if(result == NULL)
if (result == NULL)
SHOWMSG("ouch! realloc failed");
RETURN(result);
return(result);
return result;
}
/****************************************************************************/

1138
library/stdlib_slab.c Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -41,7 +41,7 @@
/****************************************************************************/
static const char * error_table[EILSEQ - EPERM + 1] =
static const char * error_table[ENOTSUP - EPERM + 1] =
{
"Operation not permitted",
"No such file or directory",
@@ -127,7 +127,8 @@ static const char * error_table[EILSEQ - EPERM + 1] =
"Identifier removed",
"No message of the desired type.",
"Value too large to be stored in data type.",
"Encoding error detected"
"Encoding error detected",
"Not supported"
};
/****************************************************************************/
@@ -139,7 +140,7 @@ strerror_r(int number,char * buffer,size_t buffer_size)
const char * str;
size_t len;
if(number < EPERM || number > EILSEQ)
if(number < EPERM || number > ENOTSUP)
{
__set_errno(EINVAL);
goto out;

75
library/string_strnlen.c Normal file
View File

@@ -0,0 +1,75 @@
/*
* $Id: string_strlen.c,v 1.4 2006-01-08 12:04:27 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of Olaf Barthel nor the names of contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _STDLIB_NULL_POINTER_CHECK_H
#include "stdlib_null_pointer_check.h"
#endif /* _STDLIB_NULL_POINTER_CHECK_H */
/****************************************************************************/
#ifndef _STRING_HEADERS_H
#include "string_headers.h"
#endif /* _STRING_HEADERS_H */
/****************************************************************************/
size_t
strnlen(const char *s, size_t maxlen)
{
const char * start = s;
size_t result = 0;
assert( s != NULL );
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(s == NULL)
{
__set_errno(EFAULT);
goto out;
}
}
#endif /* CHECK_FOR_NULL_POINTERS */
while((maxlen != 0) && ((*s) != '\0'))
{
s++;
maxlen--;
}
result = (size_t)(s - start);
out:
return(result);
}

151
library/time_mktime.c Normal file → Executable file
View File

@@ -1,5 +1,5 @@
/*
* $Id: time_mktime.c,v 1.10 2006-01-08 12:04:27 obarthel Exp $
* $Id: time_mktime.c,v 1.11 2015-06-26 11:22:00 obarthel Exp $
*
* :ts=4
*
@@ -52,9 +52,10 @@ mktime(struct tm *tm)
{
DECLARE_UTILITYBASE();
struct ClockData clock_data;
ULONG seconds, delta;
ULONG seconds;
time_t result = (time_t)-1;
int max_month_days;
LONG combined_seconds;
int month, year;
ENTER();
@@ -73,116 +74,63 @@ mktime(struct tm *tm)
}
#endif /* CHECK_FOR_NULL_POINTERS */
/* The month must be valid. */
if(tm->tm_mon < 0 || tm->tm_mon > 11)
/* Normalize the year and month. */
year = tm->tm_year + 1900;
month = tm->tm_mon + 1;
if(month < 0 || month > 12)
{
SHOWVALUE(tm->tm_mon);
SHOWMSG("invalid month");
goto out;
int y;
y = month / 12;
month -= y * 12;
year += y;
}
/* The day of the month must be valid. */
if(tm->tm_mday < 1 || tm->tm_mday > 31)
if(month < 1)
{
SHOWVALUE(tm->tm_mday);
SHOWMSG("invalid day of month");
goto out;
month += 12;
year -= 1;
}
/* The year must be valid. */
if(tm->tm_year < 78)
/* The year must be valid. Amiga time begins with January 1st, 1978. */
if(year < 1978)
{
SHOWVALUE(tm->tm_year);
SHOWVALUE(year);
SHOWMSG("invalid year");
goto out;
}
/* Is this the month of February? */
if(tm->tm_mon == 1)
{
int year;
/* We need to have the full year number for the
leap year calculation below. */
year = tm->tm_year + 1900;
/* Now for the famous leap year calculation rules... In
the given year, how many days are there in the month
of February? */
if((year % 4) != 0)
max_month_days = 28;
else if ((year % 400) == 0)
max_month_days = 29;
else if ((year % 100) == 0)
max_month_days = 28;
else
max_month_days = 29;
}
else
{
static const char days_per_month[12] =
{
31, 0,31,
30,31,30,
31,31,30,
31,30,31
};
max_month_days = days_per_month[tm->tm_mon];
}
/* The day of the month must be valid. */
if(tm->tm_mday < 0 || tm->tm_mday > max_month_days)
{
SHOWVALUE(tm->tm_mday);
SHOWMSG("invalid day of month");
goto out;
}
/* The hour must be valid. */
if(tm->tm_hour < 0 || tm->tm_hour > 23)
{
SHOWVALUE(tm->tm_hour);
SHOWMSG("invalid hour");
goto out;
}
/* The minute must be valid. */
if(tm->tm_min < 0 || tm->tm_min > 59)
{
SHOWVALUE(tm->tm_min);
SHOWMSG("invalid minute");
goto out;
}
/* Note: the number of seconds can be larger than 59
in order to account for leap seconds. */
if(tm->tm_sec < 0 || tm->tm_sec > 60)
{
SHOWVALUE(tm->tm_sec);
SHOWMSG("invalid seconds");
goto out;
}
clock_data.sec = (tm->tm_sec > 59) ? 59 : tm->tm_sec;
clock_data.min = tm->tm_min;
clock_data.hour = tm->tm_hour;
clock_data.mday = tm->tm_mday;
clock_data.month = tm->tm_mon + 1;
clock_data.year = tm->tm_year + 1900;
seconds = Date2Amiga(&clock_data) + (tm->tm_sec - 59);
/* The AmigaOS "epoch" starts with January 1st, 1978, which was
a Sunday. */
tm->tm_wday = (seconds / (24 * 60 * 60)) % 7;
/* Convert the first day of the month in the given year
into the corresponding number of seconds. */
memset(&clock_data, 0, sizeof(clock_data));
clock_data.mday = 1;
clock_data.month = 1;
clock_data.month = month;
clock_data.year = year;
delta = Date2Amiga(&clock_data);
seconds = Date2Amiga(&clock_data);
tm->tm_yday = (seconds - delta) / (24 * 60 * 60);
/* Put the combined number of seconds involved together,
covering the seconds/minutes/hours of the day as well
as the number of days of the month. This will be added
to the number of seconds for the date. */
combined_seconds = tm->tm_sec + 60 * (tm->tm_min + 60 * (tm->tm_hour + 24 * (tm->tm_mday-1)));
/* If the combined number of seconds is negative, adding it
* to the number of seconds for the date should not produce
* a negative value.
*/
if(combined_seconds < 0 && seconds < (ULONG)(-combined_seconds))
{
SHOWVALUE(seconds);
SHOWVALUE(combined_seconds);
SHOWMSG("invalid combined number of seconds");
goto out;
}
seconds += combined_seconds;
__locale_lock();
@@ -193,10 +141,13 @@ mktime(struct tm *tm)
__locale_unlock();
/* Finally, adjust for the difference between the Unix and the
/* Adjust for the difference between the Unix and the
AmigaOS epochs, which differ by 8 years. */
result = seconds + UNIX_TIME_OFFSET;
/* Finally, normalize the provided time and date information. */
localtime_r(&result, tm);
out:
RETURN(result);

48
library/time_tzset.c Normal file
View File

@@ -0,0 +1,48 @@
/*
* $Id: $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2017 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of Olaf Barthel nor the names of contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TIME_HEADERS_H
#include "time_headers.h"
#endif /* _TIME_HEADERS_H */
#ifndef _LOCALE_HEADERS_H
#include "locale_headers.h"
#endif /* _LOCALE_HEADERS_H */
/****************************************************************************/
void
tzset(void)
{
/* For now, do nothing. */
}

View File

@@ -184,7 +184,6 @@ __getcwd(char * buffer,size_t buffer_size,const char *file,int line)
if(__unix_path_semantics)
{
const char * path_name = buffer;
size_t len;
if(__translate_amiga_to_unix_path_name(&path_name,&buffer_nti) != 0)
goto out;

View File

@@ -69,7 +69,7 @@ CLIB_DESTRUCTOR(unistd_exit)
PROFILE_OFF();
if(__unlink_list.mlh_Head != NULL && NOT IsListEmpty((struct List *)&__unlink_list))
if(__unlink_list.mlh_Head != NULL && NOT IsMinListEmpty(&__unlink_list))
{
struct UnlinkNode * uln;
BPTR old_dir;

View File

@@ -58,9 +58,19 @@ readlink(const char * path_name, char * buffer, int buffer_size)
struct name_translation_info path_name_nti;
struct name_translation_info buffer_nti;
#endif /* UNIX_PATH_SEMANTICS */
D_S(struct bcpl_name, bname);
const size_t name_size = sizeof(bname->name);
BPTR lock = ZERO;
int result = ERROR;
int target_length = -1;
struct DevProc *dvp = NULL;
char * new_name = NULL;
char * path_part;
size_t name_len;
size_t new_name_size;
LONG readlink_result;
LONG error;
ENTER();
@@ -70,12 +80,12 @@ readlink(const char * path_name, char * buffer, int buffer_size)
assert( path_name != NULL && buffer != NULL );
if(__check_abort_enabled)
if (__check_abort_enabled)
__check_abort();
#if defined(CHECK_FOR_NULL_POINTERS)
{
if(path_name == NULL || buffer == NULL)
if (path_name == NULL || buffer == NULL)
{
SHOWSTRING("invalid parameters");
@@ -87,9 +97,9 @@ readlink(const char * path_name, char * buffer, int buffer_size)
#if defined(UNIX_PATH_SEMANTICS)
{
if(__unix_path_semantics)
if (__unix_path_semantics)
{
if(path_name[0] == '\0')
if (path_name[0] == '\0')
{
SHOWMSG("no name given");
@@ -97,53 +107,144 @@ readlink(const char * path_name, char * buffer, int buffer_size)
goto out;
}
if(__translate_unix_to_amiga_path_name(&path_name,&path_name_nti) != 0)
if (__translate_unix_to_amiga_path_name(&path_name, &path_name_nti) != 0)
goto out;
}
}
#endif /* UNIX_PATH_SEMANTICS */
D(("trying to get a lock on '%s'",path_name));
name_len = strlen(path_name);
if (name_len >= name_size)
{
SHOWMSG("name too long");
SetIoErr(ERROR_LINE_TOO_LONG);
goto out;
}
/* Convert the name into a BCPL string. */
bname->name[0] = name_len;
memcpy(&bname->name[1], path_name, name_len);
/* Get a handle on the device, volume or assignment name in the path. */
dvp = GetDeviceProc((STRPTR)path_name, dvp);
if (dvp == NULL)
{
SHOWMSG("dvp == NULL");
goto out;
}
/* Try to obtain a lock on the object. It should be a link and not
* a file or directory.
*/
lock = DoPkt(dvp->dvp_Port, ACTION_LOCATE_OBJECT, dvp->dvp_Lock, MKBADDR(bname), SHARED_LOCK, 0, 0);
if (lock != ZERO)
{
SHOWMSG("lock != ZERO");
SetIoErr(ERROR_OBJECT_WRONG_TYPE);
goto out;
}
error = IoErr();
if (error != ERROR_IS_SOFT_LINK)
{
SHOWMSG("not a soft link");
goto out;
}
/* We only need the leading path name. */
name_len = ((BYTE *)PathPart(path_name)) - (BYTE *)path_name;
path_part = malloc(name_len+1);
if (path_part == NULL)
{
SHOWMSG("path_part too long");
SetIoErr(ERROR_NO_FREE_STORE);
goto out;
}
memcpy(path_part, path_name, name_len);
path_part[name_len] = '\0';
PROFILE_OFF();
lock = __lock((STRPTR)path_name,SHARED_LOCK,&target_length,buffer,(size_t)buffer_size);
lock = Lock((STRPTR)path_part, SHARED_LOCK);
PROFILE_ON();
if(lock != ZERO)
new_name_size = name_size+1;
/* Provide as much buffer space as possible. */
if (buffer_size > 0 && (size_t)buffer_size > new_name_size)
new_name_size = buffer_size;
/* For soft link resolution we need a temporary buffer to
let the file system store the resolved path name in. */
new_name = malloc(new_name_size);
if (new_name == NULL)
{
__set_errno(EINVAL);
goto out;
}
else if (target_length <= 0) /* No a soft-link. */
{
__set_errno(__translate_io_error_to_errno(IoErr()));
SHOWMSG("new_name too long");
SetIoErr(ERROR_NO_FREE_STORE);
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)
goto out;
if (__unix_path_semantics)
{
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:
PROFILE_OFF();
if (dvp != NULL)
FreeDeviceProc(dvp);
UnLock(lock);
PROFILE_ON();
RETURN(result);
return(result);
return result;
}

View File

@@ -1,5 +1,5 @@
/*
* $Id: unistd_translateu2a.c,v 1.12 2010-08-20 15:33:36 obarthel Exp $
* $Id: unistd_translateu2a.c,v 1.13 2015-06-26 11:22:00 obarthel Exp $
*
* :ts=4
*
@@ -477,7 +477,10 @@ __translate_unix_to_amiga_path_name(char const ** name_ptr,struct name_translati
for(i = j = 0 ; i < len ; i++)
{
if(i < len - 3 && name[i] == '/' && name[i + 1] == '.' && name[i + 2] == '.' && name[i + 3] == '/')
i += 2;
{
replace[j++] = '/';
i += 3;
}
replace[j++] = name[i];
}

View File

@@ -41,7 +41,7 @@
/****************************************************************************/
void
int
usleep(unsigned long microseconds)
{
ENTER();
@@ -51,4 +51,6 @@ usleep(unsigned long microseconds)
__time_delay(0,microseconds);
LEAVE();
return 0;
}

View File

@@ -334,7 +334,7 @@ __wildcard_expand_init(void)
}
else if (rc != OK)
{
/* Some error occured. */
/* Some error occurred. */
error = EIO;
break;
}

View File

@@ -1,6 +1,6 @@
#define VERSION 1
#define REVISION 212
#define DATE "27.11.2016"
#define VERS "unix.lib 1.212"
#define VSTRING "unix.lib 1.212 (27.11.2016)\r\n"
#define VERSTAG "\0$VER: unix.lib 1.212 (27.11.2016)"
#define REVISION 215
#define DATE "26.6.2017"
#define VERS "unix.lib 1.215"
#define VSTRING "unix.lib 1.215 (26.6.2017)\r\n"
#define VERSTAG "\0$VER: unix.lib 1.215 (26.6.2017)"

View File

@@ -1 +1 @@
212
215

View File

@@ -37,9 +37,12 @@
/****************************************************************************/
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
size_t
mbrlen(wchar_t *pwc, const char * s, size_t n, mbstate_t *ps)
mbrlen(const char *restrict s, size_t n, mbstate_t *restrict ps)
{
/* ZZZ unimplemented */
return(0);
}
#endif /* __STDC_VERSION__ && __STDC_VERSION__ >= 199901L */

64
library/wchar_mbrtowc.c Normal file
View File

@@ -0,0 +1,64 @@
/*
* $Id: wchar_mbrlen.c,v 1.3 2006-01-08 12:04:27 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of Olaf Barthel nor the names of contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _WCHAR_HEADERS_H
#include "wchar_headers.h"
#endif /* _WCHAR_HEADERS_H */
/****************************************************************************/
/* Mostly non-working stub based on bionic */
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
size_t
mbrtowc(wchar_t *restrict pwc, const char *restrict s, size_t n, mbstate_t *restrict ps)
{
if (s == NULL)
{
s = "";
pwc = NULL;
}
if (n == 0)
{
if (pwc)
*pwc = 0;
return 0;
}
if (pwc)
*pwc = *s;
return (*s != 0);
}
#endif /* __STDC_VERSION__ && __STDC_VERSION__ >= 199901L */

View File

@@ -40,6 +40,5 @@
int
mbsinit(const mbstate_t *ps)
{
/* ZZZ unimplemented */
return(0);
return !ps || !*(unsigned *)ps;
}

View File

@@ -38,7 +38,7 @@
/****************************************************************************/
int
vswprintf(char *s, const wchar_t *format,va_list arg)
vswprintf(wchar_t *s, size_t maxlen, const wchar_t *format, va_list arg)
{
/* ZZZ unimplemented */
return(0);

View File

@@ -35,11 +35,13 @@
#include "wchar_headers.h"
#endif /* _WCHAR_HEADERS_H */
/* Implementation based on musl */
/****************************************************************************/
wchar_t *
wcscat(wchar_t *dest, const wchar_t *src)
{
/* ZZZ unimplemented */
return(NULL);
wcscpy(dest + wcslen(dest), src);
return dest;
}

View File

@@ -37,9 +37,12 @@
/****************************************************************************/
/* Implementation based on musl */
wchar_t *
wcschr(const wchar_t *s, wchar_t c)
{
/* ZZZ unimplemented */
return(NULL);
if (!c) return (wchar_t *)s + wcslen(s);
for (; *s && *s != c; s++);
return *s ? (wchar_t *)s : 0;
}

View File

@@ -40,6 +40,6 @@
int
wcscmp(const wchar_t *s1, const wchar_t * s2)
{
/* ZZZ unimplemented */
return(0);
for (; *s1==*s2 && *s1 && *s2; s1++, s2++);
return *s1 - *s2;
}

45
library/wchar_wcscoll.c Normal file
View File

@@ -0,0 +1,45 @@
/*
* $Id: wchar_wscoll.c,v 1.3 2006-01-08 12:04:27 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of Olaf Barthel nor the names of contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _WCHAR_HEADERS_H
#include "wchar_headers.h"
#endif /* _WCHAR_HEADERS_H */
/****************************************************************************/
int
wcscoll(const wchar_t *ws1, const wchar_t *ws2)
{
/* ZZZ unimplemented */
return(0);
}

View File

@@ -40,6 +40,7 @@
wchar_t *
wcscpy(wchar_t *dest, const wchar_t *src)
{
/* ZZZ unimplemented */
return(NULL);
wchar_t *a = dest;
while ((*dest++ = *src++));
return a;
}

50
library/wchar_wcscspn.c Normal file
View File

@@ -0,0 +1,50 @@
/*
* $Id: wchar_wcsspn.c,v 1.3 2006-01-08 12:04:27 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of Olaf Barthel nor the names of contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _WCHAR_HEADERS_H
#include "wchar_headers.h"
#endif /* _WCHAR_HEADERS_H */
/****************************************************************************/
/* Implementation based on musl */
size_t
wcscspn(const wchar_t *s, const wchar_t *c)
{
const wchar_t *a;
if (!c[0]) return wcslen(s);
if (!c[1]) return (s=wcschr(a=s, *c)) ? (size_t)(s-a) : wcslen(a);
for (a=s; *s && !wcschr(c, *s); s++);
return s-a;
}

View File

@@ -37,9 +37,12 @@
/****************************************************************************/
/* Implementation based on musl */
size_t
wcslen(const wchar_t *s)
{
/* ZZZ unimplemented */
return(0);
const wchar_t *a;
for (a=s; *s; s++);
return s-a;
}

Some files were not shown because too many files have changed in this diff Show More