1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * numutils.c |
4 | * utility functions for I/O of built-in numeric types. |
5 | * |
6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
7 | * Portions Copyright (c) 1994, Regents of the University of California |
8 | * |
9 | * |
10 | * IDENTIFICATION |
11 | * src/backend/utils/adt/numutils.c |
12 | * |
13 | *------------------------------------------------------------------------- |
14 | */ |
15 | #include "postgres.h" |
16 | |
17 | #include <math.h> |
18 | #include <limits.h> |
19 | #include <ctype.h> |
20 | |
21 | #include "common/int.h" |
22 | #include "utils/builtins.h" |
23 | |
24 | /* |
25 | * pg_atoi: convert string to integer |
26 | * |
27 | * allows any number of leading or trailing whitespace characters. |
28 | * |
29 | * 'size' is the sizeof() the desired integral result (1, 2, or 4 bytes). |
30 | * |
31 | * c, if not 0, is a terminator character that may appear after the |
32 | * integer (plus whitespace). If 0, the string must end after the integer. |
33 | * |
34 | * Unlike plain atoi(), this will throw ereport() upon bad input format or |
35 | * overflow. |
36 | */ |
37 | int32 |
38 | pg_atoi(const char *s, int size, int c) |
39 | { |
40 | long l; |
41 | char *badp; |
42 | |
43 | /* |
44 | * Some versions of strtol treat the empty string as an error, but some |
45 | * seem not to. Make an explicit test to be sure we catch it. |
46 | */ |
47 | if (s == NULL) |
48 | elog(ERROR, "NULL pointer" ); |
49 | if (*s == 0) |
50 | ereport(ERROR, |
51 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
52 | errmsg("invalid input syntax for type %s: \"%s\"" , |
53 | "integer" , s))); |
54 | |
55 | errno = 0; |
56 | l = strtol(s, &badp, 10); |
57 | |
58 | /* We made no progress parsing the string, so bail out */ |
59 | if (s == badp) |
60 | ereport(ERROR, |
61 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
62 | errmsg("invalid input syntax for type %s: \"%s\"" , |
63 | "integer" , s))); |
64 | |
65 | switch (size) |
66 | { |
67 | case sizeof(int32): |
68 | if (errno == ERANGE |
69 | #if defined(HAVE_LONG_INT_64) |
70 | /* won't get ERANGE on these with 64-bit longs... */ |
71 | || l < INT_MIN || l > INT_MAX |
72 | #endif |
73 | ) |
74 | ereport(ERROR, |
75 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
76 | errmsg("value \"%s\" is out of range for type %s" , s, |
77 | "integer" ))); |
78 | break; |
79 | case sizeof(int16): |
80 | if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX) |
81 | ereport(ERROR, |
82 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
83 | errmsg("value \"%s\" is out of range for type %s" , s, |
84 | "smallint" ))); |
85 | break; |
86 | case sizeof(int8): |
87 | if (errno == ERANGE || l < SCHAR_MIN || l > SCHAR_MAX) |
88 | ereport(ERROR, |
89 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
90 | errmsg("value \"%s\" is out of range for 8-bit integer" , s))); |
91 | break; |
92 | default: |
93 | elog(ERROR, "unsupported result size: %d" , size); |
94 | } |
95 | |
96 | /* |
97 | * Skip any trailing whitespace; if anything but whitespace remains before |
98 | * the terminating character, bail out |
99 | */ |
100 | while (*badp && *badp != c && isspace((unsigned char) *badp)) |
101 | badp++; |
102 | |
103 | if (*badp && *badp != c) |
104 | ereport(ERROR, |
105 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
106 | errmsg("invalid input syntax for type %s: \"%s\"" , |
107 | "integer" , s))); |
108 | |
109 | return (int32) l; |
110 | } |
111 | |
112 | /* |
113 | * Convert input string to a signed 16 bit integer. |
114 | * |
115 | * Allows any number of leading or trailing whitespace characters. Will throw |
116 | * ereport() upon bad input format or overflow. |
117 | * |
118 | * NB: Accumulate input as a negative number, to deal with two's complement |
119 | * representation of the most negative number, which can't be represented as a |
120 | * positive number. |
121 | */ |
122 | int16 |
123 | pg_strtoint16(const char *s) |
124 | { |
125 | const char *ptr = s; |
126 | int16 tmp = 0; |
127 | bool neg = false; |
128 | |
129 | /* skip leading spaces */ |
130 | while (likely(*ptr) && isspace((unsigned char) *ptr)) |
131 | ptr++; |
132 | |
133 | /* handle sign */ |
134 | if (*ptr == '-') |
135 | { |
136 | ptr++; |
137 | neg = true; |
138 | } |
139 | else if (*ptr == '+') |
140 | ptr++; |
141 | |
142 | /* require at least one digit */ |
143 | if (unlikely(!isdigit((unsigned char) *ptr))) |
144 | goto invalid_syntax; |
145 | |
146 | /* process digits */ |
147 | while (*ptr && isdigit((unsigned char) *ptr)) |
148 | { |
149 | int8 digit = (*ptr++ - '0'); |
150 | |
151 | if (unlikely(pg_mul_s16_overflow(tmp, 10, &tmp)) || |
152 | unlikely(pg_sub_s16_overflow(tmp, digit, &tmp))) |
153 | goto out_of_range; |
154 | } |
155 | |
156 | /* allow trailing whitespace, but not other trailing chars */ |
157 | while (*ptr != '\0' && isspace((unsigned char) *ptr)) |
158 | ptr++; |
159 | |
160 | if (unlikely(*ptr != '\0')) |
161 | goto invalid_syntax; |
162 | |
163 | if (!neg) |
164 | { |
165 | /* could fail if input is most negative number */ |
166 | if (unlikely(tmp == PG_INT16_MIN)) |
167 | goto out_of_range; |
168 | tmp = -tmp; |
169 | } |
170 | |
171 | return tmp; |
172 | |
173 | out_of_range: |
174 | ereport(ERROR, |
175 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
176 | errmsg("value \"%s\" is out of range for type %s" , |
177 | s, "smallint" ))); |
178 | |
179 | invalid_syntax: |
180 | ereport(ERROR, |
181 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
182 | errmsg("invalid input syntax for type %s: \"%s\"" , |
183 | "smallint" , s))); |
184 | |
185 | return 0; /* keep compiler quiet */ |
186 | } |
187 | |
188 | /* |
189 | * Convert input string to a signed 32 bit integer. |
190 | * |
191 | * Allows any number of leading or trailing whitespace characters. Will throw |
192 | * ereport() upon bad input format or overflow. |
193 | * |
194 | * NB: Accumulate input as a negative number, to deal with two's complement |
195 | * representation of the most negative number, which can't be represented as a |
196 | * positive number. |
197 | */ |
198 | int32 |
199 | pg_strtoint32(const char *s) |
200 | { |
201 | const char *ptr = s; |
202 | int32 tmp = 0; |
203 | bool neg = false; |
204 | |
205 | /* skip leading spaces */ |
206 | while (likely(*ptr) && isspace((unsigned char) *ptr)) |
207 | ptr++; |
208 | |
209 | /* handle sign */ |
210 | if (*ptr == '-') |
211 | { |
212 | ptr++; |
213 | neg = true; |
214 | } |
215 | else if (*ptr == '+') |
216 | ptr++; |
217 | |
218 | /* require at least one digit */ |
219 | if (unlikely(!isdigit((unsigned char) *ptr))) |
220 | goto invalid_syntax; |
221 | |
222 | /* process digits */ |
223 | while (*ptr && isdigit((unsigned char) *ptr)) |
224 | { |
225 | int8 digit = (*ptr++ - '0'); |
226 | |
227 | if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) || |
228 | unlikely(pg_sub_s32_overflow(tmp, digit, &tmp))) |
229 | goto out_of_range; |
230 | } |
231 | |
232 | /* allow trailing whitespace, but not other trailing chars */ |
233 | while (*ptr != '\0' && isspace((unsigned char) *ptr)) |
234 | ptr++; |
235 | |
236 | if (unlikely(*ptr != '\0')) |
237 | goto invalid_syntax; |
238 | |
239 | if (!neg) |
240 | { |
241 | /* could fail if input is most negative number */ |
242 | if (unlikely(tmp == PG_INT32_MIN)) |
243 | goto out_of_range; |
244 | tmp = -tmp; |
245 | } |
246 | |
247 | return tmp; |
248 | |
249 | out_of_range: |
250 | ereport(ERROR, |
251 | (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
252 | errmsg("value \"%s\" is out of range for type %s" , |
253 | s, "integer" ))); |
254 | |
255 | invalid_syntax: |
256 | ereport(ERROR, |
257 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
258 | errmsg("invalid input syntax for type %s: \"%s\"" , |
259 | "integer" , s))); |
260 | |
261 | return 0; /* keep compiler quiet */ |
262 | } |
263 | |
264 | /* |
265 | * pg_itoa: converts a signed 16-bit integer to its string representation |
266 | * |
267 | * Caller must ensure that 'a' points to enough memory to hold the result |
268 | * (at least 7 bytes, counting a leading sign and trailing NUL). |
269 | * |
270 | * It doesn't seem worth implementing this separately. |
271 | */ |
272 | void |
273 | pg_itoa(int16 i, char *a) |
274 | { |
275 | pg_ltoa((int32) i, a); |
276 | } |
277 | |
278 | /* |
279 | * pg_ltoa: converts a signed 32-bit integer to its string representation |
280 | * |
281 | * Caller must ensure that 'a' points to enough memory to hold the result |
282 | * (at least 12 bytes, counting a leading sign and trailing NUL). |
283 | */ |
284 | void |
285 | pg_ltoa(int32 value, char *a) |
286 | { |
287 | char *start = a; |
288 | bool neg = false; |
289 | |
290 | /* |
291 | * Avoid problems with the most negative integer not being representable |
292 | * as a positive integer. |
293 | */ |
294 | if (value == PG_INT32_MIN) |
295 | { |
296 | memcpy(a, "-2147483648" , 12); |
297 | return; |
298 | } |
299 | else if (value < 0) |
300 | { |
301 | value = -value; |
302 | neg = true; |
303 | } |
304 | |
305 | /* Compute the result string backwards. */ |
306 | do |
307 | { |
308 | int32 remainder; |
309 | int32 oldval = value; |
310 | |
311 | value /= 10; |
312 | remainder = oldval - value * 10; |
313 | *a++ = '0' + remainder; |
314 | } while (value != 0); |
315 | |
316 | if (neg) |
317 | *a++ = '-'; |
318 | |
319 | /* Add trailing NUL byte, and back up 'a' to the last character. */ |
320 | *a-- = '\0'; |
321 | |
322 | /* Reverse string. */ |
323 | while (start < a) |
324 | { |
325 | char swap = *start; |
326 | |
327 | *start++ = *a; |
328 | *a-- = swap; |
329 | } |
330 | } |
331 | |
332 | /* |
333 | * pg_lltoa: convert a signed 64-bit integer to its string representation |
334 | * |
335 | * Caller must ensure that 'a' points to enough memory to hold the result |
336 | * (at least MAXINT8LEN+1 bytes, counting a leading sign and trailing NUL). |
337 | */ |
338 | void |
339 | pg_lltoa(int64 value, char *a) |
340 | { |
341 | char *start = a; |
342 | bool neg = false; |
343 | |
344 | /* |
345 | * Avoid problems with the most negative integer not being representable |
346 | * as a positive integer. |
347 | */ |
348 | if (value == PG_INT64_MIN) |
349 | { |
350 | memcpy(a, "-9223372036854775808" , 21); |
351 | return; |
352 | } |
353 | else if (value < 0) |
354 | { |
355 | value = -value; |
356 | neg = true; |
357 | } |
358 | |
359 | /* Compute the result string backwards. */ |
360 | do |
361 | { |
362 | int64 remainder; |
363 | int64 oldval = value; |
364 | |
365 | value /= 10; |
366 | remainder = oldval - value * 10; |
367 | *a++ = '0' + remainder; |
368 | } while (value != 0); |
369 | |
370 | if (neg) |
371 | *a++ = '-'; |
372 | |
373 | /* Add trailing NUL byte, and back up 'a' to the last character. */ |
374 | *a-- = '\0'; |
375 | |
376 | /* Reverse string. */ |
377 | while (start < a) |
378 | { |
379 | char swap = *start; |
380 | |
381 | *start++ = *a; |
382 | *a-- = swap; |
383 | } |
384 | } |
385 | |
386 | |
387 | /* |
388 | * pg_ltostr_zeropad |
389 | * Converts 'value' into a decimal string representation stored at 'str'. |
390 | * 'minwidth' specifies the minimum width of the result; any extra space |
391 | * is filled up by prefixing the number with zeros. |
392 | * |
393 | * Returns the ending address of the string result (the last character written |
394 | * plus 1). Note that no NUL terminator is written. |
395 | * |
396 | * The intended use-case for this function is to build strings that contain |
397 | * multiple individual numbers, for example: |
398 | * |
399 | * str = pg_ltostr_zeropad(str, hours, 2); |
400 | * *str++ = ':'; |
401 | * str = pg_ltostr_zeropad(str, mins, 2); |
402 | * *str++ = ':'; |
403 | * str = pg_ltostr_zeropad(str, secs, 2); |
404 | * *str = '\0'; |
405 | * |
406 | * Note: Caller must ensure that 'str' points to enough memory to hold the |
407 | * result. |
408 | */ |
409 | char * |
410 | pg_ltostr_zeropad(char *str, int32 value, int32 minwidth) |
411 | { |
412 | char *start = str; |
413 | char *end = &str[minwidth]; |
414 | int32 num = value; |
415 | |
416 | Assert(minwidth > 0); |
417 | |
418 | /* |
419 | * Handle negative numbers in a special way. We can't just write a '-' |
420 | * prefix and reverse the sign as that would overflow for INT32_MIN. |
421 | */ |
422 | if (num < 0) |
423 | { |
424 | *start++ = '-'; |
425 | minwidth--; |
426 | |
427 | /* |
428 | * Build the number starting at the last digit. Here remainder will |
429 | * be a negative number, so we must reverse the sign before adding '0' |
430 | * in order to get the correct ASCII digit. |
431 | */ |
432 | while (minwidth--) |
433 | { |
434 | int32 oldval = num; |
435 | int32 remainder; |
436 | |
437 | num /= 10; |
438 | remainder = oldval - num * 10; |
439 | start[minwidth] = '0' - remainder; |
440 | } |
441 | } |
442 | else |
443 | { |
444 | /* Build the number starting at the last digit */ |
445 | while (minwidth--) |
446 | { |
447 | int32 oldval = num; |
448 | int32 remainder; |
449 | |
450 | num /= 10; |
451 | remainder = oldval - num * 10; |
452 | start[minwidth] = '0' + remainder; |
453 | } |
454 | } |
455 | |
456 | /* |
457 | * If minwidth was not high enough to fit the number then num won't have |
458 | * been divided down to zero. We punt the problem to pg_ltostr(), which |
459 | * will generate a correct answer in the minimum valid width. |
460 | */ |
461 | if (num != 0) |
462 | return pg_ltostr(str, value); |
463 | |
464 | /* Otherwise, return last output character + 1 */ |
465 | return end; |
466 | } |
467 | |
468 | /* |
469 | * pg_ltostr |
470 | * Converts 'value' into a decimal string representation stored at 'str'. |
471 | * |
472 | * Returns the ending address of the string result (the last character written |
473 | * plus 1). Note that no NUL terminator is written. |
474 | * |
475 | * The intended use-case for this function is to build strings that contain |
476 | * multiple individual numbers, for example: |
477 | * |
478 | * str = pg_ltostr(str, a); |
479 | * *str++ = ' '; |
480 | * str = pg_ltostr(str, b); |
481 | * *str = '\0'; |
482 | * |
483 | * Note: Caller must ensure that 'str' points to enough memory to hold the |
484 | * result. |
485 | */ |
486 | char * |
487 | pg_ltostr(char *str, int32 value) |
488 | { |
489 | char *start; |
490 | char *end; |
491 | |
492 | /* |
493 | * Handle negative numbers in a special way. We can't just write a '-' |
494 | * prefix and reverse the sign as that would overflow for INT32_MIN. |
495 | */ |
496 | if (value < 0) |
497 | { |
498 | *str++ = '-'; |
499 | |
500 | /* Mark the position we must reverse the string from. */ |
501 | start = str; |
502 | |
503 | /* Compute the result string backwards. */ |
504 | do |
505 | { |
506 | int32 oldval = value; |
507 | int32 remainder; |
508 | |
509 | value /= 10; |
510 | remainder = oldval - value * 10; |
511 | /* As above, we expect remainder to be negative. */ |
512 | *str++ = '0' - remainder; |
513 | } while (value != 0); |
514 | } |
515 | else |
516 | { |
517 | /* Mark the position we must reverse the string from. */ |
518 | start = str; |
519 | |
520 | /* Compute the result string backwards. */ |
521 | do |
522 | { |
523 | int32 oldval = value; |
524 | int32 remainder; |
525 | |
526 | value /= 10; |
527 | remainder = oldval - value * 10; |
528 | *str++ = '0' + remainder; |
529 | } while (value != 0); |
530 | } |
531 | |
532 | /* Remember the end+1 and back up 'str' to the last character. */ |
533 | end = str--; |
534 | |
535 | /* Reverse string. */ |
536 | while (start < str) |
537 | { |
538 | char swap = *start; |
539 | |
540 | *start++ = *str; |
541 | *str-- = swap; |
542 | } |
543 | |
544 | return end; |
545 | } |
546 | |
547 | /* |
548 | * pg_strtouint64 |
549 | * Converts 'str' into an unsigned 64-bit integer. |
550 | * |
551 | * This has the identical API to strtoul(3), except that it will handle |
552 | * 64-bit ints even where "long" is narrower than that. |
553 | * |
554 | * For the moment it seems sufficient to assume that the platform has |
555 | * such a function somewhere; let's not roll our own. |
556 | */ |
557 | uint64 |
558 | pg_strtouint64(const char *str, char **endptr, int base) |
559 | { |
560 | #ifdef _MSC_VER /* MSVC only */ |
561 | return _strtoui64(str, endptr, base); |
562 | #elif defined(HAVE_STRTOULL) && SIZEOF_LONG < 8 |
563 | return strtoull(str, endptr, base); |
564 | #else |
565 | return strtoul(str, endptr, base); |
566 | #endif |
567 | } |
568 | |