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