diff options
Diffstat (limited to 'src/file.c')
-rw-r--r-- | src/file.c | 214 |
1 files changed, 161 insertions, 53 deletions
diff --git a/src/file.c b/src/file.c index 627664a9c261..e5d2f6ac73d8 100644 --- a/src/file.c +++ b/src/file.c @@ -44,22 +44,26 @@ #include <file.h> #include <vm.h> +#if !BC_ENABLE_LINE_LIB + /** * Translates an integer into a string. * @param val The value to translate. * @param buf The return parameter. */ -static void bc_file_ultoa(unsigned long long val, char buf[BC_FILE_ULL_LENGTH]) +static void +bc_file_ultoa(unsigned long long val, char buf[BC_FILE_ULL_LENGTH]) { char buf2[BC_FILE_ULL_LENGTH]; size_t i, len; // We need to make sure the entire thing is zeroed. + // NOLINTNEXTLINE memset(buf2, 0, BC_FILE_ULL_LENGTH); // The i = 1 is to ensure that there is a null byte at the end. - for (i = 1; val; ++i) { - + for (i = 1; val; ++i) + { unsigned long long mod = val % 10; buf2[i] = ((char) mod) + '0'; @@ -69,7 +73,10 @@ static void bc_file_ultoa(unsigned long long val, char buf[BC_FILE_ULL_LENGTH]) len = i; // Since buf2 is reversed, reverse it into buf. - for (i = 0; i < len; ++i) buf[i] = buf2[len - i - 1]; + for (i = 0; i < len; ++i) + { + buf[i] = buf2[len - i - 1]; + } } /** @@ -80,22 +87,23 @@ static void bc_file_ultoa(unsigned long long val, char buf[BC_FILE_ULL_LENGTH]) * @return A status indicating error or success. We could have a fatal I/O * error or EOF. */ -static BcStatus bc_file_output(int fd, const char *buf, size_t n) { - +static BcStatus +bc_file_output(int fd, const char* buf, size_t n) +{ size_t bytes = 0; sig_atomic_t lock; BC_SIG_TRYLOCK(lock); // While the number of bytes written is less than intended... - while (bytes < n) { - + while (bytes < n) + { // Write. ssize_t written = write(fd, buf + bytes, n - bytes); // Check for error and return, if any. - if (BC_ERR(written == -1)) { - + if (BC_ERR(written == -1)) + { BC_SIG_TRYUNLOCK(lock); return errno == EPIPE ? BC_STATUS_EOF : BC_STATUS_ERROR_FATAL; @@ -109,20 +117,31 @@ static BcStatus bc_file_output(int fd, const char *buf, size_t n) { return BC_STATUS_SUCCESS; } -BcStatus bc_file_flushErr(BcFile *restrict f, BcFlushType type) +#endif // !BC_ENABLE_LINE_LIB + +BcStatus +bc_file_flushErr(BcFile* restrict f, BcFlushType type) { BcStatus s; BC_SIG_ASSERT_LOCKED; - // If there is stuff to output... - if (f->len) { +#if BC_ENABLE_LINE_LIB + + // Just flush and propagate the error. + if (fflush(f->f) == EOF) s = BC_STATUS_ERROR_FATAL; + else s = BC_STATUS_SUCCESS; + +#else // BC_ENABLE_LINE_LIB + // If there is stuff to output... + if (f->len) + { #if BC_ENABLE_HISTORY // If history is enabled... - if (BC_TTY) { - + if (BC_TTY) + { // If we have been told to save the extras, and there *are* // extras... if (f->buf[f->len - 1] != '\n' && @@ -132,7 +151,10 @@ BcStatus bc_file_flushErr(BcFile *restrict f, BcFlushType type) size_t i; // Look for the last newline. - for (i = f->len - 2; i < f->len && f->buf[i] != '\n'; --i); + for (i = f->len - 2; i < f->len && f->buf[i] != '\n'; --i) + { + continue; + } i += 1; @@ -140,7 +162,8 @@ BcStatus bc_file_flushErr(BcFile *restrict f, BcFlushType type) bc_vec_string(&vm.history.extras, f->len - i, f->buf + i); } // Else clear the extras if told to. - else if (type >= BC_FLUSH_NO_EXTRAS_CLEAR) { + else if (type >= BC_FLUSH_NO_EXTRAS_CLEAR) + { bc_vec_popAll(&vm.history.extras); } } @@ -152,11 +175,14 @@ BcStatus bc_file_flushErr(BcFile *restrict f, BcFlushType type) } else s = BC_STATUS_SUCCESS; +#endif // BC_ENABLE_LINE_LIB + return s; } -void bc_file_flush(BcFile *restrict f, BcFlushType type) { - +void +bc_file_flush(BcFile* restrict f, BcFlushType type) +{ BcStatus s; sig_atomic_t lock; @@ -165,10 +191,11 @@ void bc_file_flush(BcFile *restrict f, BcFlushType type) { s = bc_file_flushErr(f, type); // If we have an error... - if (BC_ERR(s)) { - + if (BC_ERR(s)) + { // For EOF, set it and jump. - if (s == BC_STATUS_EOF) { + if (s == BC_STATUS_EOF) + { vm.status = (sig_atomic_t) s; BC_SIG_TRYUNLOCK(lock); BC_JMP; @@ -180,23 +207,44 @@ void bc_file_flush(BcFile *restrict f, BcFlushType type) { BC_SIG_TRYUNLOCK(lock); } -void bc_file_write(BcFile *restrict f, BcFlushType type, - const char *buf, size_t n) +#if !BC_ENABLE_LINE_LIB + +void +bc_file_write(BcFile* restrict f, BcFlushType type, const char* buf, size_t n) { sig_atomic_t lock; BC_SIG_TRYLOCK(lock); // If we have enough to flush, do it. - if (n > f->cap - f->len) { + if (n > f->cap - f->len) + { bc_file_flush(f, type); assert(!f->len); } // If the output is large enough to flush by itself, just output it. // Otherwise, put it into the buffer. - if (BC_UNLIKELY(n > f->cap - f->len)) bc_file_output(f->fd, buf, n); - else { + if (BC_UNLIKELY(n > f->cap - f->len)) + { + BcStatus s = bc_file_output(f->fd, buf, n); + + if (BC_ERR(s)) + { + // For EOF, set it and jump. + if (s == BC_STATUS_EOF) + { + vm.status = (sig_atomic_t) s; + BC_SIG_TRYUNLOCK(lock); + BC_JMP; + } + // Blow up on fatal error. Okay, not blow up, just quit. + else bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); + } + } + else + { + // NOLINTNEXTLINE memcpy(f->buf + f->len, buf, n); f->len += n; } @@ -204,7 +252,10 @@ void bc_file_write(BcFile *restrict f, BcFlushType type, BC_SIG_TRYUNLOCK(lock); } -void bc_file_printf(BcFile *restrict f, const char *fmt, ...) +#endif // BC_ENABLE_LINE_LIB + +void +bc_file_printf(BcFile* restrict f, const char* fmt, ...) { va_list args; sig_atomic_t lock; @@ -218,13 +269,24 @@ void bc_file_printf(BcFile *restrict f, const char *fmt, ...) BC_SIG_TRYUNLOCK(lock); } -void bc_file_vprintf(BcFile *restrict f, const char *fmt, va_list args) { +void +bc_file_vprintf(BcFile* restrict f, const char* fmt, va_list args) +{ + BC_SIG_ASSERT_LOCKED; - char *percent; - const char *ptr = fmt; - char buf[BC_FILE_ULL_LENGTH]; +#if BC_ENABLE_LINE_LIB - BC_SIG_ASSERT_LOCKED; + // Just print and propagate the error. + if (BC_ERR(vfprintf(f->f, fmt, args) < 0)) + { + bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); + } + +#else // BC_ENABLE_LINE_LIB + + char* percent; + const char* ptr = fmt; + char buf[BC_FILE_ULL_LENGTH]; // This is a poor man's printf(). While I could look up algorithms to make // it as fast as possible, and should when I write the standard library for @@ -232,13 +294,14 @@ void bc_file_vprintf(BcFile *restrict f, const char *fmt, va_list args) { // for now. // Find each percent sign. - while ((percent = strchr(ptr, '%')) != NULL) { - + while ((percent = strchr(ptr, '%')) != NULL) + { char c; // If the percent sign is not where we are, write what's inbetween to // the buffer. - if (percent != ptr) { + if (percent != ptr) + { size_t len = (size_t) (percent - ptr); bc_file_write(f, bc_flush_none, ptr, len); } @@ -247,40 +310,42 @@ void bc_file_vprintf(BcFile *restrict f, const char *fmt, va_list args) { // We only parse some format specifiers, the ones bc uses. If you add // more, you need to make sure to add them here. - if (c == 'c') { - + if (c == 'c') + { uchar uc = (uchar) va_arg(args, int); bc_file_putchar(f, bc_flush_none, uc); } - else if (c == 's') { - - char *s = va_arg(args, char*); + else if (c == 's') + { + char* s = va_arg(args, char*); bc_file_puts(f, bc_flush_none, s); } #if BC_DEBUG_CODE // We only print signed integers in debug code. - else if (c == 'd') { - + else if (c == 'd') + { int d = va_arg(args, int); // Take care of negative. Let's not worry about overflow. - if (d < 0) { + if (d < 0) + { bc_file_putchar(f, bc_flush_none, '-'); d = -d; } // Either print 0 or translate and print. if (!d) bc_file_putchar(f, bc_flush_none, '0'); - else { + else + { bc_file_ultoa((unsigned long long) d, buf); bc_file_puts(f, bc_flush_none, buf); } } #endif // BC_DEBUG_CODE - else { - + else + { unsigned long long ull; // These are the ones that it expects from here. Fortunately, all of @@ -293,7 +358,8 @@ void bc_file_vprintf(BcFile *restrict f, const char *fmt, va_list args) { // Either print 0 or translate and print. if (!ull) bc_file_putchar(f, bc_flush_none, '0'); - else { + else + { bc_file_ultoa(ull, buf); bc_file_puts(f, bc_flush_none, buf); } @@ -306,18 +372,42 @@ void bc_file_vprintf(BcFile *restrict f, const char *fmt, va_list args) { // If we get here, there are no more percent signs, so we just output // whatever is left. if (ptr[0]) bc_file_puts(f, bc_flush_none, ptr); + +#endif // BC_ENABLE_LINE_LIB } -void bc_file_puts(BcFile *restrict f, BcFlushType type, const char *str) { +void +bc_file_puts(BcFile* restrict f, BcFlushType type, const char* str) +{ +#if BC_ENABLE_LINE_LIB + // This is used because of flushing issues with using bc_file_write() when + // bc is using a line library. It's also using printf() because puts() + // writes a newline. + bc_file_printf(f, "%s", str); +#else // BC_ENABLE_LINE_LIB bc_file_write(f, type, str, strlen(str)); +#endif // BC_ENABLE_LINE_LIB } -void bc_file_putchar(BcFile *restrict f, BcFlushType type, uchar c) { - +void +bc_file_putchar(BcFile* restrict f, BcFlushType type, uchar c) +{ sig_atomic_t lock; BC_SIG_TRYLOCK(lock); +#if BC_ENABLE_LINE_LIB + + if (BC_ERR(fputc(c, f->f) == EOF)) + { + // This is here to prevent a stack overflow from unbounded recursion. + if (f->f == stderr) exit(BC_STATUS_ERROR_FATAL); + + bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); + } + +#else // BC_ENABLE_LINE_LIB + if (f->len == f->cap) bc_file_flush(f, type); assert(f->len < f->cap); @@ -325,11 +415,25 @@ void bc_file_putchar(BcFile *restrict f, BcFlushType type, uchar c) { f->buf[f->len] = (char) c; f->len += 1; +#endif // BC_ENABLE_LINE_LIB + BC_SIG_TRYUNLOCK(lock); } -void bc_file_init(BcFile *f, int fd, char *buf, size_t cap) { +#if BC_ENABLE_LINE_LIB + +void +bc_file_init(BcFile* f, FILE* file) +{ + BC_SIG_ASSERT_LOCKED; + f->f = file; +} + +#else // BC_ENABLE_LINE_LIB +void +bc_file_init(BcFile* f, int fd, char* buf, size_t cap) +{ BC_SIG_ASSERT_LOCKED; f->fd = fd; @@ -338,7 +442,11 @@ void bc_file_init(BcFile *f, int fd, char *buf, size_t cap) { f->cap = cap; } -void bc_file_free(BcFile *f) { +#endif // BC_ENABLE_LINE_LIB + +void +bc_file_free(BcFile* f) +{ BC_SIG_ASSERT_LOCKED; bc_file_flush(f, bc_flush_none); } |