]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/numutils.c
More cleanups. I can now compile without PORTNAME being defined n
[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.18 1997/12/19 02:08:01 scrappy 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 HAVE_FCVT
32 #  include <port-protos.h>              /* ecvt(), fcvt() */
33 #endif
34
35 #ifndef INT_MAX
36 #define INT_MAX (0x7FFFFFFFL)
37 #endif
38 #ifndef INT_MIN
39 #define INT_MIN (-0x80000000L)
40 #endif
41 #ifndef SHRT_MAX
42 #define SHRT_MAX (0x7FFF)
43 #endif
44 #ifndef SHRT_MIN
45 #define SHRT_MIN (-0x8000)
46 #endif
47 #ifndef SCHAR_MAX
48 #define SCHAR_MAX (0x7F)
49 #endif
50 #ifndef SCHAR_MIN
51 #define SCHAR_MIN (-0x80)
52 #endif
53
54 int32
55 pg_atoi(char *s, int size, int c)
56 {
57         long            l;
58         char       *badp = (char *) NULL;
59
60         Assert(s);
61
62         errno = 0;
63         l = strtol(s, &badp, 10);
64         if (errno)                                      /* strtol must set ERANGE */
65                 elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
66         if (badp && *badp && (*badp != c))
67                 elog(WARN, "pg_atoi: error in \"%s\": can\'t parse \"%s\"", s, badp);
68
69         switch (size)
70         {
71                 case sizeof(int32):
72 #ifdef HAS_LONG_LONG
73                         /* won't get ERANGE on these with 64-bit longs... */
74                         if (l < INT_MIN)
75                         {
76                                 errno = ERANGE;
77                                 elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
78                         }
79                         if (l > INT_MAX)
80                         {
81                                 errno = ERANGE;
82                                 elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
83                         }
84 #endif                                                  /* HAS_LONG_LONG */
85                         break;
86                 case sizeof(int16):
87                         if (l < SHRT_MIN)
88                         {
89                                 errno = ERANGE;
90                                 elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
91                         }
92                         if (l > SHRT_MAX)
93                         {
94                                 errno = ERANGE;
95                                 elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
96                         }
97                         break;
98                 case sizeof(int8):
99                         if (l < SCHAR_MIN)
100                         {
101                                 errno = ERANGE;
102                                 elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
103                         }
104                         if (l > SCHAR_MAX)
105                         {
106                                 errno = ERANGE;
107                                 elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
108                         }
109                         break;
110                 default:
111                         elog(WARN, "pg_atoi: invalid result size: %d", size);
112         }
113         return ((int32) l);
114 }
115
116 /*
117  *              itoa                    - converts a short int to its string represention
118  *
119  *              Note:
120  *                              previously based on ~ingres/source/gutil/atoi.c
121  *                              now uses vendor's sprintf conversion
122  */
123 void
124 itoa(int i, char *a)
125 {
126         sprintf(a, "%hd", (short) i);
127 }
128
129 /*
130  *              ltoa                    - converts a long int to its string represention
131  *
132  *              Note:
133  *                              previously based on ~ingres/source/gutil/atoi.c
134  *                              now uses vendor's sprintf conversion
135  */
136 void
137 ltoa(int32 l, char *a)
138 {
139         sprintf(a, "%d", l);
140 }
141
142 /*
143  **  ftoa               - FLOATING POINT TO ASCII CONVERSION
144  **
145  **             CODE derived from ingres, ~ingres/source/gutil/ftoa.c
146  **
147  **             'Value' is converted to an ascii character string and stored
148  **             into 'ascii'.  Ascii should have room for at least 'width' + 1
149  **             characters.  'Width' is the width of the output field (max).
150  **             'Prec' is the number of characters to put after the decimal
151  **             point.  The format of the output string is controlled by
152  **             'format'.
153  **
154  **             'Format' can be:
155  **                             e or E: "E" format output
156  **                             f or F:  "F" format output
157  **                             g or G:  "F" format output if it will fit, otherwise
158  **                                             use "E" format.
159  **                             n or N:  same as G, but decimal points will not always
160  **                                             be aligned.
161  **
162  **             If 'format' is upper case, the "E" comes out in upper case;
163  **             otherwise it comes out in lower case.
164  **
165  **             When the field width is not big enough, it fills the field with
166  **             stars ("*****") and returns zero.  Normal return is the width
167  **             of the output field (sometimes shorter than 'width').
168  */
169 #ifdef NOT_USED
170 int
171 ftoa(double value, char *ascii, int width, int prec1, char format)
172 {
173 #ifndef HAVE_FCVT
174         char            out[256];
175         char            fmt[256];
176         int                     ret;
177
178         sprintf(fmt, "%%%d.%d%c", width, prec1, format);
179         sprintf(out, fmt, value);
180         if ((ret = strlen(out)) > width)
181         {
182                 MemSet(ascii, '*', width - 2);
183                 ascii[width] = 0;
184                 return (0);
185         }
186         strcpy(ascii, out);
187         return (ret);
188 #else
189         auto int        expon;
190         auto int        sign;
191         register int avail = 0;
192         register char *a = NULL;
193         register char *p = NULL;
194         char            mode;
195         int                     lowercase;
196         int                     prec;
197
198 /*        extern char           *ecvt(), *fcvt();*/
199
200         prec = prec1;
201         mode = format;
202         lowercase = 'a' - 'A';
203         if (mode >= 'a')
204                 mode -= 'a' - 'A';
205         else
206                 lowercase = 0;
207
208         if (mode != 'E')
209         {
210                 /* try 'F' style output */
211                 p = fcvt(value, prec, &expon, &sign);
212                 avail = width;
213                 a = ascii;
214
215                 /* output sign */
216                 if (sign)
217                 {
218                         avail--;
219                         *a++ = '-';
220                 }
221
222                 /* output '0' before the decimal point */
223                 if (expon <= 0)
224                 {
225                         *a++ = '0';
226                         avail--;
227                 }
228
229                 /* compute space length left after dec pt and fraction */
230                 avail -= prec + 1;
231                 if (mode == 'G')
232                         avail -= 4;
233
234                 if (avail >= expon)
235                 {
236
237                         /* it fits.  output */
238                         while (expon > 0)
239                         {
240                                 /* output left of dp */
241                                 expon--;
242                                 if (*p)
243                                 {
244                                         *a++ = *p++;
245                                 }
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         register char *p;
378         double          v;
379         double          fact;
380         int                     minus;
381         register char c;
382         int                     expon;
383         register 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