浏览代码

A number of updates from Manuel Novoa III. Things look good...

Eric Andersen 24 年之前
父节点
当前提交
c6218dbae5

+ 6 - 0
include/math.h

@@ -28,6 +28,11 @@ typedef struct {
 #define M_SQRT1_2	0.70710678118654752440	/* 1/sqrt(2) */
 #define M_SQRT1_2	0.70710678118654752440	/* 1/sqrt(2) */
 
 
 
 
+#if 1
+extern double sin(double);
+extern double cos(double);
+extern double sqrt(double);
+#else
 extern float acos ( float x );
 extern float acos ( float x );
 extern float acosh ( float xx );
 extern float acosh ( float xx );
 extern int airy ( float xx, float *ai, float *aip, float *bi, float *bip );
 extern int airy ( float xx, float *ai, float *aip, float *bi, float *bip );
@@ -168,3 +173,4 @@ extern float yn ( int nn, float xx );
 extern float yv ( float vv, float xx );
 extern float yv ( float vv, float xx );
 extern float zetac ( float xx );
 extern float zetac ( float xx );
 extern float zeta ( float xx, float qq );
 extern float zeta ( float xx, float qq );
+#endif

+ 2 - 2
include/stdlib.h

@@ -46,8 +46,8 @@ typedef __compar_fn_t comparison_fn_t;
 extern long strtol __P ((const char * nptr, char ** endptr, int base));
 extern long strtol __P ((const char * nptr, char ** endptr, int base));
 extern unsigned long strtoul __P ((const char * nptr, char ** endptr, int base));
 extern unsigned long strtoul __P ((const char * nptr, char ** endptr, int base));
 #ifndef __HAS_NO_FLOATS__
 #ifndef __HAS_NO_FLOATS__
-extern char * gcvt __P ((float number, size_t ndigit, char * buf));
+/*TODO: extern char * gcvt __P ((double number, size_t ndigit, char * buf)); */
-extern float strtod __P ((const char * nptr, char ** endptr));
+extern double strtod __P ((const char * nptr, char ** endptr));
 #endif
 #endif
 
 
 
 

+ 33 - 11
libc/inet/addr.c

@@ -3,6 +3,15 @@
  * under the GNU Library General Public License.
  * under the GNU Library General Public License.
  */
  */
 
 
+/*
+ * Manuel Novoa III       Dec 2000
+ *
+ * Converted to use my new (un)signed long (long) to string routines, which
+ * are smaller than the previous functions and don't require static buffers.
+ * In the process, removed the reference to strcat and cut object size of
+ * inet_ntoa in half (from 190 bytes down to 94).
+ */
+
 #include <string.h>
 #include <string.h>
 #include <ctype.h>
 #include <ctype.h>
 #include <netinet/in.h>
 #include <netinet/in.h>
@@ -63,22 +72,35 @@ const char *cp;
 
 
 #ifdef L_inet_ntoa
 #ifdef L_inet_ntoa
 
 
-extern char *itoa(int);
+#include <limits.h>
+
+#if (ULONG_MAX >> 32)
+/* We're set up for 32 bit unsigned longs */
+#error need to check size allocation for static buffer 'buf'
+#endif
+
+extern char *__ultostr(char *buf, unsigned long uval, int base, int uppercase);
 
 
 char *inet_ntoa(in)
 char *inet_ntoa(in)
 struct in_addr in;
 struct in_addr in;
 {
 {
-	static char buf[18];
+	static char buf[16];		/* max 12 digits + 3 '.'s + 1 nul */
-	unsigned long addr = ntohl(in.s_addr);
 
 
-	strcpy(buf, itoa((addr >> 24) & 0xff));
+	unsigned long addr = ntohl(in.s_addr);
-	strcat(buf, ".");
+	int i;
-	strcat(buf, itoa((addr >> 16) & 0xff));
+	char *p, *q;
-	strcat(buf, ".");
+   
-	strcat(buf, itoa((addr >> 8) & 0xff));
+	q = 0;
-	strcat(buf, ".");
+	p = buf + sizeof(buf) - 1;
-	strcat(buf, itoa(addr & 0xff));
+	for (i=0 ; i < 4 ; i++ ) {
+		p = __ultostr(p, addr & 0xff, 10, 0 ) - 1;
+		addr >>= 8;
+		if (q) {
+			*q = '.';
+		}
+		q = p;
+	}
 
 
-	return buf;
+	return p+1;
 }
 }
 #endif
 #endif

+ 17 - 2
libc/misc/assert/__assert.c

@@ -3,11 +3,24 @@
  * under the GNU Library General Public License.
  * under the GNU Library General Public License.
  */
  */
 
 
+/*
+ * Manuel Novoa III       Dec 2000
+ *
+ * Converted to use my new (un)signed long (long) to string routines, which
+ * are smaller than the previous functions and don't require static buffers.
+ */
+
 #include <unistd.h>
 #include <unistd.h>
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include <limits.h>
 
 
-extern char *itoa(int);
+#if (INT_MAX >> 31)
+/* We're set up for 32 bit ints */
+#error need to check size allocation for buffer 'buf'
+#endif
+
+extern char *__ltostr(char *buf, unsigned long uval, int base, int uppercase);
 
 
 static void errput(str)
 static void errput(str)
 const char *str;
 const char *str;
@@ -21,9 +34,11 @@ const char *filename;
 int linenumber;
 int linenumber;
 const char *function;
 const char *function;
 {
 {
+	char buf[12];
+
 	errput(filename);
 	errput(filename);
 	errput(":");
 	errput(":");
-	errput(itoa(linenumber));
+	errput(__ltostr(buf + sizeof(buf) - 1, linenumber, 10, 0));
 	errput(function ? ": " : "");
 	errput(function ? ": " : "");
 	errput(function ? function : "");
 	errput(function ? function : "");
 	errput(function ? "() " : "");
 	errput(function ? "() " : "");

+ 34 - 1
libc/misc/ctype/ctype.c

@@ -9,106 +9,139 @@
 #define USE_CTYPE_C_FUNCTIONS
 #define USE_CTYPE_C_FUNCTIONS
 #include <ctype.h>
 #include <ctype.h>
 
 
+#ifdef L_isalnum
 int
 int
 isalnum( int c )
 isalnum( int c )
 {
 {
     return (isalpha(c) || isdigit(c));
     return (isalpha(c) || isdigit(c));
 }
 }
+#endif
 
 
+#ifdef L_isalpha
 int
 int
 isalpha( int c )
 isalpha( int c )
 {
 {
     return (isupper(c) || islower(c));
     return (isupper(c) || islower(c));
 }
 }
+#endif
 
 
+#ifdef L_isascii
 int
 int
 isascii( int c )
 isascii( int c )
 {
 {
     return (c > 0 && c <= 0x7f);
     return (c > 0 && c <= 0x7f);
 }
 }
+#endif
 
 
+#ifdef L_iscntrl
 int
 int
 iscntrl( int c )
 iscntrl( int c )
 {
 {
     return ((c > 0) && ((c <= 0x1f) || (c == 0x7f)));
     return ((c > 0) && ((c <= 0x1f) || (c == 0x7f)));
 }
 }
+#endif
 
 
+#ifdef L_isdigit
 int
 int
 isdigit( int c )
 isdigit( int c )
 {
 {
     return (c >= '0' && c <= '9');
     return (c >= '0' && c <= '9');
 }
 }
+#endif
 
 
+#ifdef L_isgraph
 int
 int
 isgraph( int c )
 isgraph( int c )
 {
 {
     return (c != ' ' && isprint(c));
     return (c != ' ' && isprint(c));
 }
 }
+#endif
 
 
+#ifdef L_islower
 int
 int
 islower( int c )
 islower( int c )
 {
 {
     return (c >=  'a' && c <= 'z');
     return (c >=  'a' && c <= 'z');
 }
 }
+#endif
 
 
+#ifdef L_isprint
 int
 int
 isprint( int c )
 isprint( int c )
 {
 {
     return (c >= ' ' && c <= '~');
     return (c >= ' ' && c <= '~');
 }
 }
+#endif
 
 
+#ifdef L_ispunct
 int
 int
 ispunct( int c )
 ispunct( int c )
 {
 {
     return ((c > ' ' && c <= '~') && !isalnum(c));
     return ((c > ' ' && c <= '~') && !isalnum(c));
 }
 }
+#endif
 
 
+#ifdef L_isspace
 int
 int
 isspace( int c )
 isspace( int c )
 {
 {
     return (c == ' ' || c == '\f' || c == '\n' || c == '\r' ||
     return (c == ' ' || c == '\f' || c == '\n' || c == '\r' ||
 	    c == '\t' || c == '\v');
 	    c == '\t' || c == '\v');
 }
 }
+#endif
 
 
+#ifdef L_isupper
 int
 int
 isupper( int c )
 isupper( int c )
 {
 {
     return (c >=  'A' && c <= 'Z');
     return (c >=  'A' && c <= 'Z');
 }
 }
+#endif
 
 
+#ifdef L_isxdigit
 int
 int
 isxdigit( int c )
 isxdigit( int c )
 {
 {
     return (isxupper(c) || isxlower(c));
     return (isxupper(c) || isxlower(c));
 }
 }
+#endif
 
 
+#ifdef L_isxlower
 int
 int
 isxlower( int c )
 isxlower( int c )
 {
 {
     return (isdigit(c) || (c >= 'a' && c <= 'f'));
     return (isdigit(c) || (c >= 'a' && c <= 'f'));
 }
 }
+#endif
 
 
+#ifdef L_isxupper
 int
 int
 isxupper( int c )
 isxupper( int c )
 {
 {
     return (isdigit(c) || (c >= 'A' && c <= 'F'));
     return (isdigit(c) || (c >= 'A' && c <= 'F'));
 }
 }
+#endif
 
 
+#ifdef L_toascii
 int
 int
 toascii( int c )
 toascii( int c )
 {
 {
     return (c & 0x7f);
     return (c & 0x7f);
 }
 }
+#endif
 
 
+#ifdef L_tolower
 int
 int
 tolower( int c )
 tolower( int c )
 {
 {
     return (isupper(c) ? ( c - 'A' + 'a') : (c));
     return (isupper(c) ? ( c - 'A' + 'a') : (c));
 }
 }
+#endif
 
 
+#ifdef L_toupper
 int
 int
 toupper( int c )
 toupper( int c )
 {
 {
     return (islower(c) ? (c - 'a' + 'A') : (c));
     return (islower(c) ? (c - 'a' + 'A') : (c));
 }
 }
-
+#endif

+ 1 - 1
libc/misc/internals/Makefile

@@ -24,7 +24,7 @@ TOPDIR=../../
 include $(TOPDIR)Rules.mak
 include $(TOPDIR)Rules.mak
 LIBC=$(TOPDIR)libc.a
 LIBC=$(TOPDIR)libc.a
 
 
-CSRC=itoa.c ltoa.c ltostr.c
+CSRC=ultostr.c ltostr.c ulltostr.c lltostr.c zoicheck.c dtostr.c
 COBJS=$(patsubst %.c,%.o, $(CSRC))
 COBJS=$(patsubst %.c,%.o, $(CSRC))
 OBJS=$(COBJS)
 OBJS=$(COBJS)
 
 

+ 271 - 0
libc/misc/internals/dtostr.c

@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2000 Manuel Novoa III
+ *
+ * Function:  const char *__dtostr(double x)
+ *
+ * This was written for uClibc to give it the ability to at least output
+ * floating point values in exponential form.  No formatting is done.
+ * No trailing 0's are removed.  Number of digits generated is not
+ * runtime selectable.  It does however handle +/- infinity and nan on i386.
+ *
+ * The goal was usable floating point %e-type output in minimal size.  For
+ * me, "gcc -c -Os -fomit-frame-pointer dtostr.c && size dtostr.o" gives
+ *   text    data     bss    dec     hex filename
+ *   535       9      26     570     23a dtostr.o    (WANT_EXP_FORM = 1)
+ *   530       9      26     565     235 dtostr.o    (WANT_EXP_FORM = 0)
+ *
+ * Output is of the form [-][#].######{e|E}{+|-}##.  Choices of upper or
+ * lower case exponent character, and initial digit/initial decimal forms
+ * are compile-time options.  Number of digits generated is also selected
+ * at compile time (MAX_DIGITS).
+ *
+ * Notes:
+ *
+ * The primary objective of this implementation was minimal size while
+ * maintaining reasonable accuracy.  It should also be fairly portable,
+ * as not assumptions are made about the bit-layout of doubles.
+ *
+ * It should be too difficult to convert this to handle long doubles on i386.
+ * For information, see the comments below.
+ *
+ * There are 2 compile-time options below, as well as some tuning parameters.
+ *
+ * TODO: 
+ *   long double and/or float version?  (note: for float can trim code some).
+ */
+
+/*****************************************************************************/
+/*                            OPTIONS                                        */
+/*****************************************************************************/
+
+/*
+ * Set this if you want output results with 1 digit before the decimal point.
+ * If this is 0, all digits follow a leading decimal point.
+ */
+#define WANT_EXP_FORM   1
+
+/*
+ * Set if you want exponent character 'E' rather than 'e'.
+ */
+#define EXP_UPPERCASE   1
+
+/*****************************************************************************/
+/* Don't change anything that follows unless you know what you're doing.     */
+/*****************************************************************************/
+
+/*
+ * Configuration for the scaling power table.  Ignoring denormals, you
+ * should have 2**EXP_TABLE_SIZE >= MAX_DBL_EXP >= 2**(EXP_TABLE_SIZE-1).
+ * The minimum for standard C is 6.  For IEEE 8bit doubles, 9 suffices.
+ */
+#define EXP_TABLE_SIZE       9
+
+/* 
+ * 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.
+ */
+#define MAX_DIGITS          17
+
+/*
+ * This is really only used to check for infinities.  The macro produces
+ * smaller code for i386 and, since this is tested before any floating point
+ * calculations, it doesn't appear to suffer from the excess precision problem
+ * 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.
+ * If you have a better version, comment this out.
+ */
+#define isnan(x) (x != x)
+
+/*****************************************************************************/
+/* Don't change anything that follows peroid!!!  ;-)                         */
+/*****************************************************************************/
+
+#include <float.h>
+#include <limits.h>
+
+/*
+ * Set things up for the scaling power table.
+ */
+
+#if EXP_TABLE_SIZE < 6
+#error EXP_TABLE_SIZE should be at least 6 to comply with standards
+#endif
+
+#define EXP_TABLE_MAX      (1U<<(EXP_TABLE_SIZE-1))
+
+/*
+ * 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
+#error larger EXP_TABLE_SIZE needed
+#endif
+
+/*
+ * With 32 bit ints, we can get 9 digits per block.
+ */
+#define DIGITS_PER_BLOCK     9
+
+#if (INT_MAX >> 30)
+#define DIGIT_BLOCK_TYPE     int
+#elif (LONG_MAX >> 30)
+#define DIGIT_BLOCK_TYPE     long
+#else
+#error need at least 32 bit longs
+#endif
+
+/*
+ * This is kind of a place-holder for LONG_DOUBLE support to show what I
+ * think needs to be changed.  I haven't tried it though.  Changing this
+ * from 3 to 4 and converting double to long double should work on i386.
+ * DON'T FORGET to increase EXP_TABLE_SIZE and MAX_DIGITS.
+ * DON'T FORGET the "larger EXP_TABLE_SIZE needed" check above.
+ */
+#define MAX_EXP_DIGITS 3
+
+/*****************************************************************************/
+
+#define NUM_DIGIT_BLOCKS   ((MAX_DIGITS+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
+
+static char infstr[] = " inf";	/* save space for a - sign */
+static char nanstr[] = "nan";
+
+/* extra space for '-', '.', 'e+###', and nul */
+/*static char buf[ 5 + MAX_EXP_DIGITS + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK];*/
+#define BUF_SIZE  ( 5 + MAX_EXP_DIGITS + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
+/*****************************************************************************/
+
+const char *__dtostr(char *buf, double x)
+{
+	double exp_table[EXP_TABLE_SIZE];
+	double p10;
+	DIGIT_BLOCK_TYPE digit_block; /* int of at least 32 bits */
+	int i, j;
+	int exp, exp_neg;
+	int negative = 0;
+	char *pos;
+
+	if (isnan(x)) {				/* nan check */
+		return nanstr;
+	}
+
+	if (x == 0) {				/* handle 0 now to avoid false positive */
+		exp = 0;				/* with inf test, and to avoid scaling  */
+		goto GENERATE_DIGITS;	/* note: time vs space tradeoff */
+	}
+
+	if (x < 0) {				/* convert negatives to positives */
+		negative = 1;
+		x = -x;
+	}
+
+	if (_zero_or_inf_check(x)) { /* must be inf since zero handled above */
+		pos = infstr + 1;
+		goto DO_SIGN;
+	}
+
+	/* need to build the scaling table */
+	for (i = 0, p10 = 10 ; i < EXP_TABLE_SIZE ; i++) {
+		exp_table[i] = p10;
+		p10 *= p10;
+	}
+
+	exp_neg = 0;
+	if (x < 1e8) {				/* do we need to scale up or down? */
+		exp_neg = 1;
+	}
+
+#if WANT_EXP_FORM
+	exp = DIGITS_PER_BLOCK - 1;
+#else
+	exp = DIGITS_PER_BLOCK;
+#endif
+
+	i = EXP_TABLE_SIZE;
+	j = EXP_TABLE_MAX;
+	while ( i-- ) {				/* scale x such that 1e8 <= x < 1e9 */
+		if (exp_neg) {
+			if (x * exp_table[i] < 1e9) {
+				x *= exp_table[i];
+				exp -= j;
+			}
+		} else {
+			if (x / exp_table[i] >= 1e8) {
+				x /= exp_table[i];
+				exp += j;
+			}
+		}
+		j >>= 1;
+	}
+
+ GENERATE_DIGITS:
+	pos = buf - BUF_SIZE + 1 + DIGITS_PER_BLOCK + 1; /* leave space for '.' and - */
+
+	for (i = 0 ; i < NUM_DIGIT_BLOCKS ; ++i ) {
+		digit_block = (int) x;
+		x = (x - digit_block) * 1e9;
+		for (j = 0 ; j < DIGITS_PER_BLOCK ; j++) {
+			*--pos = '0' + (digit_block % 10);
+			digit_block /= 10;
+		}
+		pos += (2*DIGITS_PER_BLOCK);
+	}
+	pos -= (DIGITS_PER_BLOCK*(NUM_DIGIT_BLOCKS+1))-MAX_DIGITS;
+
+	/* start generating the exponent */
+#if EXP_UPPERCASE
+	*pos = 'E';
+#else
+	*pos = 'e';
+#endif
+	*++pos = '+';
+	if (exp < 0) {
+		*pos = '-';
+		exp = -exp;
+	}
+	pos += 3;					/* WARNING: Assumes max exp < 1000!!! */
+	if (exp >= 100) {
+		++pos;
+#if MAX_EXP_DIGITS > 4
+#error need to modify exponent string generation code
+#elif MAX_EXP_DIGITS > 3
+		if (exp >= 1000) {		/* WARNING: hasn't been checked */
+			++pos;				/*    but should work */
+		}
+#endif
+	}
+	*pos = '\0';
+		
+	for (j = 0 ; (j < 2) || exp ; j++) { /* standard says at least 2 digits */
+		*--pos = '0' + (exp % 10);
+		exp /= 10;
+	}
+
+	/* insert the decimal point */
+	pos = buf - BUF_SIZE + 1;
+
+#if WANT_EXP_FORM
+	*pos = *(pos+1);
+	*(pos+1) = '.';
+#else
+	*pos = '.';
+#endif
+
+ DO_SIGN:
+	if (negative) {
+		*--pos = '-';
+	}
+
+	return pos;
+}

+ 0 - 21
libc/misc/internals/itoa.c

@@ -1,21 +0,0 @@
-/* itoa.c <ndf@linux.mit.edu> */
-#define __MAX_INT_CHARS 7
-
-char *itoa(int i)
-{
-	static char a[__MAX_INT_CHARS];
-	char *b = a + sizeof(a) - 1;
-	int sign = (i < 0);
-
-	if (sign)
-		i = -i;
-	*b = 0;
-	do {
-		*--b = '0' + (i % 10);
-		i /= 10;
-	}
-	while (i);
-	if (sign)
-		*--b = '-';
-	return b;
-}

+ 39 - 0
libc/misc/internals/lltostr.c

@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2000 Manuel Novoa III
+ *
+ * Note: buf is a pointer to the END of the buffer passed.
+ * Call like this:
+ *     char buf[SIZE], *p;
+ *     p = __lltostr(buf + sizeof(buf) - 1, ...)
+ * For long longs of 64 bits, appropriate buffer sizes are:
+ *     base =  2      66  = 1 (possible -) sign + 64 digits + 1 nul
+ *     base = 10      21  = 1 (possible -) sign + 19 digits + 1 nul
+ *     base = 16      18  = 1 (possible -) sign + 16 hex digits + 1 nul
+ */
+
+extern char *__ulltostr(char *buf, unsigned long long uval, int base, 
+						int uppercase);
+
+char *__lltostr(char *buf, long long val, int base, int uppercase)
+{
+	unsigned long long uval;
+	char *pos;
+    int negative;
+
+	negative = 0;
+    if (val < 0) {
+		negative = 1;
+		uval = ((unsigned long long)(-(1+val))) + 1;
+    } else {
+		uval = val;
+	}
+
+
+    pos = __ulltostr(buf, uval, base, uppercase);
+
+    if (pos && negative) {
+		*--pos = '-';
+    }
+
+    return pos;
+}

+ 0 - 40
libc/misc/internals/ltoa.c

@@ -1,40 +0,0 @@
-/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
- * This file is part of the Linux-8086 C library and is distributed
- * under the GNU Library General Public License.
- */
-
-static char buf[12];
-
-extern char *ultoa();
-
-char *ltoa(val)
-long val;
-{
-	char *p;
-	int flg = 0;
-
-	if (val < 0) {
-		flg++;
-		val = -val;
-	}
-	p = ultoa(val);
-	if (flg)
-		*--p = '-';
-	return p;
-}
-
-char *ultoa(val)
-unsigned long val;
-{
-	char *p;
-
-	p = buf + sizeof(buf);
-	*--p = '\0';
-
-	do {
-		*--p = '0' + val % 10;
-		val /= 10;
-	}
-	while (val);
-	return p;
-}

+ 29 - 42
libc/misc/internals/ltostr.c

@@ -1,52 +1,39 @@
-/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+/*
- * This file is part of the Linux-8086 C library and is distributed
+ * Copyright (C) 2000 Manuel Novoa III
- * under the GNU Library General Public License.
+ *
+ * Note: buf is a pointer to the END of the buffer passed.
+ * Call like this:
+ *     char buf[SIZE], *p;
+ *     p = __ltostr(buf + sizeof(buf) - 1, ...)
+ *
+ * For longs of 32 bits, appropriate buffer sizes are:
+ *     base =  2      34  = 1 (possible -) sign + 32 digits + 1 nul
+ *     base = 10      12  = 1 (possible -) sign + 10 digits + 1 nul
+ *     base = 16      10  = 1 (possible -) sign + 8 hex digits + 1 nul
  */
  */
 
 
-static char buf[34];
+extern char *__ultostr(char *buf, unsigned long uval, int base, int uppercase);
 
 
-extern char *ultostr();
+char *__ltostr(char *buf, long val, int base, int uppercase)
-
-char *ltostr(val, radix, uppercase)
-long val;
-int radix;
-int uppercase;
 {
 {
-	char *p;
+	unsigned long uval;
-	int flg = 0;
+	char *pos;
-
+    int negative;
-	if (val < 0) {
+
-		flg++;
+	negative = 0;
-		val = -val;
+    if (val < 0) {
+		negative = 1;
+		uval = ((unsigned long)(-(1+val))) + 1;
+    } else {
+		uval = val;
 	}
 	}
-	p = ultostr(val, radix, uppercase);
-	if (p && flg)
-		*--p = '-';
-	return p;
-}
 
 
-char *ultostr(val, radix, uppercase)
-unsigned long val;
-int radix;
-int uppercase;
-{
-	register char *p;
-	register int c;
 
 
-	if (radix > 36 || radix < 2)
+    pos = __ultostr(buf, uval, base, uppercase);
-		return 0;
 
 
-	p = buf + sizeof(buf);
+    if (pos && negative) {
-	*--p = '\0';
+		*--pos = '-';
+    }
 
 
-	do {
+    return pos;
-		c = val % radix;
-		val /= radix;
-		if (c > 9)
-			*--p = (uppercase ? 'A' : 'a') - 10 + c;
-		else
-			*--p = '0' + c;
-	}
-	while (val);
-	return p;
 }
 }

+ 37 - 0
libc/misc/internals/ulltostr.c

@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2000 Manuel Novoa III
+ *
+ * Note: buf is a pointer to the END of the buffer passed.
+ * Call like this:
+ *     char buf[SIZE], *p;
+ *     p = __ulltostr(buf + sizeof(buf) - 1, ...)
+ *
+ * For long longs of 64 bits, appropriate buffer sizes are:
+ *     base =  2      65  = 64 digits + 1 nul
+ *     base = 10      20  = 19 digits + 1 nul
+ *     base = 16      17  = 16 hex digits + 1 nul
+ */
+
+char *__ulltostr(char *buf, unsigned long long uval, int base, int uppercase)
+{
+    int digit;
+
+    if ((base < 2) || (base > 36)) {
+		return 0;
+    }
+
+    *buf = '\0';
+
+    do {
+		digit = uval % base;
+		uval /= base;
+
+		/* note: slightly slower but generates less code */
+		*--buf = '0' + digit;
+		if (digit > 9) {
+			*buf = (uppercase ? 'A' : 'a') + digit - 10;
+		}
+    } while (uval);
+
+    return buf;
+}

+ 37 - 0
libc/misc/internals/ultostr.c

@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2000 Manuel Novoa III
+ *
+ * Note: buf is a pointer to the END of the buffer passed.
+ * Call like this;
+ *     char buf[SIZE], *p;
+ *     p = __ultostr(buf + sizeof(buf) - 1, ...)
+ *
+ * For longs of 32 bits, appropriate buffer sizes are:
+ *     base =  2      33  = 32 digits + 1 nul
+ *     base = 10      11  = 10 digits + 1 nul
+ *     base = 16       9  = 8 hex digits + 1 nul
+ */
+
+char *__ultostr(char *buf, unsigned long uval, int base, int uppercase)
+{
+    int digit;
+
+    if ((base < 2) || (base > 36)) {
+		return 0;
+    }
+
+    *buf = '\0';
+
+    do {
+		digit = uval % base;
+		uval /= base;
+
+		/* note: slightly slower but generates less code */
+		*--buf = '0' + digit;
+		if (digit > 9) {
+			*buf = (uppercase ? 'A' : 'a') + digit - 10;
+		}
+    } while (uval);
+
+    return buf;
+}

+ 16 - 0
libc/misc/internals/zoicheck.c

@@ -0,0 +1,16 @@
+
+/*
+ * Copyright (C) 2000 Manuel Novoa III
+ *
+ * This is a utility routine for strtod errno support.
+ * As the name implies, it checks if a double is either 0 or +/-infinity.
+ * Doing this inline doesn't work on i386 because of excess precission
+ * stored in the FPU.
+ *
+ * TODO: Check bitmasks directly?
+ */
+
+int _zero_or_inf_check(double x)
+{
+	return ( x == x/4 );
+}

+ 398 - 220
libc/stdio/printf.c

@@ -17,11 +17,92 @@
  * -RDB
  * -RDB
  */
  */
 
 
+/*
+ *                    Manuel Novoa III   Dec 2000
+ *
+ * The previous vfprintf routine was almost completely rewritten with the
+ * goal of fixing some shortcomings and reducing object size.
+ *
+ * The summary of changes:
+ *
+ * Converted print conversion specification parsing from one big switch
+ *   to a method using string tables.  This new method verifies that the
+ *   conversion flags, field width, precision, qualifier, and specifier
+ *   appear in the correct order.  Many questionable specifications were
+ *   accepted by the previous code.  This new method also resulted in a
+ *   substantial reduction in object size of about 330 bytes (20%) from
+ *   the old version (1627 bytes) on i386, even with the following
+ *   improvements.
+ *
+ *     Implemented %n specifier as required by the standards.
+ *     Implemented proper handling of precision for int types.
+ *     Implemented # for hex and pointer, fixed error for octal rep of 0.
+ *     Implemented return of -1 on stream error.
+ *
+ * Added optional support for the GNU extension %m which prints the string
+ *   corresponding the errno.
+ *
+ * Added optional support for long long ints and unsigned long long ints
+ *   using the conversion qualifiers "ll", "L", or "q" (like glibc).
+ *
+ * Added optional support for doubles in a very limited form.  None of
+ *   the formating options are obeyed.  The string returned by __dtostr
+ *   is printed directly.
+ *
+ * Converted to use my (un)signed long (long) to string routines, which are
+ * smaller than the previous functions and don't require static buffers.
+ *
+ */
+
+/*****************************************************************************/
+/*                            OPTIONS                                        */
+/*****************************************************************************/
+/* The optional support for long longs and doubles comes in two forms.
+ *
+ *   1) Normal (or partial for doubles) output support.  Set to 1 to turn on.
+ *      Adds about 54 byes and about 217 bytes for long longss to the base size
+ *      of 1298.  (Bizarre: both turned on is smaller than WANT_LONG_LONG only.)
+ */
+
+#define WANT_LONG_LONG         0
+#define WANT_DOUBLE            0
+
+/*   2) An error message is inserted into the stream, an arg of the
+ *      appropriate size is removed from the arglist, and processing
+ *      continues.  This is adds less code and may be useful in some
+ *      cases.  Set to 1 to turn on.  Adds about 31 bytes for doubles
+ *      and about 54 bytes for long longs to the base size of 1298.
+ */
+
+#define WANT_LONG_LONG_ERROR   0
+#define WANT_DOUBLE_ERROR      0
+
+/*
+ * Set to support GNU extension of %m to print string corresponding to errno.
+ *
+ * Warning: This adds about 50 bytes (i386) to the code but it also pulls in
+ * strerror and the corresponding string table which together are about 3.8k.
+ */
+
+#define WANT_GNU_ERRNO         0
+
+/*
+ * Use fputc instead of macro putc.  Slower but saves about 36 bytes.
+ */
+
+#define WANT_FPUTC             0
+
+/**************************************************************************/
+
 #include <sys/types.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <fcntl.h>
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
 
 
+#if WANT_GNU_ERRNO
+#include <errno.h>
+#endif
+
 #ifdef __STDC__
 #ifdef __STDC__
 #include <stdarg.h>
 #include <stdarg.h>
 #define va_strt      va_start
 #define va_strt      va_start
@@ -32,14 +113,16 @@
 
 
 #include "stdio.h"
 #include "stdio.h"
 
 
+#if WANT_FPUTC
+#undef putc
+#define putc(c,s) fputc(c,s)
+#endif
 
 
 
 
 extern int vfnprintf(FILE * op, size_t max_size,
 extern int vfnprintf(FILE * op, size_t max_size,
 					 register __const char *fmt, register va_list ap);
 					 register __const char *fmt, register va_list ap);
 
 
 
 
-
-
 #ifdef L_printf
 #ifdef L_printf
 int printf(const char *fmt, ...)
 int printf(const char *fmt, ...)
 {
 {
@@ -150,93 +233,64 @@ int vsnprintf(char *sp, size_t size, __const char *fmt, va_list ap)
 
 
 #ifdef L_vfprintf
 #ifdef L_vfprintf
 
 
-#if FLOATS
+extern char *__ultostr(char *buf, unsigned long uval, int base, int uppercase);
-int _vfprintf_fp_ref = 1;
+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 char *__dtostr(char *buf, double x);
+
+enum {
+	FLAG_PLUS = 0,
+	FLAG_MINUS_LJUSTIFY,
+	FLAG_HASH,
+	FLAG_0_PAD,
+	FLAG_SPACE,
+};
+
+/* layout                   01234  */
+static const char spec[] = "+-#0 ";
+
+#if WANT_LONG_LONG || WANT_LONG_LONG_ERROR
+static const char qual[] = "hlLq";
 #else
 #else
-int _vfprintf_fp_ref = 0;
+static const char qual[] = "hl";
 #endif
 #endif
 
 
-static int
+#if !WANT_LONG_LONG && WANT_LONG_LONG_ERROR
-printfield(op, buf, ljustf, sign, pad, width, preci, buffer_mode, max_size,
+static const char ll_err[] = "<LONG-LONG>";
-		   current_size)
+#endif
-register FILE *op;
-register unsigned char *buf;
-int ljustf;
-register char sign;
-char pad;
-register int width;
-int preci;
-int buffer_mode;
-size_t max_size;
-size_t current_size;
-
-/*
- * Output the given field in the manner specified by the arguments. Return
- * the number of characters output.
- */
-{
-	register int cnt = 0, len;
-	register unsigned char ch;
-
-	len = strlen(buf);
-
-	if (*buf == '-')
-		sign = *buf++;
-	else if (sign)
-		len++;
-
-	if ((preci != -1) && (len > preci))	/* limit max data width */
-		len = preci;
-
-	if (width < len)			/* flexible field width or width overflow */
-		width = len;
-
-	/*
-	 * at this point: width = total field width len   = actual data width
-	 * (including possible sign character)
-	 */
-	cnt = width;
-	width -= len;
-
-	while (width || len) {
-		if (!ljustf && width) {	/* left padding */
-			if (len && sign && (pad == '0'))
-				goto showsign;
-			ch = pad;
-			--width;
-		} else if (len) {
-			if (sign) {
-			  showsign:ch = sign;
-								/* sign */
-				sign = '\0';
-			} else
-				ch = *buf++;	/* main field */
-			--len;
-		} else {
-			ch = pad;			/* right padding */
-			--width;
-		}
-		current_size++;
-		if (max_size > 0 && current_size < max_size)
-			putc(ch, op);
-		if (ch == '\n' && buffer_mode == _IOLBF)
-			fflush(op);
-	}
 
 
-	return (cnt);
+#if !WANT_DOUBLE && WANT_DOUBLE_ERROR
-}
+static const char dbl_err[] = "<DOUBLE>";
+#endif
 
 
+#if WANT_DOUBLE || WANT_DOUBLE_ERROR
+/* layout                     012345678901234567   */
+static const char u_spec[] = "%nbopxXudicsfgGeEaA";
+#else
+/* layout                     0123456789012   */
+static const char u_spec[] = "%nbopxXudics0";
+#endif
 
 
+/* WARNING: u_spec and u_radix need to stay in agreement!!! */
+/* u_radix[i] <-> u_spec[i+2] for unsigned entries only */
+static const char u_radix[] = "\x02\x08\x10\x10\x10\x0a";
 
 
-int vfnprintf(FILE * op, size_t max_size, register __const char *fmt,
+int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)
-			  register va_list ap)
 {
 {
-	register int i, cnt = 0, ljustf, lval;
+	int i, cnt = 0, lval;
-	int preci, dpoint, width;
+	char *p;
-	char pad, sign, radix, hash;
+	const char *fmt0;
-	register char *ptmp;
-	char tmp[64], *ltostr(), *ultostr();
 	int buffer_mode;
 	int buffer_mode;
+	int preci, width;
+#define upcase i
+	int radix, dpoint /*, upcase*/;
+#if WANT_LONG_LONG
+	char tmp[65];
+#else
+	char tmp[33];
+#endif
+	char flag[sizeof(spec)];
 
 
 	/* This speeds things up a bit for unbuffered */
 	/* This speeds things up a bit for unbuffered */
 	buffer_mode = (op->mode & __MODE_BUF);
 	buffer_mode = (op->mode & __MODE_BUF);
@@ -244,172 +298,296 @@ int vfnprintf(FILE * op, size_t max_size, register __const char *fmt,
 
 
 	while (*fmt) {
 	while (*fmt) {
 		if (*fmt == '%') {
 		if (*fmt == '%') {
-			if (buffer_mode == _IONBF)
+			fmt0 = fmt;			/* save our position in case of bad format */
+			++fmt;
+			if (buffer_mode == _IONBF) {
 				fflush(op);
 				fflush(op);
-			ljustf = 0;			/* left justify flag */
+			}
-			sign = '\0';		/* sign char & status */
-			pad = ' ';			/* justification padding char */
 			width = -1;			/* min field width */
 			width = -1;			/* min field width */
-			dpoint = 0;			/* found decimal point */
+			preci = -5;			/* max string width or mininum digits */
-			preci = -1;			/* max data width */
 			radix = 10;			/* number base */
 			radix = 10;			/* number base */
-			ptmp = tmp;			/* pointer to area to print */
+			dpoint = 0;			/* found decimal point */
-			hash = 0;
 			lval = (sizeof(int) == sizeof(long));	/* long value flaged */
 			lval = (sizeof(int) == sizeof(long));	/* long value flaged */
 
 
-		  fmtnxt:
+			tmp[1] = 0;			/* set things up for %c -- better done here */
-			i = 0;
-			for (;;) {
-				++fmt;
-				if (*fmt < '0' || *fmt > '9')
-					break;
-				i = (i * 10) + (*fmt - '0');
-				if (dpoint)
-					preci = i;
-				else if (!i && (pad == ' ')) {
-					pad = '0';
-					goto fmtnxt;
-				} else
-					width = i;
-			}
-
-			switch (*fmt) {
-			case '\0':			/* early EOS */
-				--fmt;
-				goto charout;
 
 
-			case '-':			/* left justification */
+			/* init flags */
-				ljustf = 1;
+			for (p =(char *) spec ; *p ; p++) {
-				goto fmtnxt;
+				flag[p-spec] = '\0';
+			}
+			flag[FLAG_0_PAD] = ' ';
 
 
-			case ' ':
+			/* process optional flags */
-			case '+':			/* leading sign flag */
+			for (p = (char *)spec ; *p ; p++) {
-				sign = *fmt;
+				if (*fmt == *p) {
-				goto fmtnxt;
+					flag[p-spec] = *fmt++;
+					p = (char *)spec; /* restart scan */
+				}
+			}
+			
+			if (!flag[FLAG_PLUS]) {
+				flag[FLAG_PLUS] = flag[FLAG_SPACE];
+			}
 
 
-			case '*':			/* parameter width value */
+			/* process optional width and precision */
-				i = va_arg(ap, int);
+			do {
+				if (*fmt == '.') {
+					++fmt;
+					dpoint = 1;
+				}
+				if (*fmt == '*') {	/* parameter width value */
+					++fmt;
+					i = va_arg(ap, int);
+				} else {
+					for ( i = 0 ; (*fmt >= '0') && (*fmt <= '9') ; ++fmt ) {
+						i = (i * 10) + (*fmt - '0');
+					}
+				}
 
 
-				if (dpoint)
+				if (dpoint) {
 					preci = i;
 					preci = i;
-				else
+					if (i<0) {
+						preci = 0;
+					}
+				} else {
 					width = i;
 					width = i;
-				goto fmtnxt;
+					if (i<0) {
-
+						width = -i;
-			case '.':			/* secondary width field */
+						flag[FLAG_MINUS_LJUSTIFY] = 1;
-				dpoint = 1;
+					}
-				goto fmtnxt;
+				}
-
+			} while ((*fmt == '.') && !dpoint );
-			case 'l':			/* long data */
+
-				lval = 1;
+			/* process optional qualifier */
-				goto fmtnxt;
+			for (p = (char *) qual ; *p ; p++) {
+				if (*p == *fmt) {
+					lval = p - qual;
+					++fmt;
+#if WANT_LONG_LONG || WANT_LONG_LONG_ERROR
+					if ((*p == 'l') && (*fmt == *p)) {
+						++lval;
+						++fmt;
+					}
+#endif /* WANT_LONG_LONG || WANT_LONG_LONG_ERROR */
+				}
+			}
 
 
-			case 'h':			/* short data */
+#if WANT_GNU_ERRNO
-				lval = 0;
+			if (*fmt == 'm') {
-				goto fmtnxt;
+				flag[FLAG_PLUS] = '\0';
+				flag[FLAG_0_PAD] = ' ';
+				p = strerror(errno);
+				goto print;
+			}
+#endif
 
 
-			case 'd':			/* Signed decimal */
+			/* process format specifier */
-			case 'i':
+			for (p = (char *) u_spec ; *p ; p++) {
-				ptmp = ltostr((long) ((lval)
+				if (*fmt != *p) continue;
+				if (p-u_spec < 1) {	/* print a % */
+					goto charout;
+				}
+				if (p-u_spec < 2) {	/* store output count in int ptr */
+					*(va_arg(ap, int *)) = cnt;
+					goto nextfmt;
+				}
+				if (p-u_spec < 8) { /* unsigned conversion */
+					radix = u_radix[p-u_spec-2];
+					upcase = ((int)'x') - *p;
+					if (*p == 'p') {
+						lval = (sizeof(char *) == sizeof(long));
+						upcase = 0;
+					}
+#if WANT_LONG_LONG || WANT_LONG_LONG_ERROR
+					if (lval >= 2) {
+#if WANT_LONG_LONG
+						p = __ulltostr(tmp + sizeof(tmp) - 1,
+									   va_arg(ap, unsigned long long),
+									   radix, upcase);
+#else
+						(void) va_arg(ap, unsigned long long);	/* cary on */
+						p = (char *) ll_err;
+#endif /* WANT_LONG_LONG */
+					} else {
+#endif /* WANT_LONG_LONG || WANT_LONG_LONG_ERROR */
+						p = __ultostr(tmp + sizeof(tmp) - 1, (unsigned long)
+									  ((lval)
+									   ? va_arg(ap, unsigned long)
+									   : va_arg(ap, unsigned short)),
+									  radix, upcase);
+#if WANT_LONG_LONG || WANT_LONG_LONG_ERROR
+					}
+#endif /* WANT_LONG_LONG || WANT_LONG_LONG_ERROR */
+					flag[FLAG_PLUS] = '\0';	/* meaningless for unsigned */
+					if (flag[FLAG_HASH]) {
+						switch (radix) {
+							case 16:
+								flag[FLAG_PLUS] = '0';
+								*--p = 'x';
+								if (*fmt == 'X') {
+									*p = 'X';
+								}
+								break;
+							case 8:
+								if (*p != '0') { /* if not zero */
+									*--p = '0';	/* add leadding zero */
+								}
+						}
+					}
+				} else if (p-u_spec < 10) { /* signed conversion */
+#if WANT_LONG_LONG || WANT_LONG_LONG_ERROR
+					if (lval >= 2) {
+#if WANT_LONG_LONG
+						p = __lltostr(tmp + sizeof(tmp) - 1,
+									  va_arg(ap, long long), 10, 0);
+#else
+						(void) va_arg(ap, long long); /* carry on */
+						p = (char *) ll_err;
+#endif /* WANT_LONG_LONG */
+					} else {
+#endif /* WANT_LONG_LONG || WANT_LONG_LONG_ERROR */
+						p = __ltostr(tmp + sizeof(tmp) - 1, (long)
+									 ((lval)
 									  ? va_arg(ap, long)
 									  ? va_arg(ap, long)
 									  : va_arg(ap, short)), 10, 0);
 									  : va_arg(ap, short)), 10, 0);
+#if WANT_LONG_LONG || WANT_LONG_LONG_ERROR
+					}
+#endif /* WANT_LONG_LONG || WANT_LONG_LONG_ERROR */
+				} else if (p-u_spec < 12) {	/* character or string */
+					flag[FLAG_PLUS] = '\0';
+					flag[FLAG_0_PAD] = ' ';
+					if (*p == 'c') {	/* character */
+						p = tmp;
+						*p = va_arg(ap, int);
+					} else {	/* string */
+						p = va_arg(ap, char *);
+					}
+#if WANT_DOUBLE || WANT_DOUBLE_ERROR
+				} else if (p-u_spec < 27) {		/* floating point */
+#endif /* WANT_DOUBLE || WANT_DOUBLE_ERROR */
+#if WANT_DOUBLE
+					p = __dtostr(tmp + sizeof(tmp) - 1, va_arg(ap, double));
+#elif WANT_DOUBLE_ERROR
+					(void) va_arg(ap,double); /* carry on */
+					p = (char *) dbl_err;
+#endif /* WANT_DOUBLE */
+				}
 
 
-				goto printit;
+#if WANT_GNU_ERRNO
-
+			print:
-			case 'b':			/* Unsigned binary */
+#endif
-				radix = 2;
+				{				/* this used to be printfield */
-				goto usproc;
+					int len;
-
-			case 'o':			/* Unsigned octal */
-				radix = 8;
-				goto usproc;
-
-			case 'p':			/* Pointer */
-				lval = (sizeof(char *) == sizeof(long));
-
-				pad = '0';
-				width = 6;
-				preci = 8;
-				/* fall thru */
-
-			case 'x':			/* Unsigned hexadecimal */
-			case 'X':
-				radix = 16;
-				/* fall thru */
 
 
-			case 'u':			/* Unsigned decimal */
+					/* cheaper than strlen call */
-			  usproc:
+					for ( len = 0 ; p[len] ; len++ ) { }
-				ptmp = ultostr((unsigned long) ((lval)
-												? va_arg(ap, unsigned long)
-												: va_arg(ap,
-														 unsigned short)),
-							   radix, (*fmt == 'X') ? 1 : 0);
 
 
-				if (hash && radix == 8) {
+					if ((*p == '-')
-					width = strlen(ptmp) + 1;
+#if WANT_GNU_ERRNO
-					pad = '0';
+						&& (*fmt != 'm')
-				}
-				goto printit;
-
-			case '#':
-				hash = 1;
-				goto fmtnxt;
-
-			case 'c':			/* Character */
-				ptmp[0] = va_arg(ap, int);
-
-				ptmp[1] = '\0';
-				goto nopad;
-
-			case 's':			/* String */
-				ptmp = va_arg(ap, char *);
-
-			  nopad:
-				sign = '\0';
-				pad = ' ';
-			  printit:
-				cnt += printfield(op, ptmp, ljustf, sign, pad, width,
-								  preci, buffer_mode, max_size, cnt);
-				break;
-
-#if FLOATS
-			case 'e':			/* float */
-			case 'f':
-			case 'g':
-			case 'E':
-			case 'G':
-				fprintf(stderr, "LIBM:PRINTF");
-				gcvt(va_arg(ap, double), preci, ptmp);
-
-				preci = -1;
-				goto printit;
-#else
-			case 'e':			/* float */
-			case 'f':
-			case 'g':
-			case 'E':
-			case 'G':
-				fprintf(stderr, "LIBC:PRINTF");
-				exit(-1);
 #endif
 #endif
-
+						&& (*fmt != 's')) {
-			default:			/* unknown character */
+						flag[FLAG_PLUS] = *p++;
-				goto charout;
+						--len;
+					}
+				    if (flag[FLAG_PLUS]) {
+						++len;
+						++preci;
+						if (flag[FLAG_PLUS] == '0') { /* base 16 */
+							++preci; /* account for x or X */
+						}
+					}
+
+					if (preci >= 0) {
+						if ((*fmt == 's')
+#if WANT_GNU_ERRNO
+						|| (*fmt == 'm')
+#endif
+						) {
+							len = preci;
+						}
+						preci -= len;
+						if (preci < 0) {
+							preci = 0;
+						}
+						width -= preci;
+					}
+
+					width -= len;
+					if (width < 0) {
+						width = 0;
+					}
+
+					if (preci < 0) {
+						preci = 0;
+						if (flag[FLAG_PLUS]
+							&& !flag[FLAG_MINUS_LJUSTIFY]
+							&& (flag[FLAG_0_PAD] == '0')) { 
+							preci = width;
+							width = 0;
+						}
+					}
+
+					while (width + len + preci) {
+						unsigned char ch;
+						/* right padding || left padding */
+						if ((!len && !preci)
+							|| (width && !flag[FLAG_MINUS_LJUSTIFY])) {
+							ch = ' ';
+							--width;
+						} else if (flag[FLAG_PLUS]) {
+							ch = flag[FLAG_PLUS]; /* sign */
+							if (flag[FLAG_PLUS]=='0') {	/* base 16 case */
+								flag[FLAG_PLUS] = *p++;	/* get the x|X */
+							} else {
+								flag[FLAG_PLUS] = '\0';
+							}
+							--len;
+						} else if (preci) {
+							ch = '0';
+							--preci;
+						} else {
+							ch = *p++;	/* main field */
+							--len;
+						}
+
+						if (++cnt < max_size) {
+							putc(ch, op);
+						}
+						if ((ch == '\n') && (buffer_mode == _IOLBF)) {
+							fflush(op);
+						}
+					}
+				}
+				goto nextfmt;
 			}
 			}
-		} else {
+
-		  charout:
+			fmt = fmt0;	/* this was an illegal format */
-			if (max_size > 0 && ++cnt < max_size)
+		}
-				putc(*fmt, op);	/* normal char out */
+
-			if (*fmt == '\n' && buffer_mode == _IOLBF)
+		charout:
-				fflush(op);
+		if (++cnt < max_size) {
+			putc(*fmt, op);	/* normal char out */
+		}
+		if ((*fmt == '\n') && (buffer_mode == _IOLBF)) {
+			fflush(op);
 		}
 		}
+
+	nextfmt:
 		++fmt;
 		++fmt;
 	}
 	}
+
 	op->mode |= buffer_mode;
 	op->mode |= buffer_mode;
-	if (buffer_mode == _IONBF)
+	if (buffer_mode == _IONBF) {
 		fflush(op);
 		fflush(op);
-	if (buffer_mode == _IOLBF)
+	}
+	if (buffer_mode == _IOLBF) {
 		op->bufwrite = op->bufstart;
 		op->bufwrite = op->bufstart;
+	}
+
+	if (ferror(op)) {
+		cnt = -1;
+	}
 	return (cnt);
 	return (cnt);
 }
 }
 
 

+ 4 - 2
libc/stdlib/Makefile

@@ -26,13 +26,15 @@ LIBC=$(TOPDIR)libc.a
 
 
 DIRS = $(MALLOC)
 DIRS = $(MALLOC)
 
 
+MSRC=strto_l.c
+MOBJ=strtol.o strtoul.o strto_l.o
 
 
 MSRC2=atexit.c
 MSRC2=atexit.c
 MOBJ2=on_exit.o atexit.o __do_exit.o exit.o
 MOBJ2=on_exit.o atexit.o __do_exit.o exit.o
 
 
 
 
-CSRC =	abort.c getenv.c  mktemp.c  qsort.c  realpath.c strtod.c strtoul.c \
+CSRC =	abort.c getenv.c  mktemp.c  qsort.c  realpath.c strtod.c \
-	abs.c   bsearch.c mkstemp.c putenv.c rand.c setenv.c strtol.c system.c
+	abs.c   bsearch.c mkstemp.c putenv.c rand.c setenv.c  system.c
 COBJS=$(patsubst %.c,%.o, $(CSRC))
 COBJS=$(patsubst %.c,%.o, $(CSRC))
 
 
 
 

+ 192 - 0
libc/stdlib/strto_l.c

@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2000 Manuel Novoa III
+ *
+ * Notes:
+ *
+ * The primary objective of this implementation was minimal size.
+ *
+ * Note: Assumes char layout 0-9.*A-Z.*a-z for ordinals values.
+ *
+ * There are a couple of compile-time options below.
+ *
+ */
+
+/*****************************************************************************/
+/*                            OPTIONS                                        */
+/*****************************************************************************/
+
+/* Set if we want strtod to set errno appropriately. */
+/* NOTE: Implies _STRTO_ENDPTR below */
+#define _STRTO_ERRNO            0
+
+/* Set if we want support for the endptr arg. */
+/* Implied by _STRTO_ERRNO. */
+#define _STRTO_ENDPTR           1
+
+/*****************************************************************************/
+/* Don't change anything that follows.                                       */
+/*****************************************************************************/
+
+#if _STRTO_ERRNO
+#undef _STRTO_ENDPTR
+#define _STRTO_ENDPTR           1
+#endif
+
+/*****************************************************************************/
+
+/* Are there actually any machines where this might fail? */
+#if 'A' > 'a'
+#error ordering assumption violated : 'A' > 'a'
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+
+#if _STRTO_ERRNO
+#include <errno.h>
+#endif
+
+unsigned long _strto_l(const char *str, char **endptr, int base, int uflag);
+
+#if L_strto_l
+
+/*
+ * This is the main work fuction which handles both strtol (uflag = 0) and
+ * strtoul (uflag = 1).
+ */
+
+unsigned long _strto_l(const char *str, char **endptr, int base, int uflag)
+{
+    unsigned long number = 0;
+    unsigned long cutoff;
+    char *pos = (char *) str;
+#if _STRTO_ENDPTR
+    char *fail_char = (char *) str;
+#endif
+    int digit, cutoff_digit;
+    int negative;
+
+    while (isspace(*pos)) {	/* skip leading whitespace */
+	++pos;
+    }
+
+    /* handle optional sign */
+    negative = 0;
+    switch(*pos) {
+    case '-': negative = 1;	/* fall through to increment pos */
+    case '+': ++pos;
+    }
+
+    if ((base == 16) && (*pos == '0')) { /* handle option prefix */
+	++pos;
+#if _STRTO_ENDPTR
+	fail_char = pos;
+#endif
+	if ((*pos == 'x') || (*pos == 'X')) {
+	    ++pos;
+	}
+    }
+    
+    if (base == 0) {		/* dynamic base */
+	base = 10;		/* default is 10 */
+	if (*pos == '0') {
+	    ++pos;
+	    base -= 2;		/* now base is 8 (or 16) */
+#if _STRTO_ENDPTR
+	    fail_char = pos;
+#endif
+	    if ((*pos == 'x') || (*pos == 'X')) {
+		base += 8;	/* base is 16 */
+		++pos;
+	    }
+	}
+    }
+
+    if ((base < 2) || (base > 36)) { /* illegal base */
+	goto DONE;
+    }
+
+    cutoff = ULONG_MAX / base;
+    cutoff_digit = ULONG_MAX - cutoff * base;
+
+    while (1) {
+	digit = 40;
+	if ((*pos >= '0') && (*pos <= '9')) {
+	    digit = (*pos - '0');
+	} else if (*pos >= 'a') {
+	    digit = (*pos - 'a' + 10);
+	} else if (*pos >= 'A') {
+	    digit = (*pos - 'A' + 10);
+	} else break;
+
+	if (digit >= base) {
+	    break;
+	}
+
+	++pos;
+#if _STRTO_ENDPTR
+	fail_char = pos;
+#endif
+
+	/* adjust number, with overflow check */
+	if ((number > cutoff)
+	    || ((number == cutoff) && (digit > cutoff_digit))) {
+	    number = ULONG_MAX;
+	    if (uflag) {
+		negative = 0; /* since unsigned returns ULONG_MAX */
+	    }
+#if _STRTO_ERRNO
+	    errno = ERANGE;
+#endif
+	} else {
+	    number = number * base + digit;
+	}
+
+    }
+
+ DONE:
+#if _STRTO_ENDPTR
+    if (endptr) {
+	*endptr = fail_char;
+    }
+#endif
+
+    if (negative) {
+	if (!uflag && (number > ((unsigned long)(-(1+LONG_MIN)))+1)) {
+#if _STRTO_ERRNO
+	    errno = ERANGE;
+#endif
+	    return (unsigned long) LONG_MIN;
+	}
+	return (unsigned long)(-((long)number));
+    } else {
+	if (!uflag && (number > (unsigned long) LONG_MAX)) {
+#if _STRTO_ERRNO
+	    errno = ERANGE;
+#endif
+	    return LONG_MAX;
+	}
+	return number;
+    }
+}
+
+#endif
+
+#if L_strtoul
+
+unsigned long strtoul(const char *str, char **endptr, int base)
+{
+    return _strto_l(str, endptr, base, 1);
+}
+
+#endif
+
+#if L_strtol
+
+long strtol(const char *str, char **endptr, int base)
+{
+    return _strto_l(str, endptr, base, 0);
+}
+
+#endif

+ 246 - 66
libc/stdlib/strtod.c

@@ -1,83 +1,263 @@
 /*
 /*
- * strtod.c - This file is part of the libc-8086 package for ELKS,
+ * Copyright (C) 2000 Manuel Novoa III
- * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
- * 
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Library General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
  *
  *
- *  This library is distributed in the hope that it will be useful,
+ * Notes:
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Library General Public License for more details.
  *
  *
- *  You should have received a copy of the GNU Library General Public
+ * The primary objective of this implementation was minimal size while
- *  License along with this library; if not, write to the Free
+ * providing robustness and resonable accuracy.
- *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This implementation depends on IEEE floating point behavior and expects
+ * to be able to generate +/- infinity as a result.
+ *
+ * There are a number of compile-time options below.
  *
  *
  */
  */
+
+/*****************************************************************************/
+/*                            OPTIONS                                        */
+/*****************************************************************************/
+
+/* Set if we want to scale with a O(log2(exp)) multiplications. */
+#define _STRTOD_LOG_SCALING      1
+
+/* Set if we want strtod to set errno appropriately. */
+/* NOTE: Implies all options below and pulls in _zero_or_inf_check. */
+#define _STRTOD_ERRNO            0
+
+/* Set if we want support for the endptr arg. */
+/* Implied by _STRTOD_ERRNO. */
+#define _STRTOD_ENDPTR           1
+
+/* Set if we want to prevent overflow in accumulating the exponent. */
+#define _STRTOD_RESTRICT_EXP     1
+
+/* Set if we want to process mantissa digits more intelligently. */
+/* Implied by _STRTOD_ERRNO. */
+#define _STRTOD_RESTRICT_DIGITS  1
+
+/* Set if we want to skip scaling 0 for the exponent. */
+/* Implied by _STRTOD_ERRNO. */
+#define _STRTOD_ZERO_CHECK       0
+
+/*****************************************************************************/
+/* Don't change anything that follows.                                       */
+/*****************************************************************************/
+
+#if _STRTOD_ERRNO
+#undef _STRTOD_ENDPTR
+#undef _STRTOD_RESTRICT_EXP
+#undef _STRTOD_RESTRICT_DIGITS
+#undef _STRTOD_ZERO_CHECK
+#define _STRTOD_ENDPTR           1
+#define _STRTOD_RESTRICT_EXP     1
+#define _STRTOD_RESTRICT_DIGITS  1
+#define _STRTOD_ZERO_CHECK       1
+#endif
+
+/*****************************************************************************/
+
 #include <stdlib.h>
 #include <stdlib.h>
+
+#include <float.h>
+
+#if _STRTOD_RESTRICT_DIGITS
+#define MAX_SIG_DIGITS 20
+#define EXP_DENORM_ADJUST MAX_SIG_DIGITS
+#define MAX_ALLOWED_EXP (MAX_SIG_DIGITS  + EXP_DENORM_ADJUST - DBL_MIN_10_EXP)
+
+#if DBL_DIG > MAX_SIG_DIGITS
+#error need to adjust MAX_SIG_DIGITS
+#endif
+
+#include <limits.h>
+#if MAX_ALLOWED_EXP > INT_MAX
+#error size assumption violated for MAX_ALLOWED_EXP
+#endif
+#else
+/* We want some excess if we're not restricting mantissa digits. */
+#define MAX_ALLOWED_EXP ((20 - DBL_MIN_10_EXP) * 2)
+#endif
+
 #include <ctype.h>
 #include <ctype.h>
+/* Note: For i386 the macro resulted in smaller code than the function call. */
+#if 1
+#undef isdigit
+#define isdigit(x) ( (x >= '0') && (x <= '9') )
+#endif
+
+#if _STRTOD_ERRNO
+#include <errno.h>
+extern int _zero_or_inf_check(double x);
+#endif
 
 
-float strtod(const char *nptr, char **endptr)
+double strtod(const char *str, char **endptr)
 {
 {
-	unsigned short negative;
+    double number;
-	float number;
+#if _STRTOD_LOG_SCALING
-	float fp_part;
+    double p10;
-	int exponent;
+#endif
-	unsigned short exp_negative;
+    char *pos0;
-
+#if _STRTOD_ENDPTR
-	/* advance beyond any leading whitespace */
+    char *pos1;
-	while (isspace(*nptr))
+#endif
-		nptr++;
+    char *pos = (char *) str;
-
+    int exponent_power;
-	/* check for optional '+' or '-' */
+    int exponent_temp;
-	negative = 0;
+    int negative;
-	if (*nptr == '-') {
+#if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR
-		negative = 1;
+    int num_digits;
-		nptr++;
+#endif
-	} else if (*nptr == '+')
+
-		nptr++;
+    while (isspace(*pos)) {	/* skip leading whitespace */
-
+	++pos;
-	number = 0;
+    }
-	while (isdigit(*nptr)) {
+
-		number = number * 10 + (*nptr - '0');
+    negative = 0;
-		nptr++;
+    switch(*pos) {		/* handle optional sign */
+    case '-': negative = 1;	/* fall through to increment position */
+    case '+': ++pos;
+    }
+
+    number = 0.;
+#if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR
+    num_digits = -1;
+#endif
+    exponent_power = 0;
+    pos0 = NULL;
+
+ LOOP:
+    while (isdigit(*pos)) {	/* process string of digits */
+#if _STRTOD_RESTRICT_DIGITS
+	if (num_digits < 0) {	/* first time through? */
+	    ++num_digits;	/* we've now seen a digit */
+	}
+	if (num_digits || (*pos != '0')) { /* had/have nonzero */
+	    ++num_digits;
+	    if (num_digits <= MAX_SIG_DIGITS) { /* is digit significant */
+		number = number * 10. + (*pos - '0');
+	    }
 	}
 	}
+#else
+#if _STRTOD_ENDPTR
+	++num_digits;
+#endif
+	number = number * 10. + (*pos - '0');
+#endif
+	++pos;
+    }
+
+    if ((*pos == '.') && !pos0) { /* is this the first decimal point? */
+	pos0 = ++pos;		/* save position of decimal point */
+	goto LOOP;		/* and process rest of digits */
+    }
+
+#if _STRTOD_ENDPTR
+    if (num_digits<0) {		/* must have at least one digit */
+	pos = (char *) str;
+	goto DONE;
+    }
+#endif
+
+#if _STRTOD_RESTRICT_DIGITS
+    if (num_digits > MAX_SIG_DIGITS) { /* adjust exponent for skipped digits */
+	exponent_power += num_digits - MAX_SIG_DIGITS;
+    }
+#endif
+
+    if (pos0) {
+	exponent_power += pos0 - pos; /* adjust exponent for decimal point */
+    }
+
+    if (negative) {		/* correct for sign */
+	number = -number;
+	negative = 0;		/* reset for exponent processing below */
+    }
 
 
-	if (*nptr == '.') {
+    /* process an exponent string */
-		nptr++;
+    if (*pos == 'e' || *pos == 'E') {
-		fp_part = 0;
+#if _STRTOD_ENDPTR
-		while (isdigit(*nptr)) {
+	pos1 = pos;
-			fp_part = fp_part / 10.0 + (*nptr - '0') / 10.0;
+#endif
-			nptr++;
+	switch(*++pos) {	/* handle optional sign */
-		}
+	case '-': negative = 1;	/* fall through to increment pos */
-		number += fp_part;
+	case '+': ++pos;
 	}
 	}
 
 
-	if (*nptr == 'e' || *nptr == 'E') {
+	pos0 = pos;
-		nptr++;
+	exponent_temp = 0;
-		exp_negative = 0;
+	while (isdigit(*pos)) {	/* process string of digits */
-		if (*nptr == '-') {
+#if _STRTOD_RESTRICT_EXP
-			exp_negative = 1;
+	    if (exponent_temp < MAX_ALLOWED_EXP) { /* overflow check */
-			nptr++;
+		exponent_temp = exponent_temp * 10 + (*pos - '0');
-		} else if (*nptr == '+')
+	    }
-			nptr++;
+#else
-
+	    exponent_temp = exponent_temp * 10 + (*pos - '0');
-		exponent = 0;
+#endif
-		while (isdigit(*nptr)) {
+	    ++pos;
-			exponent = exponent * 10 + (*nptr - '0');
-			exponent++;
-		}
 	}
 	}
 
 
-	while (exponent) {
+#if _STRTOD_ENDPTR
-		if (exp_negative)
+	if (pos == pos0) {	/* were there no digits? */
-			number /= 10;
+	    pos = pos1;		/* back up to e|E */
-		else
+	} /* else */
-			number *= 10;
+#endif
-		exponent--;
+	if (negative) {
+	    exponent_power -= exponent_temp;
+	} else {
+	    exponent_power += exponent_temp;
 	}
 	}
-	return (negative ? -number : number);
+    }
+
+#if _STRTOD_ZERO_CHECK
+    if (number == 0.) {
+	goto DONE;
+    }
+#endif
+
+    /* scale the result */
+#if _STRTOD_LOG_SCALING
+    exponent_temp = exponent_power;
+    p10 = 10.;
+
+    if (exponent_temp < 0) {
+	exponent_temp = -exponent_temp;
+    }
+
+    while (exponent_temp) {
+	if (exponent_temp & 1) {
+	    if (exponent_power < 0) {
+		number /= p10;
+	    } else {
+		number *= p10;
+	    }
+	}
+	exponent_temp >>= 1;
+	p10 *= p10;
+    }
+#else
+    while (exponent_power) {
+	if (exponent_power < 0) {
+	    number /= 10.;
+	    exponent_power++;
+	} else {
+	    number *= 10.;
+	    exponent_power--;
+	}
+    }
+#endif
+
+#if _STRTOD_ERRNO
+    if (_zero_or_inf_check(number)) {
+	errno=ERANGE;
+    }
+#endif
+
+ DONE:
+#if _STRTOD_ENDPTR
+    if (endptr) {
+	*endptr = pos;
+    }
+#endif
+
+    return number;
 }
 }

+ 50 - 11
libc/string/strerror.c

@@ -16,31 +16,70 @@ License along with the GNU C Library; see the file COPYING.LIB.  If
 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
 Cambridge, MA 02139, USA.  */
 Cambridge, MA 02139, USA.  */
 
 
+/*
+ * Manuel Novoa III       Dec 2000
+ *
+ * Converted to use my new (un)signed long (long) to string routines, which
+ * are smaller than the previous functions and don't require static buffers.
+ * Removed dependence on strcat in the process.
+ *
+ * Also appended a test routine ( -DSTRERROR_TEST ) to allow a quick check
+ * on the buffer length when the sys_errorlist is modified.
+ */
+
 #include <stdio.h>
 #include <stdio.h>
 #include <string.h>
 #include <string.h>
 #include <errno.h>
 #include <errno.h>
+#include <limits.h>
+
+#if (INT_MAX >> 31)
+/* We're set up for 32 bit ints */
+#error need to check size allocation for static buffer 'retbuf'
+#endif
 
 
-extern char *itoa(int);
+extern char *__ltostr(char *buf, long uval, int base, int uppercase);
+
+static char retbuf[33];			/* 33 is sufficient for 32 bit ints */
+static const char unknown_error[] = "Unknown Error: errno"; /* = */
 
 
 /* Return a string descibing the errno code in ERRNUM.
 /* Return a string descibing the errno code in ERRNUM.
    The storage is good only until the next call to strerror.
    The storage is good only until the next call to strerror.
    Writing to the storage causes undefined behavior.  */
    Writing to the storage causes undefined behavior.  */
 char *strerror(int err)
 char *strerror(int err)
 {
 {
-	static char retbuf[80];
+	char *pos;
 
 
-	if (sys_nerr) {
+	if ((err >= 0) && (err < sys_nerr)) {
-		if (err < 0 || err >= sys_nerr)
-			goto unknown;
 		strcpy(retbuf, sys_errlist[err]);
 		strcpy(retbuf, sys_errlist[err]);
 		return retbuf;
 		return retbuf;
 	}
 	}
 
 
-	if (err <= 0)
+	/* unknown error */
-		goto unknown;
+	pos = __ltostr(retbuf + sizeof(retbuf) + 1, err, 10, 0)
+		- sizeof(unknown_error); /* leave space for the '=' */
+	strcpy(pos, unknown_error);
+	*(pos + sizeof(unknown_error) - 1) = '=';
+	return pos;
+}
+
+#if STRERROR_TEST
+/* quick way to check for sufficient buffer length */
+#include <stdio.h>
+#include <stdlib.h>
+int main(void)
+{
+	int max = 0;
+	int i, j;
+	char *p;
+	for ( i=0 ; i < sys_nerr ; i++ ) {
+		j = strlen(sys_errlist[i])+1;
+		if (j > max) max = j;
+	}
+	printf("max len = %i\n", j);
 
 
-  unknown:
+	p = strerror(INT_MIN);
-	strcpy(retbuf, "Unknown Error: errno=");
+	printf("<%s>  %d\n", p, strlen(p)+1);
-	strcat(retbuf, (char *) itoa(err));
+	printf("current buffer length is %d\n", sizeof(retbuf));
-	return retbuf;
+	return EXIT_SUCCESS;
 }
 }
+#endif

+ 63 - 12
libc/string/strsignal.c

@@ -4,11 +4,25 @@
  * GNU Library General Public License.
  * GNU Library General Public License.
  */
  */
 
 
+/*
+ * Manuel Novoa III       Dec 2000
+ *
+ * Converted to use my new (un)signed long (long) to string routines, which
+ * are smaller than the previous functions and don't require static buffers.
+ * Removed dependence on strcat in the process.
+ * 
+ * Also fixed a bug in the signal name lookup code.  While the table is
+ * declared with dimension > 60, there are currently on 32 signals listed.
+ *
+ * Also appended a test routine ( -DSTRSIGNAL_TEST ) to allow a quick check
+ * on the buffer length when the sys_errorlist is modified.
+ */
+
 #include <string.h>
 #include <string.h>
 #include <malloc.h>
 #include <malloc.h>
 #include <signal.h>
 #include <signal.h>
 
 
-extern char *itoa(int i);
+extern char *__ltostr(char *buf, long uval, int base, int uppercase);
 
 
 const char *const sys_siglist[] = {
 const char *const sys_siglist[] = {
 	"Unknown signal",
 	"Unknown signal",
@@ -46,26 +60,63 @@ const char *const sys_siglist[] = {
 	NULL
 	NULL
 };
 };
 
 
+#include <limits.h>
+
+#if (INT_MAX >> 31)
+/* We're set up for 32 bit ints */
+#error need to check size allocation for static buffer 'retbuf'
+#endif
+
 /********************** Function strsignal ************************************/
 /********************** Function strsignal ************************************/
 
 
 char *strsignal(int sig)
 char *strsignal(int sig)
 {
 {
-	static char retbuf[80];
+	static char retbuf[28];		/* 28 is sufficient for 32 bit ints */
+	static const char unknown_signal[] = "Unknown Signal:";
+	char *pos;
 
 
-	if (sys_siglist) {
+	/* if ((sig >= 0) && (sig < _NSIG)) { */
-		if (sig < 0 || sig >= _NSIG)
+	if ((sig >= 0) && (sig < 32)) { /* WARNING!!! NOT ALL _NSIG DEFINED!!! */
-			goto unknown;
 		strcpy(retbuf, sys_siglist[sig]);
 		strcpy(retbuf, sys_siglist[sig]);
 		return retbuf;
 		return retbuf;
 	}
 	}
 
 
-	if (sig <= 0)
+	pos = __ltostr(retbuf + sizeof(unknown_signal) + 1, sig, 10, 0)
-		goto unknown;
+		- sizeof(unknown_signal);
-
+	strcpy(pos, unknown_signal);
-  unknown:
+	*(pos + sizeof(unknown_signal) - 1) = ' ';
-	strcpy(retbuf, "Unknown Signal: ");
+	return pos;
-	strcat(retbuf, (char *) itoa(sig));
-	return retbuf;
 }
 }
 
 
 /********************** THE END ********************************************/
 /********************** THE END ********************************************/
+
+#if STRSIGNAL_TEST
+/* quick way to check for sufficient buffer length */
+#include <stdio.h>
+#include <stdlib.h>
+int main(void)
+{
+	int max = 0;
+	int i, j;
+	const char *p;
+
+	printf("_NSIG = %d  from headers\n", _NSIG);
+	for ( i=0 ; i < _NSIG ; i++ ) {
+		p = sys_siglist[i];
+		if (!p) {
+			printf("Warning! I only count %d signals!\n", i);
+			break;
+		}
+		j = strlen(sys_siglist[i])+1;
+		if (j > max) max = j;
+	}
+	printf("max len = %i\n", j);
+
+	p = strsignal(INT_MIN);
+	printf("<%s>  %d\n", p, strlen(p)+1);
+
+	p = strsignal(i-1);
+	printf("last signal %d is %s\n", i-1, p);
+	return EXIT_SUCCESS;
+}
+#endif

+ 8 - 2
libc/sysdeps/linux/common/Makefile

@@ -29,14 +29,16 @@ LIBC=$(TOPDIR)libc.a
 CSRC =closedir.c dirfd.c getdents.c getdnnm.c gethstnm.c getpagesize.c \
 CSRC =closedir.c dirfd.c getdents.c getdnnm.c gethstnm.c getpagesize.c \
 	isatty.c kernel_version.c mkfifo.c opendir.c readdir.c rewinddir.c \
 	isatty.c kernel_version.c mkfifo.c opendir.c readdir.c rewinddir.c \
 	seekdir.c setegid.c seteuid.c setpgrp.c statfix.c tell.c telldir.c \
 	seekdir.c setegid.c seteuid.c setpgrp.c statfix.c tell.c telldir.c \
-	wait.c wait3.c _xmknod.c _fxstat.c _lxstat.c _xstat.c libc_init.c tcgetatr.c
+	wait.c wait3.c _xmknod.c libc_init.c tcgetatr.c
 COBJS=$(patsubst %.c,%.o, $(CSRC))
 COBJS=$(patsubst %.c,%.o, $(CSRC))
 
 
+NISRC= _fxstat.c _lxstat.c _xstat.c
+NIOBJS=$(patsubst %.c,%.o, $(NISRC))
 
 
 MSRC=syscalls.c
 MSRC=syscalls.c
 MOBJ=$(shell ./list_syscalls.sh)
 MOBJ=$(shell ./list_syscalls.sh)
 
 
-OBJ=$(COBJS) $(MOBJ)
+OBJ=$(COBJS) $(NIOBJS) $(MOBJ)
 
 
 all: $(OBJ) $(LIBC)
 all: $(OBJ) $(LIBC)
 
 
@@ -53,6 +55,10 @@ $(COBJS):
 	$(CC) $(CFLAGS) $< -c $*.c -o $*.o
 	$(CC) $(CFLAGS) $< -c $*.c -o $*.o
 	$(STRIPTOOL) -x -R .note -R .comment $*.o
 	$(STRIPTOOL) -x -R .note -R .comment $*.o
 
 
+$(NIOBJS):
+	$(CC) $(CFLAGS) $< -c $*.c -o $*.o -fno-inline
+	$(STRIPTOOL) -x -R .note -R .comment $*.o
+
 clean:
 clean:
 	rm -f *.[oa] *~ core
 	rm -f *.[oa] *~ core