/* * fwrite — пишет nmemb элементов по size байт из ptr в поток * (буферизованно, вариант B+). * * Большой блок (>= BUFSIZ, или нет буфера): сброс накопленного и один * write() напрямую из ptr мимо буфера. Мелкий: memcpy в буфер (со * сбросом ПЕРЕД записью, если не влезает). Если поток был в режиме * чтения — _file_sync откатит readahead. Возвращает число ПОЛНЫХ * записанных элементов; ошибка/короткая запись ставит _F_ERROR. * Ошибки буферизованной части могут вылезти позже (fflush/fclose). * Консольный поток — посимвольно через putchar(). */ #include #include #include #include "_file.h" size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp) { #ifndef LIBC_NOCHECK if (!ptr || !fp) return 0; #endif if (size == 0 || nmemb == 0) return 0; const uint8_t *p = (const uint8_t *)ptr; size_t total = size * nmemb; if (fp->flags & _F_CONOUT) { for (size_t i = 0; i < total; i++) { putchar(p[i]); } return nmemb; } #ifndef LIBC_NOCHECK if (!(fp->flags & _F_WRITE)) { errno = EBADF; return 0; } #endif if (!(fp->flags & _F_DIROUT)) { if (_file_sync(fp)) return 0; /* откат readahead/hold */ } if (total >= BUFSIZ || !_file_buf(fp)) { /* Большой блок (или нет буфера): сброс хвоста + прямой write. */ if (_file_sync(fp)) return 0; int w = write(fp->fd, p, (uint16_t)total); if (w < 0) { fp->flags |= _F_ERROR; return 0; } if ((size_t)w < total) fp->flags |= _F_ERROR; return (size_t)w / size; } /* Мелкий блок — в буфер; сброс ПЕРЕД записью, если не влезает. */ if (fp->level + total > BUFSIZ) { if (_file_sync(fp)) return 0; } if (!(fp->flags & _F_DIROUT)) { fp->flags |= _F_DIROUT; fp->curp = fp->buf; } memcpy(fp->curp, p, total); fp->curp += total; fp->level += (uint16_t)total; return nmemb; }