Commit Graph

196 Commits

Author SHA1 Message Date
Stephen Heumann
3eb8a9cb55 Fix bug where ftell would inappropriately change the file mark.
ftell would set the mark as if the buffer and putback were being discarded, but not actually discard them. This resulted in characters being reread once the end of the buffer was reached.

Here is an example that illustrates the problem:

#include <stdio.h>
#include <string.h>
char buf[100];
int main(void) {
        FILE *f = fopen("somefile","r"); // a file with some text
        if (!f) return 0;
        setvbuf(f, 0L, _IOFBF, 14); // to see problem sooner
        fgets(buf, 10, f);
        printf("first read : %s\n", buf);
        ftell(f);
        memset(buf, 0, sizeof(buf));
        fgets(buf, 10, f);
        printf("second read: %s\n", buf);]
}
2022-07-02 22:05:40 -05:00
Stephen Heumann
36808404ca Fix fread bug causing it to discard buffered data.
If you read from a file using fgetc (or another function that calls it internally), and then later read from it using fread, any data left in the buffer from fgetc would be skipped over. The pattern causing this to happen was as follows:

fread called ~SetFilePointer, which (if there was buffered data) called fseek(f, 0, SEEK_CUR). fseek would call fflush, which calls ~InitBuffer. That zeros out the buffer count. fseek then calls ftell, which gets the current mark from GS/OS and then subtracts the buffer count.  But the count was set to 0 in ~InitBuffer, so ftell reflects the position after any previously buffered data. fseek sets the mark to the position returned by ftell, i.e. after any data that was previously read and buffered, so that data would get skipped over. (Before commits 0047b755c9 and c95bfc19fb the behavior would be somewhat different due to the issue with ~InitBuffer that they addressed, but you could still get similar symptoms.)

The fix is simply to use the buffered data (if any), rather than discarding it.

Here is a test program illustrating the problem:

#include <stdio.h>
char buf[BUFSIZ+1];
#define RECSIZE 2
int main(void) {
        FILE *f = fopen("somefile","r"); // a file with some data
        if (!f) return 0;
        fgetc(f);
        size_t count = fread(buf, RECSIZE, BUFSIZ/RECSIZE, f);
        printf("read %zu records: %s\n", count, buf);
}
2022-07-02 18:24:57 -05:00
Stephen Heumann
84f471474a Use newer, more efficient ph2/ph4 macros throughout ORCALib.
These push DP values with pei, rather than lda+pha as in the old versions of the macros.
2022-06-30 19:01:47 -05:00
Stephen Heumann
c95bfc19fb Fix a logic error.
There was a problem with the fix in commit 0047b755c9660: an instruction should have had an immediate operand, but did not because it was missing the #. This might cause the code to behave incorrectly, depending on memory contents.
2022-06-28 22:25:10 -05:00
Stephen Heumann
a2b3d4541a fread fixes.
This includes changes to fread to fix two problems. The first is that fread would ignore and discard characters put back with ungetc(). The second is that it would generally return the wrong value if reading from stdin with an element size other than 1 (it would return the count of bytes, not elements).

This fixes #9 (the first problem mentioned above).
2022-06-27 18:24:52 -05:00
Stephen Heumann
1f88a38e2e Clear the EOF flag on successful calls to ungetc().
This is specified by the C standards.
2022-06-27 17:59:21 -05:00
Stephen Heumann
38666ee111 Restore changes to allow ungetc of byte values 0x80 through 0xFF.
These are the stdio.asm changes that were present in the beta source code on Opus ][, but had been reverted in commit e3c0c962d4. As it turns out, the changes to stdio.asm were OK--the issue was simply that the definitions of stdin/stdout/stderr and the associated initialization code in vars.asm had not been updated to account for the new version of the FILE structure. That has now been done, allowing the changes to work properly.

This fixes #7.
2022-06-27 17:58:23 -05:00
Stephen Heumann
7c2fb70c4a freopen improvements
This adds a check for the filename argument being null, in which case it bails out and returns NULL. Previously, it would just dereference the null pointer and treat the contents of memory location 0 as a filename, with unpredictable results. A null filename indicates freopen should try to reopen the same file with a different mode, but the degree of support for that is implementation-defined. We still don't really support it, but at least this will report the failure and avoid unpredictable behavior.

It also removes some unused code at the end, but still forces fputc and fgetc to be linked in. These are needed because there are weak references to them in putchar and getchar, which may need to be used if stdin/stdout have been reopened.
2022-06-26 21:20:23 -05:00
Stephen Heumann
8cfb73a474 Force the file mark to EOF whenever writing to a stream in append mode.
This is what the standards require. Note that the mark is only set to EOF when actually writing to the underlying file, not merely buffering data to write later. This is consistent with the usual POSIX implementation using O_APPEND.
2022-06-26 18:59:57 -05:00
Stephen Heumann
0047b755c9 Fix bug with fseek(..., SEEK_CUR) on read-only streams.
This would seek to the wrong location, and in some cases try to seek before the beginning of the file, leading to an error condition.

The problem stemmed from fseek calling fflush, which sets up the stream's buffer state in a way appropriate for writing but not for reading. It then calls ftell, which (for a read-only stream) would misinterpret this state and miscalculate the current position.

The fix is to make fflush work correctly on a read-only stream, setting up the state for reading. (User code calling fflush on a read-only stream would be undefined behavior, but since fseek does it we need to make it work.)

This fixes #6.
2022-06-26 14:35:56 -05:00
Stephen Heumann
3581d20a7c Standardize indentation using spaces.
Most files already used spaces, but three used tabs for indentation. These have been converted to use spaces. This allows the files to be displayed with proper formatting in modern editors and on GitHub. It also removes any dependency on SysTabs settings when assembling them.

The spacing in fpextra.asm was also modified to use standard column positions.

There are no non-whitespace changes in this commit.
2022-06-25 18:27:20 -05:00
Stephen Heumann
ab2f17c249 Clear the IO error indicator as part of rewind().
The C standards require it to do this, in addition to calling fseek.

Here is a test that can show the issue (in a realistic program, the indicator would be set due to an actual IO error, but for testing purposes this just sets it explicitly):

#include <stdio.h>
int main(void) {
        FILE *f = tmpfile();
        if (!f) return 0;
        f->_flag |= _IOERR;
        if (!ferror(f)) puts("bad ferror");
        rewind(f);
        if (ferror(f)) puts("rewind does not reset ferror");
        fclose(f);
}
2022-06-24 18:36:25 -05:00
Stephen Heumann
28f653693c Update GNO version makefile to include new source files. 2022-01-10 19:10:50 -06:00
Stephen Heumann
522a6fc3f8 Merge branch 'master' into gno-version 2022-01-10 19:07:55 -06:00
Stephen Heumann
997e430562 Implement asinh().
This is similar to the approach recommended in Apple Numerics Manual Ch. 9, except that there is an added case for large values that would otherwise cause an overflow or spuriously report underflow.
2021-12-24 15:56:36 -06:00
Stephen Heumann
b62940404f Implement atanh().
This basically follows the approach recommended in Apple Numerics Manual Ch. 9.
2021-12-23 18:30:52 -06:00
Stephen Heumann
818707ed8c Use a more accurate implementation of cbrt().
The previous simple one could be wrong in several low-order digits due to the inaccuracy in the representation of the exponent (1/3). This version effectively breaks the number up into the form a*8^b, computes the cube root of 8^b exactly (i.e. 2^b), and uses the slightly inaccurate exponentiation only for a.
2021-12-21 19:11:18 -06:00
Stephen Heumann
a45f531fe6 Implement hypot().
This uses the obvious calculation, except with scaling to avoid unnecessary overflow/underflow.

There is a discussion of hypot implementations in C. Borges, An Improved Algorithm for hypot(a,b) (https://arxiv.org/pdf/1904.09481.pdf). This implementation is similar to the "Naive (Unfused)" version discussed in that paper. As the paper notes, it is possible to get better accuracy by adding a correction term, but the "naive" version is already reasonably good, so we skip the correction in the interest of code size and speed.
2021-12-20 21:52:48 -06:00
Stephen Heumann
b01800ff77 Fix rounding issues introduced by SANE bug workarounds.
The lrint functions could give the wrong result for negative numbers in upward/downward rounding modes. Casts to comp could also have different rounding behavior.
2021-11-30 20:19:57 -06:00
Stephen Heumann
b6690c4826 Implement acosh().
This is basically the implementation recommended in Apple Numerics Manual Ch. 9, except that there is an added case for large values that would otherwise cause an overflow.
2021-11-30 19:15:54 -06:00
Stephen Heumann
eddf778f09 Implement llround(). 2021-11-28 18:30:20 -06:00
Stephen Heumann
66cfa0d406 Remove unnecessary code in lround(). 2021-11-28 18:30:01 -06:00
Stephen Heumann
e00c21dd70 Work around bug in FX2C and FX2L.
These SANE operations can sometimes return incorrect values for certain negative integers such as -2147483648 and -53021371269120 (numbers with at least 16 low-order zero bits in their two's-complement representation). To work around this, we now avoid calling FX2C or FX2L on negative numbers, generally by saving and restoring the sign separately.

These workarounds are used in several of the new <math.h> rounding functions, and also for code that converts floating-point values to comp or long long. There are some places in SysFloat that should be patched similarly, so we may still hit this problem in certain situations until that is done.
2021-11-28 14:18:27 -06:00
Stephen Heumann
503182e435 Initial implementation of lround().
This should work, and mostly does. However, it is affected by a bug in FX2L (and FX2C) which can sometimes give the wrong results for certain negative integers (such as -2147483648). I believe this can occur when at least the lower 16 bits if the integer (in two's-complement representation) are zeros.
2021-11-27 17:52:46 -06:00
Stephen Heumann
88a7bbebcc Implement round().
This is a bit more complex than other rounding functions, because it rounds to nearest but always away from zero in halfway cases, which is not a rounding direction directly supported by SANE.
2021-11-27 15:55:54 -06:00
Stephen Heumann
d08773af0d Implement nextafter and nexttoward.
Unlike most of the math functions, these actually have separate implementations for float/double/long double.
2021-11-26 12:47:02 -06:00
Stephen Heumann
6364d0f48f Implement llrint. 2021-11-23 21:16:12 -06:00
Stephen Heumann
ce05615a63 Implement fmax and fmin. 2021-11-23 18:54:18 -06:00
Stephen Heumann
14908ebcd6 Implement the nan() function.
This parses the NaN code string itself, but it should give equivalent behavior to the SANE parser.
2021-11-22 21:59:50 -06:00
Stephen Heumann
c025bba177 Implement nearbyint and fdim. 2021-11-22 19:25:25 -06:00
Stephen Heumann
2334443437 Implement scalbln.
This differs from scalbn in that the exponent has type long. When scaling an extended value, exponents slightly outside the range of int can actually be used meaningfully. We address this by doing multiple SCALBX calls (at most 2) in a loop.
2021-11-21 20:10:36 -06:00
Stephen Heumann
268892b671 Add float and long double versions of functions in SysFloat.
Most of these actually just jump to the existing functions, since they really use extended precision anyway. The exception is the modf functions, which need a separate implementation for each type because they store a value through a pointer to that type.
2021-11-21 14:34:52 -06:00
Stephen Heumann
3ec8a8797f Implement some of the math functions added in C99.
The functions implemented so far are largely the ones that map (nearly) directly to SANE calls.

Note that C99 specifies separate float/double/long double versions of each of these functions, but under ORCA/C they generally use the same code.
2021-11-20 19:24:51 -06:00
Stephen Heumann
fb5683a14d Add a function to implement the FP comparison macros in <math.h>.
These macros differ from the normal comparison operators in that they will not signal invalid due to the operands being unordered. However, this implementation will still signal invalid for SNaNs. That is clearly OK according to the wording in draft C23. C17 and earlier do not mention that possibility, but they do not really specify the behavior of SNaNs in general.
2021-11-02 21:56:30 -05:00
Stephen Heumann
b8605de33f Add a new helper function to record varargs info when va_end is called.
This will be used in conjunction with the new implementation of variable arguments, where they are not removed from the stack until the end of the function.
2021-10-23 21:08:30 -05:00
Stephen Heumann
e3c9bc96bc Add implementation of the <uchar.h> functions. 2021-10-03 16:02:30 -05:00
Stephen Heumann
ae504c6e4f Add support for EILSEQ errno value.
EILSEQ is required by C95 and later.
2021-10-02 14:34:35 -05:00
Stephen Heumann
09942026a8 Add mblen function.
The currently implementation assumes we do not actually support a multi-byte character set for char strings.
2021-09-30 18:38:57 -05:00
Stephen Heumann
3a847d245e Add strcoll and strxfrm functions.
This is currently a minimalistic implementation in which strcoll always sorts strings the same way as strcmp.
2021-09-30 18:37:54 -05:00
Stephen Heumann
512fadeff0 Add an implementation of the <locale.h> functions.
This is currently a minimalistic implementation, which only supports the C locale.
2021-09-30 18:34:54 -05:00
Stephen Heumann
5ad86f4a0b Implement strftime.
This is intended to be a complete implementation of strftime as specified in C17, although it lacks meaningful support for time zones or non-C locales.
2021-09-26 20:31:15 -05:00
Stephen Heumann
379f2f93ad Fix bug causing data corruption when assigning to multiple structs.
This affects code where multiple structs or unions are assigned by successive = operators in one expression, e.g. "s1=s2=s3". The middle struct assignment(s) would use the ~Move2 or ~LongMove2 helper functions (for <64k or >=64k moves, respectively). These functions are supposed to leave the destination pointer on the stack so it can be used as the source of a subsequent move, but they both had bugs where they could modify dest and leave that modified value on the stack, which would cause subsequent moves to use the wrong source location. In the case of ~Move2, this only happened if the size was odd.

Here is a program that demonstrated the problems with both functions:

#pragma memorymodel 1
#include <stdio.h>

struct S1 {
        char s[80000];
} a,b,c;

int main(void) {
        struct S2 {
                int x,y;
                char z;
        } d,e,f;

        c.s[66000] = 123;
        f.y = 5678;

        a = b = c;
        d = e = f;

        printf("%i %i %i\n", a.s[66000], b.s[66000], c.s[66000]);
        printf("%i %i %i\n", d.y, e.y, f.y);
}
2021-09-17 18:25:32 -05:00
Stephen Heumann
3dac15e6b9 Update GNO version makefile to include new source files. 2021-09-03 22:03:17 -05:00
Stephen Heumann
cc6ee968f3 Merge branch 'master' into gno-version 2021-09-03 21:59:40 -05:00
Stephen Heumann
ee395c371b Update misleading comments that referred to stddef instead of stdlib. 2021-09-02 17:41:31 -05:00
Stephen Heumann
9937ef7003 In system(), avoid depending on the data bank value at entry.
The previous code relied on the data bank value at entry being the bank that contained the library code. This might not be the case when called from code using the large memory model, which could lead to the wrong value being returned.
2021-09-02 17:38:38 -05:00
Stephen Heumann
869f8726a6 Add __assert2 function to include the function name when reporting assertion failures.
This is required by C99 and later.

The old __assert function is retained for compatibility with existing object code.
2021-08-24 18:21:39 -05:00
Stephen Heumann
690ee7137f Add a function to get the proper value of CLOCKS_PER_SEC.
This may be either 50 or 60, depending on the system's video frequency setting (50Hz PAL or 60Hz NTSC). The video setting can be determined by inspecting bit 4 of the LANGSEL soft switch, documented in Appendix E of the Apple IIGS Firmware Reference.
2021-08-23 19:00:09 -05:00
Stephen Heumann
79201198a1 Fix a bug in memset.
If the upper byte of the int argument was nonzero, it could write the wrong value (the OR of the upper and lower bytes). It should convert the value to unsigned char, i.e. just use the lower byte.
2021-03-10 20:08:36 -06:00
Stephen Heumann
9e727697d3 Add a helper function to get the sign bit. 2021-03-09 00:24:26 -06:00