1 karl 1.13 //%2005////////////////////////////////////////////////////////////////////////
|
2 chuck 1.2 //
|
3 karl 1.13 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
|
6 chuck 1.2 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.13 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 chuck 1.2 //
12 // Permission is hereby granted, free of charge, to any person obtaining a copy
13 // of this software and associated documentation files (the "Software"), to
14 // deal in the Software without restriction, including without limitation the
15 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
16 // sell copies of the Software, and to permit persons to whom the Software is
17 // furnished to do so, subject to the following conditions:
18 //
19 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
20 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
21 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
22 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
23 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 //==============================================================================
29 //
30 // Authors: David Rosckes (rosckes@us.ibm.com)
31 // Bert Rivero (hurivero@us.ibm.com)
32 chuck 1.2 // Chuck Carmack (carmack@us.ibm.com)
33 // Brian Lucier (lucier@us.ibm.com)
34 //
35 // Modified By:
36 //
37 //%/////////////////////////////////////////////////////////////////////////////
|
38 lucier 1.7
|
39 chuck 1.2 #include <Pegasus/CQL/CQLUtilities.h>
|
40 lucier 1.7
41 // Query includes
42 #include <Pegasus/Query/QueryCommon/QueryException.h>
43
44 // Pegasus Common includes
45 #include <Pegasus/Common/Tracer.h>
46
47 // standard includes
|
48 chuck 1.3 #include <errno.h>
|
49 chuck 1.2
|
50 lucier 1.7 // symbol defines
|
51 chuck 1.2 #define PEGASUS_SINT64_MIN (PEGASUS_SINT64_LITERAL(0x8000000000000000))
52 #define PEGASUS_UINT64_MAX PEGASUS_UINT64_LITERAL(0xFFFFFFFFFFFFFFFF)
53
|
54 lucier 1.7 // required for the windows compile
|
55 lucier 1.5 #ifndef _MSC_VER
56 #define _MSC_VER 0
57 #endif
58
|
59 chuck 1.2 PEGASUS_NAMESPACE_BEGIN
60
|
61 lucier 1.4 inline Uint8 _CQLUtilities_hexCharToNumeric(const Char16 c)
|
62 chuck 1.2 {
63 Uint8 n;
64
65 if (isdigit(c))
66 n = (c - '0');
67 else if (isupper(c))
68 n = (c - 'A' + 10);
69 else // if (islower(c))
70 n = (c - 'a' + 10);
71
72 return n;
73 }
74
75 Uint64 CQLUtilities::stringToUint64(const String &stringNum)
76 {
|
77 lucier 1.7 PEG_METHOD_ENTER(TRC_CQL,"CQLUtilities::stringToUint64()");
78
|
79 chuck 1.2 Uint64 x = 0;
80 const Char16* p = stringNum.getChar16Data();
81 const Char16* pStart = p;
82
|
83 lucier 1.8 if (String::equal(stringNum, String::EMPTY))
84 {
85 MessageLoaderParms mload(String("CQL.CQLUtilities.EMPTY_STRING"),
|
86 humberto 1.12 String("Error converting string to $0. String cannot be $1."),
87 String("Uint64"), String("empty"));
|
88 lucier 1.8 throw CQLRuntimeException(mload);
89 }
90
|
91 chuck 1.2 if (!p)
|
92 lucier 1.7 {
|
93 humberto 1.12 MessageLoaderParms mload(String("CQL.CQLUtilities.EMPTY_STRING"),
94 String("Error converting string to $0. String cannot be $1."),
95 String("Uint64"), String("NULL"));
|
96 lucier 1.7 throw CQLRuntimeException(mload);
97 }
|
98 chuck 1.2
|
99 humberto 1.12 // If the string is a real number, use stringToReal, then convert to a Uint64
100 if (isReal(stringNum))
101 {
102 // Note: the cast will rip off any non-whole number precision. CQL spec
103 // is silent on whether to round up, round down, throw an error, or allow
104 // the platform to round as it sees fit. We chose the latter for now.
105 return (Uint64) stringToReal64(stringNum);
106 }
107
|
108 chuck 1.2 // There cannot be a negative '-' sign
109 if (*p == '-')
|
110 lucier 1.7 {
111 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_NEG"),
|
112 humberto 1.12 String("Error converting string to $0. String '$1' cannot begin with '-'."),
113 String("Uint64"),
|
114 lucier 1.7 stringNum);
115 throw CQLRuntimeException(mload);
116 }
|
117 chuck 1.2 if (*p == '+')
118 p++; // skip over the positive sign
119
120 if (!isdigit(*p))
|
121 lucier 1.7 {
122 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_NUM_FORMAT"),
|
123 humberto 1.12 String("Error converting string to $0. String '$1' is badly formed."),
124 String("Uint64"),
|
125 lucier 1.7 stringNum);
126 throw CQLRuntimeException(mload);
127 }
|
128 chuck 1.2
|
129 humberto 1.12 // if hexidecimal
130 if ( (*p == '0') && ((p[1] == 'x') || (p[1] == 'X')) )
|
131 chuck 1.2 {
|
132 humberto 1.12 // Convert a hexadecimal string
133
134 // Skip over the "0x"
135 p+=2;
136
137 // At least one hexadecimal digit is required
138 if (!*p)
139 {
140 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_HEX_FORMAT"),
141 String("Error converting string to $0. String '$1' needs a hexadecimal digit character following '0x'"),
142 String("Uint64"),
143 stringNum);
144 throw CQLRuntimeException(mload);
145 }
146
|
147 chuck 1.2 // Add on each digit, checking for overflow errors
|
148 humberto 1.12 while (isxdigit(*p))
|
149 chuck 1.2 {
|
150 humberto 1.12 // Make sure we won't overflow when we multiply by 16
151 if (x > PEGASUS_UINT64_MAX/16)
|
152 lucier 1.7 {
153 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
154 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
155 String("Uint64"),
|
156 lucier 1.7 stringNum);
157 throw CQLRuntimeException(mload);
158 }
|
159 chuck 1.2
|
160 humberto 1.12 x = x << 4;
|
161 chuck 1.2
162 // We can't overflow when we add the next digit
|
163 humberto 1.12 Uint64 newDigit = Uint64(_CQLUtilities_hexCharToNumeric(*p++));
|
164 chuck 1.2 if (PEGASUS_UINT64_MAX - x < newDigit)
|
165 lucier 1.7 {
166 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
167 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
168 String("Uint64"),
169 stringNum);
|
170 lucier 1.7 throw CQLRuntimeException(mload);
171 }
|
172 chuck 1.2
173 x = x + newDigit;
174 }
175
|
176 humberto 1.12 // If we found a non-hexadecimal digit, report an error
177 if (*p)
|
178 lucier 1.7 {
|
179 humberto 1.12 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_HEX_CHAR"),
180 String("Error converting string to $0. Character '$1' in string '$2' is not a hexidecimal digit."),
181 String("Uint64"),
182 String(p, 1), stringNum);
|
183 lucier 1.7 throw CQLRuntimeException(mload);
184 }
|
185 chuck 1.2
|
186 humberto 1.12 // return value from the hex string
|
187 lucier 1.7 PEG_METHOD_EXIT();
|
188 humberto 1.12 return x;
189 } // end if hexidecimal
|
190 chuck 1.2
|
191 humberto 1.12 // if binary
192 Uint32 endString = stringNum.size() - 1;
193 if ( (pStart[endString] == 'b') || (pStart[endString] == 'B') )
|
194 chuck 1.2 {
195 // Add on each digit, checking for overflow errors
|
196 humberto 1.12 while ((*p == '0') || (*p == '1'))
|
197 chuck 1.2 {
|
198 humberto 1.12 // Make sure we won't overflow when we multiply by 2
199 if (x > PEGASUS_UINT64_MAX/2)
|
200 lucier 1.7 {
201 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
202 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
203 String("Uint64"),
|
204 lucier 1.7 stringNum);
205 throw CQLRuntimeException(mload);
206 }
|
207 chuck 1.2
|
208 humberto 1.12 x = x << 1;
|
209 chuck 1.2
210 // We can't overflow when we add the next digit
|
211 humberto 1.12 Uint64 newDigit = 0;
212 if (*p++ == '1')
213 newDigit = 1;
|
214 chuck 1.2 if (PEGASUS_UINT64_MAX - x < newDigit)
|
215 lucier 1.7 {
216 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
217 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
218 String("Uint64"),
|
219 lucier 1.7 stringNum);
220 throw CQLRuntimeException(mload);
221 }
|
222 chuck 1.2
223 x = x + newDigit;
224 }
225
|
226 humberto 1.12 // If we found a non-binary digit before the terminating 'b', then report an error
227 if (*p && (p-pStart < (Sint32)endString || (*p != 'b' && *p != 'B')))
|
228 lucier 1.7 {
|
229 humberto 1.12 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_BIN_CHAR"),
230 String("Error converting string to $0. Character '$1' in string '$2' is not a binary digit."),
231 String("Uint64"),
232 String(p, 1), stringNum);
|
233 lucier 1.7 throw CQLRuntimeException(mload);
234 }
|
235 chuck 1.2
|
236 humberto 1.12 // return value from the binary string
|
237 lucier 1.7 PEG_METHOD_EXIT();
|
238 humberto 1.12 return x;
239 } // end if binary
|
240 chuck 1.2
241
242 // Expect a positive decimal digit:
243
244 // Add on each digit, checking for overflow errors
245 while (isdigit(*p))
246 {
247 // Make sure we won't overflow when we multiply by 10
248 if (x > PEGASUS_UINT64_MAX/10)
|
249 lucier 1.7 {
250 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
251 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
252 String("Uint64"),
|
253 lucier 1.7 stringNum);
254 throw CQLRuntimeException(mload);
255 }
|
256 chuck 1.2 x = 10 * x;
257
258 // Make sure we won't overflow when we add the next digit
259 Uint64 newDigit = (*p++ - '0');
260 if (PEGASUS_UINT64_MAX - x < newDigit)
|
261 lucier 1.7 {
262 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
263 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
264 String("Uint64"),
265 stringNum);
|
266 lucier 1.7 throw CQLRuntimeException(mload);
267 }
|
268 chuck 1.2
269 x = x + newDigit;
270 }
271
|
272 lucier 1.9 // If we found a non-decimal digit, report an error
|
273 chuck 1.2 if (*p)
|
274 lucier 1.7 {
|
275 lucier 1.9 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_DECIMAL_CHAR"),
|
276 humberto 1.12 String("Error converting string to $0. Character '$1' in string '$2' is not a decimal digit."),
277 String("Uint64"),
|
278 lucier 1.9 String(p, 1), stringNum);
279 throw CQLRuntimeException(mload);
|
280 lucier 1.7 }
|
281 chuck 1.2
282 // return the value for the decimal string
|
283 lucier 1.7 PEG_METHOD_EXIT();
|
284 chuck 1.2 return x;
285 }
286
287 Sint64 CQLUtilities::stringToSint64(const String &stringNum)
288 {
|
289 lucier 1.7 PEG_METHOD_ENTER(TRC_CQL,"CQLUtilities::stringToSint64()");
290
|
291 chuck 1.2 Sint64 x = 0;
292 Boolean invert = false;
293 const Char16* p = stringNum.getChar16Data();
294 const Char16* pStart = p;
295
|
296 lucier 1.8 if (String::equal(stringNum, String::EMPTY))
297 {
298 MessageLoaderParms mload(String("CQL.CQLUtilities.EMPTY_STRING"),
|
299 humberto 1.12 String("Error converting string to $0. String cannot be $1."),
300 String("Sint64"), String("empty"));
|
301 lucier 1.8 throw CQLRuntimeException(mload);
302 }
303
|
304 chuck 1.2 if (!p)
|
305 lucier 1.7 {
|
306 humberto 1.12 MessageLoaderParms mload(String("CQL.CQLUtilities.EMPTY_STRING"),
307 String("Error converting string to $0. String cannot be $1."),
308 String("Sint64"), String("NULL"));
|
309 lucier 1.7 throw CQLRuntimeException(mload);
310 }
|
311 chuck 1.2
|
312 humberto 1.12 // If the string is a real number, use stringToReal, then convert to a Sint64
313 if (isReal(stringNum))
314 {
315 // Note: the cast will rip off any non-whole number precision. CQL spec
316 // is silent on whether to round up, round down, throw an error, or allow
317 // the platform to round as it sees fit. We chose the latter for now.
318 return (Sint64) stringToReal64(stringNum);
319 }
320
|
321 chuck 1.2 // skip over the sign if there is one
322 if (*p == '-')
323 {
324 invert = true;
325 p++;
326 }
327 if (*p == '+')
328 p++;
329
330 if (!isdigit(*p))
|
331 lucier 1.7 {
332 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_NUM_FORMAT"),
|
333 humberto 1.12 String("Error converting string to $0. String '$1' is badly formed."),
334 String("Uint64"),
|
335 lucier 1.7 stringNum);
336 throw CQLRuntimeException(mload);
337 }
|
338 chuck 1.2
339 // ********************
340 // Build the Sint64 as a negative number, regardless of the
341 // eventual sign (negative numbers can be bigger than positive ones)
342 // ********************
343
|
344 humberto 1.12 // if hexidecimal
345 if ( (*p == '0') && ((p[1] == 'x') || (p[1] == 'X')) )
|
346 chuck 1.2 {
|
347 humberto 1.12 // Convert a hexadecimal string
348
349 // Skip over the "0x"
350 p+=2;
351
352 // At least one hexidecimal digit is required
353 if (!*p)
354 {
355 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_HEX_FORMAT"),
356 String("Error converting string to $0. String '$1' needs a hexadecimal digit character following '0x'."),
357 String("Sint64"),
358 stringNum);
359 throw CQLRuntimeException(mload);
360 }
361
|
362 chuck 1.2 // Add on each digit, checking for overflow errors
|
363 humberto 1.12 while (isxdigit(*p))
|
364 chuck 1.2 {
|
365 humberto 1.12 // Make sure we won't overflow when we multiply by 16
366 if (x < PEGASUS_SINT64_MIN/16)
|
367 lucier 1.7 {
368 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
369 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
370 String("Sint64"),
|
371 lucier 1.7 stringNum);
372 throw CQLRuntimeException(mload);
373 }
|
374 chuck 1.2
|
375 humberto 1.12 x = x << 4;
|
376 chuck 1.2
377 // We can't overflow when we add the next digit
|
378 humberto 1.12 Sint64 newDigit = Sint64(_CQLUtilities_hexCharToNumeric(*p++));
|
379 chuck 1.2 if (PEGASUS_SINT64_MIN - x > -newDigit)
|
380 lucier 1.7 {
381 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
382 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
383 String("Sint64"),
|
384 lucier 1.7 stringNum);
385 throw CQLRuntimeException(mload);
386 }
|
387 chuck 1.2
388 x = x - newDigit;
389 }
390
|
391 humberto 1.12 // If we found a non-hexidecimal digit, report an error
392 if (*p)
|
393 lucier 1.7 {
|
394 humberto 1.12 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_HEX_CHAR"),
395 String("Error converting string to $0. Character '$1' in string '$2' is not a hexidecimal digit."),
396 String("Sint64"),
397 String(p, 1), stringNum);
|
398 lucier 1.7 throw CQLRuntimeException(mload);
399 }
|
400 chuck 1.2
401 // Return the integer to positive, if necessary, checking for an
402 // overflow error
403 if (!invert)
404 {
405 if (x == PEGASUS_SINT64_MIN)
|
406 lucier 1.7 {
407 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
408 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
409 String("Sint64"),
|
410 lucier 1.7 stringNum);
411 throw CQLRuntimeException(mload);
412 }
|
413 chuck 1.2 x = -x;
414 }
415
|
416 humberto 1.12 // return value from the hex string
|
417 lucier 1.7 PEG_METHOD_EXIT();
|
418 humberto 1.12 return x;
419 } // end if hexidecimal
|
420 chuck 1.2
|
421 humberto 1.12 // if binary
422 Uint32 endString = stringNum.size() - 1;
423 if ( (pStart[endString] == 'b') || (pStart[endString] == 'B') )
|
424 chuck 1.2 {
425 // Add on each digit, checking for overflow errors
|
426 humberto 1.12 while ((*p == '0') || (*p == '1'))
|
427 chuck 1.2 {
|
428 humberto 1.12 // Make sure we won't overflow when we multiply by 2
429 if (x < PEGASUS_SINT64_MIN/2)
|
430 lucier 1.7 {
431 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
432 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
433 String("Sint64"),
434 stringNum);
|
435 lucier 1.7 throw CQLRuntimeException(mload);
436 }
|
437 chuck 1.2
|
438 humberto 1.12 x = x << 1;
|
439 chuck 1.2
440 // We can't overflow when we add the next digit
|
441 humberto 1.12 Sint64 newDigit = 0;
442 if (*p++ == '1')
443 newDigit = 1;
|
444 chuck 1.2 if (PEGASUS_SINT64_MIN - x > -newDigit)
|
445 lucier 1.7 {
446 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
447 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
448 String("Sint64"),
|
449 lucier 1.7 stringNum);
450 throw CQLRuntimeException(mload);
451 }
|
452 chuck 1.2
|
453 lucier 1.4 x = x - newDigit;
|
454 chuck 1.2 }
455
|
456 humberto 1.12 // If we found a non-binary digit before the terminating 'b', then report an error
457 if (*p && (p-pStart < (Sint32)endString || (*p != 'b' && *p != 'B')))
|
458 lucier 1.7 {
|
459 humberto 1.12 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_BIN_CHAR"),
460 String("Error converting string to $0. Character '$1' in string '$2' is not a binary digit."),
461 String("Sint64"),
462 String(p, 1), stringNum);
|
463 lucier 1.7 throw CQLRuntimeException(mload);
464 }
|
465 chuck 1.2
466 // Return the integer to positive, if necessary, checking for an
467 // overflow error
468 if (!invert)
469 {
470 if (x == PEGASUS_SINT64_MIN)
|
471 lucier 1.7 {
472 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
473 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
474 String("Sint64"),
|
475 lucier 1.7 stringNum);
476 throw CQLRuntimeException(mload);
477 }
|
478 chuck 1.2 x = -x;
479 }
480
|
481 humberto 1.12 // return value from the binary string
|
482 lucier 1.7 PEG_METHOD_EXIT();
|
483 humberto 1.12 return x;
484 } // end if binary
|
485 chuck 1.2
486 // Expect a positive decimal digit:
487
488 // Add on each digit, checking for overflow errors
489 while (isdigit(*p))
490 {
491 // Make sure we won't overflow when we multiply by 10
|
492 lucier 1.4 if (x < PEGASUS_SINT64_MIN/10)
|
493 lucier 1.7 {
494 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
495 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
496 String("Sint64"),
|
497 lucier 1.7 stringNum);
498 throw CQLRuntimeException(mload);
499 }
|
500 chuck 1.2 x = 10 * x;
501
502 // Make sure we won't overflow when we add the next digit
503 Sint64 newDigit = (*p++ - '0');
504 if (PEGASUS_SINT64_MIN - x > -newDigit)
|
505 lucier 1.7 {
506 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
507 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
508 String("Sint64"),
|
509 lucier 1.7 stringNum);
510 throw CQLRuntimeException(mload);
511 }
|
512 chuck 1.2
|
513 lucier 1.4 x = x - newDigit;
|
514 chuck 1.2 }
515
516 // If we found a non-decimal digit, report an error
517 if (*p)
|
518 lucier 1.7 {
519 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_DECIMAL_CHAR"),
|
520 humberto 1.12 String("Error converting string to $0. Character '$1' in string '$2' is not a decimal digit."),
521 String("Sint64"),
|
522 lucier 1.9 String(p, 1), stringNum);
|
523 lucier 1.7 throw CQLRuntimeException(mload);
524 }
|
525 chuck 1.2
526 // Return the integer to positive, if necessary, checking for an
527 // overflow error
528 if (!invert)
529 {
530 if (x == PEGASUS_SINT64_MIN)
|
531 lucier 1.7 {
532 MessageLoaderParms mload(String("CQL.CQLUtilities.OVERFLOW"),
|
533 humberto 1.12 String("Error converting string to $0. String '$1' caused an overflow."),
534 String("Sint64"),
|
535 lucier 1.7 stringNum);
536 throw CQLRuntimeException(mload);
537 }
|
538 chuck 1.2 x = -x;
539 }
540
541 // return the value for the decimal string
|
542 lucier 1.7 PEG_METHOD_EXIT();
|
543 chuck 1.2 return x;
544 }
545
546 Real64 CQLUtilities::stringToReal64(const String &stringNum)
547 {
|
548 lucier 1.7 PEG_METHOD_ENTER(TRC_CQL,"CQLUtilities::stringToReal64()");
549
|
550 chuck 1.2 Real64 x = 0;
551 const Char16* p = stringNum.getChar16Data();
|
552 lucier 1.4 Boolean neg = false;
553 const Char16* pStart = p;
|
554 chuck 1.2
|
555 lucier 1.8 if (String::equal(stringNum, String::EMPTY))
556 {
557 MessageLoaderParms mload(String("CQL.CQLUtilities.EMPTY_STRING"),
|
558 humberto 1.12 String("Error converting string to $0. String cannot be $1."),
559 String("Real64"), String("empty"));
|
560 lucier 1.8 throw CQLRuntimeException(mload);
561 }
562
563 if (!p)
|
564 lucier 1.7 {
|
565 humberto 1.12 MessageLoaderParms mload(String("CQL.CQLUtilities.EMPTY_STRING"),
566 String("Error converting string to $0. String cannot be $1."),
567 String("Real64"), String("NULL"));
|
568 lucier 1.7 throw CQLRuntimeException(mload);
569 }
|
570 chuck 1.2
|
571 lucier 1.4
|
572 chuck 1.2 // Skip optional sign:
573
|
574 lucier 1.4 if (*p == '+')
|
575 chuck 1.2 p++;
|
576 lucier 1.4
577 if (*p == '-')
578 {
579 neg = true;
580 p++;
581 };
|
582 lucier 1.5
|
583 lucier 1.4 // Check if it it is a binary or hex integer
584 Uint32 endString = stringNum.size() - 1;
585 if ((*p == '0' && (p[1] == 'x' || p[1] == 'X')) || // hex OR
586 pStart[endString] == 'b' || pStart[endString] == 'B') // binary
587 {
588 if (neg)
589 x = stringToSint64(stringNum);
590 else
|
591 lucier 1.5
592 // Check if the complier is MSVC 6, which does not support the conversion operator from Uint64 to Real64
593 #if defined(PEGASUS_PLATFORM_WIN32_IX86_MSVC) && (_MSC_VER < 1300)
594 {
595 Uint64 num = stringToUint64(stringNum);
596 Sint64 half = num / 2;
597 x = half;
|
598 lucier 1.6 x += half;
|
599 lucier 1.5 if (num % 2) // if odd, then add the lost remainder
600 x += 1;
601 }
602 #else
|
603 lucier 1.4 x = stringToUint64(stringNum);
|
604 lucier 1.5 #endif
|
605 lucier 1.7 PEG_METHOD_EXIT();
|
606 lucier 1.4 return x;
607 }
608
|
609 chuck 1.2 // Skip optional first set of digits:
610
611 while (isdigit(*p))
612 p++;
613
614 // Test if optional dot is there
615 if (*p++ == '.')
616 {
617 // One or more digits required:
618 if (!isdigit(*p++))
|
619 lucier 1.7 {
620 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_CHAR_POST_DOT"),
|
621 humberto 1.12 String("Error converting string to Real64. String '$0' must have a digit character following the decimal point."),
|
622 lucier 1.7 stringNum);
623 throw CQLRuntimeException(mload);
624 }
|
625 chuck 1.2
626 while (isdigit(*p))
627 p++;
628
629 // If there is an exponent now:
630 if (*p)
631 {
632 // Test exponent:
633
634 if (*p != 'e' && *p != 'E')
|
635 lucier 1.7 {
636 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_REAL_CHAR"),
|
637 humberto 1.12 String("Error converting string to $0. Character '$1' in string '$2` is invalid."),
638 String("Real64"),
|
639 lucier 1.9 String(p-1, 1), stringNum);
|
640 lucier 1.7 throw CQLRuntimeException(mload);
641 }
|
642 chuck 1.2 p++;
643
644 // Skip optional sign:
645
646 if (*p == '+' || *p == '-')
647 p++;
648
649 // One or more digits required:
650 if (!isdigit(*p++))
|
651 lucier 1.7 {
652 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_REAL_EXP"),
|
653 humberto 1.12 String("Error converting string to Real64. String '$0' has an badly formed exponent. Character '$1' is invalid."),
|
654 lucier 1.9 stringNum, String(p, 1));
|
655 lucier 1.7 throw CQLRuntimeException(mload);
656 }
|
657 chuck 1.2
658 while (isdigit(*p))
659 p++;
660 }
|
661 lucier 1.7 } // end-if optional decimal point
|
662 humberto 1.12 if (*p && p - pStart <= (Sint32) stringNum.size())
|
663 lucier 1.7 {
|
664 lucier 1.8 // printf("This is char # %d\n", p - pStart);
|
665 lucier 1.7 MessageLoaderParms mload(String("CQL.CQLUtilities.INVALID_DECIMAL_CHAR"),
|
666 humberto 1.12 String("Error converting string to $0. Character '$1' in string '$2' is not a decimal digit."),
667 String("Real64"),
|
668 lucier 1.9 String(p-1, 1), stringNum);
|
669 lucier 1.7 throw CQLRuntimeException(mload);
|
670 chuck 1.2 }
671 //
672 // Do the conversion
673 //
674 char* end;
675 errno = 0;
676 CString temp = stringNum.getCString();
677 x = strtod((const char *) temp, &end);
678 if (*end || (errno == ERANGE))
679 {
|
680 humberto 1.10 MessageLoaderParms mload(String("CQL.CQLUtilities.CONVERSION_REAL_ERROR"),
|
681 humberto 1.12 String("String '$0' was unable to be converted to a Real64. It could be out of range."),
|
682 lucier 1.7 stringNum);
683 throw CQLRuntimeException(mload);
|
684 chuck 1.2 }
|
685 lucier 1.7 PEG_METHOD_EXIT();
|
686 lucier 1.9 // printf("String %s = %.16e\n", (const char *)stringNum.getCString(), x);
|
687 chuck 1.2 return x;
688 }
689
|
690 lucier 1.11 String CQLUtilities::formatRealStringExponent(const String &realString)
691 {
692 String newString(realString);
693 Uint32 expIndex = PEG_NOT_FOUND;
694 Uint32 index = newString.size() - 1;
695
696 expIndex = newString.find('E');
697 if (expIndex == PEG_NOT_FOUND)
698 expIndex = newString.find('e');
699
700 if (expIndex == PEG_NOT_FOUND)
701 return newString; // no exponent symbol, so just return
702
703 // format the exponent
704 index = expIndex + 1; // start index at next character
705 if (newString[index] == '+')
706 newString.remove(index, 1); // remove the '+' symbol
707
708 if (newString[index] == '-')
709 index++; // skip the '-' exponent sign
710
711 lucier 1.11 while (newString[index] == '0' && index < newString.size())
712 {
713 newString.remove(index, 1);
714 }
715
716 // If only an 'e' is left (only 0's behind it) then strip the 'e'
717 if (index >= newString.size())
718 newString.remove(expIndex, 1);
719
720 return newString;
721 }
722
|
723 humberto 1.12 Boolean CQLUtilities::isReal(const String &numString)
724 {
725 // If there is a decimal point, we consider it to be a real.
726 if (numString.find('.') == PEG_NOT_FOUND)
727 return false;
728 return true;
729 }
730
|
731 chuck 1.2 PEGASUS_NAMESPACE_END
|