OSDN Git Service

8b6b43ac8945e9740be67280834b017e6894afa2
[pg-rex/syncrep.git] / 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.56 2003/08/04 00:43:25 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 ereport() upon bad input format or
55  * overflow.
56  */
57 int32
58 pg_atoi(char *s, int size, int c)
59 {
60         long            l;
61         char       *badp = NULL;
62
63         /*
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.
66          */
67         if (s == (char *) NULL)
68                 elog(ERROR, "NULL pointer");
69         if (*s == 0)
70                 ereport(ERROR,
71                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
72                                  errmsg("invalid input syntax for integer: \"%s\"",
73                                                 s)));
74
75         errno = 0;
76         l = strtol(s, &badp, 10);
77
78         /*
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.
82          */
83         if (errno && errno != ERANGE && errno != EINVAL)
84                 ereport(ERROR,
85                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
86                                  errmsg("invalid input syntax for integer: \"%s\"",
87                                                 s)));
88         if (badp && *badp && *badp != c)
89                 ereport(ERROR,
90                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
91                                  errmsg("invalid input syntax for integer: \"%s\"",
92                                                 s)));
93
94         switch (size)
95         {
96                 case sizeof(int32):
97                         if (errno == ERANGE
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
101 #endif
102                                 )
103                                 ereport(ERROR,
104                                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
105                                                  errmsg("%s is out of range for int4", s)));
106                         break;
107                 case sizeof(int16):
108                         if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
109                                 ereport(ERROR,
110                                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
111                                                  errmsg("%s is out of range for int2", s)));
112                         break;
113                 case sizeof(int8):
114                         if (errno == ERANGE || l < SCHAR_MIN || l > SCHAR_MAX)
115                                 ereport(ERROR,
116                                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
117                                                  errmsg("%s is out of range for int1", s)));
118                         break;
119                 default:
120                         elog(ERROR, "unsupported result size: %d", size);
121         }
122         return (int32) l;
123 }
124
125 /*
126  *              pg_itoa                 - converts a short int to its string represention
127  *
128  *              Note:
129  *                              previously based on ~ingres/source/gutil/atoi.c
130  *                              now uses vendor's sprintf conversion
131  */
132 void
133 pg_itoa(int16 i, char *a)
134 {
135         sprintf(a, "%hd", (short) i);
136 }
137
138 /*
139  *              pg_ltoa                 - converts a long int to its string represention
140  *
141  *              Note:
142  *                              previously based on ~ingres/source/gutil/atoi.c
143  *                              now uses vendor's sprintf conversion
144  */
145 void
146 pg_ltoa(int32 l, char *a)
147 {
148         sprintf(a, "%d", l);
149 }
150
151 /*
152  **  ftoa               - FLOATING POINT TO ASCII CONVERSION
153  **
154  **             CODE derived from ingres, ~ingres/source/gutil/ftoa.c
155  **
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
161  **             'format'.
162  **
163  **             'Format' can be:
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
167  **                                             use "E" format.
168  **                             n or N:  same as G, but decimal points will not always
169  **                                             be aligned.
170  **
171  **             If 'format' is upper case, the "E" comes out in upper case;
172  **             otherwise it comes out in lower case.
173  **
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').
177  */
178 #ifdef NOT_USED
179 int
180 ftoa(double value, char *ascii, int width, int prec1, char format)
181 {
182 #ifndef HAVE_FCVT
183         char            out[256];
184         char            fmt[256];
185         int                     ret;
186
187         sprintf(fmt, "%%%d.%d%c", width, prec1, format);
188         sprintf(out, fmt, value);
189         if ((ret = strlen(out)) > width)
190         {
191                 MemSet(ascii, '*', width - 2);
192                 ascii[width] = 0;
193                 return 0;
194         }
195         strcpy(ascii, out);
196         return ret;
197 #else
198         auto int        expon;
199         auto int        sign;
200         int                     avail = 0;
201         char       *a = NULL;
202         char       *p = NULL;
203         char            mode;
204         int                     lowercase;
205         int                     prec;
206
207 /*        extern char           *ecvt(), *fcvt();*/
208
209         prec = prec1;
210         mode = format;
211         lowercase = 'a' - 'A';
212         if (mode >= 'a')
213                 mode -= 'a' - 'A';
214         else
215                 lowercase = 0;
216
217         if (mode != 'E')
218         {
219                 /* try 'F' style output */
220                 p = fcvt(value, prec, &expon, &sign);
221                 avail = width;
222                 a = ascii;
223
224                 /* output sign */
225                 if (sign)
226                 {
227                         avail--;
228                         *a++ = '-';
229                 }
230
231                 /* output '0' before the decimal point */
232                 if (expon <= 0)
233                 {
234                         *a++ = '0';
235                         avail--;
236                 }
237
238                 /* compute space length left after dec pt and fraction */
239                 avail -= prec + 1;
240                 if (mode == 'G')
241                         avail -= 4;
242
243                 if (avail >= expon)
244                 {
245
246                         /* it fits.  output */
247                         while (expon > 0)
248                         {
249                                 /* output left of dp */
250                                 expon--;
251                                 if (*p)
252                                         *a++ = *p++;
253                                 else
254                                         *a++ = '0';
255                         }
256
257                         /* output fraction (right of dec pt) */
258                         avail = expon;
259                         goto frac_out;
260                 }
261                 /* won't fit; let's hope for G format */
262         }
263
264         if (mode != 'F')
265         {
266                 /* try to do E style output */
267                 p = ecvt(value, prec + 1, &expon, &sign);
268                 avail = width - 5;
269                 a = ascii;
270
271                 /* output the sign */
272                 if (sign)
273                 {
274                         *a++ = '-';
275                         avail--;
276                 }
277         }
278
279         /* check for field too small */
280         if (mode == 'F' || avail < prec)
281         {
282                 /* sorry joker, you lose */
283                 a = ascii;
284                 for (avail = width; avail > 0; avail--)
285                         *a++ = '*';
286                 *a = 0;
287                 return 0;
288         }
289
290         /* it fits; output the number */
291         mode = 'E';
292
293         /* output the LHS single digit */
294         *a++ = *p++;
295         expon--;
296
297         /* output the rhs */
298         avail = 1;
299
300 frac_out:
301         *a++ = '.';
302         while (prec > 0)
303         {
304                 prec--;
305                 if (avail < 0)
306                 {
307                         avail++;
308                         *a++ = '0';
309                 }
310                 else
311                 {
312                         if (*p)
313                                 *a++ = *p++;
314                         else
315                                 *a++ = '0';
316                 }
317         }
318
319         /* output the exponent */
320         if (mode == 'E')
321         {
322                 *a++ = 'E' + lowercase;
323                 if (expon < 0)
324                 {
325                         *a++ = '-';
326                         expon = -expon;
327                 }
328                 else
329                         *a++ = '+';
330                 *a++ = (expon / 10) % 10 + '0';
331                 *a++ = expon % 10 + '0';
332         }
333
334         /* output spaces on the end in G format */
335         if (mode == 'G')
336         {
337                 *a++ = ' ';
338                 *a++ = ' ';
339                 *a++ = ' ';
340                 *a++ = ' ';
341         }
342
343         /* finally, we can return */
344         *a = 0;
345         avail = a - ascii;
346         return avail;
347 #endif
348 }
349 #endif
350
351 /*
352  **   atof1             - ASCII TO FLOATING CONVERSION
353  **
354  **             CODE derived from ~ingres/source/gutil/atof.c
355  **
356  **             Converts the string 'str' to floating point and stores the
357  **             result into the cell pointed to by 'val'.
358  **
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.
365  **
366  **             Parameters:
367  **                             str -- string to convert.
368  **                             val -- pointer to place to put the result (which
369  **                                             must be type double).
370  **
371  **             Returns:
372  **                             zero -- ok.
373  **                             -1 -- syntax error.
374  **                             +1 -- overflow (not implemented).
375  **
376  **             Side Effects:
377  **                             clobbers *val.
378  */
379 #ifdef NOT_USED
380 int
381 atof1(char *str, double *val)
382 {
383         char       *p;
384         double          v;
385         double          fact;
386         int                     minus;
387         char            c;
388         int                     expon;
389         int                     gotmant;
390
391         v = 0.0;
392         p = str;
393         minus = 0;
394
395         /* skip leading blanks */
396         while ((c = *p) != '\0')
397         {
398                 if (c != ' ')
399                         break;
400                 p++;
401         }
402
403         /* handle possible sign */
404         switch (c)
405         {
406                 case '-':
407                         minus++;
408
409                 case '+':
410                         p++;
411         }
412
413         /* skip blanks after sign */
414         while ((c = *p) != '\0')
415         {
416                 if (c != ' ')
417                         break;
418                 p++;
419         }
420
421         /* start collecting the number to the decimal point */
422         gotmant = 0;
423         for (;;)
424         {
425                 c = *p;
426                 if (c < '0' || c > '9')
427                         break;
428                 v = v * 10.0 + (c - '0');
429                 gotmant++;
430                 p++;
431         }
432
433         /* check for fractional part */
434         if (c == '.')
435         {
436                 fact = 1.0;
437                 for (;;)
438                 {
439                         c = *++p;
440                         if (c < '0' || c > '9')
441                                 break;
442                         fact *= 0.1;
443                         v += (c - '0') * fact;
444                         gotmant++;
445                 }
446         }
447
448         /* skip blanks before possible exponent */
449         while ((c = *p) != '\0')
450         {
451                 if (c != ' ')
452                         break;
453                 p++;
454         }
455
456         /* test for exponent */
457         if (c == 'e' || c == 'E')
458         {
459                 p++;
460                 expon = pg_atoi(p, sizeof(expon), '\0');
461                 if (!gotmant)
462                         v = 1.0;
463                 fact = expon;
464                 v *= pow(10.0, fact);
465         }
466         else
467         {
468                 /* if no exponent, then nothing */
469                 if (c != 0)
470                         return -1;
471         }
472
473         /* store the result and exit */
474         if (minus)
475                 v = -v;
476         *val = v;
477         return 0;
478 }
479
480 #endif