/** * Convert a string to basic numeric types. This source code is in * the public domain. * * @author Paul Serice * @file */ #include "string_conversions.h" #include #include #include #include #include #include #include #include int string_to_int(const char* s, int* n, int base) { int rv = 0; long int tmp = 0; if (string_to_long(s, &tmp, base)) { if ((tmp >= INT_MIN) && (tmp <= INT_MAX)) { if (n) { *n = (int)tmp; } rv = 1; } } return rv; } int string_to_unsigned(const char* s, unsigned int* n, int base) { int rv = 0; unsigned long int tmp = 0; if (string_to_unsigned_long(s, &tmp, base)) { if (tmp <= UINT_MAX) { if (n) { *n = (unsigned int)tmp; } rv = 1; } } return rv; } int string_to_long(const char* s, long int* n, int base) { int rv = 0; long int tmp = 0; char* first_bad_char = NULL; const char* r = NULL; /* Remainder of the string. */ /* You have to manually check for an empty string. */ for ( ; *s != '\0' ; ++s) { if (!isspace(*s)) { break; } } if (*s == '\0') { goto done; } /* Do the conversion. */ errno = 0; tmp = strtol(s, &first_bad_char, base); /* Check for errors. */ if (errno) { goto done; } /* Allow trailing space. */ r = first_bad_char; for ( ; *r != '\0' ; ++r) { if (!isspace(*r)) { break; } } if (*r != '\0') { errno = EINVAL; goto done; } /* Success. */ if (n) { *n = tmp; } rv = 1; done: return rv; } int string_to_unsigned_long(const char* s, unsigned long int* n, int base) { int rv = 0; int is_negative = 0; unsigned long int tmp = 0; char* first_bad_char = NULL; const char* r = NULL; /* Remainder of the string. */ /* You have to manually check for a leading minus sign or an empty * string. */ for ( ; *s != '\0' ; ++s) { if (!isspace(*s)) { break; } } if (*s == '\0') { goto done; } /* You want to allow "-0" to succeed. So we have to wait to see * how the conversion goes. */ if (*s == '-') { is_negative = 1; } /* Do the conversion. */ errno = 0; tmp = strtoul(s, &first_bad_char, base); /* Check for errors. */ if (errno) { goto done; } /* Allow trailing space. */ r = first_bad_char; for ( ; *r != '\0' ; ++r) { if (!isspace(*r)) { break; } } if (*r != '\0') { errno = EINVAL; goto done; } /* Only "-0" is allowed. */ if (is_negative && (tmp != 0)) { goto done; } /* Success. */ if (n) { *n = tmp; } rv = 1; done: return rv; } int string_to_float(const char* s, float* n) { int rv = 0; double tmp = 0.0; double magnitude = 0.0; /* There is no portable strtof() so use strtod() (indirectly) to * try to convert to the wider "double" type. */ rv = string_to_double(s, &tmp); if (!rv) { goto done; } /* * Bounds check to make sure the value fits in a float. */ /* The actual magnitude has to be zero or between the otherwise * smallest and largest normalized magnitudes. IEEE floating * point does support subnormal numbers (or "gradual underflow"), * but these numbers have less precision than the normalized * numbers. Thus, subnormal numbers are considered underflow. */ magnitude = fabs(tmp); if ((magnitude != 0.0) && ((magnitude < FLT_MIN) || (magnitude > FLT_MAX))) { rv = 0; errno = ERANGE; goto done; } /* Success. */ if (n) { *n = (float)tmp; } rv = 1; done: return rv; } int string_to_double(const char* s, double* n) { int rv = 0; double tmp = 0.0; char* first_bad_char = NULL; const char* r = NULL; /* Remainder of the string. */ /* You have to manually check for an empty string. */ for ( ; *s != '\0' ; ++s) { if (!isspace(*s)) { break; } } if (*s == '\0') { goto done; } /* Do the conversion. */ errno = 0; tmp = strtod(s, &first_bad_char); /* Check for errors. */ if (errno) { goto done; } /* Allow trailing space. */ r = first_bad_char; for ( ; *r != '\0' ; ++r) { if (!isspace(*r)) { break; } } if (*r != '\0') { errno = EINVAL; goto done; } /* Success. */ if (n) { *n = tmp; } rv = 1; done: return rv; }