057dd615ba
- ESTEX WRITE ($14) на успехе возвращает DE=0, а НЕ счётчик записанного (вопреки докам; solid-c в своём fflush тоже отключил сравнение по счётчику) — write() теперь судит по CF/A: CF=0&A=0 → n, CF=0&A!=0 → ENOSPC/-1 - DSS выдаёт 8 манипуляторов (fd 2..9; fd 1 держит шелл под запущенный exe), а 9-й OPEN не возвращает 06h — ВЕШАЕТ систему; предохранитель _fd_guard: счётчик в open()/close(), отказ EMFILE без захода в DSS - tests/fdmax — эмпирика лимита (8 хендлов, затем EMFILE=6); tests/fbench — бенчмарк буферизации (floor 512-байтными read, оценка небуферизованного по 1-байтным, fgetc/fgets/fputc) - filetest расширен: raw-probe возврата write, сценарий r+ (чтение-запись-чтение с инвалидацией буфера), ungetc, fprintf Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
123 lines
4.2 KiB
C
123 lines
4.2 KiB
C
/*
|
||
* 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;
|
||
}
|