You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
4.0 KiB
159 lines
4.0 KiB
/* misc.c */
|
|
|
|
/* Written by Andrew Makhorin <mao@gnu.org>, October 2015. */
|
|
|
|
#include <ctype.h>
|
|
#include <float.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include "misc.h"
|
|
|
|
/***********************************************************************
|
|
* NAME
|
|
*
|
|
* str2int - convert character string to value of int type
|
|
*
|
|
* SYNOPSIS
|
|
*
|
|
* #include "misc.h"
|
|
* int str2int(const char *str, int *val);
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* The routine str2int converts the character string str to a value of
|
|
* integer type and stores the value into location, which the parameter
|
|
* val points to (in the case of error content of this location is not
|
|
* changed).
|
|
*
|
|
* RETURNS
|
|
*
|
|
* The routine returns one of the following error codes:
|
|
*
|
|
* 0 - no error;
|
|
* 1 - value out of range;
|
|
* 2 - character string is syntactically incorrect. */
|
|
|
|
int str2int(const char *str, int *val_)
|
|
{ int d, k, s, val = 0;
|
|
/* scan optional sign */
|
|
if (str[0] == '+')
|
|
s = +1, k = 1;
|
|
else if (str[0] == '-')
|
|
s = -1, k = 1;
|
|
else
|
|
s = +1, k = 0;
|
|
/* check for the first digit */
|
|
if (!isdigit((unsigned char)str[k]))
|
|
return 2;
|
|
/* scan digits */
|
|
while (isdigit((unsigned char)str[k]))
|
|
{ d = str[k++] - '0';
|
|
if (s > 0)
|
|
{ if (val > INT_MAX / 10)
|
|
return 1;
|
|
val *= 10;
|
|
if (val > INT_MAX - d)
|
|
return 1;
|
|
val += d;
|
|
}
|
|
else /* s < 0 */
|
|
{ if (val < INT_MIN / 10)
|
|
return 1;
|
|
val *= 10;
|
|
if (val < INT_MIN + d)
|
|
return 1;
|
|
val -= d;
|
|
}
|
|
}
|
|
/* check for terminator */
|
|
if (str[k] != '\0')
|
|
return 2;
|
|
/* conversion has been done */
|
|
*val_ = val;
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* NAME
|
|
*
|
|
* str2num - convert character string to value of double type
|
|
*
|
|
* SYNOPSIS
|
|
*
|
|
* #include "misc.h"
|
|
* int str2num(const char *str, double *val);
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* The routine str2num converts the character string str to a value of
|
|
* double type and stores the value into location, which the parameter
|
|
* val points to (in the case of error content of this location is not
|
|
* changed).
|
|
*
|
|
* RETURNS
|
|
*
|
|
* The routine returns one of the following error codes:
|
|
*
|
|
* 0 - no error;
|
|
* 1 - value out of range;
|
|
* 2 - character string is syntactically incorrect. */
|
|
|
|
int str2num(const char *str, double *val_)
|
|
{ int k;
|
|
double val;
|
|
/* scan optional sign */
|
|
k = (str[0] == '+' || str[0] == '-' ? 1 : 0);
|
|
/* check for decimal point */
|
|
if (str[k] == '.')
|
|
{ k++;
|
|
/* a digit should follow it */
|
|
if (!isdigit((unsigned char)str[k]))
|
|
return 2;
|
|
k++;
|
|
goto frac;
|
|
}
|
|
/* integer part should start with a digit */
|
|
if (!isdigit((unsigned char)str[k]))
|
|
return 2;
|
|
/* scan integer part */
|
|
while (isdigit((unsigned char)str[k]))
|
|
k++;
|
|
/* check for decimal point */
|
|
if (str[k] == '.') k++;
|
|
frac: /* scan optional fraction part */
|
|
while (isdigit((unsigned char)str[k]))
|
|
k++;
|
|
/* check for decimal exponent */
|
|
if (str[k] == 'E' || str[k] == 'e')
|
|
{ k++;
|
|
/* scan optional sign */
|
|
if (str[k] == '+' || str[k] == '-')
|
|
k++;
|
|
/* a digit should follow E, E+ or E- */
|
|
if (!isdigit((unsigned char)str[k]))
|
|
return 2;
|
|
}
|
|
/* scan optional exponent part */
|
|
while (isdigit((unsigned char)str[k]))
|
|
k++;
|
|
/* check for terminator */
|
|
if (str[k] != '\0')
|
|
return 2;
|
|
/* perform conversion */
|
|
{ char *endptr;
|
|
val = strtod(str, &endptr);
|
|
if (*endptr != '\0')
|
|
return 2;
|
|
}
|
|
/* check for overflow */
|
|
if (!(-DBL_MAX <= val && val <= +DBL_MAX))
|
|
return 1;
|
|
/* check for underflow */
|
|
if (-DBL_MIN < val && val < +DBL_MIN)
|
|
val = 0.0;
|
|
/* conversion has been done */
|
|
*val_ = val;
|
|
return 0;
|
|
}
|
|
|
|
/* eof */
|