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.
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.
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);
}
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);
}
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.
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.
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.
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.
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.
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.
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.
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.
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.
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().
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.
They could previously give the wrong sign on the remainder in certain cases where one or both of the arguments were negative, because they were using the wrong condition to decide whether to negate it.
This exits the programs without calling atexit functions and possibly without doing other clean-up operations. In ORCA/C, it is functionally identical to _exit().
perror() should write only a single new-line. Also, it should not write the prefix string, colon and space if the prefix string pointer is NULL or if it points to an empty string.
Previously, it just ran an Execute shell call with NULL as the command-line pointer.
The fix is to still call Execute, but with an empty string as the command line, and then check if the call gave an error. If running under plain GS/OS, this gives an error for an unknown system call, whereas both ORCA/APW and GNO shells will return with no error in this case. (Golden Gate doesn't implement the Execute shell call, so it also gives an error and will report no command processor available.)
This fixes issue #25.
These all behave identically to 'f'. Note that none of these accept the hexadecimal floating-point representation as input, which they should under C99.
'F' is currently treated identically to 'f'. This should be a correct implementation for 'F' under C99. (It's not quite correct for 'f', which should print "inf" or "nan" in lower case according to C99.)
'A' and 'a' are not correctly formatted (they are currently treated identically to 'E' and 'e', rather than using the hexadecimal floating-point representation specified by C99), but at least they print the number in some form and consume the correct number of bytes so that the stack isn't corrupted and subsequent conversion specifications print the right values.
The floating-point formats are also moved to the top of the list of conversion specifiers to check, which means they are checked last. This should marginally speed up the integer cases.
'z' corresponds to size_t, 't' to ptrdiff_t, and 'j' to intmax_t. In ORCA/C, these are all 32-bit types, so these size modifiers are equivalent to 'l'. (Note that C99/C11 require intmax_t to be at least 64-bit, but that is not currently the case in ORCA/C since there is no 64-bit integer type.)
The reverted changes relate mainly to adding a second character position in the putback buffer, but the library with those changes crashes on basic stdio operations like printing a string.
For now, this patch reverts stdio to a working, tested version. If the reverted changes are valuable, they can be fixed and then reintroduced later.