1 /*-------------------------------------------------------------------------
4 * utility functions for I/O of built-in numeric types.
7 * floating point: ftoa, atof1
9 * Copyright (c) 1994, Regents of the University of California
13 * $Header: /cvsroot/pgsql/src/backend/utils/adt/numutils.c,v 1.38 1999/07/17 20:17:58 momjian Exp $
15 *-------------------------------------------------------------------------
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)
46 pg_atoi(char *s, int size, int c)
49 char *badp = (char *) NULL;
56 * Some versions of strtol treat the empty string as an error. This
57 * code will explicitly return 0 for an empty string.
60 if (s == (char *) NULL)
61 elog(ERROR, "pg_atoi: NULL pointer!");
65 l = strtol(s, &badp, 10);
66 if (errno) /* strtol must set ERANGE */
67 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
68 if (badp && *badp && (*badp != c))
69 elog(ERROR, "pg_atoi: error in \"%s\": can\'t parse \"%s\"", s, badp);
74 #if defined(HAVE_LONG_INT_64)
75 /* won't get ERANGE on these with 64-bit longs... */
79 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
84 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
86 #endif /* HAVE_LONG_INT_64 */
92 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
97 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
104 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
109 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
113 elog(ERROR, "pg_atoi: invalid result size: %d", size);
119 * itoa - converts a short int to its string represention
122 * previously based on ~ingres/source/gutil/atoi.c
123 * now uses vendor's sprintf conversion
128 sprintf(a, "%hd", (short) i);
132 * ltoa - converts a long int to its string represention
135 * previously based on ~ingres/source/gutil/atoi.c
136 * now uses vendor's sprintf conversion
139 ltoa(int32 l, char *a)
145 ** ftoa - FLOATING POINT TO ASCII CONVERSION
147 ** CODE derived from ingres, ~ingres/source/gutil/ftoa.c
149 ** 'Value' is converted to an ascii character string and stored
150 ** into 'ascii'. Ascii should have room for at least 'width' + 1
151 ** characters. 'Width' is the width of the output field (max).
152 ** 'Prec' is the number of characters to put after the decimal
153 ** point. The format of the output string is controlled by
157 ** e or E: "E" format output
158 ** f or F: "F" format output
159 ** g or G: "F" format output if it will fit, otherwise
161 ** n or N: same as G, but decimal points will not always
164 ** If 'format' is upper case, the "E" comes out in upper case;
165 ** otherwise it comes out in lower case.
167 ** When the field width is not big enough, it fills the field with
168 ** stars ("*****") and returns zero. Normal return is the width
169 ** of the output field (sometimes shorter than 'width').
173 ftoa(double value, char *ascii, int width, int prec1, char format)
180 sprintf(fmt, "%%%d.%d%c", width, prec1, format);
181 sprintf(out, fmt, value);
182 if ((ret = strlen(out)) > width)
184 MemSet(ascii, '*', width - 2);
200 /* extern char *ecvt(), *fcvt();*/
204 lowercase = 'a' - 'A';
212 /* try 'F' style output */
213 p = fcvt(value, prec, &expon, &sign);
224 /* output '0' before the decimal point */
231 /* compute space length left after dec pt and fraction */
239 /* it fits. output */
242 /* output left of dp */
250 /* output fraction (right of dec pt) */
254 /* won't fit; let's hope for G format */
259 /* try to do E style output */
260 p = ecvt(value, prec + 1, &expon, &sign);
264 /* output the sign */
272 /* check for field too small */
273 if (mode == 'F' || avail < prec)
275 /* sorry joker, you lose */
277 for (avail = width; avail > 0; avail--)
283 /* it fits; output the number */
286 /* output the LHS single digit */
312 /* output the exponent */
315 *a++ = 'E' + lowercase;
323 *a++ = (expon / 10) % 10 + '0';
324 *a++ = expon % 10 + '0';
327 /* output spaces on the end in G format */
336 /* finally, we can return */
346 ** atof1 - ASCII TO FLOATING CONVERSION
348 ** CODE derived from ~ingres/source/gutil/atof.c
350 ** Converts the string 'str' to floating point and stores the
351 ** result into the cell pointed to by 'val'.
353 ** The syntax which it accepts is pretty much what you would
354 ** expect. Basically, it is:
355 ** {<sp>} [+|-] {<sp>} {<digit>} [.{digit}] {<sp>} [<exp>]
356 ** where <exp> is "e" or "E" followed by an integer, <sp> is a
357 ** space character, <digit> is zero through nine, [] is zero or
358 ** one, and {} is zero or more.
361 ** str -- string to convert.
362 ** val -- pointer to place to put the result (which
363 ** must be type double).
367 ** -1 -- syntax error.
368 ** +1 -- overflow (not implemented).
375 atof1(char *str, double *val)
389 /* skip leading blanks */
390 while ((c = *p) != '\0')
397 /* handle possible sign */
407 /* skip blanks after sign */
408 while ((c = *p) != '\0')
415 /* start collecting the number to the decimal point */
420 if (c < '0' || c > '9')
422 v = v * 10.0 + (c - '0');
427 /* check for fractional part */
434 if (c < '0' || c > '9')
437 v += (c - '0') * fact;
442 /* skip blanks before possible exponent */
443 while ((c = *p) != '\0')
450 /* test for exponent */
451 if (c == 'e' || c == 'E')
454 expon = pg_atoi(p, sizeof(expon), '\0');
458 v *= pow(10.0, fact);
462 /* if no exponent, then nothing */
467 /* store the result and exit */