summaryrefslogtreecommitdiff
path: root/libc/stdio/stdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/stdio/stdio.c')
-rw-r--r--libc/stdio/stdio.c139
1 files changed, 80 insertions, 59 deletions
diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c
index b3d514c35..7ed545742 100644
--- a/libc/stdio/stdio.c
+++ b/libc/stdio/stdio.c
@@ -49,7 +49,7 @@ extern void _free_stdio_buffer(unsigned char *buf);
extern void _free_stdio_stream(FILE *fp);
#endif
-#ifdef L__stdio_buffer
+#ifdef L__alloc_stdio_buffer
unsigned char *_alloc_stdio_buffer(size_t size)
{
if (size == BUFSIZ) {
@@ -63,7 +63,9 @@ unsigned char *_alloc_stdio_buffer(size_t size)
}
return malloc(size);
}
+#endif
+#ifdef L__free_stdio_buffer
void _free_stdio_buffer(unsigned char *buf)
{
int i;
@@ -117,8 +119,10 @@ FILE *_stderr = _stdio_streams + 2;
*/
FILE *__IO_list = _stdio_streams; /* For fflush at exit */
-/* Call the stdio initiliser; it's main job it to call atexit */
-
+/*
+ * __stdio_close_all is automatically when exiting if stdio is used.
+ * See misc/internals/__uClibc_main.c and and stdlib/atexit.c.
+ */
void __stdio_close_all(void)
{
FILE *fp;
@@ -129,6 +133,9 @@ void __stdio_close_all(void)
}
}
+/*
+ * __init_stdio is automatically by __uClibc_main if stdio is used.
+ */
void __init_stdio(void)
{
#if (FIXED_BUFFERS > 2) || (FIXED_STREAMS > 3)
@@ -148,12 +155,13 @@ void __init_stdio(void)
_fixed_buffers[0].used = 1;
_fixed_buffers[1].used = 1;
- if (isatty(1)) {
- stdout->mode |= _IOLBF;
- }
+#if _IOFBF != 0 || _IOLBF != 1
+#error Assumption violated -- values of _IOFBF and/or _IOLBF
+/* This asssumption is also made in _fopen. */
+#endif
- /* Cleanup is now taken care of in __uClibc_main. */
- /* atexit(__stdio_close_all); */
+ /* stdout uses line buffering when connected to a tty. */
+ _stdio_streams[1].mode |= isatty(1);
}
#endif
@@ -206,9 +214,18 @@ FILE *fp;
if (fp->mode & __MODE_WRITING)
fflush(fp);
+#if 1
+#warning Need to check out tie between stdin and stdout.
+ /*
+ * This bit of code needs checking. The way I read the C89 standard,
+ * there is no guarantee that stdout is flushed before reading stdin.
+ * Plus, this is broken if either stdin or stdout has been closed and
+ * reopend.
+ */
if ( (fp == stdin) && (stdout->fd != -1)
&& (stdout->mode & __MODE_WRITING) )
fflush(stdout);
+#endif
/* Can't read or there's been an EOF or error then return EOF */
if ((fp->mode & (__MODE_READ | __MODE_EOF | __MODE_ERR)) !=
@@ -572,32 +589,32 @@ const char *mode;
int fopen_mode;
int i;
- fopen_mode = 0;
+ nfp = fp;
- /* If we've got an fp close the old one (freopen) */
- if (fp) { /* We don't want to deallocate fp. */
- fopen_mode |=
- (fp->mode & (__MODE_BUF | __MODE_FREEFIL | __MODE_FREEBUF));
- fp->mode &= ~(__MODE_FREEFIL | __MODE_FREEBUF);
- fclose(fp);
+ /* If we've got an fp, flush it and close the old fd (freopen) */
+ if (nfp) { /* We don't want to deallocate fp. */
+ fflush(nfp);
+ close(nfp->fd);
+ nfp->mode &= (__MODE_FREEFIL | __MODE_FREEBUF);
}
- /* decode the new open mode */
+ /* Parse the mode string arg. */
switch (*mode++) {
case 'r': /* read */
- fopen_mode |= __MODE_READ;
+ fopen_mode = __MODE_READ;
open_mode = O_RDONLY;
break;
case 'w': /* write (create or truncate)*/
- fopen_mode |= __MODE_WRITE;
+ fopen_mode = __MODE_WRITE;
open_mode = (O_WRONLY | O_CREAT | O_TRUNC);
break;
case 'a': /* write (create or append) */
- fopen_mode |= __MODE_WRITE;
+ fopen_mode = __MODE_WRITE;
open_mode = (O_WRONLY | O_CREAT | O_APPEND);
break;
default: /* illegal mode */
- return 0;
+ errno = EINVAL;
+ goto _fopen_ERROR;
}
if ((*mode == 'b')) { /* binary mode (nop for uClibc) */
@@ -618,7 +635,6 @@ const char *mode;
++mode;
}
- nfp = 0;
if (fp == 0) { /* We need a FILE so allocate it before */
for (i = 0; i < FIXED_STREAMS; i++) { /* we potentially call open. */
if (_stdio_streams[i].fd == -1) {
@@ -629,46 +645,46 @@ const char *mode;
if ((i == FIXED_STREAMS) && (!(nfp = malloc(sizeof(FILE))))) {
return 0;
}
+ nfp->mode = __MODE_FREEFIL;
+ /* Initially set to use 8 byte buffer in FILE structure */
+ nfp->bufstart = nfp->unbuf;
+ nfp->bufend = nfp->unbuf + sizeof(nfp->unbuf);
}
-
if (fname) { /* Open the file itself */
fd = open(fname, open_mode, 0666);
}
- if (fd < 0) { /* Error from open or bad arg. */
+#warning fdopen should check that modes are compatible with existing fd.
+
+ if (fd < 0) { /* Error from open or bad arg passed. */
+ _fopen_ERROR:
if (nfp) {
+ if (nfp->mode & __MODE_FREEBUF) {
+ _free_stdio_buffer(nfp->bufstart);
+ }
_free_stdio_stream(nfp);
}
return 0;
}
+ nfp->fd = fd; /* Set FILE's fd before adding to open list. */
+
if (fp == 0) { /* Not freopen so... */
- fp = nfp; /* use newly created FILE and */
- fp->next = __IO_list; /* add it to the list of open files. */
- __IO_list = fp;
-
- fp->mode = __MODE_FREEFIL;
- if (!(fp->bufstart = _alloc_stdio_buffer(BUFSIZ))) {
- /* Allocation failed so use 8 byte buffer in FILE structure */
- fp->bufstart = fp->unbuf;
- fp->bufend = fp->unbuf + sizeof(fp->unbuf);
- } else {
- fp->bufend = fp->bufstart + BUFSIZ;
- fp->mode |= __MODE_FREEBUF;
- }
- }
+ nfp->next = __IO_list; /* use newly created FILE and */
+ __IO_list = nfp; /* add it to the list of open files. */
- if (isatty(fd)) {
- fp->mode |= _IOLBF;
- } else { /* Note: the following should be optimized */
- fp->mode |= _IOFBF; /* away since we should have _IOFBF = 0. */
+ if ((nfp->bufstart = _alloc_stdio_buffer(BUFSIZ)) != 0) {
+ nfp->bufend = nfp->bufstart + BUFSIZ;
+ nfp->mode |= __MODE_FREEBUF;
+ }
}
/* Ok, file's ready clear the buffer and save important bits */
- fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
- fp->mode |= fopen_mode;
- fp->fd = fd;
- return fp;
+ nfp->bufpos = nfp->bufread = nfp->bufwrite = nfp->bufstart;
+ nfp->mode |= fopen_mode;
+ nfp->mode |= isatty(fd);
+
+ return nfp;
}
#endif
@@ -688,33 +704,38 @@ FILE *fp;
rv = EOF;
}
- if (fp->mode & __MODE_FREEBUF) {
+ if (fp->mode & __MODE_FREEBUF) { /* Free buffer if necessary. */
_free_stdio_buffer(fp->bufstart);
}
- if (fp->mode & __MODE_FREEFIL) {
- prev = 0;
- for (ptr = __IO_list; ptr ; ptr = ptr->next) {
- if (ptr == fp) {
- if (prev == 0) {
- __IO_list = fp->next;
- } else {
- prev->next = fp->next;
- }
- _free_stdio_stream(fp);
- break;
+ prev = 0; /* Remove file from open list. */
+ for (ptr = __IO_list; ptr ; ptr = ptr->next) {
+ if (ptr == fp) {
+ if (prev == 0) {
+ __IO_list = fp->next;
+ } else {
+ prev->next = fp->next;
}
- prev = ptr;
+ break;
}
+ prev = ptr;
}
+ _free_stdio_stream(fp); /* Finally free the stream if necessary. */
+
return rv;
}
+#endif
-/* The following is only called by fclose and _fopen (which calls fclose) */
+#ifdef L__free_stdio_stream
+/* The following is only called by fclose and _fopen. */
void _free_stdio_stream(FILE *fp)
{
int i;
+
+ if (!(fp->mode & __MODE_FREEFIL)) {
+ return;
+ }
for (i = 0; i < FIXED_STREAMS; i++) {
if (fp == _stdio_streams + i) {