Index: uspace/lib/posix/stdlib/strtol.c
===================================================================
--- uspace/lib/posix/stdlib/strtol.c	(revision 102a729e88b697a95ed9ce5fbcd3097ac1b9b456)
+++ uspace/lib/posix/stdlib/strtol.c	(revision aa5acd47c619ede464db035895050e4f20d27526)
@@ -38,7 +38,11 @@
 #include "../stdlib.h"
 
-#include "../limits.h"
 #include "../ctype.h"
 #include "../errno.h"
+#include "../inttypes.h"
+#include "../limits.h"
+
+#define intmax_t posix_intmax_t
+#define uintmax_t posix_uintmax_t
 
 /**
@@ -63,8 +67,7 @@
  *
  * @param c Character representation of the digit.
- * @param base Base into which the digit belongs to.
  * @return Digit value represented by an integer.
  */
-static inline int get_digit_in_base(int c, int base)
+static inline int digit_value(int c)
 {
 	if (c <= '9') {
@@ -76,11 +79,17 @@
 
 /**
- * Backend for all integer conversion functions. Can be configured by arguments
- * to convert both signed and unsigned integers of various sizes.
+ * Generic function for parsing an integer from it's string representation.
+ * Different variants differ in lower and upper bounds.
+ * The parsed string returned by this function is always positive, sign
+ * information is provided via a dedicated parameter.
  *
  * @param nptr Input string.
  * @param endptr If non-NULL, *endptr is set to the position of the first
- *     unrecognized character.
- * @param base Expected base of the string representation.
+ *     unrecognized character. If no digit has been parsed, value of
+ *     nptr is stored there (regardless of any skipped characters at the
+ *     beginning).
+ * @param base Expected base of the string representation. If 0, base is
+ *    determined to be decimal, octal or hexadecimal using the same rules
+ *    as C syntax. Otherwise, value must be between 2 and 36, inclusive.
  * @param min_value Lower bound for the resulting conversion.
  * @param max_value Upper bound for the resulting conversion.
@@ -88,9 +97,11 @@
  *     bool variable into which shall be placed the negativity of the resulting
  *     converted value.
- * @return Result of the conversion.
- */
-static inline unsigned long long internal_strtol(
+ * @return The absolute value of the parsed value, or the closest in-range value
+ *     if the parsed value is out of range. If the input is invalid, zero is
+ *     returned and errno is set to EINVAL.
+ */
+static inline uintmax_t internal_strtol(
     const char *restrict nptr, char **restrict endptr, int base,
-    const long long min_value, const unsigned long long max_value,
+    const intmax_t min_value, const uintmax_t max_value,
     bool *restrict out_negative)
 {
@@ -105,8 +116,11 @@
 	}
 	
-	unsigned long long real_max_value = max_value;
+	/* The maximal absolute value that can be returned in this run.
+	 * Depends on sign.
+	 */
+	uintmax_t real_max_value = max_value;
 	
 	/* Current index in the input string. */
-	int i = 0;
+	size_t i = 0;
 	bool negative = false;
 	
@@ -120,5 +134,14 @@
 	case '-':
 		negative = true;
-		real_max_value = -min_value;
+		
+		/* The strange computation is are there to avoid a corner case
+		 * where -min_value can't be represented in intmax_t.
+		 * (I'm not exactly sure what the semantics are in such a
+		 *  case, but this should be safe for any case.)
+		 */
+		real_max_value = (min_value == 0)
+		    ? 0
+		    :(((uintmax_t) -(min_value + 1)) + 1);
+		
 		/* fallthrough */
 	case '+':
@@ -131,14 +154,18 @@
 		if (nptr[i] == '0') {
 			if (tolower(nptr[i + 1]) == 'x') {
+				/* 0x... is hex. */
 				base = 16;
 				i += 2;
 			} else {
+				/* 0... is octal. */
 				base = 8;
 			}
 		} else {
+			/* Anything else is decimal by default. */
 			base = 10;
 		}
 		break;
 	case 16:
+		/* Allow hex number to be prefixed with "0x". */
 		if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x') {
 			i += 2;
@@ -160,7 +187,7 @@
 	 * of overflow.
 	 */
-	unsigned long long max_safe_value = (real_max_value - base + 1) / base;
-	
-	unsigned long long result = 0;
+	uintmax_t max_safe_value = (real_max_value - base + 1) / base;
+	
+	uintmax_t result = 0;
 	
 	if (real_max_value == 0) {
@@ -172,5 +199,5 @@
 			if (nptr[i] != '0') {
 				errno = ERANGE;
-				result = max_value;
+				result = 0;
 			}
 			i++;
@@ -179,11 +206,10 @@
 	
 	while (is_digit_in_base(nptr[i], base)) {
-		int digit = get_digit_in_base(nptr[i], base);
+		int digit = digit_value(nptr[i]);
 		
 		if (result > max_safe_value) {
 			/* corner case, check for overflow */
 			
-			unsigned long long
-			    boundary = (real_max_value - digit) / base;
+			uintmax_t boundary = (real_max_value - digit) / base;
 			
 			if (result > boundary) {
@@ -224,8 +250,8 @@
 {
 	bool neg = false;
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, NULL, 10, INT_MIN, INT_MAX, &neg);
 
-	return (int) (neg ? -result : result);
+	return (neg ? ((int) -result) : (int) result);
 }
 
@@ -239,8 +265,8 @@
 {
 	bool neg = false;
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, NULL, 10, LONG_MIN, LONG_MAX, &neg);
 
-	return (long) (neg ? -result : result);
+	return (neg ? ((long) -result) : (long) result);
 }
 
@@ -254,8 +280,8 @@
 {
 	bool neg = false;
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, NULL, 10, LLONG_MIN, LLONG_MAX, &neg);
 
-	return (long long) (neg ? -result : result);
+	return (neg ? ((long long) -result) : (long long) result);
 }
 
@@ -272,8 +298,8 @@
 {
 	bool neg = false;
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, endptr, base, LONG_MIN, LONG_MAX, &neg);
 
-	return (long) (neg ? -result : result);
+	return (neg ? ((long) -result) : ((long) result));
 }
 
@@ -291,8 +317,27 @@
 {
 	bool neg = false;
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &neg);
 
-	return (long long) (neg ? -result : result);
+	return (neg ? ((long long) -result) : (long long) result);
+}
+
+/**
+ * Convert a string to a largest signed integer type.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
+intmax_t posix_strtoimax(
+    const char *restrict nptr, char **restrict endptr, int base)
+{
+	bool neg = false;
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX, &neg);
+
+	return (neg ? ((intmax_t) -result) : (intmax_t) result);
 }
 
@@ -309,5 +354,5 @@
     const char *restrict nptr, char **restrict endptr, int base)
 {
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, endptr, base, 0, ULONG_MAX, NULL);
 
@@ -316,5 +361,5 @@
 
 /**
- * Convert a string to a an unsigned long long integer.
+ * Convert a string to an unsigned long long integer.
  *
  * @param nptr Input string.
@@ -327,5 +372,26 @@
     const char *restrict nptr, char **restrict endptr, int base)
 {
-	return internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
+
+	return (unsigned long long) result;
+}
+
+/**
+ * Convert a string to a largest unsigned integer type.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
+uintmax_t posix_strtoumax(
+    const char *restrict nptr, char **restrict endptr, int base)
+{
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, 0, UINTMAX_MAX, NULL);
+
+	return result;
 }
 
