// SPDX-License-Identifier: LGPL-3.0-or-later /** * \file bufio.c * * I/O stream buffering utilities implementation. * * \copyright The DoubleFourteen Code Forge (C) All Rights Reserved * \author Lorenzo Cogotti */ #include "sys/sys_local.h" // for Sys_SetErrStat() - vsnprintf() #include "bufio.h" #include "numlib.h" #include "smallbytecopy.h" #include #include #include #include static Judgement Bufio_FillRdBuf(Stmrdbuf *sb) { assert(sb->pos == sb->availIn); Sint64 n = sb->ops->Read(sb->streamp, sb->buf, sizeof(sb->buf)); if (n < 0) { sb->hasError = TRUE; return NG; } sb->isEof = (n == 0); sb->availIn = n; sb->totalIn += n; sb->pos = 0; return OK; } Sint64 Bufio_Read(Stmrdbuf *sb, void *buf, size_t nbytes) { assert(sb->ops->Read); if (sb->hasError) return -1; // refuse unless somebody clears error Uint8 *dest = (Uint8 *) buf; while (nbytes > 0) { if (sb->pos >= sb->availIn) { if (Bufio_FillRdBuf(sb) != OK) { if (dest > (Uint8 *) buf) break; // delay error to next read return -1; } if (sb->isEof) break; // end of file } size_t size = MIN((size_t) (sb->availIn - sb->pos), nbytes); memcpy(dest, sb->buf + sb->pos, size); sb->pos += size; nbytes -= size; dest += size; } return dest - (Uint8 *) buf; } void Bufio_Close(Stmrdbuf *sb) { if (sb->ops->Close) sb->ops->Close(sb->streamp); } NOINLINE Sint64 Bufio_Flush(Stmwrbuf *sb) { assert(sb->ops->Write); while (sb->availOut > 0) { Sint64 n = sb->ops->Write(sb->streamp, sb->buf, sb->availOut); if (n < 0) return -1; memmove(sb->buf, sb->buf + n, sb->availOut - n); sb->availOut -= n; sb->totalOut += n; } return sb->totalOut; } Sint64 _Bufio_SmallPutsn(Stmwrbuf *sb, const char *s, size_t nbytes) { if (sb->availOut + nbytes > sizeof(sb->buf) && Bufio_Flush(sb) == -1) return -1; _smallbytecopy64(sb->buf + sb->availOut, s, nbytes); sb->availOut += nbytes; return nbytes; } Sint64 _Bufio_Putsn(Stmwrbuf *sb, const char *s, size_t nbytes) { if (sb->availOut + nbytes > sizeof(sb->buf) && Bufio_Flush(sb) == -1) return -1; if (nbytes > sizeof(sb->buf)) return sb->ops->Write(sb->streamp, sb, nbytes); memcpy(sb->buf + sb->availOut, s, nbytes); sb->availOut += nbytes; return nbytes; } Sint64 Bufio_Putu(Stmwrbuf *sb, unsigned long long val) { if (sb->availOut + DIGS(val) + 1 > sizeof(sb->buf) && Bufio_Flush(sb) == -1) return -1; char *sptr = sb->buf + sb->availOut; char *eptr = Utoa(val, sptr); Sint64 n = eptr - sptr; sb->availOut += n; return n; } Sint64 Bufio_Putx(Stmwrbuf *sb, unsigned long long val) { if (sb->availOut + XDIGS(val) + 1 > sizeof(sb->buf) && Bufio_Flush(sb) == -1) return -1; char *sptr = sb->buf + sb->availOut; char *eptr = Xtoa(val, sptr); Sint64 n = eptr - sptr; sb->availOut += n; return n; } Sint64 Bufio_Puti(Stmwrbuf *sb, long long val) { if (sb->availOut + 1 + DIGS(val) + 1 > sizeof(sb->buf) && Bufio_Flush(sb) == -1) return -1; char *sptr = sb->buf + sb->availOut; char *eptr = Itoa(val, sptr); Sint64 n = eptr - sptr; sb->availOut += n; return n; } Sint64 Bufio_Putf(Stmwrbuf *sb, double val) { char buf[DOUBLE_STRLEN + 1]; char *eptr = Ftoa(val, buf); return Bufio_Putsn(sb, buf, eptr - buf); } Sint64 Bufio_Printf(Stmwrbuf *sb, const char *fmt, ...) { va_list va; Sint64 n; va_start(va, fmt); n = Bufio_Vprintf(sb, fmt, va); va_end(va); return n; } Sint64 Bufio_Vprintf(Stmwrbuf *sb, const char *fmt, va_list va) { va_list vc; char *buf; int n1, n2; va_copy(vc, va); n1 = vsnprintf(NULL, 0, fmt, vc); va_end(vc); if (n1 < 0) { Sys_SetErrStat(errno, "vsnprintf() failed"); return -1; } buf = (char *) alloca(n1 + 1); n2 = vsnprintf(buf, n1 + 1, fmt, va); if (n2 < 0) { Sys_SetErrStat(errno, "vsnprintf() failed"); return -1; } assert(n1 == n2); return Bufio_Putsn(sb, buf, n2); } static Sint64 Bufio_StmRead(void *streamp, void *buf, size_t nbytes) { return Bufio_Read((Stmrdbuf *) streamp, buf, nbytes); } static Sint64 Bufio_StmTell(void *streamp) { Stmrdbuf *sb = (Stmrdbuf *) streamp; return (sb->hasError) ? -1 : sb->totalIn + (Sint64) sb->pos; } static void Bufio_StmClose(void *streamp) { Bufio_Close((Stmrdbuf *) streamp); } static const StmOps _Stm_RdBufOps = { Bufio_StmRead, NULL, NULL, Bufio_StmTell, NULL, Bufio_StmClose }; static const StmOps _Stm_NcRdBufOps = { Bufio_StmRead, NULL, NULL, Bufio_StmTell, NULL, NULL }; const StmOps *const Stm_RdBufOps = &_Stm_RdBufOps; const StmOps *const Stm_NcRdBufOps = &_Stm_NcRdBufOps;