238 Commits
Author SHA1 Message Date
Stephen Heumann 0519320f06 Implement strfromd/f/l (C23).
We just make these aliases for snprintf, which should work fine for all valid cases given our calling convention. Since they are actually implemented via snprintf (and the printf machinery in general), they are in stdio.asm, even though the functions are declared in <stdlib.h>.
2026-04-05 20:26:48 -05:00
Stephen Heumann 6b63c1ee32 Implement strdup and strndup (C23).
Note that the input for strndup is not required to be a null-terminated string, so we need to avoid using operations like strlen on it. Also, we limit the length allocated for strndup to the minimum of n+1 or the length needed to hold the whole input string. Some implementations might always allocate n+1 bytes, but that could lead to avoidable allocation failures on a fairly memory-constrained system like the IIGS.
2026-04-05 18:28:22 -05:00
Stephen Heumann 52a6cd1b41 Implement memalignment (C23).
Note that this returns the actual alignment of the address, which can be greater than what can be used with alignas. In IIGS-specific code, it could be used to test for page or bank alignment.
2026-04-05 16:08:54 -05:00
Stephen Heumann 374022f4bf Optimize printf flag handling.
This effectively inlines the former Flag subroutine, which saves a few bytes and a few cycles.
2026-04-04 21:28:27 -05:00
Stephen Heumann 5051f137cd mktime: small tweaks. 2026-03-22 22:08:04 -05:00
Stephen Heumann 33f3fe83e4 timegm: avoid possible failures near start or end of time range.
The previous code could fail for times within the first or last few hours of the representable range, depending on the time zone. Specifically, it failed for times that would be outside the representable range if they were local time, but were representable when they were UTC times due to the time zone offset.
2026-03-22 22:07:28 -05:00
Stephen Heumann 3889494c34 gmtime/localtime: avoid 3 multiplies by using remainder from division. 2026-03-22 18:07:25 -05:00
Stephen Heumann f75e3d99bb gmtime/localtime: avoid recomputing seconds past start of year.
This avoids a call to factor.
2026-03-22 15:59:14 -05:00
Stephen Heumann 9271f6cb34 Optimize multiplies and divides in factor.
Several of the multiplies and divides are now implemented via shifts and additions, which should be significantly faster. (These also take advantage of the limited range of operands to use only 16-bit operations where possible.)
2026-03-22 14:44:46 -05:00
Stephen Heumann 847d8dff03 gmtime/localtime: improve year estimates to reduce computation.
This uses a "year length" slightly longer than the real average. Because our (time_t)0 is November 13, this brings the cutoffs for the year estimates closer to the end of the year as years pass, which reduces the number of dates for which the initial estimate is incorrect. This means that there are fewer instances where an extra factor call is required, so it should produce a slight speedup on average.

If we ever move to 64-bit time_t, this fudge factor would have to be removed, since it is only valid within our 32-bit time_t range.
2026-03-21 22:24:33 -05:00
Stephen Heumann 2a629d0a36 gmtime/localtime: estimate month with simple division.
This uses a similar approach to the year and further reduces factor calls.
2026-03-21 20:57:11 -05:00
Stephen Heumann 83d0ca5502 gmtime/localtime: estimate year with simple division.
This now requires only one factor call for the year computation. Previously, year-1969 factor calls were required, so the new approach is significantly faster.
2026-03-21 15:18:43 -05:00
Stephen Heumann 1a2d979a6b Implement timegm (C23).
This will use the Time Tool for time zone info if __useTimeTool is non-zero, similarly to other <time.h> functions.
2026-03-20 17:24:38 -05:00
Stephen Heumann b278419443 Implement localtime_r and gmtime_r (C23). 2026-03-20 17:16:02 -05:00
Stephen Heumann b449edaa77 Fix time zone handling in localtime when using large memory model.
The former code could potentially access the lasttime and lastDST variables in the wrong bank, leading tm_isdst to be set incorrectly.
2026-03-16 22:24:35 -05:00
Stephen Heumann 802889f8fb Implement timespec_getres (C23).
Like timespec_get, this only supports TIME_UTC, not any of the other optional time bases from C23.
2026-03-16 18:58:21 -05:00
Stephen Heumann cb4b99c644 Small optimizations in strtoull. 2026-03-15 21:24:49 -05:00
Stephen Heumann fc4e5d8838 strto(u)l(l): Support 0B/0b prefixes for binary (C23).
These are supported both with base=0 (where they indicate the number is in binary) and with base=2 (where the prefix is optional and does not change the base).
2026-03-15 21:18:35 -05:00
Stephen Heumann 832bb39fb6 strto(u)l(l): Fix handling of 0x with no hex digits following.
When base is 0 or 16 and the numeric part of the string (after possible leading white space and/or sign) starts with 0x or 0X but is not followed by a hex digit, only the 0 should be taken as part of the subject sequence. Thus, this is not an error condition (errno should not be set), the result should be 0, and if endptr is non-null, *endptr should be set to point to the x or X.
2026-03-15 20:11:49 -05:00
Stephen Heumann 7f54afd42d scanf: implement wN/wfN length modifiers (C23).
Note that like with fprintf, unsupported wN/wfN length modifiers do not cause undefined behavior. In the case of fscanf, they are handled similarly to a matching failure. In such cases, we assume that there was a pointer-sized parameter passed corresponding to the unsupported conversion (unless assignment was suppressed), so that and any parameters matching the rest of the format string are removed from the stack.
2026-03-15 14:41:18 -05:00
Stephen Heumann ead0b68cfe printf: implement wN/wfN length modifiers (C23).
Note that fprintf is specified as returning a negative number for unsupported wN/wfN length modifiers (i.e. it's not undefined behavior). This implements that behavior. However, there's no good way to know how many parameter bytes were passed for the unsupported conversion, and thus no way no pull those and subsequent parameter bytes off the stack. Accordingly, we just leave them on the stack. That works fine if the caller has varargs stack repair code enabled, but not otherwise, so this is another situation where varargs stack repair code is necessary for full standards conformance. This generally shouldn't be an issue for real code, since we support the power-of-2 widths from 8 to 64, which are the only ones likely to be used in practice.
2026-03-08 18:37:10 -05:00
Stephen Heumann f9808c6970 scanf: Replace count of digits read with a simple gotDigit flag.
This makes the code slightly smaller and faster. It also fixes a theoretical bug, which is that the old code would report a matching failure if the number of digits was a multiple of 64K (of course, this would only have defined behavior if the vast majority of the digits were leading zeros).
2026-03-06 21:50:42 -06:00
Stephen Heumann 1b51b5df4c scanf: support binary numbers in 'i' format in C23 mode.
Like in other places, the binary number support is conditional on ~C23ORLATER.

This is implemented by integrating the code for scanf 'i' and 'd' formats with the formats for unsigned integers. This shrinks the code size and reduces duplication. It also fixes at least one bug, which is that if a hexadecimal number was used as input to an 'i' conversion, the next character after it could be changed, e.g. capitalizing a letter.
2026-03-06 20:43:29 -06:00
Stephen Heumann d4ace7d4d3 scanf: add support for C23 'b' format, controlled by a flag.
This is controlled by the ~C23ORLATER flag, in the same way as for printf.
2026-03-06 19:48:20 -06:00
Stephen Heumann 696c2eabf7 printf: add support for C23 'b' format, controlled by a flag.
A new label is added in the library named ~C23ORLATER. Its presence in the executable acts as a flag for enabling C23 library behavior, including the new 'b' format. The compiler will generate a reference to it when compiling a program in C23 mode, causing it to be linked in. This can then be detected in library code by including a soft (weak) reference to it, which will be non-zero if the flag is linked in (C23+) or zero if it is not (pre-C23).
2026-03-04 19:25:50 -06:00
Stephen Heumann 07408538e0 printf: add support for 'B' format (C23).
This prints integers in binary, with an optional '0B' prefix. It is specified but optional in C23.

The similar 'b' format (differing only in the case used for the '0b' prefix) is required in C23, but not yet implemented here, since 'b' has historically been used for something different in ORCA/C. The C23 'b' format would be simple to implement with small adjustments to the entry code, but I plan to provide compatibility support to pick between the two versions based on the standard in use.
2026-03-03 18:14:10 -06:00
Stephen Heumann 28ed2ac029 Add new call for assert that takes a 32-bit line number.
The ORCA/C compiler was updated to support 32-bit line numbers some time ago (as required by C99 and later), so assert should support them as well.

The code to return from any of the assert calls is also removed, since it was unreachable.
2025-11-25 22:18:31 -06:00
Stephen Heumann 7f1241c588 Implement free_sized and free_aligned_sized (C23).
In some implementations, these functions could potentially be faster than free() and/or perform additional safety checks, but this implementation just ignores the extra arguments.
2025-11-13 20:45:51 -06:00
Stephen Heumann 0f88d093f2 Implement memccpy (C23). 2025-11-12 20:02:59 -06:00
Stephen Heumann 37af2453b7 Implement memset_explicit (C23).
This is just equivalent to memset in ORCA/C, since there are no optimizations that would remove memset operations. Note that in addition to clearing the old data in memory, this implementation of memset/memset_explicit also will not leave any of the old data in registers or in the stack space that it used.
2025-09-21 17:52:48 -05:00
Stephen Heumann 81e6b8b0a8 Implement call_once (C23).
This implementation includes synchronization suitable for multithreading (albeit with inefficient busy waiting), even though ORCA/C does not currently support that. This could potentially be used with forked processes under GNO.
2025-09-21 16:29:17 -05:00
Stephen Heumann 5b04986f08 Add tool glue code for ReadMouse2.
This is documented in TBR3 and is already declared in <misctool.h>, but did not previously have glue code. TBR3 says "Applications should never make this call," but it may be useful in system utilities.
orcalib-221
2024-04-17 19:57:23 -05:00
Stephen Heumann d9e26d4467 Small optimizations related to 8/16-bit register switching. 2024-03-22 21:10:33 -05:00
Stephen Heumann 0e519e1e58 Small optimizations in memset and memcpy. 2024-02-29 17:16:47 -06:00
Stephen Heumann 49ffb1065b Unroll the core loop of strlen one time.
This makes the core loop about 10% faster at the cost of 5 extra code bytes, which seems like a reasonable tradeoff.
2024-02-26 22:14:59 -06:00
Stephen Heumann 9181b0bd73 fclose: Free the file buffer earlier.
This moves the free() call for the file buffer before the malloc() that occurs when closing a temp file, which should at least slightly reduce the chances that the malloc() call fails.
2024-02-20 22:22:26 -06:00
Stephen Heumann 7384c82667 fclose: Check for malloc failure when closing temp files.
Previously, the code for closing a temporary file assumed that malloc would succeed. If it did not, the code would trash memory and (at least in my testing) crash the system. Now it checks for and handles malloc failures, although they will still lead to the temporary file not being deleted.

Here is a test program illustrating the problem:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
        FILE *f = tmpfile();
        if (!f)
                return 0;

        void *p;
        do {
                p = malloc(8*1024);
        } while (p);

        fclose(f);
}
2024-02-20 22:20:17 -06:00
Stephen Heumann 16c7952648 fclose: close stream even if there is an error flushing buffered data.
This can happen, e.g., if there is an IO error or if there is insufficient free disk space to flush the data. In this case, fclose should return -1 to report an error, but it should still effectively close the stream and deallocate the buffer for it. (This behavior is explicitly specified in the C99 and later standards.)

Previously, ORCA/C effectively left the stream open in these cases. As a result, the buffer was not deallocated. More importantly, this could cause the program to hang at exit, because the stream would never be removed from the list of open files.

Here is an example program that demonstrates the problem:

/*
 * Run this on a volume with less than 1MB of free space, e.g. a floppy.
 * The fclose return value should be -1 (EOF), indicating an error, but
 * the two RealFreeMem values should be close to each other (indicating
 * that the buffer was freed), and the program should not hang on exit.
 */

#include <stdio.h>
#include <stddef.h>
#include <memory.h>

#define BUFFER_SIZE 1000000

int main(void) {
        size_t i;
        int ret;

        printf("At start, RealFreeMem = %lu\n", RealFreeMem());

        FILE *f = fopen("testfile", "wb");
        if (!f)
                return 0;

        setvbuf(f, NULL, _IOFBF, BUFFER_SIZE);

        for (i = 0; i < BUFFER_SIZE; i++) {
                putc('x', f);
        }

        ret = fclose(f);
        printf("fclose return value = %d\n", ret);

        printf("At end, RealFreeMem = %lu (should be close to start value)\n",
                RealFreeMem());
}
2024-02-19 22:30:15 -06:00
Stephen Heumann 9d42552756 strncmp: Fix issues related to very large n values.
This fixes the following issues:
*If n was 0x80000000 or greater, strncmp would return 0 without performing a comparison.
*If n was 0x1000000 or greater, strncmp might compare fewer characters than it should because the high byte of n was effectively ignored, causing it to return 0 when it should not.

Here is an example demonstrating these issues:

#pragma memorymodel 1
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define LEN 100000
int main(void) {
        char *s1 = malloc(LEN+1);
        char *s2 = malloc(LEN+1);
        if (!s1 || !s2)
                return 0;
        for (unsigned long i = 0; i < LEN; i++) {
                s2[i] = s1[i] = '0' + (i & 0x07);
        }
        s1[LEN] = 'x';
        return strncmp(s1,s2,0xFFFFFFFF);
}
2024-02-19 22:12:26 -06:00
Stephen Heumann bbfad1e299 strncat: fix more issues related to large n values.
This addresses the following issues:
*If the low-order 16 bits of n were 0x0000, no concatenation would be performed.
*If n was 0x1000000 or greater, the output could be cut off prematurely because the high byte of n was effectively ignored.

The following test program demonstrates these issues:

#pragma memorymodel 1
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define LEN2 100000
int main(void) {
        char *s1 = malloc(LEN2+2);
        char *s2 = malloc(LEN2+1);
        if (!s1 || !s2)
                return 0;
        for (unsigned long i = 0; i < LEN2; i++)
                s2[i] = '0' + (i & 0x07);
        strcpy(s1,"a");
        strncat(s1, s2, 0x1000000);
        puts(s1);
        printf("len = %zu\n", strlen(s1));
}
2024-02-19 22:01:53 -06:00
Stephen Heumann f1582be5a2 Fix handling of large strings in strncat.
There were two issues:
*If bit 15 of the n value was set, the second string would not be copied.
*If the length of the second string was 64K or more, it would not be copied properly because the pointers were not updated.

This test program demonstrates both issues:

#pragma memorymodel 1
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define LEN2 100000
int main(void) {
        char *s1 = malloc(LEN2+2);
        char *s2 = malloc(LEN2+1);
        if (!s1 || !s2)
                return 0;
        for (unsigned long i = 0; i < LEN2; i++)
                s2[i] = '0' + (i & 0x07);
        strcpy(s1,"a");
        strncat(s1, s2, LEN2);
        puts(s1);
        printf("len = %zu\n", strlen(s1));
}
2024-02-18 21:53:03 -06:00
Stephen Heumann b60c307ee6 Make strcat and strncat work properly when first string crosses a bank boundary.
Previously, the pointer was not properly updated to account for the bank crossing, so the characters from the second string would be written to the wrong bank.

Here is an example that illustrates this:

#include <memory.h>
#include <string.h>
#include <orca.h>
#include <stdio.h>
int main(void) {
        Handle hndl = NewHandle(0x1000f, userid(), 0xC000, 0);
        if (toolerror())
                return 0;
        char *s = *hndl;
        s = (void*)((unsigned long)s | 0xffff);
        strcpy(s, "foo");
        strcat(s, "bar");
        strncat(s, "baz", 5);
        puts(s);
}
2024-02-18 21:01:01 -06:00
Stephen Heumann bf3a4d7ceb Small optimizations in library code.
There should be no functional differences.
2024-02-18 17:35:21 -06:00
Stephen Heumann ce87c0e008 Add script to set filetypes. 2023-08-06 17:48:41 -05:00
Stephen Heumann 3f70daed7d Remove floating-point code from ORCALib.
It is being moved to SysFloat.
orcalib-220
2023-06-23 15:52:46 -05:00
Stephen Heumann a81a9964c2 Change several JMP instructions to BRL.
This avoids the need for run-time relocation and makes executables smaller.
2023-06-19 18:05:46 -05:00
Stephen Heumann a5504be621 scanf: skip remaining directives after encountering EOF.
Encountering EOF is an input failure, which terminates scanf processing. Thus, remaining directives (even %n) should not be processed.
2023-06-11 16:07:19 -05:00
Stephen Heumann 6bc1c3741c scanf: Do not test for EOF at the beginning of scanf processing.
If the format string is empty or contains only %n conversions, then nothing should be read from the stream, so no error should be indicated even if it is at EOF. If a directive does read from the stream and encounter EOF, that will be handled when the directive is processed.

This could cause scanf to pause waiting for input from the console in cases where it should not.
2023-06-11 16:05:12 -05:00
Stephen Heumann 614af65c68 printf: print inf/nan rather than INF/NAN when using f and a formats.
This works in conjunction with SysFloat commit e409ecd4717, and at least that version of SysFloat is now required.
2023-06-01 20:10:12 -05:00
Stephen Heumann b21a51ba33 Optimize lgamma.
This includes adjustments that make it a little faster for most input values, but especially for |x| < 7. The impact on accuracy should be minimal.
2023-05-22 18:05:15 -05:00