207
|
1
|
|
2 // Written in the D programming language.
|
|
3
|
|
4 /*
|
|
5 * Copyright (C) 2002-2006 by Digital Mars, www.digitalmars.com
|
|
6 * Written by Walter Bright
|
|
7 * Some parts contributed by David L. Davis
|
|
8 *
|
|
9 * This software is provided 'as-is', without any express or implied
|
|
10 * warranty. In no event will the authors be held liable for any damages
|
|
11 * arising from the use of this software.
|
|
12 *
|
|
13 * Permission is granted to anyone to use this software for any purpose,
|
|
14 * including commercial applications, and to alter it and redistribute it
|
|
15 * freely, subject to the following restrictions:
|
|
16 *
|
|
17 * o The origin of this software must not be misrepresented; you must not
|
|
18 * claim that you wrote the original software. If you use this software
|
|
19 * in a product, an acknowledgment in the product documentation would be
|
|
20 * appreciated but is not required.
|
|
21 * o Altered source versions must be plainly marked as such, and must not
|
|
22 * be misrepresented as being the original software.
|
|
23 * o This notice may not be removed or altered from any source
|
|
24 * distribution.
|
|
25 */
|
|
26
|
|
27 /***********
|
|
28 * Conversion building blocks. These differ from the C equivalents
|
|
29 * <tt>atoi()</tt> and <tt>atol()</tt> by
|
|
30 * checking for overflow and not allowing whitespace.
|
|
31 *
|
|
32 * For conversion to signed types, the grammar recognized is:
|
|
33 * <pre>
|
|
34 $(I Integer):
|
|
35 $(I Sign UnsignedInteger)
|
|
36 $(I UnsignedInteger)
|
|
37
|
|
38 $(I Sign):
|
|
39 $(B +)
|
|
40 $(B -)
|
|
41 * </pre>
|
|
42 * For conversion to signed types, the grammar recognized is:
|
|
43 * <pre>
|
|
44 $(I UnsignedInteger):
|
|
45 $(I DecimalDigit)
|
|
46 $(I DecimalDigit) $(I UnsignedInteger)
|
|
47 * </pre>
|
|
48 * Macros:
|
|
49 * WIKI=Phobos/StdConv
|
|
50 */
|
|
51
|
|
52
|
|
53 /*************************
|
|
54 Changed to be used next to tango.
|
|
55
|
|
56 Unittests removed.
|
|
57 *************************/
|
|
58
|
|
59 module basic.conv;
|
|
60
|
|
61 private import tango.text.Util; // for atof(), toString()
|
|
62 private import tango.stdc.stringz;
|
|
63 private import tango.stdc.ctype;
|
|
64 private import tango.stdc.stdlib;
|
|
65 private import tango.stdc.errno;
|
|
66 //private import std.c.stdlib;
|
|
67 //private import std.math; // for fabs(), isnan()
|
|
68
|
|
69 private
|
|
70 {
|
|
71 extern (C) int getErrno();
|
|
72 extern (C) int setErrno(int);
|
|
73 }
|
|
74
|
|
75 //debug=conv; // uncomment to turn on debugging printf's
|
|
76
|
|
77 /* ************* Exceptions *************** */
|
|
78
|
|
79 /**
|
|
80 * Thrown on conversion errors, which happens on deviation from the grammar.
|
|
81 */
|
|
82 class ConvError : Exception
|
|
83 {
|
|
84 this(char[] s)
|
|
85 {
|
|
86 super("conversion " ~ s);
|
|
87 }
|
|
88 }
|
|
89
|
|
90 private void conv_error(char[] s)
|
|
91 {
|
|
92 throw new ConvError(s);
|
|
93 }
|
|
94
|
|
95 /**
|
|
96 * Thrown on conversion overflow errors.
|
|
97 */
|
|
98 class ConvOverflowError : Exception
|
|
99 {
|
|
100 this(char[] s)
|
|
101 {
|
|
102 super("Error: overflow " ~ s);
|
|
103 }
|
|
104 }
|
|
105
|
|
106 private void conv_overflow(char[] s)
|
|
107 {
|
|
108 throw new ConvOverflowError(s);
|
|
109 }
|
|
110
|
|
111 /***************************************************************
|
|
112 * Convert character string to the return type.
|
|
113 */
|
|
114
|
|
115 int toInt(char[] s)
|
|
116 {
|
|
117 int length = s.length;
|
|
118
|
|
119 if (!length)
|
|
120 goto Lerr;
|
|
121
|
|
122 int sign = 0;
|
|
123 int v = 0;
|
|
124
|
|
125 for (int i = 0; i < length; i++)
|
|
126 {
|
|
127 char c = s[i];
|
|
128 if (c >= '0' && c <= '9')
|
|
129 {
|
|
130 if (v < int.max/10 || (v == int.max/10 && c + sign <= '7'))
|
|
131 v = v * 10 + (c - '0');
|
|
132 else
|
|
133 goto Loverflow;
|
|
134 }
|
|
135 else if (c == '-' && i == 0)
|
|
136 {
|
|
137 sign = -1;
|
|
138 if (length == 1)
|
|
139 goto Lerr;
|
|
140 }
|
|
141 else if (c == '+' && i == 0)
|
|
142 {
|
|
143 if (length == 1)
|
|
144 goto Lerr;
|
|
145 }
|
|
146 else
|
|
147 goto Lerr;
|
|
148 }
|
|
149 if (sign == -1)
|
|
150 {
|
|
151 if (cast(uint)v > 0x80000000)
|
|
152 goto Loverflow;
|
|
153 v = -v;
|
|
154 }
|
|
155 else
|
|
156 {
|
|
157 if (cast(uint)v > 0x7FFFFFFF)
|
|
158 goto Loverflow;
|
|
159 }
|
|
160 return v;
|
|
161
|
|
162 Loverflow:
|
|
163 conv_overflow(s);
|
|
164
|
|
165 Lerr:
|
|
166 conv_error(s);
|
|
167 return 0;
|
|
168 }
|
|
169
|
|
170 /*******************************************************
|
|
171 * ditto
|
|
172 */
|
|
173
|
|
174 uint toUint(char[] s)
|
|
175 {
|
|
176 int length = s.length;
|
|
177
|
|
178 if (!length)
|
|
179 goto Lerr;
|
|
180
|
|
181 uint v = 0;
|
|
182
|
|
183 for (int i = 0; i < length; i++)
|
|
184 {
|
|
185 char c = s[i];
|
|
186 if (c >= '0' && c <= '9')
|
|
187 {
|
|
188 if (v < uint.max/10 || (v == uint.max/10 && c <= '5'))
|
|
189 v = v * 10 + (c - '0');
|
|
190 else
|
|
191 goto Loverflow;
|
|
192 }
|
|
193 else
|
|
194 goto Lerr;
|
|
195 }
|
|
196 return v;
|
|
197
|
|
198 Loverflow:
|
|
199 conv_overflow(s);
|
|
200
|
|
201 Lerr:
|
|
202 conv_error(s);
|
|
203 return 0;
|
|
204 }
|
|
205
|
|
206 /*******************************************************
|
|
207 * ditto
|
|
208 */
|
|
209
|
|
210 long toLong(char[] s)
|
|
211 {
|
|
212 int length = s.length;
|
|
213
|
|
214 if (!length)
|
|
215 goto Lerr;
|
|
216
|
|
217 int sign = 0;
|
|
218 long v = 0;
|
|
219
|
|
220 for (int i = 0; i < length; i++)
|
|
221 {
|
|
222 char c = s[i];
|
|
223 if (c >= '0' && c <= '9')
|
|
224 {
|
|
225 if (v < long.max/10 || (v == long.max/10 && c + sign <= '7'))
|
|
226 v = v * 10 + (c - '0');
|
|
227 else
|
|
228 goto Loverflow;
|
|
229 }
|
|
230 else if (c == '-' && i == 0)
|
|
231 {
|
|
232 sign = -1;
|
|
233 if (length == 1)
|
|
234 goto Lerr;
|
|
235 }
|
|
236 else if (c == '+' && i == 0)
|
|
237 {
|
|
238 if (length == 1)
|
|
239 goto Lerr;
|
|
240 }
|
|
241 else
|
|
242 goto Lerr;
|
|
243 }
|
|
244 if (sign == -1)
|
|
245 {
|
|
246 if (cast(ulong)v > 0x8000000000000000)
|
|
247 goto Loverflow;
|
|
248 v = -v;
|
|
249 }
|
|
250 else
|
|
251 {
|
|
252 if (cast(ulong)v > 0x7FFFFFFFFFFFFFFF)
|
|
253 goto Loverflow;
|
|
254 }
|
|
255 return v;
|
|
256
|
|
257 Loverflow:
|
|
258 conv_overflow(s);
|
|
259
|
|
260 Lerr:
|
|
261 conv_error(s);
|
|
262 return 0;
|
|
263 }
|
|
264
|
|
265 /*******************************************************
|
|
266 * ditto
|
|
267 */
|
|
268
|
|
269 ulong toUlong(char[] s)
|
|
270 {
|
|
271 int length = s.length;
|
|
272
|
|
273 if (!length)
|
|
274 goto Lerr;
|
|
275
|
|
276 ulong v = 0;
|
|
277
|
|
278 for (int i = 0; i < length; i++)
|
|
279 {
|
|
280 char c = s[i];
|
|
281 if (c >= '0' && c <= '9')
|
|
282 {
|
|
283 if (v < ulong.max/10 || (v == ulong.max/10 && c <= '5'))
|
|
284 v = v * 10 + (c - '0');
|
|
285 else
|
|
286 goto Loverflow;
|
|
287 }
|
|
288 else
|
|
289 goto Lerr;
|
|
290 }
|
|
291 return v;
|
|
292
|
|
293 Loverflow:
|
|
294 conv_overflow(s);
|
|
295
|
|
296 Lerr:
|
|
297 conv_error(s);
|
|
298 return 0;
|
|
299 }
|
|
300
|
|
301 /*******************************************************
|
|
302 * ditto
|
|
303 */
|
|
304
|
|
305 short toShort(char[] s)
|
|
306 {
|
|
307 int v = toInt(s);
|
|
308
|
|
309 if (v != cast(short)v)
|
|
310 goto Loverflow;
|
|
311
|
|
312 return cast(short)v;
|
|
313
|
|
314 Loverflow:
|
|
315 conv_overflow(s);
|
|
316 return 0;
|
|
317 }
|
|
318
|
|
319 /*******************************************************
|
|
320 * ditto
|
|
321 */
|
|
322
|
|
323 ushort toUshort(char[] s)
|
|
324 {
|
|
325 uint v = toUint(s);
|
|
326
|
|
327 if (v != cast(ushort)v)
|
|
328 goto Loverflow;
|
|
329
|
|
330 return cast(ushort)v;
|
|
331
|
|
332 Loverflow:
|
|
333 conv_overflow(s);
|
|
334 return 0;
|
|
335 }
|
|
336
|
|
337 /*******************************************************
|
|
338 * ditto
|
|
339 */
|
|
340
|
|
341 byte toByte(char[] s)
|
|
342 {
|
|
343 int v = toInt(s);
|
|
344
|
|
345 if (v != cast(byte)v)
|
|
346 goto Loverflow;
|
|
347
|
|
348 return cast(byte)v;
|
|
349
|
|
350 Loverflow:
|
|
351 conv_overflow(s);
|
|
352 return 0;
|
|
353 }
|
|
354
|
|
355 /*******************************************************
|
|
356 * ditto
|
|
357 */
|
|
358
|
|
359 ubyte toUbyte(char[] s)
|
|
360 {
|
|
361 uint v = toUint(s);
|
|
362
|
|
363 if (v != cast(ubyte)v)
|
|
364 goto Loverflow;
|
|
365
|
|
366 return cast(ubyte)v;
|
|
367
|
|
368 Loverflow:
|
|
369 conv_overflow(s);
|
|
370 return 0;
|
|
371 }
|
|
372
|
|
373 /*******************************************************
|
|
374 * ditto
|
|
375 */
|
|
376
|
|
377 float toFloat(in char[] s)
|
|
378 {
|
|
379 float f;
|
|
380 char* endptr;
|
|
381 char* sz;
|
|
382
|
|
383 //writefln("toFloat('%s')", s);
|
|
384 sz = toStringz(s);
|
|
385 if (tango.stdc.ctype.isspace(*sz))
|
|
386 goto Lerr;
|
|
387
|
|
388 // BUG: should set __locale_decpoint to "." for DMC
|
|
389
|
|
390 setErrno(0);
|
|
391 f = strtof(sz, &endptr);
|
|
392 if (getErrno() == ERANGE)
|
|
393 goto Lerr;
|
|
394 if (endptr && (endptr == sz || *endptr != 0))
|
|
395 goto Lerr;
|
|
396
|
|
397 return f;
|
|
398
|
|
399 Lerr:
|
|
400 conv_error(s ~ " not representable as a float");
|
|
401 assert(0);
|
|
402 }
|
|
403
|
|
404 /*******************************************************
|
|
405 * ditto
|
|
406 */
|
|
407
|
|
408 double toDouble(in char[] s)
|
|
409 {
|
|
410 double f;
|
|
411 char* endptr;
|
|
412 char* sz;
|
|
413
|
|
414 //writefln("toDouble('%s')", s);
|
|
415 sz = toStringz(s);
|
|
416 if (tango.stdc.ctype.isspace(*sz))
|
|
417 goto Lerr;
|
|
418
|
|
419 // BUG: should set __locale_decpoint to "." for DMC
|
|
420
|
|
421 setErrno(0);
|
|
422 f = strtod(sz, &endptr);
|
|
423 if (getErrno() == ERANGE)
|
|
424 goto Lerr;
|
|
425 if (endptr && (endptr == sz || *endptr != 0))
|
|
426 goto Lerr;
|
|
427
|
|
428 return f;
|
|
429
|
|
430 Lerr:
|
|
431 conv_error(s ~ " not representable as a double");
|
|
432 assert(0);
|
|
433 }
|
|
434
|
|
435 /*******************************************************
|
|
436 * ditto
|
|
437 */
|
|
438 real toReal(in char[] s)
|
|
439 {
|
|
440 real f;
|
|
441 char* endptr;
|
|
442 char* sz;
|
|
443
|
|
444 //writefln("toReal('%s')", s);
|
|
445 sz = toStringz(s);
|
|
446 if (tango.stdc.ctype.isspace(*sz))
|
|
447 goto Lerr;
|
|
448
|
|
449 // BUG: should set __locale_decpoint to "." for DMC
|
|
450
|
|
451 setErrno(0);
|
|
452 f = strtold(sz, &endptr);
|
|
453 if (getErrno() == ERANGE)
|
|
454 goto Lerr;
|
|
455 if (endptr && (endptr == sz || *endptr != 0))
|
|
456 goto Lerr;
|
|
457
|
|
458 return f;
|
|
459
|
|
460 Lerr:
|
|
461 conv_error(s ~ " not representable as a real");
|
|
462 assert(0);
|
|
463 }
|
|
464
|