/*
 * filetest — exercise the buffered FILE * stream API (variant B+).
 *
 * Steps:
 *   0. RAW probe: open/write/close — печатает ГОЛЫЙ возврат write()
 *      (диагностика: что реально возвращает ESTEX WRITE в DE).
 *   1. fopen("FILE.TXT","w"), fputs+fputc lines, fclose (с errno).
 *   2. fopen("FILE.TXT","r"), fgets each line, fclose.
 *   3. fopen("r"), fread block, fseek, ftell, feof.
 *   4. fputs to stdout/stderr (console pseudo-streams).
 *   5. "r+" mix: fgetc×10 → fputc×10 → fseek(0) → контроль, что
 *      чтение видит записанное (инвалидация буфера); ungetc; fprintf.
 */

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

int main(void)
{
    const char *path = "FILE.TXT";

    /* ----- 0. RAW write() return probe ----- */
    {
        int fd = open("WRT.TMP", O_WRONLY | O_CREAT | O_TRUNC);
        if (fd >= 0) {
            errno = 0;
            int w = write(fd, "12345", 5);
            printf("  raw write(5) -> %d, errno=%d\n", w, errno);
            close(fd);
            unlink("WRT.TMP");
        } else {
            printf("  raw probe: open failed errno=%d\n", errno);
        }
    }

    /* ----- 1. Write via fputs + fputc ----- */
    {
        FILE *fp = fopen(path, "w");
        if (!fp) {
            printf("fopen(w) failed: errno=%d (%s)\n", errno, strerror(errno));
            return 1;
        }
        int r1 = fputs("Hello from FILE*\n", fp);
        int r2 = fputs("Second line via fputs\n", fp);
        if (r1 || r2) printf("  fputs ret: %d %d\n", r1, r2);
        for (int i = '0'; i <= '9'; i++) fputc(i, fp);
        fputc('\n', fp);
        errno = 0;
        if (fclose(fp) != 0)
            printf("fclose: error, errno=%d (%s)\n", errno, strerror(errno));
    }

    /* ----- 2. Read via fgets ----- */
    {
        FILE *fp = fopen(path, "r");
        if (!fp) {
            printf("fopen(r) failed: errno=%d\n", errno);
            return 1;
        }
        char buf[128];
        int n = 0;
        while (fgets(buf, sizeof buf, fp)) {
            printf("  line %d: %s", ++n, buf);
            if (buf[strlen(buf)-1] != '\n') putchar('\n');
        }
        printf("  total lines: %d, feof=%d\n", n, feof(fp));
        fclose(fp);
    }

    /* ----- 3. fread / fseek / ftell ----- */
    {
        FILE *fp = fopen(path, "r");
        if (!fp) return 1;
        char buf[16];
        size_t got = fread(buf, 1, 16, fp);
        printf("  fread(16) -> %u bytes, ftell=%ld\n",
               (unsigned)got, ftell(fp));
        if (fseek(fp, 0L, SEEK_END) == 0) {
            printf("  file size via fseek(END)+ftell = %ld\n", ftell(fp));
        }
        rewind(fp);
        printf("  rewind: ftell=%ld, feof=%d\n", ftell(fp), feof(fp));
        fclose(fp);
    }

    /* ----- 4. Console pseudo-streams ----- */
    fputs("  fputs to stdout works\n", stdout);
    fputs("  fputs to stderr works\n", stderr);
    fputc('!', stdout); fputc('\n', stdout);

    /* ----- 5. "r+": чтение→запись→чтение + ungetc + fprintf ----- */
    {
        FILE *fp = fopen(path, "r+");
        if (!fp) { puts("fopen(r+) failed"); return 1; }
        for (int i = 0; i < 10; i++) fgetc(fp);      /* поз. 10, readahead жив */
        for (int i = 0; i < 10; i++) fputc('X', fp); /* sync: запись на 10..19 */
        fseek(fp, 0L, SEEK_SET);
        char buf[24];
        size_t got = fread(buf, 1, 20, fp);
        int ok = (got == 20);
        for (int i = 10; i < 20; i++) if (buf[i] != 'X') ok = 0;
        printf("  r+ mix: %s (got=%u)\n", ok ? "OK" : "FAIL", (unsigned)got);

        /* ungetc: прочитать байт, вернуть, прочитать снова */
        int c1 = fgetc(fp);
        ungetc(c1, fp);
        int c2 = fgetc(fp);
        printf("  ungetc: %s, ftell=%ld\n", c1 == c2 ? "OK" : "FAIL", ftell(fp));

        /* fprintf в файл */
        fseek(fp, 0L, SEEK_END);
        int n = fprintf(fp, "num=%d hex=%04x\n", 42, 0xBEEF);
        printf("  fprintf -> %d chars\n", n);
        if (fclose(fp)) puts("  r+ fclose: error");
    }

    puts("filetest done.");
    return 0;
}
