llvm-mos / llvm-mos-sdk

SDK for developing with the llvm-mos compiler
https://www.llvm-mos.org
Other
255 stars 52 forks source link

Implement `atari` `fgetpos` and `fsetpos` using `NOTE`/`POINT` #334

Open mysterymath opened 1 month ago

mysterymath commented 1 month ago

The Atari DOS NOTE/POINT functionality isn't expressive enough to implement fseek, since the former use sector/offset, while the latter uses byte offsets from start/end of file. It is expressive enough to implement fgetpos and fsetpos, since these operate on an opaque fpos_t value, which could be interpreted as a sector/offset pair.

pfusik commented 2 weeks ago

I'd like to implement this.

pfusik commented 2 weeks ago

How to handle FILE buffer? NOTE will tell us sector/offset after the whole buffer we read. Writing is easier: just flush the buffer, then NOTE.

I can only think of using NOTE at every entry of fill_buffer. The time overhead should be acceptable. Unfortunately, that grows all binaries that do not use fgetpos. Then fsetpos does a POINT followed by skipping as many bytes as we had in the buffer. Possibly by just filling the buffer and moving the pointer.

mysterymath commented 2 weeks ago

NOTE-ing on every fill_buffer SGTM; there's already quite a bit of stuff brought in just for standards compliance, and it shouldn't break the bank comparatively.

pfusik commented 2 weeks ago

I'm thinking of:

typedef struct {
    unsigned short sector;          // at the beginning of the buffer
    unsigned char offset_in_sector; // at the beginning of the buffer
    size_t offset_in_buffer;        // size_t because of setvbuf
} fpos_t;
mysterymath commented 2 weeks ago

I'm thinking of:

typedef struct {
    unsigned short sector;          // at the beginning of the buffer
    unsigned char offset_in_sector; // at the beginning of the buffer
    size_t offset_in_buffer;        // size_t because of setvbuf
} fpos_t;

Providing a custom fpos_t type per target may be... tricky, since stdio-full.c is currently built as part of common. But code also currently assumes that it's a file offset, and that's probably not tenable long-term. Some design and experimentation work is probably prudent around this.

pfusik commented 2 weeks ago

Another idea (in pseudocode):

int fgetpos(FILE *stream, fpos_t *pos)
{
    if (stream->bufidx == 0)
        *pos = stream->position_at_last_fill_buffer;
    else {
        POINT(stream->position_at_last_fill_buffer);
        SKIP(stream->bufidx); // implemented as READ to buffer
        *pos = NOTE();
    }
}

This only needs 24-bit fpos_t. For the default BUFSIZ=256 it would re-read a sector or two. But no need to do that in fsetpos.