1 /*-------------------------------------------------------------------------
4 * utility functions for I/O of built-in numeric types.
6 * integer: pg_itoa, pg_ltoa
7 * floating point: ftoa, atof1
9 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
14 * $Header: /cvsroot/pgsql/src/backend/utils/adt/numutils.c,v 1.56 2003/08/04 00:43:25 momjian Exp $
16 *-------------------------------------------------------------------------
24 #include "utils/builtins.h"
27 #define INT_MAX (0x7FFFFFFFL)
30 #define INT_MIN (-INT_MAX-1)
33 #define SHRT_MAX (0x7FFF)
36 #define SHRT_MIN (-SHRT_MAX-1)
39 #define SCHAR_MAX (0x7F)
42 #define SCHAR_MIN (-SCHAR_MAX-1)
47 * pg_atoi: convert string to integer
49 * size is the sizeof() the desired integral result (1, 2, or 4 bytes).
51 * c, if not 0, is the terminator character that may appear after the
52 * integer. If 0, the string must end after the integer.
54 * Unlike plain atoi(), this will throw ereport() upon bad input format or
58 pg_atoi(char *s, int size, int c)
64 * Some versions of strtol treat the empty string as an error, but
65 * some seem not to. Make an explicit test to be sure we catch it.
67 if (s == (char *) NULL)
68 elog(ERROR, "NULL pointer");
71 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
72 errmsg("invalid input syntax for integer: \"%s\"",
76 l = strtol(s, &badp, 10);
79 * strtol() normally only sets ERANGE. On some systems it also may
80 * set EINVAL, which simply means it couldn't parse the input string.
81 * This is handled by the second "if" consistent across platforms.
83 if (errno && errno != ERANGE && errno != EINVAL)
85 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
86 errmsg("invalid input syntax for integer: \"%s\"",
88 if (badp && *badp && *badp != c)
90 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
91 errmsg("invalid input syntax for integer: \"%s\"",
98 #if defined(HAVE_LONG_INT_64)
99 /* won't get ERANGE on these with 64-bit longs... */
100 || l < INT_MIN || l > INT_MAX
104 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
105 errmsg("%s is out of range for int4", s)));
108 if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
110 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
111 errmsg("%s is out of range for int2", s)));
114 if (errno == ERANGE || l < SCHAR_MIN || l > SCHAR_MAX)
116 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
117 errmsg("%s is out of range for int1", s)));
120 elog(ERROR, "unsupported result size: %d", size);
126 * pg_itoa - converts a short int to its string represention
129 * previously based on ~ingres/source/gutil/atoi.c
130 * now uses vendor's sprintf conversion
133 pg_itoa(int16 i, char *a)
135 sprintf(a, "%hd", (short) i);
139 * pg_ltoa - converts a long int to its string represention
142 * previously based on ~ingres/source/gutil/atoi.c
143 * now uses vendor's sprintf conversion
146 pg_ltoa(int32 l, char *a)
152 ** ftoa - FLOATING POINT TO ASCII CONVERSION
154 ** CODE derived from ingres, ~ingres/source/gutil/ftoa.c
156 ** 'Value' is converted to an ascii character string and stored
157 ** into 'ascii'. Ascii should have room for at least 'width' + 1
158 ** characters. 'Width' is the width of the output field (max).
159 ** 'Prec' is the number of characters to put after the decimal
160 ** point. The format of the output string is controlled by
164 ** e or E: "E" format output
165 ** f or F: "F" format output
166 ** g or G: "F" format output if it will fit, otherwise
168 ** n or N: same as G, but decimal points will not always
171 ** If 'format' is upper case, the "E" comes out in upper case;
172 ** otherwise it comes out in lower case.
174 ** When the field width is not big enough, it fills the field with
175 ** stars ("*****") and returns zero. Normal return is the width
176 ** of the output field (sometimes shorter than 'width').
180 ftoa(double value, char *ascii, int width, int prec1, char format)
187 sprintf(fmt, "%%%d.%d%c", width, prec1, format);
188 sprintf(out, fmt, value);
189 if ((ret = strlen(out)) > width)
191 MemSet(ascii, '*', width - 2);
207 /* extern char *ecvt(), *fcvt();*/
211 lowercase = 'a' - 'A';
219 /* try 'F' style output */
220 p = fcvt(value, prec, &expon, &sign);
231 /* output '0' before the decimal point */
238 /* compute space length left after dec pt and fraction */
246 /* it fits. output */
249 /* output left of dp */
257 /* output fraction (right of dec pt) */
261 /* won't fit; let's hope for G format */
266 /* try to do E style output */
267 p = ecvt(value, prec + 1, &expon, &sign);
271 /* output the sign */
279 /* check for field too small */
280 if (mode == 'F' || avail < prec)
282 /* sorry joker, you lose */
284 for (avail = width; avail > 0; avail--)
290 /* it fits; output the number */
293 /* output the LHS single digit */
319 /* output the exponent */
322 *a++ = 'E' + lowercase;
330 *a++ = (expon / 10) % 10 + '0';
331 *a++ = expon % 10 + '0';
334 /* output spaces on the end in G format */
343 /* finally, we can return */
352 ** atof1 - ASCII TO FLOATING CONVERSION
354 ** CODE derived from ~ingres/source/gutil/atof.c
356 ** Converts the string 'str' to floating point and stores the
357 ** result into the cell pointed to by 'val'.
359 ** The syntax which it accepts is pretty much what you would
360 ** expect. Basically, it is:
361 ** {<sp>} [+|-] {<sp>} {<digit>} [.{digit}] {<sp>} [<exp>]
362 ** where <exp> is "e" or "E" followed by an integer, <sp> is a
363 ** space character, <digit> is zero through nine, [] is zero or
364 ** one, and {} is zero or more.
367 ** str -- string to convert.
368 ** val -- pointer to place to put the result (which
369 ** must be type double).
373 ** -1 -- syntax error.
374 ** +1 -- overflow (not implemented).
381 atof1(char *str, double *val)
395 /* skip leading blanks */
396 while ((c = *p) != '\0')
403 /* handle possible sign */
413 /* skip blanks after sign */
414 while ((c = *p) != '\0')
421 /* start collecting the number to the decimal point */
426 if (c < '0' || c > '9')
428 v = v * 10.0 + (c - '0');
433 /* check for fractional part */
440 if (c < '0' || c > '9')
443 v += (c - '0') * fact;
448 /* skip blanks before possible exponent */
449 while ((c = *p) != '\0')
456 /* test for exponent */
457 if (c == 'e' || c == 'E')
460 expon = pg_atoi(p, sizeof(expon), '\0');
464 v *= pow(10.0, fact);
468 /* if no exponent, then nothing */
473 /* store the result and exit */