#
source:
trunk/third/sendmail/libsm/strto.c
@
19204

Revision 19204, 5.4 KB checked in by zacheiss, 22 years ago (diff) |
---|

Line | |
---|---|

1 | /* |

2 | * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. |

3 | * All rights reserved. |

4 | * Copyright (c) 1992 |

5 | * The Regents of the University of California. All rights reserved. |

6 | * |

7 | * By using this file, you agree to the terms and conditions set |

8 | * forth in the LICENSE file which can be found at the top level of |

9 | * the sendmail distribution. |

10 | */ |

11 | |

12 | #include <sm/gen.h> |

13 | SM_IDSTR(id, "@(#)$Id: strto.c,v 1.1.1.1 2003-04-08 15:06:42 zacheiss Exp $") |

14 | |

15 | #include <sys/param.h> |

16 | #include <sys/types.h> |

17 | #include <stdlib.h> |

18 | #include <ctype.h> |

19 | #include <errno.h> |

20 | #include <sm/limits.h> |

21 | #include <sm/conf.h> |

22 | #include <sm/string.h> |

23 | |

24 | /* |

25 | ** SM_STRTOLL -- Convert a string to a (signed) long long integer. |

26 | ** |

27 | ** Ignores `locale' stuff. Assumes that the upper and lower case |

28 | ** alphabets and digits are each contiguous. |

29 | ** |

30 | ** Parameters: |

31 | ** nptr -- string containing number |

32 | ** endptr -- location of first invalid character |

33 | ** base -- numeric base that 'nptr' number is based in |

34 | ** |

35 | ** Returns: |

36 | ** Failure: on underflow LLONG_MIN is returned; on overflow |

37 | ** LLONG_MAX is returned and errno is set. |

38 | ** When 'endptr' == '\0' then the entire string 'nptr' |

39 | ** was valid. |

40 | ** Success: returns the converted number |

41 | */ |

42 | |

43 | LONGLONG_T |

44 | sm_strtoll(nptr, endptr, base) |

45 | const char *nptr; |

46 | char **endptr; |

47 | register int base; |

48 | { |

49 | register bool neg; |

50 | register const char *s; |

51 | register LONGLONG_T acc, cutoff; |

52 | register int c; |

53 | register int any, cutlim; |

54 | |

55 | /* |

56 | ** Skip white space and pick up leading +/- sign if any. |

57 | ** If base is 0, allow 0x for hex and 0 for octal, else |

58 | ** assume decimal; if base is already 16, allow 0x. |

59 | */ |

60 | |

61 | s = nptr; |

62 | do |

63 | { |

64 | c = (unsigned char) *s++; |

65 | } while (isascii(c) && isspace(c)); |

66 | if (c == '-') |

67 | { |

68 | neg = true; |

69 | c = *s++; |

70 | } |

71 | else |

72 | { |

73 | neg = false; |

74 | if (c == '+') |

75 | c = *s++; |

76 | } |

77 | if ((base == 0 || base == 16) && |

78 | c == '0' && (*s == 'x' || *s == 'X')) |

79 | { |

80 | c = s[1]; |

81 | s += 2; |

82 | base = 16; |

83 | } |

84 | if (base == 0) |

85 | base = c == '0' ? 8 : 10; |

86 | |

87 | /* |

88 | ** Compute the cutoff value between legal numbers and illegal |

89 | ** numbers. That is the largest legal value, divided by the |

90 | ** base. An input number that is greater than this value, if |

91 | ** followed by a legal input character, is too big. One that |

92 | ** is equal to this value may be valid or not; the limit |

93 | ** between valid and invalid numbers is then based on the last |

94 | ** digit. For instance, if the range for long-long's is |

95 | ** [-9223372036854775808..9223372036854775807] and the input base |

96 | ** is 10, cutoff will be set to 922337203685477580 and cutlim to |

97 | ** either 7 (!neg) or 8 (neg), meaning that if we have |

98 | ** accumulated a value > 922337203685477580, or equal but the |

99 | ** next digit is > 7 (or 8), the number is too big, and we will |

100 | ** return a range error. |

101 | ** |

102 | ** Set any if any `digits' consumed; make it negative to indicate |

103 | ** overflow. |

104 | */ |

105 | |

106 | cutoff = neg ? LLONG_MIN : LLONG_MAX; |

107 | cutlim = cutoff % base; |

108 | cutoff /= base; |

109 | if (neg) |

110 | { |

111 | if (cutlim > 0) |

112 | { |

113 | cutlim -= base; |

114 | cutoff += 1; |

115 | } |

116 | cutlim = -cutlim; |

117 | } |

118 | for (acc = 0, any = 0;; c = (unsigned char) *s++) |

119 | { |

120 | if (isascii(c) && isdigit(c)) |

121 | c -= '0'; |

122 | else if (isascii(c) && isalpha(c)) |

123 | c -= isupper(c) ? 'A' - 10 : 'a' - 10; |

124 | else |

125 | break; |

126 | if (c >= base) |

127 | break; |

128 | if (any < 0) |

129 | continue; |

130 | if (neg) |

131 | { |

132 | if (acc < cutoff || (acc == cutoff && c > cutlim)) |

133 | { |

134 | any = -1; |

135 | acc = LLONG_MIN; |

136 | errno = ERANGE; |

137 | } |

138 | else |

139 | { |

140 | any = 1; |

141 | acc *= base; |

142 | acc -= c; |

143 | } |

144 | } |

145 | else |

146 | { |

147 | if (acc > cutoff || (acc == cutoff && c > cutlim)) |

148 | { |

149 | any = -1; |

150 | acc = LLONG_MAX; |

151 | errno = ERANGE; |

152 | } |

153 | else |

154 | { |

155 | any = 1; |

156 | acc *= base; |

157 | acc += c; |

158 | } |

159 | } |

160 | } |

161 | if (endptr != 0) |

162 | *endptr = (char *) (any ? s - 1 : nptr); |

163 | return acc; |

164 | } |

165 | |

166 | /* |

167 | ** SM_STRTOULL -- Convert a string to an unsigned long long integer. |

168 | ** |

169 | ** Ignores `locale' stuff. Assumes that the upper and lower case |

170 | ** alphabets and digits are each contiguous. |

171 | ** |

172 | ** Parameters: |

173 | ** nptr -- string containing (unsigned) number |

174 | ** endptr -- location of first invalid character |

175 | ** base -- numeric base that 'nptr' number is based in |

176 | ** |

177 | ** Returns: |

178 | ** Failure: on overflow ULLONG_MAX is returned and errno is set. |

179 | ** When 'endptr' == '\0' then the entire string 'nptr' |

180 | ** was valid. |

181 | ** Success: returns the converted number |

182 | */ |

183 | |

184 | ULONGLONG_T |

185 | sm_strtoull(nptr, endptr, base) |

186 | const char *nptr; |

187 | char **endptr; |

188 | register int base; |

189 | { |

190 | register const char *s; |

191 | register ULONGLONG_T acc, cutoff; |

192 | register int c; |

193 | register bool neg; |

194 | register int any, cutlim; |

195 | |

196 | /* See sm_strtoll for comments as to the logic used. */ |

197 | s = nptr; |

198 | do |

199 | { |

200 | c = (unsigned char) *s++; |

201 | } while (isascii(c) && isspace(c)); |

202 | neg = (c == '-'); |

203 | if (neg) |

204 | { |

205 | c = *s++; |

206 | } |

207 | else |

208 | { |

209 | if (c == '+') |

210 | c = *s++; |

211 | } |

212 | if ((base == 0 || base == 16) && |

213 | c == '0' && (*s == 'x' || *s == 'X')) |

214 | { |

215 | c = s[1]; |

216 | s += 2; |

217 | base = 16; |

218 | } |

219 | if (base == 0) |

220 | base = c == '0' ? 8 : 10; |

221 | |

222 | cutoff = ULLONG_MAX / (ULONGLONG_T)base; |

223 | cutlim = ULLONG_MAX % (ULONGLONG_T)base; |

224 | for (acc = 0, any = 0;; c = (unsigned char) *s++) |

225 | { |

226 | if (isascii(c) && isdigit(c)) |

227 | c -= '0'; |

228 | else if (isascii(c) && isalpha(c)) |

229 | c -= isupper(c) ? 'A' - 10 : 'a' - 10; |

230 | else |

231 | break; |

232 | if (c >= base) |

233 | break; |

234 | if (any < 0) |

235 | continue; |

236 | if (acc > cutoff || (acc == cutoff && c > cutlim)) |

237 | { |

238 | any = -1; |

239 | acc = ULLONG_MAX; |

240 | errno = ERANGE; |

241 | } |

242 | else |

243 | { |

244 | any = 1; |

245 | acc *= (ULONGLONG_T)base; |

246 | acc += c; |

247 | } |

248 | } |

249 | if (neg && any > 0) |

250 | acc = -((LONGLONG_T) acc); |

251 | if (endptr != 0) |

252 | *endptr = (char *) (any ? s - 1 : nptr); |

253 | return acc; |

254 | } |

**Note:**See TracBrowser for help on using the repository browser.