mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 10:48:29 +00:00
Get GNU GMP test suite fully passing
- Fix stdio fmemopen() buffer behaviors - Fix scanf() to return EOF when appropriate - Prefer fseek/ftell names over fseeko/ftello - Ensure locale field is always set in the TIB - Fix recent regression in vfprintf() return count - Make %n directive in scanf() have standard behavior
This commit is contained in:
parent
755ae64e73
commit
63a1636e1f
20 changed files with 228 additions and 51 deletions
|
@ -25,8 +25,6 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
// TODO(jart): POSIX says buffer needs to grow in write modes?
|
||||
|
||||
/**
|
||||
* Opens buffer as stream.
|
||||
*
|
||||
|
@ -63,7 +61,9 @@ FILE *fmemopen(void *buf, size_t size, const char *mode) {
|
|||
}
|
||||
f->fd = -1;
|
||||
f->buf = buf;
|
||||
f->end = size;
|
||||
if (!(iomode & O_TRUNC)) {
|
||||
f->end = size;
|
||||
}
|
||||
f->size = size;
|
||||
f->iomode = iomode;
|
||||
if (iomode & O_APPEND) {
|
||||
|
|
|
@ -35,14 +35,14 @@
|
|||
* @returns 0 on success or -1 on error
|
||||
* @threadsafe
|
||||
*/
|
||||
int fseeko(FILE *f, int64_t offset, int whence) {
|
||||
int fseek(FILE *f, int64_t offset, int whence) {
|
||||
int rc;
|
||||
flockfile(f);
|
||||
rc = fseeko_unlocked(f, offset, whence);
|
||||
STDIOTRACE("fseeko(%p, %'ld, %s) → %d %s", f, offset, DescribeWhence(whence),
|
||||
rc = fseek_unlocked(f, offset, whence);
|
||||
STDIOTRACE("fseek(%p, %'ld, %s) → %d %s", f, offset, DescribeWhence(whence),
|
||||
rc, DescribeStdioState(f->state));
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
||||
__strong_reference(fseeko, fseek);
|
||||
__strong_reference(fseek, fseeko);
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -35,7 +36,7 @@
|
|||
* @param whence can be SEET_SET, SEEK_CUR, or SEEK_END
|
||||
* @returns 0 on success or -1 on error
|
||||
*/
|
||||
int fseeko_unlocked(FILE *f, int64_t offset, int whence) {
|
||||
int fseek_unlocked(FILE *f, int64_t offset, int whence) {
|
||||
int res;
|
||||
ssize_t rc;
|
||||
int64_t pos;
|
||||
|
@ -68,6 +69,7 @@ int fseeko_unlocked(FILE *f, int64_t offset, int whence) {
|
|||
pos = -1;
|
||||
break;
|
||||
}
|
||||
f->end = MAX(f->beg, f->end);
|
||||
if (0 <= pos && pos <= f->end) {
|
||||
f->beg = pos;
|
||||
f->state = 0;
|
|
@ -24,7 +24,7 @@
|
|||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
static inline int64_t ftello_unlocked(FILE *f) {
|
||||
static inline int64_t ftell_unlocked(FILE *f) {
|
||||
int64_t pos;
|
||||
uint32_t skew;
|
||||
if (f->fd != -1) {
|
||||
|
@ -48,12 +48,12 @@ static inline int64_t ftello_unlocked(FILE *f) {
|
|||
* @returns current byte offset from beginning, or -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
int64_t ftello(FILE *f) {
|
||||
int64_t ftell(FILE *f) {
|
||||
int64_t rc;
|
||||
flockfile(f);
|
||||
rc = ftello_unlocked(f);
|
||||
rc = ftell_unlocked(f);
|
||||
funlockfile(f);
|
||||
return rc;
|
||||
}
|
||||
|
||||
__strong_reference(ftello, ftell);
|
||||
__strong_reference(ftell, ftello);
|
|
@ -29,7 +29,7 @@
|
|||
*/
|
||||
void rewind(FILE *f) {
|
||||
flockfile(f);
|
||||
fseeko_unlocked(f, 0, SEEK_SET);
|
||||
fseek_unlocked(f, 0, SEEK_SET);
|
||||
f->state = 0;
|
||||
funlockfile(f);
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ wchar_t *fgetws_unlocked(wchar_t *, int, FILE *);
|
|||
int fputws_unlocked(const wchar_t *, FILE *);
|
||||
wint_t ungetwc_unlocked(wint_t, FILE *) paramsnonnull();
|
||||
int ungetc_unlocked(int, FILE *) paramsnonnull();
|
||||
int fseeko_unlocked(FILE *, int64_t, int) paramsnonnull();
|
||||
int fseek_unlocked(FILE *, int64_t, int) paramsnonnull();
|
||||
ssize_t getdelim_unlocked(char **, size_t *, int, FILE *) paramsnonnull();
|
||||
int fprintf_unlocked(FILE *, const char *, ...) printfesque(2)
|
||||
paramsnonnull((1, 2)) dontthrow nocallback;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
@ -27,6 +28,13 @@
|
|||
#include "libc/str/utf16.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define READ \
|
||||
({ \
|
||||
int c = callback(arg); \
|
||||
if (c != -1) ++consumed; \
|
||||
c; \
|
||||
})
|
||||
|
||||
/**
|
||||
* String / file / stream decoder.
|
||||
*
|
||||
|
@ -54,10 +62,12 @@ int __vcscanf(int callback(void *), //
|
|||
void *ptr;
|
||||
} *freeme = NULL;
|
||||
const unsigned char *p = (const unsigned char *)fmt;
|
||||
unsigned i = 0;
|
||||
int *n_ptr;
|
||||
int items = 0;
|
||||
int c = callback(arg);
|
||||
while (c != -1) {
|
||||
int consumed = 0;
|
||||
unsigned i = 0;
|
||||
int c = READ;
|
||||
for (;;) {
|
||||
switch (p[i++]) {
|
||||
case '\0':
|
||||
if (c != -1 && unget) {
|
||||
|
@ -70,7 +80,7 @@ int __vcscanf(int callback(void *), //
|
|||
case '\r':
|
||||
case '\v':
|
||||
while (isspace(c)) {
|
||||
c = callback(arg);
|
||||
c = READ;
|
||||
}
|
||||
break;
|
||||
case '%': {
|
||||
|
@ -115,8 +125,11 @@ int __vcscanf(int callback(void *), //
|
|||
case 'c':
|
||||
rawmode = true;
|
||||
if (!width) width = 1;
|
||||
/* εpsilon transition */
|
||||
// fallthrough
|
||||
case 's':
|
||||
while (isspace(c)) {
|
||||
c = READ;
|
||||
}
|
||||
goto DecodeString;
|
||||
case '\'':
|
||||
thousands = true;
|
||||
|
@ -144,38 +157,61 @@ int __vcscanf(int callback(void *), //
|
|||
case 'b': /* binary */
|
||||
base = 2;
|
||||
prefix = 'b';
|
||||
while (isspace(c)) {
|
||||
c = READ;
|
||||
}
|
||||
goto ConsumeBasePrefix;
|
||||
case 'p': /* pointer (NexGen32e) */
|
||||
bits = 48;
|
||||
while (isspace(c)) {
|
||||
c = READ;
|
||||
}
|
||||
/* fallthrough */
|
||||
case 'x':
|
||||
case 'X': /* hexadecimal */
|
||||
base = 16;
|
||||
prefix = 'x';
|
||||
while (isspace(c)) {
|
||||
c = READ;
|
||||
}
|
||||
goto ConsumeBasePrefix;
|
||||
case 'o': /* octal */
|
||||
base = 8;
|
||||
goto DecodeNumber;
|
||||
case 'd': /* decimal */
|
||||
case 'n': /* TODO(jart): flexidecimal */
|
||||
issigned = true;
|
||||
if (c == '+' || (isneg = c == '-')) {
|
||||
c = callback(arg);
|
||||
while (isspace(c)) {
|
||||
c = READ;
|
||||
}
|
||||
/* εpsilon transition */
|
||||
goto DecodeNumber;
|
||||
case 'n':
|
||||
goto ReportConsumed;
|
||||
case 'd': // decimal
|
||||
issigned = true;
|
||||
while (isspace(c)) {
|
||||
c = READ;
|
||||
}
|
||||
if (c == '+' || (isneg = c == '-')) {
|
||||
c = READ;
|
||||
}
|
||||
// fallthrough
|
||||
case 'u':
|
||||
base = 10;
|
||||
while (isspace(c)) {
|
||||
c = READ;
|
||||
}
|
||||
goto DecodeNumber;
|
||||
default:
|
||||
items = einval();
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
ReportConsumed:
|
||||
n_ptr = va_arg(va, int *);
|
||||
*n_ptr = consumed - 1; // minus lookahead
|
||||
continue;
|
||||
ConsumeBasePrefix:
|
||||
if (c == '0') {
|
||||
c = callback(arg);
|
||||
c = READ;
|
||||
if (c == prefix || c == prefix + ('a' - 'A')) {
|
||||
c = callback(arg);
|
||||
c = READ;
|
||||
} else if (c == -1) {
|
||||
c = '0';
|
||||
}
|
||||
|
@ -195,7 +231,7 @@ int __vcscanf(int callback(void *), //
|
|||
} else {
|
||||
break;
|
||||
}
|
||||
} while ((c = callback(arg)) != -1 && width > 0);
|
||||
} while ((c = READ) != -1 && width > 0);
|
||||
if (!discard) {
|
||||
uint128_t bane = (uint128_t)1 << (bits - 1);
|
||||
if (!(number & ~((bane - 1) | (issigned ? 0 : bane))) ||
|
||||
|
@ -228,7 +264,13 @@ int __vcscanf(int callback(void *), //
|
|||
*(uint8_t *)out = (uint8_t)number;
|
||||
break;
|
||||
}
|
||||
} else if (!items && c == -1) {
|
||||
items = -1;
|
||||
goto Done;
|
||||
}
|
||||
} else if (!items) {
|
||||
items = -1;
|
||||
goto Done;
|
||||
}
|
||||
continue;
|
||||
DecodeString:
|
||||
|
@ -256,7 +298,7 @@ int __vcscanf(int callback(void *), //
|
|||
if (c != -1 && j + !rawmode < bufsize && (rawmode || !isspace(c))) {
|
||||
if (charbytes == 1) {
|
||||
((unsigned char *)buf)[j++] = (unsigned char)c;
|
||||
c = callback(arg);
|
||||
c = READ;
|
||||
} else if (tpdecodecb((wint_t *)&c, c, (void *)callback, arg) !=
|
||||
-1) {
|
||||
if (charbytes == sizeof(char16_t)) {
|
||||
|
@ -270,10 +312,13 @@ int __vcscanf(int callback(void *), //
|
|||
} else {
|
||||
((wchar_t *)buf)[j++] = (wchar_t)c;
|
||||
}
|
||||
c = callback(arg);
|
||||
c = READ;
|
||||
}
|
||||
} else {
|
||||
if (!rawmode && j < bufsize) {
|
||||
if (!j && c == -1 && !items) {
|
||||
items = -1;
|
||||
goto Done;
|
||||
} else if (!rawmode && j < bufsize) {
|
||||
if (charbytes == sizeof(char)) {
|
||||
((unsigned char *)buf)[j] = '\0';
|
||||
} else if (charbytes == sizeof(char16_t)) {
|
||||
|
@ -292,13 +337,13 @@ int __vcscanf(int callback(void *), //
|
|||
} else {
|
||||
do {
|
||||
if (isspace(c)) break;
|
||||
} while ((c = callback(arg)) != -1);
|
||||
} while ((c = READ) != -1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NonDirectiveCharacter:
|
||||
c = (c == p[i - 1]) ? callback(arg) : -1;
|
||||
c = (c == p[i - 1]) ? READ : -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ static int __vfprintf_flbuf(const char *s, struct state *t, size_t n) {
|
|||
if (n) {
|
||||
if (n == 1 && *s != '\n' && t->f->beg < t->f->size) {
|
||||
t->f->buf[t->f->beg++] = *s;
|
||||
t->n += n;
|
||||
rc = 0;
|
||||
} else if (fwrite_unlocked(s, 1, n, t->f)) {
|
||||
rc = 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue