summaryrefslogtreecommitdiff
path: root/src/stdio
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdio')
-rw-r--r--src/stdio/__printf.c44
-rw-r--r--src/stdio/_stdio.h28
-rw-r--r--src/stdio/clearerr.c2
-rw-r--r--src/stdio/feof.c3
-rw-r--r--src/stdio/ferror.c2
-rw-r--r--src/stdio/fgetc.c3
-rw-r--r--src/stdio/freopen.c4
-rw-r--r--src/stdio/fseek.c11
8 files changed, 68 insertions, 29 deletions
diff --git a/src/stdio/__printf.c b/src/stdio/__printf.c
index e86f91ee..7fa7a46b 100644
--- a/src/stdio/__printf.c
+++ b/src/stdio/__printf.c
@@ -169,15 +169,14 @@ int (__printf)(struct io_options *opt, const char * format, va_list arg)
i++;
if (format[i] == '*') {
+ /* TODO */
i++;
} else if (isdigit(format[i])) {
char *end;
precision = (int)strtoumax(format + i, &end, 10);
i = end - format;
} else {
- /* invalid precision */
- nout = -nout;
- goto end;
+ precision = 0;
}
}
@@ -216,25 +215,25 @@ int (__printf)(struct io_options *opt, const char * format, va_list arg)
}
if ((flags & ALT) && (!strchr("xXaAeEfFgG", format[i]))) {
- __undefined("In call to %s(): The '#' flag is undefined for %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): The '#' flag is undefined for %%%c", opt->fnname, format[i]);
} else if ((flags & ZERO) && (!strchr("diouxXaAeEfFgG", format[i]))) {
- __undefined("In call to %s(): The '0' flag is undefined for %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): The '0' flag is undefined for %%%c", opt->fnname, format[i]);
} else if ((length == hh) && (!strchr("diouxXn", format[i]))) {
- __undefined("In call to %s(): The length 'hh' is undefined for %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): The length 'hh' is undefined for %%%c", opt->fnname, format[i]);
} else if ((length == h) && (!strchr("diouxXn", format[i]))) {
- __undefined("In call to %s(): The length 'h' is undefined for %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): The length 'h' is undefined for %%%c", opt->fnname, format[i]);
} else if ((length == l) && (!strchr("diouxXncsaAeEfFgG", format[i]))) {
- __undefined("In call to %s(): The length 'l' is undefined for %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): The length 'l' is undefined for %%%c", opt->fnname, format[i]);
} else if ((length == ll) && (!strchr("diouxXn", format[i]))) {
- __undefined("In call to %s(): The length 'll' is undefined for %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): The length 'll' is undefined for %%%c", opt->fnname, format[i]);
} else if ((length == j) && (!strchr("diouxXn", format[i]))) {
- __undefined("In call to %s(): The length 'j' is undefined for %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): The length 'j' is undefined for %%%c", opt->fnname, format[i]);
} else if ((length == z) && (!strchr("diouxXn", format[i]))) {
- __undefined("In call to %s(): The length 'z' is undefined for %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): The length 'z' is undefined for %%%c", opt->fnname, format[i]);
} else if ((length == t) && (!strchr("diouxXn", format[i]))) {
- __undefined("In call to %s(): The length 't' is undefined for %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): The length 't' is undefined for %%%c", opt->fnname, format[i]);
} else if ((length == L) && (!strchr("aAeEfFgG", format[i]))) {
- __undefined("In call to %s(): The length 'L' is undefined for %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): The length 'L' is undefined for %%%c", opt->fnname, format[i]);
}
switch (format[i]) {
@@ -297,6 +296,10 @@ int (__printf)(struct io_options *opt, const char * format, va_list arg)
break;
case 'c': /* char */
+ if (specified & PRECISION) {
+ UNDEFINED("In call to %s(): Precision with %%c conversions", opt->fnname);
+ }
+
if (length == def) {
char c = va_arg(arg, int);
if (nout < (int)n) {
@@ -341,6 +344,9 @@ int (__printf)(struct io_options *opt, const char * format, va_list arg)
break;
case 'p': /* pointer */
+ if (specified & PRECISION) {
+ UNDEFINED("In call to %s(): Precision with %%p conversion", opt->fnname);
+ }
argptr = va_arg(arg, void *);
nout = __append(s, "0x", nout, n);
__itos(numbuf, (intptr_t)argptr, ZERO, sizeof(argptr) * 2, 16);
@@ -349,13 +355,13 @@ int (__printf)(struct io_options *opt, const char * format, va_list arg)
case 'n': /* write-back */
if (specified & FLAG) {
- __undefined("In call to %s(): Flags with %%n conversion", opt->fnname);
+ UNDEFINED("In call to %s(): Flags with %%n conversion", opt->fnname);
} else if (specified & 0) {
/* TODO: output suppression (might only be for input) */
} else if (specified & WIDTH) {
- __undefined("In call to %s(): Width with %%n conversion", opt->fnname);
+ UNDEFINED("In call to %s(): Width with %%n conversion", opt->fnname);
} else if (specified & PRECISION) {
- __undefined("In call to %s(): Precision with %%n conversion", opt->fnname);
+ UNDEFINED("In call to %s(): Precision with %%n conversion", opt->fnname);
}
switch (length) {
@@ -392,13 +398,13 @@ int (__printf)(struct io_options *opt, const char * format, va_list arg)
*pd = nout;
break;
case L:
- __undefined("In call to %s(): Invalid length 'L' for %%n conversion", opt->fnname);
+ UNDEFINED("In call to %s(): Invalid length 'L' for %%n conversion", opt->fnname);
}
break;
case '%': /* literal '%' */
if (specified != 0) {
- __undefined("In call to %s(): \"%%%%\" conversion is not literally \"%%%%\"", opt->fnname);
+ UNDEFINED("In call to %s(): \"%%%%\" conversion is not literally \"%%%%\"", opt->fnname);
}
if (nout < (int)n) {
s[nout] = '%';
@@ -407,7 +413,7 @@ int (__printf)(struct io_options *opt, const char * format, va_list arg)
break;
default: /* undefined */
- __undefined("In call to %s(): Unknown conversion specifier %%%c", opt->fnname, format[i]);
+ UNDEFINED("In call to %s(): Unknown conversion specifier %%%c", opt->fnname, format[i]);
}
}
diff --git a/src/stdio/_stdio.h b/src/stdio/_stdio.h
index 516ce659..d47ac5dd 100644
--- a/src/stdio/_stdio.h
+++ b/src/stdio/_stdio.h
@@ -22,6 +22,23 @@
#define GCC_SSE_HACK __attribute__((noinline, target("no-sse")))
+#define ORIENT_WIDE (1)
+#define ORIENT_BYTE (-1)
+
+#define OP_INPUT (1)
+#define OP_OUTPUT (2)
+
+#ifdef NDEBUG
+#define ASSERT_STREAM(__stream, __orientation, __operation)
+#else
+#define ASSERT_STREAM(__stream, __orientation, __operation) do { \
+ ASSERT_NONNULL(__stream); \
+ if (((__orientation) && stream->orientation) && ((__orientation) != stream->orientation)) { \
+ UNDEFINED("In call to %s(): Requested %s operation on %s oriented stream", __func__, (__orientation) > 0 ? "wide" : "byte", (stream->orientation) > 0 ? "wide" : "byte"); \
+ } \
+ } while (0)
+#endif
+
struct __FILE {
fpos_t pos;
@@ -38,14 +55,15 @@ struct __FILE {
int fd; /* the backing file descriptor */
- int orientation; /* 0 = undetermind, < 0 = byte, > 0 = wide */
-
- int eof; /* eof indicator */
- int err; /* error indicator */
-
int nlocks; /* in multithreaded, used by flockfile() */
int thread; /* the owning thread if locked */
+ int orientation:2; /* 0 = undetermind, < 0 = byte, > 0 = wide */
+ int operation; /* TODO: previous operation, NONE, INPUT, OUTPUT (are there others?) */
+ int eof:1; /* eof indicator */
+ int err:1; /* error indicator */
+ int text:1; /* is this a text file? */
+
#ifdef _POSIX_C_SOURCE
pid_t pipe_pid; /* if stream is a pipe, the child pid */
#endif
diff --git a/src/stdio/clearerr.c b/src/stdio/clearerr.c
index f7d2aac1..9f13851e 100644
--- a/src/stdio/clearerr.c
+++ b/src/stdio/clearerr.c
@@ -7,6 +7,8 @@
void clearerr(FILE * stream)
{
SIGNAL_SAFE(0);
+ ASSERT_STREAM(stream, 0, 0);
+
flockfile(stream);
if (stream != NULL) {
stream->eof = 0;
diff --git a/src/stdio/feof.c b/src/stdio/feof.c
index 39d9b645..fdcb9ea9 100644
--- a/src/stdio/feof.c
+++ b/src/stdio/feof.c
@@ -6,7 +6,8 @@
int feof(FILE *stream)
{
SIGNAL_SAFE(0);
- ASSERT_NONNULL(stream);
+ ASSERT_STREAM(stream, 0, 0);
+
flockfile(stream);
if (stream->eof) {
diff --git a/src/stdio/ferror.c b/src/stdio/ferror.c
index 66299ab9..1d2fcc8d 100644
--- a/src/stdio/ferror.c
+++ b/src/stdio/ferror.c
@@ -6,7 +6,7 @@
int ferror(FILE *stream)
{
SIGNAL_SAFE(0);
- ASSERT_NONNULL(stream);
+ ASSERT_STREAM(stream, 0, 0);
/*
RETURN(0, the error indicator is not set);
RETURN(NONZERO, the error indicator is set);
diff --git a/src/stdio/fgetc.c b/src/stdio/fgetc.c
index 06e4c064..2bae1eb7 100644
--- a/src/stdio/fgetc.c
+++ b/src/stdio/fgetc.c
@@ -12,9 +12,12 @@
int fgetc(FILE *stream)
{
SIGNAL_SAFE(0);
+ ASSERT_STREAM(stream, ORIENT_BYTE, OP_INPUT);
+
flockfile(stream);
char c = getc_unlocked(stream);
funlockfile(stream);
+
/*
RETURN_SUCCESS(the next character);
RETURN_FAILURE(CONSTANT(EOF));
diff --git a/src/stdio/freopen.c b/src/stdio/freopen.c
index 0fd0a2f8..3a1ef656 100644
--- a/src/stdio/freopen.c
+++ b/src/stdio/freopen.c
@@ -70,7 +70,7 @@ FILE * freopen(const char * restrict filename, const char * restrict mode, FILE
}
if (openmode == -1) {
- __undefined("\"%s\" is not a valid mode for fopen() or freopen()", mode);
+ UNDEFINED("\"%s\" is not a valid mode for fopen() or freopen()", mode);
#ifdef EINVAL
errno = EINVAL;
#endif
@@ -96,6 +96,8 @@ FILE * freopen(const char * restrict filename, const char * restrict mode, FILE
stream->buf = stream->ibuf;
}
+ stream->text = !(strchr(mode, 'b'));
+
/*
RETURN_SUCCESS(ARGUMENT(stream));
RETURN_FAILURE(CONSTANT(NULL));
diff --git a/src/stdio/fseek.c b/src/stdio/fseek.c
index e1c6db57..47388c9a 100644
--- a/src/stdio/fseek.c
+++ b/src/stdio/fseek.c
@@ -6,8 +6,15 @@
int fseek(FILE *stream, long int offset, int whence)
{
SIGNAL_SAFE(0);
-
- (void)stream; (void)offset;
+ ASSERT_STREAM(stream, 0, 0);
+
+ if (stream->text && offset != 0) {
+ if (whence != SEEK_SET) {
+ UNDEFINED("In call to fseek(): Only SEEK_SET is supported for text files");
+ }
+ /* if offset is not previous */
+ /* UNDEFINED("fseek() on text files requires an offset previously returned by ftell()"); */
+ }
if (whence == SEEK_CUR) {
} else if (whence == SEEK_END) {