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

  1. /* misc.c */
  2. /* Written by Andrew Makhorin <mao@gnu.org>, October 2015. */
  3. #include <ctype.h>
  4. #include <float.h>
  5. #include <limits.h>
  6. #include <stdlib.h>
  7. #include "misc.h"
  8. /***********************************************************************
  9. * NAME
  10. *
  11. * str2int - convert character string to value of int type
  12. *
  13. * SYNOPSIS
  14. *
  15. * #include "misc.h"
  16. * int str2int(const char *str, int *val);
  17. *
  18. * DESCRIPTION
  19. *
  20. * The routine str2int converts the character string str to a value of
  21. * integer type and stores the value into location, which the parameter
  22. * val points to (in the case of error content of this location is not
  23. * changed).
  24. *
  25. * RETURNS
  26. *
  27. * The routine returns one of the following error codes:
  28. *
  29. * 0 - no error;
  30. * 1 - value out of range;
  31. * 2 - character string is syntactically incorrect. */
  32. int str2int(const char *str, int *val_)
  33. { int d, k, s, val = 0;
  34. /* scan optional sign */
  35. if (str[0] == '+')
  36. s = +1, k = 1;
  37. else if (str[0] == '-')
  38. s = -1, k = 1;
  39. else
  40. s = +1, k = 0;
  41. /* check for the first digit */
  42. if (!isdigit((unsigned char)str[k]))
  43. return 2;
  44. /* scan digits */
  45. while (isdigit((unsigned char)str[k]))
  46. { d = str[k++] - '0';
  47. if (s > 0)
  48. { if (val > INT_MAX / 10)
  49. return 1;
  50. val *= 10;
  51. if (val > INT_MAX - d)
  52. return 1;
  53. val += d;
  54. }
  55. else /* s < 0 */
  56. { if (val < INT_MIN / 10)
  57. return 1;
  58. val *= 10;
  59. if (val < INT_MIN + d)
  60. return 1;
  61. val -= d;
  62. }
  63. }
  64. /* check for terminator */
  65. if (str[k] != '\0')
  66. return 2;
  67. /* conversion has been done */
  68. *val_ = val;
  69. return 0;
  70. }
  71. /***********************************************************************
  72. * NAME
  73. *
  74. * str2num - convert character string to value of double type
  75. *
  76. * SYNOPSIS
  77. *
  78. * #include "misc.h"
  79. * int str2num(const char *str, double *val);
  80. *
  81. * DESCRIPTION
  82. *
  83. * The routine str2num converts the character string str to a value of
  84. * double type and stores the value into location, which the parameter
  85. * val points to (in the case of error content of this location is not
  86. * changed).
  87. *
  88. * RETURNS
  89. *
  90. * The routine returns one of the following error codes:
  91. *
  92. * 0 - no error;
  93. * 1 - value out of range;
  94. * 2 - character string is syntactically incorrect. */
  95. int str2num(const char *str, double *val_)
  96. { int k;
  97. double val;
  98. /* scan optional sign */
  99. k = (str[0] == '+' || str[0] == '-' ? 1 : 0);
  100. /* check for decimal point */
  101. if (str[k] == '.')
  102. { k++;
  103. /* a digit should follow it */
  104. if (!isdigit((unsigned char)str[k]))
  105. return 2;
  106. k++;
  107. goto frac;
  108. }
  109. /* integer part should start with a digit */
  110. if (!isdigit((unsigned char)str[k]))
  111. return 2;
  112. /* scan integer part */
  113. while (isdigit((unsigned char)str[k]))
  114. k++;
  115. /* check for decimal point */
  116. if (str[k] == '.') k++;
  117. frac: /* scan optional fraction part */
  118. while (isdigit((unsigned char)str[k]))
  119. k++;
  120. /* check for decimal exponent */
  121. if (str[k] == 'E' || str[k] == 'e')
  122. { k++;
  123. /* scan optional sign */
  124. if (str[k] == '+' || str[k] == '-')
  125. k++;
  126. /* a digit should follow E, E+ or E- */
  127. if (!isdigit((unsigned char)str[k]))
  128. return 2;
  129. }
  130. /* scan optional exponent part */
  131. while (isdigit((unsigned char)str[k]))
  132. k++;
  133. /* check for terminator */
  134. if (str[k] != '\0')
  135. return 2;
  136. /* perform conversion */
  137. { char *endptr;
  138. val = strtod(str, &endptr);
  139. if (*endptr != '\0')
  140. return 2;
  141. }
  142. /* check for overflow */
  143. if (!(-DBL_MAX <= val && val <= +DBL_MAX))
  144. return 1;
  145. /* check for underflow */
  146. if (-DBL_MIN < val && val < +DBL_MIN)
  147. val = 0.0;
  148. /* conversion has been done */
  149. *val_ = val;
  150. return 0;
  151. }
  152. /* eof */