[klibc] Fold fopen and fdopen

Fold common features of fopen() and fdopen().  In particular,
POSIX doesn't actually require that fdopen() modifies the flags
on the file descriptor, so *don't* -- this is klibc, after all.

With that, we can then remove __fxopen() and __parse_open_mode() and
fold them into fdopen() and fopen() respectively.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild
index a82ffa9..fc90d53 100644
--- a/usr/klibc/Kbuild
+++ b/usr/klibc/Kbuild
@@ -67,7 +67,6 @@
 	  userdb/getpwuid.o userdb/root_group.o userdb/root_user.o \
 	  setmntent.o endmntent.o getmntent.o \
 	  stdio/fclose.o stdio/fopen.o stdio/fdopen.o \
-	  stdio/openmode.o stdio/fxopen.o \
 	  stdio/fread.o stdio/fwrite.o stdio/fflush.o \
 	  stdio/ungetc.o stdio/fgetc.o \
 	  stdio/fseek.o stdio/ftell.o stdio/rewind.o \
diff --git a/usr/klibc/stdio/fdopen.c b/usr/klibc/stdio/fdopen.c
index 99f3a80..a12efe5 100644
--- a/usr/klibc/stdio/fdopen.c
+++ b/usr/klibc/stdio/fdopen.c
@@ -1,20 +1,62 @@
 /*
  * fdopen.c
+ *
+ * Common code between fopen(), fdopen() and the standard descriptors.
  */
 
 #include "stdioint.h"
 
+FILE *stdin, *stdout, *stderr;
+
+/* Doubly-linked list of all stdio structures */
+struct _IO_file_pvt __stdio_headnode =
+{
+	.prev = &__stdio_headnode,
+	.next = &__stdio_headnode,
+};
+
 FILE *fdopen(int fd, const char *mode)
 {
-	int flags = __parse_open_mode(mode);
-	int oldflags;
+	struct _IO_file_pvt *f;
+	const size_t bufoffs =
+		(sizeof *f + 4*sizeof(void *) - 1) &
+		~(4*sizeof(void *) - 1);
 
-	if (fcntl(fd, F_GETFL, &oldflags))
-		return NULL;
+	(void)mode;
 
-	oldflags = (oldflags & ~O_APPEND) | (flags & O_APPEND);
-	if (fcntl(fd, F_SETFL, &oldflags))
-		return NULL;
+	f = zalloc(bufoffs + BUFSIZ + _IO_UNGET_SLOP);
+	if (!f)
+		goto err;
 
-	return __fxopen(fd, flags, 0);
+	f->data = f->buf = (char *)f + bufoffs;
+	f->pub._io_fileno = fd;
+	f->pub._io_filepos = lseek(fd, 0, SEEK_CUR);
+	f->bufsiz = BUFSIZ;
+	f->bufmode = isatty(fd) ? _IOLBF : _IOFBF;
+
+	/* Insert into linked list */
+	f->prev = &__stdio_headnode;
+	f->next = __stdio_headnode.next;
+	f->next->prev = f;
+	__stdio_headnode.next = f;
+
+	return &f->pub;
+
+err:
+	if (f)
+		free(f);
+	errno = ENOMEM;
+	return NULL;
+}
+
+void __init_stdio(void)
+{
+	stdin  = fdopen(0, NULL);
+	stdio_pvt(stdin)->bufmode = _IOLBF;
+
+	stdout = fdopen(1, NULL);
+	stdio_pvt(stdout)->bufmode = _IOLBF;
+
+	stderr = fdopen(2, NULL);
+	stdio_pvt(stderr)->bufmode = _IONBF;
 }
diff --git a/usr/klibc/stdio/fopen.c b/usr/klibc/stdio/fopen.c
index 475620f..cf098df 100644
--- a/usr/klibc/stdio/fopen.c
+++ b/usr/klibc/stdio/fopen.c
@@ -4,16 +4,56 @@
 
 #include "stdioint.h"
 
-extern int __parse_open_mode(const char *);
+static int __parse_open_mode(const char *mode)
+{
+	int rwflags = O_RDONLY;
+	int crflags = 0;
+	int eflags  = 0;
+
+	while (*mode) {
+		switch (*mode++) {
+		case 'r':
+			rwflags = O_RDONLY;
+			crflags = 0;
+			break;
+		case 'w':
+			rwflags = O_WRONLY;
+			crflags = O_CREAT | O_TRUNC;
+			break;
+		case 'a':
+			rwflags = O_WRONLY;
+			crflags = O_CREAT | O_APPEND;
+			break;
+		case 'e':
+			eflags |= O_CLOEXEC;
+			break;
+		case 'x':
+			eflags |= O_EXCL;
+			break;
+		case '+':
+			rwflags = O_RDWR;
+			break;
+		}
+	}
+
+	return rwflags | crflags | eflags;
+}
 
 FILE *fopen(const char *file, const char *mode)
 {
 	int flags = __parse_open_mode(mode);
-	int fd;
+	int fd, err;
+	FILE *f;
 
 	fd = open(file, flags, 0666);
 	if (fd < 0)
 		return NULL;
 
-	return __fxopen(fd, flags, 1);
+	f = fdopen(fd, mode);
+	if (!f) {
+		err = errno;
+		close(fd);
+		errno = err;
+	}
+	return f;
 }
diff --git a/usr/klibc/stdio/fxopen.c b/usr/klibc/stdio/fxopen.c
deleted file mode 100644
index 1dcd377..0000000
--- a/usr/klibc/stdio/fxopen.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * fxopen.c
- *
- * Common code between fopen(), fdopen() and the standard descriptors.
- */
-
-#include "stdioint.h"
-
-FILE *stdin, *stdout, *stderr;
-
-/* Doubly-linked list of all stdio structures */
-struct _IO_file_pvt __stdio_headnode =
-{
-	.prev = &__stdio_headnode,
-	.next = &__stdio_headnode,
-};
-
-FILE *__fxopen(int fd, int flags, bool close_on_err)
-{
-	struct _IO_file_pvt *f;
-	const size_t bufoffs =
-		(sizeof *f + 4*sizeof(void *) - 1) &
-		~(4*sizeof(void *) - 1);
-
-	f = zalloc(bufoffs + BUFSIZ + _IO_UNGET_SLOP);
-	if (!f)
-		goto err;
-
-	f->data = f->buf = (char *)f + bufoffs;
-	f->pub._io_fileno = fd;
-	f->pub._io_filepos = lseek(fd, 0, SEEK_CUR);
-	f->bufsiz = BUFSIZ;
-	f->bufmode = isatty(fd) ? _IOLBF : _IOFBF;
-
-	/* Insert into linked list */
-	f->prev = &__stdio_headnode;
-	f->next = __stdio_headnode.next;
-	f->next->prev = f;
-	__stdio_headnode.next = f;
-
-	return &f->pub;
-
-err:
-	if (f)
-		free(f);
-	if (close_on_err)
-		close(fd);
-	errno = ENOMEM;
-	return NULL;
-}
-
-void __init_stdio(void)
-{
-	stdin  = __fxopen(0, O_RDONLY, 0);
-	stdio_pvt(stdin)->bufmode = _IOLBF;
-
-	stdout = __fxopen(1, O_WRONLY|O_TRUNC, 0);
-	stdio_pvt(stdout)->bufmode = _IOLBF;
-
-	stderr = __fxopen(2, O_WRONLY|O_TRUNC, 0);
-	stdio_pvt(stderr)->bufmode = _IONBF;
-}
diff --git a/usr/klibc/stdio/openmode.c b/usr/klibc/stdio/openmode.c
deleted file mode 100644
index 971237d..0000000
--- a/usr/klibc/stdio/openmode.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * openmode.c
- *
- * Parse the mode argument to fopen() or fdopen()
- */
-
-#include "stdioint.h"
-
-int __parse_open_mode(const char *mode)
-{
-	int rwflags = O_RDONLY;
-	int crflags = 0;
-	int eflags  = 0;
-
-	while (*mode) {
-		switch (*mode++) {
-		case 'r':
-			rwflags = O_RDONLY;
-			crflags = 0;
-			break;
-		case 'w':
-			rwflags = O_WRONLY;
-			crflags = O_CREAT | O_TRUNC;
-			break;
-		case 'a':
-			rwflags = O_WRONLY;
-			crflags = O_CREAT | O_APPEND;
-			break;
-		case 'e':
-			eflags |= O_CLOEXEC;
-			break;
-		case 'x':
-			eflags |= O_EXCL;
-			break;
-		case '+':
-			rwflags = O_RDWR;
-			break;
-		}
-	}
-
-	return rwflags | crflags | eflags;
-}
diff --git a/usr/klibc/stdio/stdioint.h b/usr/klibc/stdio/stdioint.h
index 4653f35..526c25a 100644
--- a/usr/klibc/stdio/stdioint.h
+++ b/usr/klibc/stdio/stdioint.h
@@ -41,8 +41,6 @@
 #define _IO_UNGET_SLOP	32
 
 __extern int __fflush(struct _IO_file_pvt *);
-__extern int __parse_open_mode(const char *mode);
-__extern FILE *__fxopen(int fd, int flags, bool close_on_err);
 
 __extern struct _IO_file_pvt __stdio_headnode;