aboutsummaryrefslogtreecommitdiff
path: root/src/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/file.c')
-rw-r--r--src/file.c214
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);
}