#ifndef _STDIO_H
#define _STDIO_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stdarg.h>

typedef struct __sFILE FILE;
typedef unsigned long size_t;

#ifndef NULL
# define NULL ((void *)0)
#endif

extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;

int  putchar(int c);
int  puts(const char *s);
int  printf(const char *fmt, ...);
int  vprintf(const char *fmt, va_list ap);
int  sprintf(char *buf, const char *fmt, ...);
int  snprintf(char *buf, size_t n, const char *fmt, ...);
int  vsprintf(char *buf, const char *fmt, va_list ap);
int  vsnprintf(char *buf, size_t n, const char *fmt, va_list ap);
int  fprintf(FILE *stream, const char *fmt, ...);
int  vfprintf(FILE *stream, const char *fmt, va_list ap);
void perror(const char *prefix);
int  fputc(int c, FILE *stream);
int  fputs(const char *s, FILE *stream);
int  fflush(FILE *stream);
int  fclose(FILE *stream);

FILE *fopen(const char *path, const char *mode);
FILE *freopen(const char *path, const char *mode, FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
int    fseek(FILE *stream, long offset, int whence);
long   ftell(FILE *stream);
int    feof(FILE *stream);
int    ferror(FILE *stream);
void   clearerr(FILE *stream);

// fgetpos / fsetpos — alternative seek API.  fpos_t holds the same
// information as ftell's long return, so the implementation is a thin
// wrapper.  Provided for source-compat with portable code.
typedef long fpos_t;
int    fgetpos(FILE *stream, fpos_t *pos);
int    fsetpos(FILE *stream, const fpos_t *pos);

// Buffer-control surface — no-ops in our buffer-less I/O model (mfs
// is direct memory, stdout flushes per putchar).  The functions exist
// so portable code compiles.
#define _IOFBF 0
#define _IOLBF 1
#define _IONBF 2
#define BUFSIZ 256
int    setvbuf(FILE *stream, char *buf, int mode, size_t size);
void   setbuf (FILE *stream, char *buf);

// File-system operations.  Return 0 on success, -1 on failure.
//
//   remove():  Tries mfsUnregister first; if the path doesn't match
//              an mfs registration AND it looks like a GS/OS path
//              (contains `/` or `:`) AND a real GS/OS dispatcher is
//              linked, dispatches Destroy ($2002).  Otherwise -1.
//   rename():  Pure-name → pure-name swaps the mfs registration in
//              place.  Two GS/OS-path inputs go through ChangePath
//              ($2004) when same-directory, or a copy+delete
//              fallback (Open + Create + Read/Write loop + Destroy)
//              when cross-directory.  Mixed mfs-name vs GS/OS-path
//              yields EXDEV.
int    remove(const char *path);
int    rename(const char *old, const char *neu);

// Temporary-file helpers.
//
//   tmpnam(s):  Returns a unique-per-invocation GS/OS-shape path
//               "/RAM5/Txxxxxxxx.TMP" (19 chars + NUL).  Uses rand()
//               which crt0 seeds from ReadTimeHex, so names differ
//               across program runs.  If s is non-NULL it must
//               point to a buffer of at least L_tmpnam bytes; the
//               same buffer is returned.  If s is NULL the name
//               lives in a static buffer overwritten on each call.
//   tmpfile():  Generates a fresh name via tmpnam, fopens it "w+",
//               marks the FILE for auto-delete-on-fclose.  Returns
//               NULL if no FILE slot is free or the GS/OS path
//               cannot be created.
FILE  *tmpfile(void);
char  *tmpnam(char *s);
#define L_tmpnam 24
#define TMP_MAX  0xFFFF

#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2

#define EOF (-1)

int   getchar(void);
int   fgetc(FILE *stream);
char *fgets(char *buf, int n, FILE *stream);
int   ungetc(int c, FILE *stream);
#define getc(s) fgetc(s)

// scanf family — sscanf/vsscanf parse a string; fscanf/vfscanf parse
// from a FILE* via fgetc/ungetc.  scanf/vscanf read from stdin (which
// returns EOF on the IIgs because there is no integrated keyboard
// stdin) so they're rarely useful but the surface compiles.  Supports
// %d %i %u %x %X %o %s %c %ld %lu %lx %li %lo %% with optional `l`.
int sscanf (const char *str, const char *fmt, ...);
int vsscanf(const char *str, const char *fmt, va_list ap);
int fscanf (FILE *stream, const char *fmt, ...);
int vfscanf(FILE *stream, const char *fmt, va_list ap);
int scanf  (const char *fmt, ...);
int vscanf (const char *fmt, va_list ap);
void  rewind(FILE *stream);  // = fseek(s, 0, SEEK_SET) + clearerr

// Memory-backed FS: register a memory region as a named file so
// fopen can open it.  `cap` should be >= size; use cap > size for
// files that may grow on write.  `writable` controls whether
// fopen("...", "w") / "a" / "r+" succeeds.  Returns 0 on success,
// -1 on duplicate name or table full.
int  mfsRegister(const char *path, void *buf, size_t size, size_t cap,
                 int writable);
int  mfsUnregister(const char *path);

#ifdef __cplusplus
}
#endif

#endif
