_strtox.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include "stdint.h"
  2. #include "ctype.h"
  3. #include "string.h"
  4. #include "errno.h"
  5. #include "limits.h"
  6. #include "_digits.h"
  7. // All code in this file was taken from PDClib
  8. intmax_t _atomax( const char * s )
  9. {
  10. intmax_t rc = 0;
  11. char sign = '+';
  12. const char * x;
  13. /* TODO: In other than "C" locale, additional patterns may be defined */
  14. while ( isspace( *s ) ) ++s;
  15. if ( *s == '+' ) ++s;
  16. else if ( *s == '-' ) sign = *(s++);
  17. /* TODO: Earlier version was missing tolower() but was not caught by tests */
  18. while ( ( x = memchr( _digits, tolower(*(s++)), 10 ) ) != NULL )
  19. {
  20. rc = rc * 10 + ( x - _digits );
  21. }
  22. return ( sign == '+' ) ? rc : -rc;
  23. }
  24. int atoi( const char * s )
  25. {
  26. return (int) _atomax( s );
  27. }
  28. const char * _strtox_prelim( const char * p, char * sign, int * base )
  29. {
  30. /* skipping leading whitespace */
  31. while ( isspace( *p ) ) ++p;
  32. /* determining / skipping sign */
  33. if ( *p != '+' && *p != '-' ) *sign = '+';
  34. else *sign = *(p++);
  35. /* determining base */
  36. if ( *p == '0' )
  37. {
  38. ++p;
  39. if ( ( *base == 0 || *base == 16 ) && ( *p == 'x' || *p == 'X' ) )
  40. {
  41. *base = 16;
  42. ++p;
  43. /* catching a border case here: "0x" followed by a non-digit should
  44. be parsed as the unprefixed zero.
  45. We have to "rewind" the parsing; having the base set to 16 if it
  46. was zero previously does not hurt, as the result is zero anyway.
  47. */
  48. if ( memchr( _digits, tolower(*p), *base ) == NULL )
  49. {
  50. p -= 2;
  51. }
  52. }
  53. else if ( *base == 0 )
  54. {
  55. *base = 8;
  56. /* Rewind one character back, so that the string composed
  57. of just a zero is correctly parsed (and endptr is set
  58. appropriately). */
  59. --p;
  60. }
  61. else
  62. {
  63. --p;
  64. }
  65. }
  66. else if ( ! *base )
  67. {
  68. *base = 10;
  69. }
  70. return ( ( *base >= 2 ) && ( *base <= 36 ) ) ? p : NULL;
  71. }
  72. uintmax_t _strtox_main( const char ** p, unsigned int base, uintmax_t error, uintmax_t limval, int limdigit, char * sign )
  73. {
  74. uintmax_t rc = 0;
  75. int digit = -1;
  76. const char * x;
  77. while ( ( x = memchr( _digits, tolower(**p), base ) ) != NULL )
  78. {
  79. digit = x - _digits;
  80. if ( ( rc < limval ) || ( ( rc == limval ) && ( digit <= limdigit ) ) )
  81. {
  82. rc = rc * base + (unsigned)digit;
  83. ++(*p);
  84. }
  85. else
  86. {
  87. errno = ERANGE;
  88. /* TODO: Only if endptr != NULL - but do we really want *another* parameter? */
  89. /* TODO: Earlier version was missing tolower() here but was not caught by tests */
  90. while ( memchr( _digits, tolower(**p), base ) != NULL ) ++(*p);
  91. /* TODO: This is ugly, but keeps caller from negating the error value */
  92. *sign = '+';
  93. return error;
  94. }
  95. }
  96. if ( digit == -1 )
  97. {
  98. *p = NULL;
  99. return 0;
  100. }
  101. return rc;
  102. }
  103. long int strtol( const char * s, char ** endptr, int base )
  104. {
  105. long int rc;
  106. char sign = '+';
  107. const char * p = _strtox_prelim( s, &sign, &base );
  108. if ( base < 2 || base > 36 ) return 0;
  109. if ( sign == '+' )
  110. {
  111. rc = (long int)_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MAX, (uintmax_t)( LONG_MAX / base ), (int)( LONG_MAX % base ), &sign );
  112. }
  113. else
  114. {
  115. rc = (long int)_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MIN, (uintmax_t)( LONG_MIN / -base ), (int)( -( LONG_MIN % base ) ), &sign );
  116. }
  117. if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
  118. return ( sign == '+' ) ? rc : -rc;
  119. }
  120. long long int strtoll( const char * s, char ** endptr, int base )
  121. {
  122. long long int rc;
  123. char sign = '+';
  124. const char * p = _strtox_prelim( s, &sign, &base );
  125. if ( base < 2 || base > 36 ) return 0;
  126. if ( sign == '+' )
  127. {
  128. rc = (long long int)_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MAX, (uintmax_t)( LLONG_MAX / base ), (int)( LLONG_MAX % base ), &sign );
  129. }
  130. else
  131. {
  132. rc = (long long int)_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MIN, (uintmax_t)( LLONG_MIN / -base ), (int)( -( LLONG_MIN % base ) ), &sign );
  133. }
  134. if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
  135. return ( sign == '+' ) ? rc : -rc;
  136. }
  137. unsigned long int strtoul( const char * s, char ** endptr, int base )
  138. {
  139. unsigned long int rc;
  140. char sign = '+';
  141. const char * p = _strtox_prelim( s, &sign, &base );
  142. if ( base < 2 || base > 36 ) return 0;
  143. rc = (unsigned long int)_strtox_main( &p, (unsigned)base, (uintmax_t)ULONG_MAX, (uintmax_t)( ULONG_MAX / base ), (int)( ULONG_MAX % base ), &sign );
  144. if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
  145. return ( sign == '+' ) ? rc : -rc;
  146. }
  147. unsigned long long int strtoull( const char * s, char ** endptr, int base )
  148. {
  149. unsigned long long int rc;
  150. char sign = '+';
  151. const char * p = _strtox_prelim( s, &sign, &base );
  152. if ( base < 2 || base > 36 ) return 0;
  153. rc = _strtox_main( &p, (unsigned)base, (uintmax_t)ULLONG_MAX, (uintmax_t)( ULLONG_MAX / base ), (int)( ULLONG_MAX % base ), &sign );
  154. if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
  155. return ( sign == '+' ) ? rc : -rc;
  156. }