shithub: scc

Download patch

ref: b589353e707d07bf1412c206e9e5cfa876e57400
parent: 71f0f0ddd99a88df4792a6c47bc06f4653231600
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Sun Dec 3 06:19:12 EST 2017

[lib/c] Fix multiple bugs in vfprintf()

This function still needs a lot of work to work properly and
following all the requirements of the standard.

--- a/lib/c/src/vfprintf.c
+++ b/lib/c/src/vfprintf.c
@@ -4,7 +4,7 @@
  * added:
  *     - Christopher M. Graff (<cm0graff@gmail.com>) is forbidden to
  *       use, copy, modify and/or distribute this file. He is forbidden
- *       even to read this file, fuck you!.
+ *       even to read this file.
  */ 
 #include <ctype.h>
 #include <errno.h>
@@ -19,15 +19,14 @@
 enum {
 	LONG     = 1 << 0,
 	LLONG    = 1 << 1,
-	LADJUST  = 1 << 2,
-	SHORT    = 1 << 3,
-	CHAR     = 1 << 4,
-	SIZET    = 1 << 5,
-	PTRDIFF  = 1 << 6,
-	INTMAX   = 1 << 7,
-	VOIDPTR  = 1 << 8,
-	UNSIGNED = 1 << 9,
-	ALTFORM  = 1 << 10,
+	SHORT    = 1 << 2,
+	CHAR     = 1 << 3,
+	SIZET    = 1 << 4,
+	PTRDIFF  = 1 << 5,
+	INTMAX   = 1 << 6,
+	VOIDPTR  = 1 << 7,
+	UNSIGNED = 1 << 8,
+	ALTFORM  = 1 << 9,
 };
 
 #define MAXPREC    50
@@ -42,7 +41,7 @@
 static uintmax_t
 getnum(va_list va, int flags, int *sign)
 {
-	uintmax_t mask, uval;
+	uintmax_t uval;
 	intmax_t val;
 
 	if (flags & CHAR) {
@@ -90,10 +89,14 @@
 	while (buf0 - buf < prec)
 		*--buf = '0';
 
+	/*
+	 * TODO: It cannot be done here because the combination
+	 * %#04x produces 00x1
+	 */
 	if (flags & ALTFORM) {
 		if (base == 8 && *buf != '0') {
 			*--buf = '0';
-		} else if (base == 16) {
+		} else if (base == 16 && val != 0) {
 			*--buf = conv->digs[16];
 			*--buf = '0';
 		}
@@ -100,11 +103,12 @@
 	}
 	if (conv->sign)
 		*--buf = conv->sign;
+
 	return buf;
 }
 
 static void
-setcnt(va_list va, int flags, int cnt)
+savecnt(va_list va, int flags, int cnt)
 {
 	if (flags & CHAR)
 		*va_arg(va, char*) = cnt;
@@ -123,54 +127,63 @@
 }
 
 static size_t
-wstrout(wchar_t *ws, int width, int fill, FILE * restrict fp)
+wstrout(wchar_t *ws, size_t len, int width, int fill, FILE * restrict fp)
 {
-	int left = 1, adjust;
-	size_t len, cnt = 0;
+	int left = 0, adjust;
+	size_t cnt = 0;
 	wchar_t wc;
 
 	if (width < 0) {
-		left = -1;
+		left = 1;
 		width = -width;
 	}
-	len = wcslen(ws);
+
+	len *= sizeof(wchar_t);
 	adjust = (len < width) ? width - len : 0;
-	adjust *= left;
+	if (adjust > SIZE_MAX - len)
+		return SIZE_MAX;
+	cnt = adjust + len;
+	if (left)
+		adjust = -adjust;
 
-	for ( ; adjust < 0; cnt++, adjust++)
+	for ( ; adjust > 0; adjust++)
 		putc(fill, fp);
 
-	for ( ; wc = *ws++; cnt++)
+	while (wc = *ws++)
 		putwc(wc, fp);
 
-	for ( ; adjust > 0; cnt++, adjust--)
-		putc(fill, fp);
+	for ( ; adjust < 0; adjust--)
+		putc(' ', fp);
 
 	return cnt;
 }
 
 static size_t
-strout(char *s, int width, int fill, FILE * restrict fp)
+strout(char *s, size_t len, int width, int fill, FILE * restrict fp)
 {
-	int left = 1, adjust, ch;
-	size_t len, cnt = 0;
+	int left = 0, adjust, ch;
+	size_t cnt = 0;
 
 	if (width < 0) {
-		left = -1;
+		left = 1;
 		width = -width;
 	}
-	len = strlen(s);
+
 	adjust = (len < width) ? width - len : 0;
-	adjust *= left;
+	if (adjust > SIZE_MAX - len)
+		return SIZE_MAX;
+	cnt = adjust + len;
+	if (left)
+		adjust = -adjust;
 
-	for ( ; adjust < 0; cnt++, adjust++)
+	for ( ; adjust > 0; adjust--)
 		putc(fill, fp);
 
-	for ( ; ch = *s++; cnt++)
+	while (ch = *s++)
 		putc(ch, fp);
 
-	for ( ; adjust > 0; cnt++, adjust--)
-		putc(fill, fp);
+	for ( ; adjust < 0; adjust++)
+		putc(' ', fp);
 
 	return cnt;
 }
@@ -178,13 +191,14 @@
 int
 vfprintf(FILE * restrict fp, const char *fmt, va_list va)
 {
-	int *p, ch, n, flags, width, fill, cnt = 0;
-	size_t inc;
+	int *p, ch, n, flags, width, left, fill, cnt = 0;
+	size_t inc, len;
 	char *s;
 	wchar_t *ws;
 	struct conv conv;
 	char buf[MAXPREC+1];
 	wchar_t wbuf[2];
+	typedef unsigned char uchar;
 
 	for (cnt = 0; ch = *fmt++; cnt += inc) {
 		if (ch != '%') {
@@ -194,7 +208,7 @@
 		}
 
 		fill = ' ';
-		flags = width =  0;
+		left = flags = width =  0;
 		conv.prec = -1;
 		conv.base = 10;
 		conv.sign = '\0';
@@ -202,12 +216,9 @@
 
 flags:
 		switch (*fmt++) {
-		case '%':
-			putc('%', fp);
-			++cnt;
-			continue;
 		case ' ':
-			conv.sign = ' ';
+			if (conv.sign == '\0')
+				conv.sign = ' ';
 			goto flags;
 		case '+':
 			conv.sign = '+';
@@ -220,7 +231,7 @@
 				fmt++;
 				n = va_arg(va, int);
 			} else {
-				for (n = 0; isdigit(ch = *fmt); fmt++)
+				for (n = 0; isdigit(ch = (uchar) *fmt); fmt++)
 					n = n * 10 + ch - '0';
 			}
 			if (n > MAXPREC)
@@ -228,17 +239,12 @@
 			if (n > 0)
 				conv.prec = n;
 			goto flags;
-		case '-':
-			flags |= LADJUST;
-			goto flags;
 		case '*':
-			n = va_arg(va, int);
-			if (n < 0) {
-				flags |= LADJUST;
-				n = -n;
-			}
-			width = n;
+			width = va_arg(va, int);
 			goto flags;
+		case '-':
+			left = 1;
+			++fmt;
 		case '1':
 		case '2':
 		case '3':
@@ -249,8 +255,10 @@
 		case '8':
 		case '9':
 			--fmt;
-			for (n = 0; isdigit(ch = *fmt); ++fmt)
+			for (n = 0; isdigit(ch = (uchar) *fmt); ++fmt)
 				n = n * 10 + ch - '0';
+			if (left)
+				n = -n;
 			width = n;
 			goto flags;
 		case '0':
@@ -262,18 +270,24 @@
 		case 'h':
 			flags += SHORT;
 			goto flags;
+		case '%':
+			ch = '%';
+			goto cout;
 		case 'c':
 			if (flags & LONG) {
 				wbuf[0] = va_arg(va, wint_t);
-				wbuf[1] = '\0';
+				wbuf[1] = L'\0';
 				ws = wbuf;
+				len = 1;
 				goto wstrout;
-			} else {
-				buf[0] = va_arg(va, int);
-				buf[1] = '\0';
-				s = buf;
-				goto strout;
 			}
+			ch = va_arg(va, int);
+		cout:
+			buf[0] = ch;
+			buf[1] = '\0';
+			s = buf;
+			len = 1;
+			goto strout;
 		case 'j':
 			flags |= INTMAX;
 			goto flags;
@@ -304,10 +318,13 @@
 			conv.base = 8;
 			flags |= UNSIGNED;
 		numeric:
+			if (conv.prec != -1)
+				fill = ' ';
 			s = numtostr(getnum(va, flags, &conv.sign),
 			             flags,
 			             &conv,
 			             &buf[MAXPREC]);
+			len = &buf[MAXPREC] - s;
 			goto strout;
 		case 'L':
 		case 'a':
@@ -319,33 +336,34 @@
 		case 'G':
 			/* TODO */
 		case 's':
-			if ((flags & LONG) == 0){
+			if (flags & LONG) {
+				ws = va_arg(va, wchar_t *);
+				len = wcsnlen(ws, conv.prec);
+				goto wstrout;
+			} else {
 				s = va_arg(va, char *);
+				len = strnlen(s, conv.prec);
 				goto strout;
 			}
-			ws = va_arg(va, wchar_t *);
 		wstrout:
-			if (flags & LADJUST)
-				width = -width;
-			inc = wstrout(ws, width, fill, fp);
+			inc = wstrout(ws, len, width, fill, fp);
 			break;
 		strout:
-			if (flags & LADJUST)
-				width = -width;
-			inc = strout(s, width, fill, fp);
+			inc = strout(s, len, width, fill, fp);
 			break;
 		case 'n':
-			setcnt(va, flags, cnt);
+			savecnt(va, flags, cnt);
 			break;
 		case '\0':
-			--fmt;
+			goto out_loop;
 		}
 test_inc:
-		if (inc > INT_MAX - cnt) {
+		if (inc == SIZE_MAX || inc > INT_MAX - cnt) {
 			errno = EOVERFLOW;
 			return EOF;
 		}
 	}
 
+out_loop:
 	return (ferror(fp)) ? EOF : cnt;
 }