/*
 * stdio.h — extends SDCC's z80 stdio with a minimal FILE * stream API.
 *
 * The bottom of the stack is the existing POSIX-style fd I/O (open/
 * read/write/close/lseek).  FILE * is a thin struct wrapping a fd plus
 * a few flag bits.  No buffering — every fread/fwrite/fputc maps 1:1
 * to a syscall.  Sprinter's I/O is already char-oriented at the ESTEX
 * level, so this stays minimal.
 *
 * stdin / stdout / stderr are predefined "virtual" FILE * pointers
 * that talk to the console via putchar()/getchar() (NOT through a fd).
 * That keeps printf-routed output going through our CR/LF mapping.
 */

#ifndef STDIO_H
#define STDIO_H

#include <stdarg.h>
#include <stddef.h>      /* size_t */
#include <stdint.h>

#ifndef EOF
#define EOF (-1)
#endif

/* ---- printf family (linked from SDCC's z80.lib) -------------------- */
int  printf (const char *, ...);
int  sprintf(char *, const char *, ...);
int  vprintf(const char *, va_list);
int  vsprintf(char *, const char *, va_list);

/* puts / putchar / getchar — overridden by our libc to use ESTEX. */
char puts   (const char *);
int  putchar(int);
int  getchar(void);

/* ---- FILE * (minimal, unbuffered) ---------------------------------- */

/* Internal layout — opaque to user.  fd == -1 marks the console
 * pseudo-streams (stdin/stdout/stderr). */
typedef struct __FILE {
    int     fd;          /* underlying POSIX fd, or -1 for console */
    uint8_t flags;       /* see _F_* below */
} FILE;

#define _F_READ    0x01
#define _F_WRITE   0x02
#define _F_APPEND  0x04
#define _F_EOF     0x10
#define _F_ERROR   0x20
#define _F_CONIN   0x40  /* console pseudo-stream — uses getchar() */
#define _F_CONOUT  0x80  /* console pseudo-stream — uses putchar() */

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

/* fseek whence — same numeric values as SEEK_SET/CUR/END in unistd.h. */
#ifndef SEEK_SET
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#endif

FILE  *fopen (const char *path, const char *mode);
int    fclose(FILE *fp);
int    fflush(FILE *fp);

int    fputc (int c, FILE *fp);
int    fgetc (FILE *fp);
int    fputs (const char *s, FILE *fp);
char  *fgets (char *buf, int n, FILE *fp);

size_t fread (void *ptr, size_t size, size_t nmemb, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp);

int    fseek (FILE *fp, long off, int whence);
long   ftell (FILE *fp);
void   rewind(FILE *fp);

int    feof  (FILE *fp);
int    ferror(FILE *fp);
void   clearerr(FILE *fp);

/* Aliases to fputc/fgetc — POSIX says they may be macros. */
#define putc(c, fp)   fputc(c, fp)
#define getc(fp)      fgetc(fp)

/* Read line from stdin into buf until '\n' or EOF; '\n' is not stored.
 * Returns buf, or NULL on EOF with empty input.  Solid-C/POSIX semantic.
 * Note: dangerous, no length check — caller must size buf appropriately. */
char *gets(char *buf);

/* Solid-C decimal/hex helpers — print uint as decimal/hex without args. */
void hex8 (uint8_t  v);   /* prints two hex digits */
void hex16(uint16_t v);   /* prints four hex digits */
void hex32(uint32_t v);   /* prints eight hex digits */
void dec8 (uint8_t  v);   /* prints up to 3 decimal digits, no padding */
void dec16(uint16_t v);   /* prints up to 5 decimal digits */
void dec32(uint32_t v);   /* prints up to 10 decimal digits */

#endif
