#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sprinter.h>

/*
 * Exercises the new open() state machine + ESTEX env API.
 *
 * Touches the floppy: creates TMP1.TXT and TMP2.TXT, writes a few bytes,
 * verifies O_CREAT / O_EXCL / O_TRUNC / O_APPEND behaviour, then deletes.
 */
 
extern uint8_t estex_file_handle;


static void show_errno(const char *label)
{
    printf("  %s: errno=%d \"%s\"\n", label, errno, strerror(errno));
}

int main(void)
{
    puts("Sprinter open() + env API test");
    puts("");

    printf("estex_file_handle: fd=%u\n", estex_file_handle);

    /* --- open() state machine ------------------------------------- */

    /* 1. O_CREAT|O_EXCL: must succeed first time, must fail on retry. */
    unlink("TMP1.TXT");          /* clean slate */
    errno = 0;
    int fd = open("TMP1.TXT", O_WRONLY | O_CREAT | O_EXCL);
    printf("create-new TMP1.TXT (1st): fd=%d\n", fd);
    show_errno("    after 1st");
    if (fd >= 0) {
        write(fd, "abcdef", 6);
        close(fd);
    }

    errno = 0;
    fd = open("TMP1.TXT", O_WRONLY | O_CREAT | O_EXCL);
    printf("create-new TMP1.TXT (2nd, should fail with EEXIST): fd=%d\n", fd);
    show_errno("    after 2nd");

    /* 2. O_CREAT|O_TRUNC: file is reset. */
    errno = 0;
    fd = open("TMP1.TXT", O_WRONLY | O_CREAT | O_TRUNC);
    printf("create-trunc TMP1.TXT: fd=%d\n", fd);
    if (fd >= 0) {
        write(fd, "XYZ", 3);
        close(fd);
    }

    /* Read back to confirm truncation overwrote "abcdef". */
    char buf[16];
    fd = open("TMP1.TXT", O_RDONLY);
    int n = read(fd, buf, sizeof(buf) - 1);
    if (n < 0) n = 0;
    buf[n] = 0;
    close(fd);
    printf("contents after trunc+write: \"%s\" (expect \"XYZ\")\n", buf);

    /* 3. O_APPEND: writes go to end. */
    fd = open("TMP1.TXT", O_WRONLY | O_APPEND);
    if (fd >= 0) {
        write(fd, "+APP", 4);
        close(fd);
    }
    fd = open("TMP1.TXT", O_RDONLY);
    n = read(fd, buf, sizeof(buf) - 1);
    if (n < 0) n = 0;
    buf[n] = 0;
    close(fd);
    printf("contents after append:      \"%s\" (expect \"XYZ+APP\")\n", buf);

    /* 4. O_CREAT alone (no EXCL/TRUNC): existing file opens, new file is
     *    created.  We open TMP1 (must succeed without truncating) then
     *    TMP2 (must be created fresh). */
    fd = open("TMP1.TXT", O_RDONLY | O_CREAT);
    n = read(fd, buf, sizeof(buf) - 1);
    if (n < 0) n = 0;
    buf[n] = 0;
    close(fd);
    printf("O_CREAT on existing TMP1:    \"%s\" (expect \"XYZ+APP\")\n", buf);

    unlink("TMP2.TXT");
    fd = open("TMP2.TXT", O_WRONLY | O_CREAT);
    printf("O_CREAT on missing TMP2:     fd=%d\n", fd);
    if (fd >= 0) {
        write(fd, "fresh", 5);
        close(fd);
    }

    /* cleanup */
    unlink("TMP1.TXT");
    unlink("TMP2.TXT");

    /* --- env API -------------------------------------------------- */
    puts("");
    puts("env API:");

    errno = 0;
    char *v = getenv("PATH");
    printf("  getenv(\"PATH\") = %p", v);
    if (v) {
        printf(" -> \"%s\"", v);
    } else {
        printf(" (NULL, errno=%d)", errno);
    }
    putchar('\n');

    errno = 0;
    int rc = putenv("SPRINTER_HELLO=world");
    printf("  putenv(\"SPRINTER_HELLO=world\"): rc=%d\n", rc);
    if (rc != 0) show_errno("    after putenv");

    errno = 0;
    v = getenv("SPRINTER_HELLO");
    printf("  getenv(\"SPRINTER_HELLO\") = %p", v);
    if (v) {
        printf(" -> \"%s\"", v);
    } else {
        printf(" (NULL, errno=%d)", errno);
    }
    putchar('\n');

    /* --- sysenv: dump the whole environment block ----------------- */
    puts("");
    puts("sysenv:");
    {
        static char envbuf[512];
        errno = 0;
        char *r = sysenv(envbuf);
        if (r == (char *)-1) {
            show_errno("    sysenv failed");
        } else {
            printf("  sysenv(%p) returned %p\n", envbuf, r);
            int n = 0;
            for (char *p = r; *p; p += strlen(p) + 1) {
                printf("    [%d] %s\n", n++, p);
            }
            printf("  total: %d variable(s)\n", n);
        }
    }

    puts("");
    puts("Press any key to exit.");
    (void)getchar();
    return 0;
}
