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