Commit Graph

82 Commits

Author SHA1 Message Date
Stephen Heumann f9d7017687 Add real to long long conversion routines.
For conversion to signed long long, we can almost just use SANE's FX2C call to convert it to comp. But LLONG_MIN corresponds to the bit pattern of the comp NaN, so it has to be treated specially. (You might think SANE would return the comp NaN when converting out-of-range values, which would give the value we want, but somewhat strangely it does not.)

For conversion to unsigned long long, we check if the value is greater than LLONG_MAX (which is also the max comp value). If so, we subtract LLONG_MAX+1 from the floating-point value before conversion and add it back in to the integer afterward.
2021-02-16 18:44:38 -06:00
Stephen Heumann 81e152f863 Add a comparison routine for signed 64-bit numbers.
This is almost the same as ~CMP8 in SysLib, except that it does not use a static location to save the DP. This makes it slightly smaller/faster, and also makes it thread/interrupt safe.
2021-02-15 18:06:54 -06:00
Stephen Heumann 6bf27c6743 Use some improved macros for 64-bit operations in the libraries.
The new m16.int64 file contains a new "negate8" macro (for 64-bit negation), as well as an improved version of "ph8". These have been added to the individual *.macros files, but if those are regenerated, m16.int64 should be used as an input to macgen ahead of m16.ORCA (which contains the original version of ph8).
2021-02-12 20:24:37 -06:00
Stephen Heumann 91f0dcbdb9 Optimize 64-bit unsigned shifts.
They now try to shift 16 bits at a time and only go bit-by-bit for the last 15 or fewer bit positions.
2021-02-12 15:58:27 -06:00
Stephen Heumann 7ad54827a3 Add 64-bit shift routines. 2021-02-12 15:05:23 -06:00
Stephen Heumann a5d0172d82 Add signed/unsigned long long to SANE extended conversion routines.
SANE does not have built in operations for this, but all the values are exactly representable in the SANE extended format, so we just do the conversion ourselves based on the definition of the extended format.
2021-02-11 12:41:36 -06:00
Stephen Heumann c185face85 Add long long support for printf d/i/u conversions.
At this point, the long long support for the printf and scanf families of functions is complete.
2021-02-10 17:51:23 -06:00
Stephen Heumann 4f9b41938a Implement vscanf/vfscanf/vsscanf (from C99).
These are equivalent to the existing scanf calls, except that they use variable arguments from a va_list.
2021-02-09 22:09:00 -06:00
Stephen Heumann cfc3fd3468 scanf: if %c gets some characters but < field width, it's a matching failure.
EOF should not be returned in this case.

I think it shouldn't actually write anything to the destination in this case, but it currently does. That problem remains unfixed for the moment; addressing it would require us to have our own internal buffer.
2021-02-09 16:03:19 -06:00
Stephen Heumann 6626aad7f0 scanf: report EOF for 's' conversions, is appropriate.
They should be treated as input failures if they got EOF before finding a non-whitespace character.
2021-02-09 15:44:39 -06:00
Stephen Heumann bc21593507 scanf: 's' and '[' conversions should "put back" EOF if it is encountered.
This ensures that a subsequent %n conversion reports the right number of characters actually read (not including EOF).
2021-02-09 15:31:19 -06:00
Stephen Heumann 375d664ae1 Recognize 'L' as a length modifier for scanf.
Conversions using it will not actually work right yet (unless assignment is suppressed), because the necessary changes have not been made in SysFloat, but the infrastructure is now in place to allow for those changes.
2021-02-09 14:32:37 -06:00
Stephen Heumann 2f68708b47 scanf: Report EOF for o/u/x conversions, if appropriate.
This was not being reported unless assignment was suppressed, because the "sta ~eofFound" instruction was too late.

(Found based on test cases by Rich Felker.)
2021-02-09 13:14:24 -06:00
Stephen Heumann 66e1835175 scanf could trash a word of the caller's stack if it did not perform all possible assignments.
Code in ~scanf would call ~RemoveWord to remove the extra parameters, but ~RemoveWord is designed to be called from one of the ~Scan_... subroutines, which is (in effect) called by JSR and thus has an extra word on the stack for its return address. This stack misalignment caused ~RemoveWord to overwrite a word of the caller's stack when called from the code to remove extra parameters.

This could cause a crash in the following program:

#include <stdio.h>
void f(void) {
    int a,b;
    sscanf("Z", "%i%i", &a, &b);
}
int main(void) {
    f();
}
2021-02-09 13:09:04 -06:00
Stephen Heumann 61bfc70b9b scanf: for 'i' or 'd' specifiers, count a leading sign toward the field width. 2021-02-09 00:40:24 -06:00
Stephen Heumann de9f830c0c scanf: when an ordinary character cannot match due to EOF, flag an input failure.
This may cause scanf to return EOF, if no conversions have been done.

This seems to be the intent of the C standards, although the wording could be clearer. It is also consistent with all the other implementations I tested.
2021-02-08 00:19:23 -06:00
Stephen Heumann 23a27bd434 scanf: accept leading whitespace in a %% conversion.
The C standards say this should be accepted.
2021-02-08 00:08:45 -06:00
Stephen Heumann 539707344a scanf: a sign and/or 0x prefix with no following digits should be a matching failure.
This applies to + or - signs for 'd' or 'i' conversions, and to '0x' or '0X' prefixes for 'i' and 'x' conversions. (The new support for signs on u/o/x conversions did not have the problem.)

These cases were treated as if they successfully matched a number, but now they are correctly treated as a failure, causing no assignment to be done and causing the function to return without processing any further directives.

(Incidentally, the handling of '0x' without following digits is something that differs in modern C libraries: macOS libc, glibc, and musl are all different. Our new behavior should match that of musl, which I believe is what is correct under the C standards.)
2021-02-07 21:57:53 -06:00
Stephen Heumann 3ef9687b7e scanf: allow u/o/x conversions to match numbers with a leading sign.
The C standards say this should be allowed.
2021-02-07 18:45:52 -06:00
Stephen Heumann aa1351f84d Add support for long long in scanf.
The 'll' length modifier is now fully supported for the d, i, o, u, x, and X conversion specifiers. The 'n' conversion specifier can also store to a long long, but the value is still limited to 64k. The 'j' length modifier (for intmax_t) is also now treated as specifying a 64-bit value.
2021-02-07 08:35:18 -06:00
Stephen Heumann 506f9fa965 Implement strtoll and strtoull (aka strtoimax and strtoumax).
This is a fairly straightforward adaptation of the strtol/strtoul code. The multiplication routine is modified to return the next 16 bits in X so that strtoull can detect overflows.
2021-02-06 14:37:42 -06:00
Stephen Heumann 6635346ae8 Implement llabs and imaxabs functions.
These give the absolute value of 64-bit numbers.
2021-02-06 00:11:44 -06:00
Stephen Heumann b072f5d042 Implement lldiv and imaxdiv functions.
These do 64-bit division and return a struct with the quotient and remainder.
2021-02-05 18:11:37 -06:00
Stephen Heumann d1d0358e4b Add 64-bit division routines.
The ~CDIV8 routine is the same as ~DIV8 in SysLib, except that it negates the remainder if the numerator is negative. This complies with the definition of the % operator in C, which gives negative (or 0) remainders if the numerator is negative, such that (a/b)*b + a%b equals a.

The ~UDIV8 routine is an unsigned version, using the same core division loop but without the sign handling.
2021-02-05 12:42:22 -06:00
Stephen Heumann 2bb5361c24 Add a new file for 64-bit integer routines, initially with an unsigned multiply.
This file will be expanded with more support routines as needed.

The unsigned multiply routine uses the core multiplication loop from the 64-bit signed multiply routine in SysLib, with new entry/exit code for the unsigned version.
2021-02-04 23:58:54 -06:00
Stephen Heumann 80dbf0c34c printf/scanf: Add 'P' conversion specifier as a synonym for 'b'.
The 'b' conversion specifier is an ORCA extension to support p-strings, but lower case letters are reserved for use in future C standards, and in fact C23 is likely to use 'b' for integers in binary notation. For the time being, 'b' is still supported with its existing meaning, but it is considered deprecated. It may be removed in the future if we want to support the C23 behavior. Upper-case letters are available to use for extensions, so 'P' should remain available for our use.
2021-01-30 19:53:50 -06:00
Stephen Heumann bd1e822a43 printf: In d/i/o/u/x/X conversions with a precision specified, the 0 flag should be ignored.
For example, the output of the following should have only two leading zeros (and the rest of the field width padded with spaces):

#include <stdio.h>

int main(void) {
        printf("%016.5i\n", 123);
}
2021-01-30 17:51:55 -06:00
Stephen Heumann 7c4141f03d printf: properly handle negative field width or precision arguments.
If the field width is given by an argument (when * is used in the format specification) and the value given is negative, it should be treated like a positive field width with the - flag. If a negative argument is given for the precision, it should be treated as if the precision was not specified.

The following is an example of code that behaved incorrectly:

#include <stdio.h>
int main(void) {
        printf("%*iXX\n", -50, 123);
}
2021-01-30 16:55:27 -06:00
Stephen Heumann 71a25f0fef printf: %#x or %#X conversions should not print the 0x/0X prefix if the value is 0.
This is the behavior specified in all versions of the C standards.
2021-01-30 16:04:18 -06:00
Stephen Heumann 37c38a7077 Add partial support for 64-bit 'long long' types in printf.
Currently, it works as follows:
*The 'll' length modifier is recognized. 'j' (for intmax_t) is also now treated as denoting a 64-bit type.
*The 'x', 'X', and 'o' format specifiers have full support for 64-bit types.
*The 'n' format specifier can write a 64-bit integer, but only actually supports values up to 64k.
*The 'd', 'i', and 'u' format specifiers can consume a 64-bit value, but they only print it correctly if it is within the range of 32-bit long/unsigned long.
2021-01-30 14:41:07 -06:00
Stephen Heumann e9de42d6c4 fopen: do not require read access when opening a file for append only.
This can cause an error if the file's permissions deny read access.
2020-02-17 19:49:18 -06:00
Stephen Heumann 717cf99071 Detect invalid base values in strtol and strtoul.
They will now return 0 and set errno to EINVAL if an invalid base value (anything other than 0 or 2..36) is detected.

This behavior is required by POSIX. It's not required by the C standards (which leave the behavior in this case undefined), but it seems reasonable to do.
2020-02-17 17:39:36 -06:00
Stephen Heumann e5360c9605 Spellcheck comments. 2020-02-16 13:29:53 -06:00
Stephen Heumann 573bc6efa9 Use consistent indentation within files.
Tabs have been expanded to spaces in several files that use mainly spaces for indentation.

The files ctype.asm, stdio.asm, and string.asm consistently use tabs for indentation. The tabs in these files have been left alone, except that a few tabs between sentences in comments were changed to spaces.  One space-indented line in stdio.asm was changed to use a tab.
2020-02-16 13:28:18 -06:00
Stephen Heumann 44dfc1d1d6 Prevent localtime() from potentially giving incorrect tm_isdst values.
This could happen when it was called for a time other than the present, because it set tm_isdst based on the current value of the DST flag in BRAM, which is valid only for the current time.

Now it works as follows: If localtime() is passed the time_t value that was produced by the most recent call to time(), it gives the DST setting in effect at the time of that call.  Otherwise, it sets tm_isdst to -1, indicating that the correct value is unknown.

This is about the best we can do without having a full timezone library/database. It should give the right tm_isdst value in probably the most common case, and avoids giving an incorrect value in any case (assuming the system's DST flag is right).

This fixes #18.
2020-02-02 12:52:42 -06:00
Stephen Heumann 9af1c093cb Ensure tmpfile() doesn't access a file created by someone else.
This could happen due to a race condition, which shouldn't generally be an issue on the GS but is at least theoretically possible under GNO or Golden Gate.
2020-01-31 12:47:34 -06:00
Stephen Heumann c439f2e3ea Make tmpnam() return the pointer passed to it, if non-null.
This is what the standards call for. It was previously always returning a pointer to its internal buffer.
2020-01-31 12:45:02 -06:00
Stephen Heumann 27a32d82bd Allow 'b' to come before '+' in freopen modes (e.g. "wb+").
Previously, only forms like "w+b" worked.
2020-01-30 21:16:48 -06:00
Stephen Heumann c77c5927d9 Support "x" in fopen()/freopen() mode strings (C11).
If the mode string ends in "x", opening a file for writing will fail if the file already exists.
2020-01-30 20:15:45 -06:00
Stephen Heumann bd6d517854 Note that ~RemoveWord is used by scanf, not printf. 2020-01-30 18:51:59 -06:00
Stephen Heumann 8490da9d85 Allow -2147483648 (LONG_MIN) as valid input to strtol(), not setting errno.
This is what other implementations do and seems to be the intent of the standards, although the wording isn't entirely clear.
2020-01-24 12:25:01 -06:00
Stephen Heumann 14554fcdc7 Make strtol() and strtoul() set the right end pointer in error cases.
Previously, they often did not do this. Now they do, as follows:

If there was a sequence of the expected numeric form, then they fully parse that sequence and give a pointer past the end of it, even if the number was out of range.  If there was not a sequence of the expected form, they give the starting pointer that they were passed in.
2020-01-23 23:47:55 -06:00
Stephen Heumann ebbb5b73ed Allow strtoul to take numbers with a minus sign.
The effect of this is to negate the number in the unsigned long type before returning it.
2020-01-23 21:50:11 -06:00
Stephen Heumann 599c1e3c7b Fix problem where strtol would accept invalid strings like "- +53".
This stemmed from its calling strtoul internally, causing it to accept extra while space and/or + signs. The fix is to have an alternate entry point for strtoul that skips that processing.
2020-01-23 20:42:25 -06:00
Stephen Heumann ee1b7e606d Implement quick_exit() and at_quick_exit() from C11.
Also, make all the exit functions quit via RTL if #pragma rtl was used. This fixes #19.
2020-01-23 18:43:20 -06:00
Stephen Heumann 07011e5b05 Fix issue causing potential stack corruption in scanf().
This could happen if a scan error occurred and certain conversion specifiers containing the % character in a scanset (e.g. %4[%]) appeared as subsequent elements in the format string. The fix is to more thoroughly parse the format string when cleaning up after a scan error.

This fixes #26.
2020-01-22 07:40:40 -06:00
Stephen Heumann d89096236e Ensure that strtok returns NULL after reaching the end of the string.
It had been doing a null pointer dereference and effectively treating memory locations starting from 0 as the continuation of the string, potentially producing inappropriate results depending on what they contained.
2020-01-21 17:12:54 -06:00
Stephen Heumann 887d66d537 Implement aligned_alloc function (C11).
This allocates memory with a specified alignment. Currently, the only allowed alignment value is 1.
2020-01-12 18:54:07 -06:00
Stephen Heumann 571c601b66 strtoul: return 0 when given an empty string, as required by the C standards.
The issue was introduced in commit 6e9790667.

errno is now set to EINVAL in this case. (This is not required by the C standards, but is consistent with various other implementations.)

This fixes the cases in #23 related to strtol() and strtoul().
2019-06-16 20:26:13 -05:00
Stephen Heumann 7a20f5f71d strtoul: don't try to parse initial '0x' as hex prefix unless base is 0 or 16.
In other bases, the 'x' either ends parsing of the number string or (in base 34 and larger) is a digit.

Also, ensure only ASCII characters (with high bit clear) are accepted in all situations.
2018-09-13 18:28:02 -05:00