100 lines
3.7 KiB
C
100 lines
3.7 KiB
C
|
|
/**
|
||
|
|
* @file disk.h
|
||
|
|
* @brief The group F file channels: DOPEN, DCLOSE, PRINT#, INPUT#, GET#.
|
||
|
|
*
|
||
|
|
* A Commodore's disk verbs address a 1541 over the serial bus. There is no 1541,
|
||
|
|
* so what these mean here is the nearest thing a filesystem offers, and the
|
||
|
|
* verbs that mean nothing without the hardware are refused by name rather than
|
||
|
|
* faked -- see TODO.md section 5.
|
||
|
|
*
|
||
|
|
* Channels are the interpreter's, not the host's: a program that opens a file
|
||
|
|
* and is then stepped by a game's frame loop keeps its channel across frames,
|
||
|
|
* and a `NEW` closes the lot.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef _AKBASIC_DISK_H_
|
||
|
|
#define _AKBASIC_DISK_H_
|
||
|
|
|
||
|
|
#include <stdio.h>
|
||
|
|
|
||
|
|
#include <akerror.h>
|
||
|
|
|
||
|
|
#include <akbasic/types.h>
|
||
|
|
|
||
|
|
/** @brief How many files may be open at once. A C128 allows ten; this allows the same. */
|
||
|
|
#define AKBASIC_MAX_CHANNELS 10
|
||
|
|
|
||
|
|
/** @brief One open file channel. */
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
FILE *fp;
|
||
|
|
char name[AKBASIC_MAX_STRING_LENGTH];
|
||
|
|
bool writing;
|
||
|
|
} akbasic_Channel;
|
||
|
|
|
||
|
|
/** @brief Every open channel. Indexed by the number a program writes after `#`. */
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
akbasic_Channel channels[AKBASIC_MAX_CHANNELS];
|
||
|
|
} akbasic_DiskState;
|
||
|
|
|
||
|
|
struct akbasic_Runtime;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Mark every channel closed. Does not close anything; nothing is open yet.
|
||
|
|
* @param obj Object to initialize, inspect, or modify.
|
||
|
|
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||
|
|
* @throws AKERR_NULLPOINTER When `obj` is NULL.
|
||
|
|
*/
|
||
|
|
akerr_ErrorContext AKERR_NOIGNORE *akbasic_disk_state_init(akbasic_DiskState *obj);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Close every open channel.
|
||
|
|
*
|
||
|
|
* Called by `DCLOSE` with no argument and by `NEW`. A program that ends without
|
||
|
|
* closing its files leaves them to this -- and to the host, which owns the
|
||
|
|
* process and outlives the program.
|
||
|
|
*
|
||
|
|
* @param obj Object to initialize, inspect, or modify.
|
||
|
|
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||
|
|
* @throws AKERR_NULLPOINTER When `obj` is NULL.
|
||
|
|
*/
|
||
|
|
akerr_ErrorContext AKERR_NOIGNORE *akbasic_disk_close_all(akbasic_DiskState *obj);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Write one line to a channel, terminator included.
|
||
|
|
*
|
||
|
|
* What `PRINT #n, ...` reaches. A line rather than raw bytes, because that is
|
||
|
|
* what `INPUT #n` reads back and the pair has to agree.
|
||
|
|
*
|
||
|
|
* @param obj Object to initialize, inspect, or modify.
|
||
|
|
* @param number The channel number.
|
||
|
|
* @param text What to write.
|
||
|
|
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||
|
|
* @throws AKERR_NULLPOINTER When `obj` or `text` is NULL.
|
||
|
|
* @throws AKBASIC_ERR_BOUNDS When the channel number is out of range.
|
||
|
|
* @throws AKBASIC_ERR_STATE When the channel is closed, or was opened for reading.
|
||
|
|
*/
|
||
|
|
akerr_ErrorContext AKERR_NOIGNORE *akbasic_disk_write(struct akbasic_Runtime *obj, int64_t number, const char *text);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Read one line from a channel, without its terminator.
|
||
|
|
*
|
||
|
|
* What `INPUT #n, VAR` reaches. End of file is reported through @p eof rather
|
||
|
|
* than raised, the same way the sink's `readline` reports it: running out of
|
||
|
|
* input is a state a program handles, not a failure.
|
||
|
|
*
|
||
|
|
* @param obj Object to initialize, inspect, or modify.
|
||
|
|
* @param number The channel number.
|
||
|
|
* @param dest Output destination populated by the function.
|
||
|
|
* @param len Capacity of @p dest.
|
||
|
|
* @param eof Output destination populated by the function; true at end of file.
|
||
|
|
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||
|
|
* @throws AKERR_NULLPOINTER When any pointer argument is NULL.
|
||
|
|
* @throws AKBASIC_ERR_BOUNDS When the channel number is out of range.
|
||
|
|
* @throws AKBASIC_ERR_STATE When the channel is closed, or was opened for writing.
|
||
|
|
*/
|
||
|
|
akerr_ErrorContext AKERR_NOIGNORE *akbasic_disk_readline(struct akbasic_Runtime *obj, int64_t number, char *dest, size_t len, bool *eof);
|
||
|
|
|
||
|
|
#endif // _AKBASIC_DISK_H_
|