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