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.
This uses an approximation based on the Stirling series for most positive values, but uses separate rational approximations for greater accuracy near 1 and 2. A reflection formula is used for negative values.
These are similar enough that they can use the same code with just a few conditionals, which saves space.
(This same code can also be used for binary when that is added.)
These print a floating-point number in a hexadecimal format, with several variations based on the conversion specification:
Upper or lower case letters (%A or %a)
Number of digits after decimal point (precision)
Use + sign for positive numbers? (+ flag)
Use leading space for positive numbers (space flag)
Include decimal point when there are no more digits? (# flag)
Pad with leading zeros after 0x? (0 flag)
If no precision is given, enough digits are printed to represent the value exactly. Otherwise, the value is correctly rounded based on the rounding mode.
This is what the standards require. Previously, the '0' flag would effectively override '-'.
Here is a program that demonstrates the problem:
#include <stdio.h>
int main(void) {
printf("|%-020d|\n", 123);
printf("|%0-20d|\n", 123);
printf("|%0*d|\n", -20, 123);
}
This tries to carefully follow the C and IEEE standards regarding rounding, exceptions, etc. Like the other ORCA/C <math.h> functions, there is really just one version that has extended precision, so double rounding is still possible if the result gets assigned to a float or double variable.
In addition to the tests I added to the ORCA/C test suite, I have also tested this against (somewhat modified versions of) the following:
*FreeBSD fma tests by David Schultz:
https://github.com/freebsd/freebsd-src/blob/release/9.3.0/tools/regression/lib/msun/test-fma.c
*Tests by Bruno Haible, in the Gnulib test suite and attached to this bug report:
https://sourceware.org/bugzilla/show_bug.cgi?id=13304
Previously, the functions registered with atexit() would be called with data bank corresponding to the blank segment, which is correct in the small memory model but not necessarily in the large memory model. This could cause memory corruption or misbehavior for certain operations accessing global variables.
ORCA/C's tmpnam() implementation is designed to use prefix 3 if it is defined and the path is sufficiently short. I think it was intended to allow up to a 15-character disk name to be specified, but it used a GS/OS result buffer size of 16, which only leaves 12 characters for the path, including initial and terminal : characters. As such, only up to a 10-character disk name could be used. This patch increases the specified buffer size to 21, allowing for a 17-character path that can encompass a 15-character disk name.
If the last element in the range being sorted has the smallest value, rsort can be called with last set to first-1, i.e. pointing to (what would be) the element before the first one. But with large enough element sizes and appropriate address values, this address computation can wrap around and produce a negative value for last. We need to treat such a value as being less than first, so it terminates that branch of the recursive computation. Previously, we were doing an unsigned comparison, so such a last value would be treated as greater than first and would lead to improper behavior including memory trashing.
Here is an example program that can show this (depending on memory layout):
#pragma memorymodel 1
#include <stdlib.h>
#include <stdio.h>
#define PADSIZE 2000000 /* may need to adjust based on memory size/layout */
#define N 2
struct big {
int i;
char pad[PADSIZE];
};
int cmp(const void *p1, const void *p2) {
int a = ((struct big *)p1)->i;
int b = ((struct big *)p2)->i;
return (a < b) ? -1 : (a > b);
}
int main(void) {
int j;
struct big *p = malloc(sizeof(struct big) * N);
if (!p)
return 0;
for (j = 0; j < N; j++) {
p[j].i = N-j;
}
qsort(p, N, sizeof(struct big), cmp);
for (j = 0; j < N; j++) {
printf("%i\n", p[j].i);
}
}
It could have O(n) recursion depth for some inputs (e.g. if already sorted or reverse sorted), which could easily cause stack overflows.
Now, recursion is only used for the smaller of the two subarrays at each step, so the maximum recursion depth is bounded to log2(n).
When using the large memory model, the wrong data bank (that of the library code rather than the program's static data) would be in place when the comparison function was called, potentially leading to data corruption or other incorrect behavior.
This code did not previously work properly, because the X register value was overwritten within the loop. This could result in incorrect behavior such as hanging or data corruption when using qsort with element sizes >= 64KiB.
This is used by the new ORCA/C debugging option to check for illegal use of null pointers. It is similar to an existing routine in PasLib used by ORCA/Pascal's similar checks.
This ensures use of the Time Tool is fully under the control of the programmer, rather than potentially being affected by other things that may load it (like the Time Zone CDev). It also avoids calls to tiStatus in the default non-Time Tool code paths, and thereby allows them to work under Golden Gate.
The UTC time may be several hours before or after local time, and therefore the UTC time/date may be slightly outside the limits of what can be represented as a local time/date. This is now handled correctly.
This also more generally fixes handling of negative seconds/minutes/hours, which is also applicable to mktime().
ORCA/C uses an unsigned 32-bit time_t which should give a range up to 2105, but calculations on it were being done with signed types, causing them not to work correctly beyond 2036-2038. Now the factor routine, mktime(), and time() should work up to 2105. (In the case of time(), this assumes ReadTimeHex reports the time correctly.)
The factor routine actually computes a 64-bit time value. Currently, the rest of the code only takes the bottom 32 bits of it, but this could be extended if we ever wanted to switch to 64-bit time_t.
It was clearly supposed to be 1 Jan 1970, but it's actually not, probably because the number of days from 1 Jan 1900 to 1 Jan 1970 was miscalculated. Changing it now could potentially cause compatibility issues (especially for GNO, which uses time_t in some kernel call interfaces and file formats), so for now it is left as is and just documented appropriately.
Nothing in the C standards requires the time_t epoch to be 1 Jan 1970, so this does not cause any standards-compliance problem for the C standards. (It is different from POSIX, though.)
This is used for the %z conversion specifier (giving the time zone offset in +-HHMM format). The %Z conversion specifier (giving the locale's time zone name or abbreviation) also prints the same thing for now.
As with gmtime, this will only use the Time Tool Set if it has already been started. Otherwise, these conversions simply produce no output.
If the Time Tool Set (tool 56, by Geoff Weiss) is present and active, gmtime will use it (plus the DST flag) to determine the local time offset from UTC, allowing it to produce the correct UTC time. If not, it will still treat local time as being equal to UTC, like it did previously.
The library code will not try to load or start the Time Tool Set, so the program will have to do that before calling gmtime if it wants to use this functionality.
Previously, 1-4 low-order bits of the input value were essentially ignored when calculating the numerator, but used to some degree when calculating the denominator. This would lead to the calculated tgamma values decreasing slightly over the range of several consecutive input values (when they should increase). Now, the low-order bits of the input value are effectively just rounded away. This should give slightly more accurate results, and greatly reduces the frequency of cases where consecutive output values go in the wrong direction.
This uses an approximation based on the Stirling series for large enough x (for which it is highly accurate). For smaller x, identities are used to express gamma(x) in terms of gamma(x+1) or gamma(1-x), ultimately letting the Stirling series approximation be used.
This implementation is based on the approximations given in the following paper:
W. J. Cody, Rational Chebyshev Approximations for the Error Function, Mathematics of Computation, Vol. 23, No. 107 (Jul., 1969), pp. 631-637.
Per the paper, the approximations have maximal relative error of 6e-19 or lower (although I have not verified what the figure is for this actual implementation).
See also Cody's FORTRAN implementation based on the same approach:
https://netlib.org/specfun/erf
The new CDev root code generated by ORCA/C will now branch to this code after each CDev call, giving it an opportunity to clean up if necessary. Specifically, it will dispose of the user ID allocated for the CDev if it is going away after this call. There are several cases where this occurs, which need to be detected based on the message code passed to the CDev and in some cases other factors.
Bugs fixes:
*fgets() would write 2 bytes in the buffer if called with n=1 (should be 1).
*fgets() would write 2 bytes in the buffer if it encountered EOF before reading any characters, but the EOF flag had not previously been set. (It should not modify the buffer in this case.)
*fgets() and gets() would return NULL if EOF was encountered after reading one or more characters. (They should return the buffer pointer).
The direction specified by the offset was essentially reversed when calling lseek with whence==2 (seek to offset from end of file). Therefore, specifying a negative offset with whence==2 would fail, rather than seeking before the end of the file as it should.
(The ORCA/C manual is not totally clear about this behavior, but the new behavior is consistent with the POSIX spec and all other implementations I'm aware of, including traditional Unix and APW C. Note that Unix/POSIX allows seeking beyond the end of the file, but GS/OS does not.)
There are also improvements to error handling, so lseek consistently reports EINVAL for invalid offsets.