Browse Source

docs/defines.txt: document _extern_inline
libc/inet/ether_addr.c: optimize tolower, we ever use it on 0-9a-f
libc/inet/ntop.c: optimize tolower, we ever use it on 0-9a-f
with locale support on, code size change is:

text data bss dec hex filename
- 396 0 24 420 1a4 libc/inet/ether_addr.os
+ 306 0 24 330 14a libc/inet/ether_addr.os
- 1453 0 0 1453 5ad libc/inet/ntop.os
+ 1430 0 0 1430 596 libc/inet/ntop.os

Denis Vlasenko 15 years ago
parent
commit
4274e51623
3 changed files with 70 additions and 75 deletions
  1. 6 1
      docs/defines.txt
  2. 24 28
      libc/inet/ether_addr.c
  3. 40 46
      libc/inet/ntop.c

+ 6 - 1
docs/defines.txt

@@ -40,10 +40,15 @@ __USE_EXTERN_INLINES
     out-of-line version of every inlined function in case user program
     calls it instead of using an inline.
 _EXTERN_INLINE
-    Define it to replace "extern __inline" string in inline definitions
+    If not defined by user prior to #include, will be defined to
+    "extern inline" or equivalent. IOW, if user defines it prior
+    #include, it replaces "extern __inline" string in inline definitions
     (those enabled by __USE_EXTERN_INLINES) with something else.
     A few uclibc .c files use it to create non-inlined functions
     by defining it to "".
+__extern_inline
+    Defined to "extern inline", modulo gcc/C standard deviations.
+    Can't be used by user to play tricks as with _EXTERN_INLINE.
 
 _LIBC
 UCLIBC_INTERNAL

+ 24 - 28
libc/inet/ether_addr.c

@@ -31,49 +31,45 @@
 #include <netinet/ether.h>
 #include <netinet/if_ether.h>
 
-/* libc_hidden_proto(ether_ntoa_r) */
-/* libc_hidden_proto(sprintf) */
-#ifdef __UCLIBC_HAS_XLOCALE__
-/* libc_hidden_proto(__ctype_b_loc) */
-/* libc_hidden_proto(__ctype_tolower_loc) */
-#elif defined __UCLIBC_HAS_CTYPE_TABLES__
-/* libc_hidden_proto(__ctype_b) */
-/* libc_hidden_proto(__ctype_tolower) */
-#endif
-
 struct ether_addr *ether_aton_r(const char *asc, struct ether_addr *addr)
 {
-	size_t cnt;
+	/* asc is "X:XX:XX:x:xx:xX" */
+	int cnt;
 
 	for (cnt = 0; cnt < 6; ++cnt) {
-		unsigned int number;
+		unsigned char number;
 		char ch;
 
-		ch = _tolower(*asc++);
+		/* | 0x20 is cheap tolower(), valid for letters/numbers only */
+		ch = (*asc++) | 0x20;
 		if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f'))
 			return NULL;
-		number = isdigit(ch) ? (ch - '0') : (ch - 'a' + 10);
-
-		ch = _tolower(*asc);
-		if ((cnt < 5 && ch != ':')
-			|| (cnt == 5 && ch != '\0' && !isspace(ch))) {
-			++asc;
+		number = !(ch > '9') ? (ch - '0') : (ch - 'a' + 10);
+
+		ch = *asc++;
+		if ((cnt != 5 && ch != ':') /* not last group */
+		/* What standard says ASCII ether address representation
+		 * may also finish with whitespace, not only NUL?
+		 * We can get rid of isspace() otherwise */
+		 || (cnt == 5 && ch != '\0' /*&& !isspace(ch)*/)
+		) {
+			ch |= 0x20; /* cheap tolower() */
 			if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f'))
 				return NULL;
-			number <<= 4;
-			number += isdigit(ch) ? (ch - '0') : (ch - 'a' + 10);
+			number = (number << 4) + (!(ch > '9') ? (ch - '0') : (ch - 'a' + 10));
 
-			ch = *asc;
-			if (cnt < 5 && ch != ':')
-				return NULL;
+			if (cnt != 5) {
+				ch = *asc++;
+				if (ch != ':')
+					return NULL;
+			}
 		}
 
 		/* Store result.  */
-		addr->ether_addr_octet[cnt] = (unsigned char) number;
-
-		/* Skip ':'.  */
-		++asc;
+		addr->ether_addr_octet[cnt] = number;
 	}
+	/* Looks like we allow garbage after last group?
+	 * "1:2:3:4:5:66anything_at_all"? */
 
 	return addr;
 }

+ 40 - 46
libc/inet/ntop.c

@@ -67,8 +67,8 @@ inet_ntop4(const u_char *src, char *dst, size_t size)
 
 #if 0	/* since src is unsigned char, it will never be > 255 ... */
 		if (src[octet] > 255) {
-			__set_errno (ENOSPC);
-			return (NULL);
+			__set_errno(ENOSPC);
+			return NULL;
 		}
 #endif
 		tmp[i++] = '0' + src[octet] / 100;
@@ -83,9 +83,9 @@ inet_ntop4(const u_char *src, char *dst, size_t size)
 	}
 	tmp[i - 1] = '\0';
 
-	if (strlen (tmp) > size) {
-		__set_errno (ENOSPC);
-		return (NULL);
+	if (strlen(tmp) > size) {
+		__set_errno(ENOSPC);
+		return NULL;
 	}
 
 	return strcpy(dst, tmp);
@@ -168,7 +168,7 @@ inet_ntop6(const u_char *src, char *dst, size_t size)
 		if (i == 6 && best.base == 0 &&
 		    (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
 			if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
-				return (NULL);
+				return NULL;
 			tp += strlen(tp);
 			break;
 		}
@@ -183,8 +183,8 @@ inet_ntop6(const u_char *src, char *dst, size_t size)
 	 * Check for overflow, copy, and we're done.
 	 */
 	if ((size_t)(tp - tmp) > size) {
-		__set_errno (ENOSPC);
-		return (NULL);
+		__set_errno(ENOSPC);
+		return NULL;
 	}
 	return strcpy(dst, tmp);
 }
@@ -216,25 +216,25 @@ inet_pton4(const char *src, u_char *dst)
 			u_int new = *tp * 10 + (ch - '0');
 
 			if (new > 255)
-				return (0);
+				return 0;
 			*tp = new;
 			if (! saw_digit) {
 				if (++octets > 4)
-					return (0);
+					return 0;
 				saw_digit = 1;
 			}
 		} else if (ch == '.' && saw_digit) {
 			if (octets == 4)
-				return (0);
+				return 0;
 			*++tp = 0;
 			saw_digit = 0;
 		} else
-			return (0);
+			return 0;
 	}
 	if (octets < 4)
-		return (0);
+		return 0;
 	memcpy(dst, tmp, 4);
-	return (1);
+	return 1;
 }
 
 /* int
@@ -253,13 +253,6 @@ inet_pton4(const char *src, u_char *dst)
 
 #ifdef __UCLIBC_HAS_IPV6__
 
-/* We cannot use the macro version of tolower() or very bad
- * things happen when '*src++' gets evaluated multiple times.
- * So undef it here so we get the function version of tolower
- * instead.
- */
-#undef tolower
-
 static int
 inet_pton6(const char *src, u_char *dst)
 {
@@ -276,19 +269,20 @@ inet_pton6(const char *src, u_char *dst)
 	/* Leading :: requires some special handling. */
 	if (*src == ':')
 		if (*++src != ':')
-			return (0);
+			return 0;
 	curtok = src;
 	saw_xdigit = 0;
 	val = 0;
-	while ((ch = tolower (*src++)) != '\0') {
+	while ((ch = *src++) != '\0') {
 		const char *pch;
 
-		pch = strchr(xdigits, ch);
+		/* | 0x20 is cheap tolower(), valid for letters/numbers only */
+		pch = strchr(xdigits, (ch | 0x20));
 		if (pch != NULL) {
 			val <<= 4;
 			val |= (pch - xdigits);
 			if (val > 0xffff)
-				return (0);
+				return 0;
 			saw_xdigit = 1;
 			continue;
 		}
@@ -296,16 +290,16 @@ inet_pton6(const char *src, u_char *dst)
 			curtok = src;
 			if (!saw_xdigit) {
 				if (colonp)
-					return (0);
+					return 0;
 				colonp = tp;
 				continue;
-			} else if (*src == '\0') {
-				return (0);
 			}
+			if (*src == '\0')
+				return 0;
 			if (tp + 2 > endp)
-				return (0);
-			*tp++ = (u_char) (val >> 8) & 0xff;
-			*tp++ = (u_char) val & 0xff;
+				return 0;
+			*tp++ = (u_char) (val >> 8);
+			*tp++ = (u_char) val;
 			saw_xdigit = 0;
 			val = 0;
 			continue;
@@ -316,13 +310,13 @@ inet_pton6(const char *src, u_char *dst)
 			saw_xdigit = 0;
 			break;	/* '\0' was seen by inet_pton4(). */
 		}
-		return (0);
+		return 0;
 	}
 	if (saw_xdigit) {
 		if (tp + 2 > endp)
-			return (0);
-		*tp++ = (u_char) (val >> 8) & 0xff;
-		*tp++ = (u_char) val & 0xff;
+			return 0;
+		*tp++ = (u_char) (val >> 8);
+		*tp++ = (u_char) val;
 	}
 	if (colonp != NULL) {
 		/*
@@ -333,7 +327,7 @@ inet_pton6(const char *src, u_char *dst)
 		int i;
 
 		if (tp == endp)
-			return (0);
+			return 0;
 		for (i = 1; i <= n; i++) {
 			endp[- i] = colonp[n - i];
 			colonp[n - i] = 0;
@@ -341,9 +335,9 @@ inet_pton6(const char *src, u_char *dst)
 		tp = endp;
 	}
 	if (tp != endp)
-		return (0);
+		return 0;
 	memcpy(dst, tmp, 16);
-	return (1);
+	return 1;
 }
 
 #endif /* __UCLIBC_HAS_IPV6__ */
@@ -364,14 +358,14 @@ inet_ntop(int af, const void *src, char *dst, socklen_t size)
 {
 	switch (af) {
 	case AF_INET:
-		return (inet_ntop4(src, dst, size));
+		return inet_ntop4(src, dst, size);
 #ifdef __UCLIBC_HAS_IPV6__
 	case AF_INET6:
-		return (inet_ntop6(src, dst, size));
+		return inet_ntop6(src, dst, size);
 #endif
 	default:
-		__set_errno (EAFNOSUPPORT);
-		return (NULL);
+		__set_errno(EAFNOSUPPORT);
+		return NULL;
 	}
 	/* NOTREACHED */
 }
@@ -395,14 +389,14 @@ inet_pton(int af, const char *src, void *dst)
 {
 	switch (af) {
 	case AF_INET:
-		return (inet_pton4(src, dst));
+		return inet_pton4(src, dst);
 #ifdef __UCLIBC_HAS_IPV6__
 	case AF_INET6:
-		return (inet_pton6(src, dst));
+		return inet_pton6(src, dst);
 #endif
 	default:
-		__set_errno (EAFNOSUPPORT);
-		return (-1);
+		__set_errno(EAFNOSUPPORT);
+		return -1;
 	}
 	/* NOTREACHED */
 }