Browse Source

stdio mostly rewritten... passes lots of tests now.
printf now supports long double, plus some bug fixes.

Manuel Novoa III 23 years ago
parent
commit
82dd793fd0
6 changed files with 487 additions and 421 deletions
  1. 34 19
      include/stdio.h
  2. 11 15
      libc/misc/internals/dtostr.c
  3. 3 3
      libc/stdio/Makefile
  4. 28 29
      libc/stdio/printf.c
  5. 6 6
      libc/stdio/scanf.c
  6. 405 349
      libc/stdio/stdio.c

+ 34 - 19
include/stdio.h

@@ -35,17 +35,17 @@ __BEGIN_DECLS
 struct __stdio_file {
   unsigned char *bufpos;   /* the next byte to write to or read from */
   unsigned char *bufread;  /* the end of data returned by last read() */
-  unsigned char *bufwrite; /* highest address writable by macro */
+  unsigned char *bufwrite; /* 1 + highest address writable by macro */
   unsigned char *bufstart; /* the start of the buffer */
   unsigned char *bufend;   /* the end of the buffer; ie the byte after the last
                               malloc()ed byte */
+  struct __stdio_file * next;
 
   int fd; /* the file descriptor associated with the stream */
-  int mode;
-
-  struct __stdio_file * next;
 
-  char unbuf[8];	   /* The buffer for 'unbuffered' streams */
+  unsigned char mode;
+  unsigned char ungot;
+  char unbuf[2];	   /* The buffer for 'unbuffered' streams */
 };
 
 typedef struct __stdio_file FILE;
@@ -65,17 +65,13 @@ typedef struct __stdio_file FILE;
 #define _IONBF 2		/* No buffering.  */
 
 /* Possible states for a file stream -- internal use only */
-#define __MODE_BUF	0x03	/* Modal buffering dependent on isatty */
-#define __MODE_FREEBUF	0x04	/* Buffer allocated with malloc, can free */
-#define __MODE_FREEFIL	0x08	/* FILE allocated with malloc, can free */
-#define __MODE_READ	0x10	/* Opened in read only */
-#define __MODE_WRITE	0x20	/* Opened in write only */
-#define __MODE_RDWR	0x30	/* Opened in read/write */
-#define __MODE_READING	0x40	/* Buffer has pending read data */
-#define __MODE_WRITING	0x80	/* Buffer has pending write data */
-#define __MODE_EOF	0x100	/* EOF status */
-#define __MODE_ERR	0x200	/* Error status */
-#define __MODE_UNGOT	0x400	/* Buffer has been polluted by ungetc */
+#define __MODE_BUF		0x03	/* Modal buffering dependent on isatty */
+#define __MODE_FREEBUF	0x04	/* Buffer allocated by stdio code, can free */
+#define __MODE_FREEFIL	0x08	/* FILE allocated by stdio code, can free */
+#define __MODE_UNGOT	0x10	/* Buffer has been polluted by ungetc */
+#define __MODE_TIED 	0x20	/* FILE is tied with stdin/stdout */
+#define __MODE_EOF		0x40	/* EOF status */
+#define __MODE_ERR		0x80	/* Error status */
 
 /* The possibilities for the third argument to `fseek'.
    These values should not be changed.  */
@@ -157,7 +153,26 @@ extern FILE *fopen __P ((__const char *__restrict __filename,
 extern FILE *freopen __P ((__const char *__restrict __filename,
 			   __const char *__restrict __mode,
 			   FILE *__restrict __stream));
-#define freopen(__file, __mode, __fp) __fopen((__file), -1, (__fp), (__mode))
+
+#ifdef __USE_MISC
+/*
+ * Open a file using an automatically (stack) or statically allocated FILE.
+ * The FILE * returned behaves just as any other FILE * with respect to the
+ * stdio functions, but be aware of the following:
+ * NOTE: The buffer used for the file is FILE's builtin 2-byte buffer, so
+ *       setting a new buffer is probably advisable.
+ * NOTE: This function is primarily intended to be used for stack-allocated
+ *       FILEs when uClibc stdio has been built with no dynamic memory support.
+ *       For the statically allocated case, it is probably better to increase
+ *        the value of FIXED_STREAMS in stdio.c.
+ * WARNING: If allocated on the stack, make sure you call fclose before the
+ *          stack memory is reclaimed!
+ */
+extern FILE *fsfopen __P ((__const char *__restrict __filename,
+			   __const char *__restrict __mode,
+			   FILE *__restrict __stream));
+#endif
+
 
 #ifdef __USE_LARGEFILE64
 extern FILE *fopen64 __P ((__const char *__restrict __filename,
@@ -390,8 +405,8 @@ extern int ferror __P ((FILE *__stream));
 /* Macro versions of the 3 previous functions */
 /* If fp is NULL... */
 #define clearerr(fp) ((fp)->mode &= ~(__MODE_EOF|__MODE_ERR), (void)0)
-#define feof(fp)   	(((fp)->mode&__MODE_EOF) != 0)
-#define ferror(fp)	(((fp)->mode&__MODE_ERR) != 0)
+#define feof(fp)   	((fp)->mode&__MODE_EOF)
+#define ferror(fp)	((fp)->mode&__MODE_ERR)
 
 /* Print a message describing the meaning of the value of errno.  */
 extern void perror __P ((__const char *__s));

+ 11 - 15
libc/misc/internals/dtostr.c

@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2000, 2001 Manuel Novoa III
  *
- * Function:  int __dtostr(FILE * fp, size_t size, double x, 
+ * Function:  int __dtostr(FILE * fp, size_t size, long double x, 
  *			               char flag[], int width, int preci, char mode)
  *
  * This was written for uClibc to provide floating point support for
@@ -32,17 +32,18 @@
 
 /*
  * Configuration for the scaling power table.  Ignoring denormals, you
- * should have 2**EXP_TABLE_SIZE >= MAX_DBL_EXP >= 2**(EXP_TABLE_SIZE-1).
+ * should have 2**EXP_TABLE_SIZE >= LDBL_MAX_EXP >= 2**(EXP_TABLE_SIZE-1).
  * The minimum for standard C is 6.  For IEEE 8bit doubles, 9 suffices.
+ * For long doubles on i386, use 13.
  */
-#define EXP_TABLE_SIZE       9
+#define EXP_TABLE_SIZE       13
 
 /* 
  * Set this to the maximum number of digits you want converted.
  * Conversion is done in blocks of DIGITS_PER_BLOCK (9 by default) digits.
- * 17 digits suffices to uniquely determine a double on i386.
+ * (20) 17 digits suffices to uniquely determine a (long) double on i386.
  */
-#define MAX_DIGITS          17
+#define MAX_DIGITS          20
 
 /*
  * Set this to the smallest integer type capable of storing a pointer.
@@ -56,11 +57,7 @@
  * caused by the FPU that strtod had.  If it causes problems, call the function
  * and compile zoicheck.c with -ffloat-store.
  */
-#if 1
 #define _zero_or_inf_check(x) ( x == (x/4) )
-#else
-extern int _zero_or_inf_check(double x);
-#endif
 
 /*
  * Fairly portable nan check.  Bitwise for i386 generated larger code.
@@ -103,10 +100,9 @@ enum {
 
 /*
  * Only bother checking if this is too small.
- * Throw in some play for denormals ( roughly O(-324) vs O(-307) on i386 ).
  */
 
-#if (3+DBL_DIG-DBL_MIN_10_EXP)/2 > EXP_TABLE_MAX
+#if LDBL_MAX_10_EXP/2 > EXP_TABLE_MAX
 #error larger EXP_TABLE_SIZE needed
 #endif
 
@@ -147,11 +143,11 @@ static const char *fmts[] = {
 
 /*****************************************************************************/
 
-int __dtostr(FILE * fp, size_t size, double x, 
+int __dtostr(FILE * fp, size_t size, long double x, 
 			 char flag[], int width, int preci, char mode)
 {
-	double exp_table[EXP_TABLE_SIZE];
-	double p10;
+	long double exp_table[EXP_TABLE_SIZE];
+	long double p10;
 	DIGIT_BLOCK_TYPE digit_block; /* int of at least 32 bits */
 	int i, j;
 	int round, o_exp;
@@ -290,7 +286,7 @@ int __dtostr(FILE * fp, size_t size, double x,
 	}
 	*++e = 0;					/* ending nul char */
 
-	if ((mode == 'g') && ((o_exp >= -4) && (o_exp < round))) {
+	if ((mode == 'g') && ((o_exp >= -4) && (o_exp <= round))) {
 		mode = 'f';
 	}
 

+ 3 - 3
libc/stdio/Makefile

@@ -36,13 +36,13 @@ endif
 
 MSRC=stdio.c
 MOBJ=_stdio_init.o \
-     _alloc_stdio_buffer.o _free_stdio_buffer.o _free_stdio_stream.o \
+     _alloc_stdio_buffer.o _free_stdio_buffer_of_file.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 \
+     fclose.o _fopen.o fopen.o freopen.o fdopen.o fflush.o fsfopen.o \
      fseek.o rewind.o ftell.o fgetpos.o fsetpos.o \
      fputc.o fgetc.o fgets.o gets.o fputs.o puts.o ungetc.o \
-     fread.o fwrite.o getchar.o putchar.o
+     fread.o fwrite.o getchar.o putchar.o _uClibc_fwrite.o _uClibc_fread.o
 
 MSRC2=printf.c
 MOBJ2=printf.o sprintf.o fprintf.o vprintf.o vsprintf.o vfprintf.o snprintf.o \

+ 28 - 29
libc/stdio/printf.c

@@ -267,7 +267,7 @@ int vsnprintf(char *sp, size_t size, __const char *fmt, va_list ap)
 	 */
 	f.bufwrite = (char *) ((unsigned) -1);
 	f.bufpos = sp;
-	f.mode = _IOFBF | __MODE_WRITE;
+	f.mode = _IOFBF;
 
 	rv = vfnprintf(&f, size, fmt, ap);
 	if (size) {					/* If this is going to a buffer, */
@@ -283,25 +283,17 @@ int vsnprintf(char *sp, size_t size, __const char *fmt, va_list ap)
  */
 extern int vdprintf(int fd, const char *fmt, va_list ap)
 {
-#if 0
-	FILE f = {f.unbuf, f.unbuf, f.unbuf, f.unbuf, f.unbuf + sizeof(f.unbuf),
-			  fd, _IONBF | __MODE_WRITE};
-
-	assert(fd >= 0);			/* fd==0 may no longer be stdin */
-
-	return vfnprintf(&f, -1, fmt, ap);
-#else
 	char buf[BUFSIZ];
-	FILE f = {buf, buf, buf, buf, buf + sizeof(buf),
-			  fd, _IOFBF | __MODE_WRITE};
+	FILE f = {buf, 0, buf+sizeof(buf), buf, buf+sizeof(buf), 0, fd, _IOFBF};
 	int rv;
 
-	assert(fd >= 0);			/* fd==0 may no longer be stdin */
-
 	rv = vfnprintf(&f, -1, fmt, ap);
-	fflush(&f);
+
+	if (fflush(&f)) {
+		return -1;
+	}
+
 	return rv;
-#endif
 }
 #endif
 
@@ -311,7 +303,7 @@ extern char *__ultostr(char *buf, unsigned long uval, int base, int uppercase);
 extern char *__ltostr(char *buf, long val, int base, int uppercase);
 extern char *__ulltostr(char *buf, unsigned long long uval, int base, int uppercase);
 extern char *__lltostr(char *buf, long long val, int base, int uppercase);
-extern int __dtostr(FILE * fp, size_t size, double x,
+extern int __dtostr(FILE * fp, size_t size, long double x,
 				  char flag[], int width, int preci, char mode);
 
 enum {
@@ -353,7 +345,7 @@ static const char u_radix[] = "\x02\x08\x10\x10\x10\x0a";
 
 int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)
 {
-	int i, cnt = 0, lval;
+	int i, cnt, lval;
 	char *p;
 	const char *fmt0;
 	int buffer_mode;
@@ -367,7 +359,9 @@ int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)
 #endif
 	char flag[sizeof(spec)];
 
-	/* This speeds things up a bit for unbuffered */
+	cnt = 0;
+
+	/* This speeds things up a bit for line unbuffered */
 	buffer_mode = (op->mode & __MODE_BUF);
 	op->mode &= (~__MODE_BUF);
 
@@ -375,9 +369,6 @@ int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)
 		if (*fmt == '%') {
 			fmt0 = fmt;			/* save our position in case of bad format */
 			++fmt;
-			if (buffer_mode == _IONBF) {
-				fflush(op);
-			}
 			width = -1;			/* min field width */
 			preci = -5;			/* max string width or mininum digits */
 			radix = 10;			/* number base */
@@ -511,7 +502,7 @@ int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)
 					if (flag[FLAG_HASH] && (*p != '0')) { /* non-zero */
 						if (radix == 8) {
 							*--p = '0';	/* add leadding zero */
-						} else { /* either 2 or 16 */
+						} else if (radix != 10) { /* either 2 or 16 */
 							flag[FLAG_PLUS] = '0';
 							*--p = 'b';
 							if (radix == 16) {
@@ -556,6 +547,9 @@ int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)
 						*p = va_arg(ap, int);
 					} else {	/* string */
 						p = va_arg(ap, char *);
+						if (!p) {
+							p = "(null)";
+						}
 					}
 #if WANT_DOUBLE || WANT_DOUBLE_ERROR
 				} else if (p-u_spec < 27) {		/* floating point */
@@ -564,11 +558,15 @@ int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)
 					if (preci < 0) {
 						preci = 6;
 					}
-					cnt += __dtostr(op, max_size, va_arg(ap, double),
+					cnt += __dtostr(op, max_size,
+									(long double) ((lval > 1)
+									 ? va_arg(ap, long double)
+									 : va_arg(ap, double)),
 									flag, width,  preci, *fmt);
 					goto nextfmt;
 #elif WANT_DOUBLE_ERROR
-					(void) va_arg(ap,double); /* carry on */
+					(void) ((lval > 1) ? va_arg(ap, long double)
+							: va_arg(ap, double)); /* carry on */
 					p = (char *) dbl_err;
 #endif /* WANT_DOUBLE */
 				}
@@ -604,7 +602,11 @@ int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)
 						|| (*fmt == 'm')
 #endif
 						) {
-							len = preci;
+							if (len > preci) {
+								len = preci;
+							} else {
+								preci = len;
+							}
 						}
 						preci -= len;
 						if (preci < 0) {
@@ -678,11 +680,8 @@ int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)
 	}
 
 	op->mode |= buffer_mode;
-	if (buffer_mode == _IONBF) {
-		fflush(op);
-	}
 	if (buffer_mode == _IOLBF) {
-		op->bufwrite = op->bufstart;
+		op->bufwrite = op->bufpos;
 	}
 
 	if (ferror(op)) {

+ 6 - 6
libc/stdio/scanf.c

@@ -35,15 +35,15 @@ va_dcl
 #endif
 {
 	FILE string[1] = {
-		{0, (char *) (unsigned) -1, 0, 0, (char *) (unsigned) -1, -1,
-		 _IOFBF | __MODE_READ}
+		{0, (unsigned char *) ((unsigned) -1), 0, 0, (char *) ((unsigned) -1),
+		 0, -1, _IOFBF}
 	};
 
 	va_list ptr;
 	int rv;
 
-	va_start(ptr, fmt);
 	string->bufpos = (unsigned char *) ((void *) sp);
+	va_start(ptr, fmt);
 	rv = vfscanf(string, fmt, ptr);
 	va_end(ptr);
 	return rv;
@@ -83,11 +83,11 @@ va_list ap;
 int vsscanf(__const char *sp, __const char *fmt, va_list ap)
 {
 	FILE string[1] = {
-		{0, (char *) (unsigned) -1, 0, 0, (char *) (unsigned) -1, -1,
-		 _IOFBF | __MODE_READ}
+		{0, (unsigned char *) ((unsigned) -1), 0, 0, (char *) ((unsigned) -1),
+		 0, -1, _IOFBF}
 	};
 
-	string->bufpos = (unsigned char *) ((void *) sp);
+	string->bufpos = (unsigned char *) sp;
 	return vfscanf(string, fmt, ap);
 }
 #endif

File diff suppressed because it is too large
+ 405 - 349
libc/stdio/stdio.c


Some files were not shown because too many files changed in this diff