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 */
37int32
38pg_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 */
122int16
123pg_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
173out_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
179invalid_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 */
198int32
199pg_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
249out_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
255invalid_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 */
272void
273pg_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 */
284void
285pg_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 */
338void
339pg_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 */
409char *
410pg_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 */
486char *
487pg_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 */
557uint64
558pg_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