/* * fputc — записать один байт в поток (буферизованно, вариант B+). * * Горячий путь («поток уже копит запись и в буфере есть место») * написан на asm — см. пояснение в fgetc.c. Остальное — медленный * C-путь fputc_slow: консольный putchar(), переключение направления * (_file_sync откатывает readahead), сброс полного буфера, ленивое * выделение, fallback без буфера (прямой write() 1 байта). * ВНИМАНИЕ: успех fputc = «байт принят в буфер»; ошибка реальной * записи может вылезти позже (fflush/fclose). * * Раскладка FILE: +0 fd, +2 flags, +3 buf, +5 curp, +7 level, +9 hold. * asm рассчитывает на BUFSIZ == 512 (проверка уровня по старшему * байту level < 2). */ #include #include #include "_file.h" #if BUFSIZ != 512 #error "asm-горячий путь fputc рассчитан на BUFSIZ == 512" #endif /* Медленный путь; зовётся из asm-обёртки. */ static int fputc_slow(int c, FILE *fp) { if (!fp) { errno = EBADF; return EOF; } if (fp->flags & _F_CONOUT) { putchar(c); return (int)(uint8_t)c; } if (!(fp->flags & _F_WRITE)) { errno = EBADF; return EOF; } if (!(fp->flags & _F_DIROUT)) { if (_file_sync(fp)) return EOF; /* откат readahead/hold */ } else if (fp->level >= BUFSIZ) { if (_file_sync(fp)) return EOF; /* буфер полон — сброс */ } uint8_t *b = _file_buf(fp); if (!b) { /* Небуферизованный fallback. */ uint8_t ch = (uint8_t)c; if (write(fp->fd, &ch, 1) != 1) { fp->flags |= _F_ERROR; return EOF; } return (int)ch; } if (!(fp->flags & _F_DIROUT)) { fp->flags |= _F_DIROUT; fp->curp = b; } *fp->curp++ = (uint8_t)c; fp->level++; return (int)(uint8_t)c; } int fputc(int c, FILE *fp) __naked { (void)c; (void)fp; (void)fputc_slow; /* используется из asm */ __asm ;; HL = c, DE = fp. ld a, d or a, e jr Z, _fp_slow ; NULL — C-путь выставит errno push de pop iy ; IY = fp ld a, 2 (iy) ; flags and a, #0x08 ; _F_DIROUT — уже копим запись? jr Z, _fp_slow ; нет (или консоль/чтение) — C-путь ld a, 8 (iy) ; level_hi < 2 <=> level < 512 cp a, #2 jr NC, _fp_slow ; буфер полон — сброс в C-пути ;; --- горячий путь: *curp++ = c, level++ --- ld e, 5 (iy) ; DE = curp (fp больше не нужен в DE) ld d, 6 (iy) ld a, l ld (de), a inc de ld 5 (iy), e ld 6 (iy), d ld a, 7 (iy) ; level++ inc a ld 7 (iy), a jr NZ, _fp_ret inc 8 (iy) _fp_ret: ld e, l ; вернуть (uint8_t)c ld d, #0 ret _fp_slow: jp _fputc_slow ; HL = c, DE = fp уже на месте __endasm; }