Browse Source

Fix a couple of bugs in _fopen and fclose, plus change a few internals.

Manuel Novoa III 23 years ago
parent
commit
93ccb0356b
2 changed files with 83 additions and 60 deletions
  1. 3 1
      libc/stdio/Makefile
  2. 80 59
      libc/stdio/stdio.c

+ 3 - 1
libc/stdio/Makefile

@@ -35,7 +35,9 @@ ifeq ($(HAS_LONG_LONG),true)
 endif
 
 MSRC=stdio.c
-MOBJ=_stdio_init.o _stdio_buffer.o  clearerr.o feof.o ferror.o fileno.o \
+MOBJ=_stdio_init.o \
+     _alloc_stdio_buffer.o _free_stdio_buffer.o _free_stdio_stream.o \
+     clearerr.o feof.o ferror.o fileno.o \
      setbuffer.o setvbuf.o setbuf.o setlinebuf.o \
      fclose.o _fopen.o fopen.o freopen.o fdopen.o fflush.o \
      fseek.o rewind.o ftell.o fgetpos.o fsetpos.o \

+ 80 - 59
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) {