]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/numutils.c
pgindent run.
[postgresql] / src / backend / utils / adt / numutils.c
1 /*-------------------------------------------------------------------------
2  *
3  * numutils.c
4  *        utility functions for I/O of built-in numeric types.
5  *
6  *              integer:                                pg_itoa, pg_ltoa
7  *              floating point:                 ftoa, atof1
8  *
9  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
10  * Portions Copyright (c) 1994, Regents of the University of California
11  *
12  *
13  * IDENTIFICATION
14  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/numutils.c,v 1.54 2002/09/04 20:31:28 momjian Exp $
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19
20 #include <errno.h>
21 #include <math.h>
22 #include <limits.h>
23
24 #include "utils/builtins.h"
25
26 #ifndef INT_MAX
27 #define INT_MAX (0x7FFFFFFFL)
28 #endif
29 #ifndef INT_MIN
30 #define INT_MIN (-INT_MAX-1)
31 #endif
32 #ifndef SHRT_MAX
33 #define SHRT_MAX (0x7FFF)
34 #endif
35 #ifndef SHRT_MIN
36 #define SHRT_MIN (-SHRT_MAX-1)
37 #endif
38 #ifndef SCHAR_MAX
39 #define SCHAR_MAX (0x7F)
40 #endif
41 #ifndef SCHAR_MIN
42 #define SCHAR_MIN (-SCHAR_MAX-1)
43 #endif
44
45
46 /*
47  * pg_atoi: convert string to integer
48  *
49  * size is the sizeof() the desired integral result (1, 2, or 4 bytes).
50  *
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.
53  *
54  * Unlike plain atoi(), this will throw elog() upon bad input format or
55  * overflow.
56  */
57 int32
58 pg_atoi(char *s, int size, int c)
59 {
60         long            l = 0;
61         char       *badp = NULL;
62
63         errno = 0;
64
65         /*
66          * Some versions of strtol treat the empty string as an error, but
67          * some seem not to.  Make an explicit test to be sure we catch it.
68          */
69
70         if (s == (char *) NULL)
71                 elog(ERROR, "pg_atoi: NULL pointer");
72         else if (*s == 0)
73                 elog(ERROR, "pg_atoi: zero-length string");
74         else
75                 l = strtol(s, &badp, 10);
76
77         /*
78          * strtol() normally only sets ERANGE.  On some systems it also may
79          * set EINVAL, which simply means it couldn't parse the input string.
80          * This is handled by the second "if" consistent across platforms.
81          */
82         if (errno && errno != EINVAL)
83                 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
84         if (badp && *badp && *badp != c)
85                 elog(ERROR, "pg_atoi: error in \"%s\": can\'t parse \"%s\"", s, badp);
86
87         switch (size)
88         {
89                 case sizeof(int32):
90 #if defined(HAVE_LONG_INT_64)
91                         /* won't get ERANGE on these with 64-bit longs... */
92                         if (l < INT_MIN)
93                         {
94                                 errno = ERANGE;
95                                 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
96                         }
97                         if (l > INT_MAX)
98                         {
99                                 errno = ERANGE;
100                                 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
101                         }
102 #endif   /* HAVE_LONG_INT_64 */
103                         break;
104                 case sizeof(int16):
105                         if (l < SHRT_MIN)
106                         {
107                                 errno = ERANGE;
108                                 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
109                         }
110                         if (l > SHRT_MAX)
111                         {
112                                 errno = ERANGE;
113                                 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
114                         }
115                         break;
116                 case sizeof(int8):
117                         if (l < SCHAR_MIN)
118                         {
119                                 errno = ERANGE;
120                                 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
121                         }
122                         if (l > SCHAR_MAX)
123                         {
124                                 errno = ERANGE;
125                                 elog(ERROR, "pg_atoi: error reading \"%s\": %m", s);
126                         }
127                         break;
128                 default:
129                         elog(ERROR, "pg_atoi: invalid result size: %d", size);
130         }
131         return (int32) l;
132 }
133
134 /*
135  *              pg_itoa                 - converts a short int to its string represention
136  *
137  *              Note:
138  *                              previously based on ~ingres/source/gutil/atoi.c
139  *                              now uses vendor's sprintf conversion
140  */
141 void
142 pg_itoa(int16 i, char *a)
143 {
144         sprintf(a, "%hd", (short) i);
145 }
146
147 /*
148  *              pg_ltoa                 - converts a long int to its string represention
149  *
150  *              Note:
151  *                              previously based on ~ingres/source/gutil/atoi.c
152  *                              now uses vendor's sprintf conversion
153  */
154 void
155 pg_ltoa(int32 l, char *a)
156 {
157         sprintf(a, "%d", l);
158 }
159
160 /*
161  **  ftoa               - FLOATING POINT TO ASCII CONVERSION
162  **
163  **             CODE derived from ingres, ~ingres/source/gutil/ftoa.c
164  **
165  **             'Value' is converted to an ascii character string and stored
166  **             into 'ascii'.  Ascii should have room for at least 'width' + 1
167  **             characters.  'Width' is the width of the output field (max).
168  **             'Prec' is the number of characters to put after the decimal
169  **             point.  The format of the output string is controlled by
170  **             'format'.
171  **
172  **             'Format' can be:
173  **                             e or E: "E" format output
174  **                             f or F:  "F" format output
175  **                             g or G:  "F" format output if it will fit, otherwise
176  **                                             use "E" format.
177  **                             n or N:  same as G, but decimal points will not always
178  **                                             be aligned.
179  **
180  **             If 'format' is upper case, the "E" comes out in upper case;
181  **             otherwise it comes out in lower case.
182  **
183  **             When the field width is not big enough, it fills the field with
184  **             stars ("*****") and returns zero.  Normal return is the width
185  **             of the output field (sometimes shorter than 'width').
186  */
187 #ifdef NOT_USED
188 int
189 ftoa(double value, char *ascii, int width, int prec1, char format)
190 {
191 #ifndef HAVE_FCVT
192         char            out[256];
193         char            fmt[256];
194         int                     ret;
195
196         sprintf(fmt, "%%%d.%d%c", width, prec1, format);
197         sprintf(out, fmt, value);
198         if ((ret = strlen(out)) > width)
199         {
200                 MemSet(ascii, '*', width - 2);
201                 ascii[width] = 0;
202                 return 0;
203         }
204         strcpy(ascii, out);
205         return ret;
206 #else
207         auto int        expon;
208         auto int        sign;
209         int                     avail = 0;
210         char       *a = NULL;
211         char       *p = NULL;
212         char            mode;
213         int                     lowercase;
214         int                     prec;
215
216 /*        extern char           *ecvt(), *fcvt();*/
217
218         prec = prec1;
219         mode = format;
220         lowercase = 'a' - 'A';
221         if (mode >= 'a')
222                 mode -= 'a' - 'A';
223         else
224                 lowercase = 0;
225
226         if (mode != 'E')
227         {
228                 /* try 'F' style output */
229                 p = fcvt(value, prec, &expon, &sign);
230                 avail = width;
231                 a = ascii;
232
233                 /* output sign */
234                 if (sign)
235                 {
236                         avail--;
237                         *a++ = '-';
238                 }
239
240                 /* output '0' before the decimal point */
241                 if (expon <= 0)
242                 {
243                         *a++ = '0';
244                         avail--;
245                 }
246
247                 /* compute space length left after dec pt and fraction */
248                 avail -= prec + 1;
249                 if (mode == 'G')
250                         avail -= 4;
251
252                 if (avail >= expon)
253                 {
254
255                         /* it fits.  output */
256                         while (expon > 0)
257                         {
258                                 /* output left of dp */
259                                 expon--;
260                                 if (*p)
261                                         *a++ = *p++;
262                                 else
263                                         *a++ = '0';
264                         }
265
266                         /* output fraction (right of dec pt) */
267                         avail = expon;
268                         goto frac_out;
269                 }
270                 /* won't fit; let's hope for G format */
271         }
272
273         if (mode != 'F')
274         {
275                 /* try to do E style output */
276                 p = ecvt(value, prec + 1, &expon, &sign);
277                 avail = width - 5;
278                 a = ascii;
279
280                 /* output the sign */
281                 if (sign)
282                 {
283                         *a++ = '-';
284                         avail--;
285                 }
286         }
287
288         /* check for field too small */
289         if (mode == 'F' || avail < prec)
290         {
291                 /* sorry joker, you lose */
292                 a = ascii;
293                 for (avail = width; avail > 0; avail--)
294                         *a++ = '*';
295                 *a = 0;
296                 return 0;
297         }
298
299         /* it fits; output the number */
300         mode = 'E';
301
302         /* output the LHS single digit */
303         *a++ = *p++;
304         expon--;
305
306         /* output the rhs */
307         avail = 1;
308
309 frac_out:
310         *a++ = '.';
311         while (prec > 0)
312         {
313                 prec--;
314                 if (avail < 0)
315                 {
316                         avail++;
317                         *a++ = '0';
318                 }
319                 else
320                 {
321                         if (*p)
322                                 *a++ = *p++;
323                         else
324                                 *a++ = '0';
325                 }
326         }
327
328         /* output the exponent */
329         if (mode == 'E')
330         {
331                 *a++ = 'E' + lowercase;
332                 if (expon < 0)
333                 {
334                         *a++ = '-';
335                         expon = -expon;
336                 }
337                 else
338                         *a++ = '+';
339                 *a++ = (expon / 10) % 10 + '0';
340                 *a++ = expon % 10 + '0';
341         }
342
343         /* output spaces on the end in G format */
344         if (mode == 'G')
345         {
346                 *a++ = ' ';
347                 *a++ = ' ';
348                 *a++ = ' ';
349                 *a++ = ' ';
350         }
351
352         /* finally, we can return */
353         *a = 0;
354         avail = a - ascii;
355         return avail;
356 #endif
357 }
358 #endif
359
360 /*
361  **   atof1             - ASCII TO FLOATING CONVERSION
362  **
363  **             CODE derived from ~ingres/source/gutil/atof.c
364  **
365  **             Converts the string 'str' to floating point and stores the
366  **             result into the cell pointed to by 'val'.
367  **
368  **             The syntax which it accepts is pretty much what you would
369  **             expect.  Basically, it is:
370  **                             {<sp>} [+|-] {<sp>} {<digit>} [.{digit}] {<sp>} [<exp>]
371  **             where <exp> is "e" or "E" followed by an integer, <sp> is a
372  **             space character, <digit> is zero through nine, [] is zero or
373  **             one, and {} is zero or more.
374  **
375  **             Parameters:
376  **                             str -- string to convert.
377  **                             val -- pointer to place to put the result (which
378  **                                             must be type double).
379  **
380  **             Returns:
381  **                             zero -- ok.
382  **                             -1 -- syntax error.
383  **                             +1 -- overflow (not implemented).
384  **
385  **             Side Effects:
386  **                             clobbers *val.
387  */
388 #ifdef NOT_USED
389 int
390 atof1(char *str, double *val)
391 {
392         char       *p;
393         double          v;
394         double          fact;
395         int                     minus;
396         char            c;
397         int                     expon;
398         int                     gotmant;
399
400         v = 0.0;
401         p = str;
402         minus = 0;
403
404         /* skip leading blanks */
405         while ((c = *p) != '\0')
406         {
407                 if (c != ' ')
408                         break;
409                 p++;
410         }
411
412         /* handle possible sign */
413         switch (c)
414         {
415                 case '-':
416                         minus++;
417
418                 case '+':
419                         p++;
420         }
421
422         /* skip blanks after sign */
423         while ((c = *p) != '\0')
424         {
425                 if (c != ' ')
426                         break;
427                 p++;
428         }
429
430         /* start collecting the number to the decimal point */
431         gotmant = 0;
432         for (;;)
433         {
434                 c = *p;
435                 if (c < '0' || c > '9')
436                         break;
437                 v = v * 10.0 + (c - '0');
438                 gotmant++;
439                 p++;
440         }
441
442         /* check for fractional part */
443         if (c == '.')
444         {
445                 fact = 1.0;
446                 for (;;)
447                 {
448                         c = *++p;
449                         if (c < '0' || c > '9')
450                                 break;
451                         fact *= 0.1;
452                         v += (c - '0') * fact;
453                         gotmant++;
454                 }
455         }
456
457         /* skip blanks before possible exponent */
458         while ((c = *p) != '\0')
459         {
460                 if (c != ' ')
461                         break;
462                 p++;
463         }
464
465         /* test for exponent */
466         if (c == 'e' || c == 'E')
467         {
468                 p++;
469                 expon = pg_atoi(p, sizeof(expon), '\0');
470                 if (!gotmant)
471                         v = 1.0;
472                 fact = expon;
473                 v *= pow(10.0, fact);
474         }
475         else
476         {
477                 /* if no exponent, then nothing */
478                 if (c != 0)
479                         return -1;
480         }
481
482         /* store the result and exit */
483         if (minus)
484                 v = -v;
485         *val = v;
486         return 0;
487 }
488
489 #endif