commit 0507169ee281ff85788004c7fd01de9e03541ce1
parent 4fcd2f187ce6d417de018324bd6463dd264cfb0c
Author: Roberto Vargas <roberto.vargas@arm.com>
Date: Wed, 7 Nov 2018 16:15:02 +0000
[libc] Fix line buffering mode in FILEs
Change-Id: Ie31ea523301c4fca584aff08737e53e8bd638175
Diffstat:
12 files changed, 60 insertions(+), 44 deletions(-)
diff --git a/include/stdio.h b/include/stdio.h
@@ -110,8 +110,8 @@ extern void perror(const char *s);
extern int __getc(FILE *fp);
extern int __putc(int, FILE *fp);
-#define getc(fp) ((fp)->rp >= (fp)->wp ? __getc(fp) : *(fp)->rp++)
-#define putc(c, fp) ((fp)->wp >= (fp)->rp ? __putc(c,fp) : (*(fp)->wp++ = c))
+#define getc(fp) ((fp)->rp >= (fp)->wp ? __getc(fp) : *(fp)->rp++)
+#define putc(c, fp) ((fp)->wp >= (fp)->rp ? __putc(c,fp) : (*(fp)->wp++ = c))
#define ferror(fp) ((fp)->flags & _IOERR)
#define feof(fp) ((fp)->flags & _IOEOF)
diff --git a/src/libc/libc.h b/src/libc/libc.h
@@ -33,7 +33,10 @@ struct tm;
extern struct tzone *_tzone(struct tm *tm);
extern int _daysyear(int year);
extern int _newyear(int year);
-
extern void *_getheap(void);
+#ifdef FILE
+extern int _flsbuf(FILE *fp);
+extern void _allocbuf(FILE *fp);
+#endif
extern int _daysmon[12];
diff --git a/src/libc/stdio/Makefile b/src/libc/stdio/Makefile
@@ -36,11 +36,12 @@ OBJS = __getc.o\
setvbuf.o\
snprintf.o\
sprintf.o\
- stdio.o\
+ __iob.o\
tmpnam.o\
vfprintf.o\
vsnprintf.o\
vsprintf.o\
vprintf.o\
+ _allocbuf.o\
all: $(OBJS)
diff --git a/src/libc/stdio/__getc.c b/src/libc/stdio/__getc.c
@@ -1,8 +1,8 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include "../libc.h"
#include "../syscall.h"
-#undef getc
int
__getc(FILE *fp)
@@ -23,15 +23,8 @@ __getc(FILE *fp)
return EOF;
}
- if (fp->buf == NULL) {
- if ((fp->buf = malloc(BUFSIZ)) == NULL) {
- errno = ENOMEM;
- return EOF;
- }
- fp->len = BUFSIZ;
- fp->flags |= _IOALLOC;
- fp->lp = fp->rp = fp->wp = fp->buf;
- }
+ if (fp->buf == NULL && _allocbuf(fp))
+ return EOF;
if ((cnt = _read(fp->fd, fp->buf, fp->len)) <= 0) {
fp->flags |= (cnt == 0) ? _IOEOF : _IOERR;
diff --git a/src/libc/stdio/stdio.c b/src/libc/stdio/__iob.c
diff --git a/src/libc/stdio/__putc.c b/src/libc/stdio/__putc.c
@@ -1,8 +1,7 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-
-extern int _flsbuf(FILE *fp);
+#include "../libc.h"
int
fflush(FILE *fp)
@@ -45,14 +44,8 @@ __putc(int ch, FILE *fp)
return EOF;
}
- if (fp->buf == NULL) {
- if ((fp->buf = malloc(BUFSIZ)) == NULL) {
- errno = ENOMEM;
+ if (fp->buf == NULL && _allocbuf(fp))
return EOF;
- }
- fp->flags |= _IOALLOC;
- fp->rp = fp->wp = fp->lp = fp->buf;
- }
if (first) {
if (atexit(cleanup)) {
@@ -64,15 +57,16 @@ __putc(int ch, FILE *fp)
}
if (fp->flags & _IOLBF) {
- if (fp->lp == fp->rp && _flsbuf(fp))
+ if (fp->wp == fp->lp && _flsbuf(fp))
return EOF;
- *fp->lp++ = ch;
+ *fp->wp++ = ch;
if (ch == '\n' && _flsbuf(fp))
return EOF;
} else if (fp->flags & _IOFBF) {
- if (fp->wp == fp->rp && _flsbuf(fp))
+ if (_flsbuf(fp))
return EOF;
*fp->wp++ = ch;
+ fp->rp = fp->buf + fp->len;
} else {
*fp->wp++ = ch;
if (_flsbuf(fp))
diff --git a/src/libc/stdio/_allocbuf.c b/src/libc/stdio/_allocbuf.c
@@ -0,0 +1,21 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "../libc.h"
+
+int
+_allocbuf(FILE *fp)
+{
+ char *bp;
+
+ if ((bp = malloc(BUFSIZ)) == NULL) {
+ fp->flags |= _IOERR;
+ errno = ENOMEM;
+ return EOF;
+ }
+ fp->len = BUFSIZ;
+ fp->rp = fp->wp = fp->buf = bp;
+ fp->lp = bp + BUFSIZ;
+
+ return 0;
+}
diff --git a/src/libc/stdio/_flsbuf.c b/src/libc/stdio/_flsbuf.c
@@ -1,21 +1,23 @@
#include <errno.h>
#include <stdio.h>
+
+#include "../libc.h"
#include "../syscall.h"
int
_flsbuf(FILE *fp)
{
- unsigned char *p;
size_t cnt;
- p = (fp->flags & _IOLBF) ? fp->lp : fp->wp;
- cnt = p - fp->buf;
+ if (fp->flags&_IOREAD)
+ return 0;
- if (_write(fp->fd, fp->buf, cnt) != cnt) {
+ cnt = fp->wp - fp->buf;
+ if (cnt > 0 && _write(fp->fd, fp->buf, cnt) != cnt) {
fp->flags |= _IOERR;
return EOF;
}
- fp->lp = fp->rp = fp->wp = fp->buf;
+ fp->wp = fp->buf;
return 0;
}
diff --git a/src/libc/stdio/fclose.c b/src/libc/stdio/fclose.c
@@ -3,8 +3,6 @@
#include "../syscall.h"
#undef fclose
-extern int _flsbuf(FILE *fp);
-
int
fclose(FILE *fp)
{
diff --git a/src/libc/stdio/fseek.c b/src/libc/stdio/fseek.c
@@ -2,8 +2,6 @@
#include "../syscall.h"
#undef fseek
-extern int _flsbuf(FILE *fp);
-
int
fseek(FILE *fp, long off, int whence)
{
diff --git a/src/libc/stdio/setvbuf.c b/src/libc/stdio/setvbuf.c
@@ -3,23 +3,29 @@
#include <stdlib.h>
#undef setvbuf
-extern int _flsbuf(FILE *fp);
-
int
setvbuf(FILE * restrict fp, char * restrict buf, int mode, size_t size)
{
int flags;
+ char *p;
+ size_t l;
if (_flsbuf(fp) == EOF)
return EOF;
+ if (buf)
+ p = buf, l = size;
+ else
+ p = fp->buf, l = fp->len;
+
switch (mode) {
case _IONBF:
- size = sizeof(fp->unbuf);
- buf = fp->unbuf;
- break;
+ l = sizeof(fp->unbuf);
+ p = fp->unbuf;
case _IOLBF:
case _IOFBF:
+ fp->rp = fp->wp = p;
+ fp->lp = p + l;
break;
default:
errno = EINVAL;
@@ -27,13 +33,13 @@ setvbuf(FILE * restrict fp, char * restrict buf, int mode, size_t size)
}
flags = fp->flags;
- if (buf && (flags & _IOALLOC)) {
+ if (flags&_IOALLOC && (buf || mode == _IONBF)) {
free(fp->buf);
- fp->buf = buf;
- fp->len = size;
flags &= ~_IOALLOC;
}
+ fp->buf = p;
+ fp->len = l;
flags &= ~(_IONBF | _IOLBF | _IOFBF);
flags |= mode;
fp->flags = flags;
diff --git a/src/libc/stdio/vprintf.c b/src/libc/stdio/vprintf.c
@@ -7,5 +7,5 @@ vprintf(const char *fmt, va_list ap)
va_list ap2;
va_copy(ap2, ap);
- return vfprintf(stdin, fmt, ap2);
+ return vfprintf(stdout, fmt, ap2);
}