]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/numutils.c
Fix pgproc names over 15 chars in output. Add strNcpy() function. remove 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.11 1997/08/12 20:16:02 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 #ifndef HAVE_FCVT
141         char    out[256];
142         char    fmt[256];
143         int     ret;
144
145         (void) sprintf(fmt, "%%%d.%d%c", width, prec1, format);
146         (void) sprintf(out, fmt, value);
147         if ((ret = strlen(out)) > width) {
148                 memset(ascii, '*', width - 2);
149                 ascii[width] = 0;
150                 return(0);
151         }
152         strcpy(ascii, out);
153         return(ret);
154 #else
155     auto int    expon;
156     auto int    sign;
157     register int        avail = 0;
158     register char       *a = NULL;
159     register char       *p = NULL;
160     char                mode;
161     int         lowercase;
162     int         prec;
163 /*    extern char       *ecvt(), *fcvt();*/
164     
165     prec = prec1;
166     mode = format;
167     lowercase = 'a' - 'A';
168     if (mode >= 'a')
169         mode -= 'a' - 'A';
170     else
171         lowercase = 0;
172     
173     if (mode != 'E') {
174         /* try 'F' style output */
175         p = fcvt(value, prec, &expon, &sign);
176         avail = width;
177         a = ascii;
178         
179         /* output sign */
180         if (sign) {
181             avail--;
182             *a++ = '-';
183         }
184         
185         /* output '0' before the decimal point */
186         if (expon <= 0) {
187             *a++ = '0';
188             avail--;
189         }
190         
191         /* compute space length left after dec pt and fraction */
192         avail -= prec + 1;
193         if (mode == 'G')
194             avail -= 4;
195         
196         if (avail >= expon) {
197             
198             /* it fits.  output */
199             while (expon > 0) {
200                 /* output left of dp */
201                 expon--;
202                 if (*p) {
203                     *a++ = *p++;
204                 } else
205                     *a++ = '0';
206             }
207             
208             /* output fraction (right of dec pt) */
209             avail = expon;
210             goto frac_out;
211         }
212         /* won't fit; let's hope for G format */
213     }
214     
215     if (mode != 'F') {
216         /* try to do E style output */
217         p = ecvt(value, prec + 1, &expon, &sign);
218         avail = width - 5;
219         a = ascii;
220         
221         /* output the sign */
222         if (sign) {
223             *a++ = '-';
224             avail--;
225         }
226     }
227     
228     /* check for field too small */
229     if (mode == 'F' || avail < prec) {
230         /* sorry joker, you lose */
231         a = ascii;
232         for (avail = width; avail > 0; avail--)
233             *a++ = '*';
234         *a = 0;
235         return (0);
236     }
237     
238     /* it fits; output the number */
239     mode = 'E';
240     
241     /* output the LHS single digit */
242     *a++ = *p++;
243     expon--;
244     
245     /* output the rhs */
246     avail = 1;
247     
248  frac_out:
249     *a++ = '.';
250     while (prec > 0) {
251         prec--;
252         if (avail < 0) {
253             avail++;
254             *a++ = '0';
255         } else {
256             if (*p)
257                 *a++ = *p++;
258             else
259                 *a++ = '0';
260         }
261     }
262     
263     /* output the exponent */
264     if (mode == 'E') {
265         *a++ = 'E' + lowercase;
266         if (expon < 0) {
267             *a++ = '-';
268             expon = -expon;
269         } else
270             *a++ = '+';
271         *a++ = (expon / 10) % 10 + '0';
272         *a++ = expon % 10 + '0';
273     }
274     
275     /* output spaces on the end in G format */
276     if (mode == 'G') {
277         *a++ = ' ';
278         *a++ = ' ';
279         *a++ = ' ';
280         *a++ = ' ';
281     }
282     
283     /* finally, we can return */
284     *a = 0;
285     avail = a - ascii;
286     return (avail);
287 #endif /* !BSD44_derived */
288 }
289
290 /*
291  **   atof1     - ASCII TO FLOATING CONVERSION
292  **
293  **     CODE derived from ~ingres/source/gutil/atof.c
294  **
295  **     Converts the string 'str' to floating point and stores the
296  **     result into the cell pointed to by 'val'.
297  **
298  **     The syntax which it accepts is pretty much what you would
299  **     expect.  Basically, it is:
300  **             {<sp>} [+|-] {<sp>} {<digit>} [.{digit}] {<sp>} [<exp>]
301  **     where <exp> is "e" or "E" followed by an integer, <sp> is a
302  **     space character, <digit> is zero through nine, [] is zero or
303  **     one, and {} is zero or more.
304  **
305  **     Parameters:
306  **             str -- string to convert.
307  **             val -- pointer to place to put the result (which
308  **                     must be type double).
309  **
310  **     Returns:
311  **             zero -- ok.
312  **             -1 -- syntax error.
313  **             +1 -- overflow (not implemented).
314  **
315  **     Side Effects:
316  **             clobbers *val.
317  */
318 int
319 atof1(char *str, double *val)
320 {
321     register char       *p;
322     double              v;
323     double              fact;
324     int         minus;
325     register char       c;
326     int         expon;
327     register int        gotmant;
328     
329     v = 0.0;
330     p = str;
331     minus = 0;
332     
333     /* skip leading blanks */
334     while ((c = *p) != '\0') {
335         if (c != ' ')
336             break;
337         p++;
338     }
339     
340     /* handle possible sign */
341     switch (c) {
342     case '-':
343         minus++;
344         
345     case '+':
346         p++;
347     }
348     
349     /* skip blanks after sign */
350     while ((c = *p) != '\0') {
351         if (c != ' ')
352             break;
353         p++;
354     }
355     
356     /* start collecting the number to the decimal point */
357     gotmant = 0;
358     for (;;) {
359         c = *p;
360         if (c < '0' || c > '9')
361             break;
362         v = v * 10.0 + (c - '0');
363         gotmant++;
364         p++;
365     }
366     
367     /* check for fractional part */
368     if (c == '.') {
369         fact = 1.0;
370         for (;;) {
371             c = *++p;
372             if (c < '0' || c > '9')
373                 break;
374             fact *= 0.1;
375             v += (c - '0') * fact;
376             gotmant++;
377         }
378     }
379     
380     /* skip blanks before possible exponent */
381     while ((c = *p) != '\0') {
382         if (c != ' ')
383             break;
384         p++;
385     }
386     
387     /* test for exponent */
388     if (c == 'e' || c == 'E') {
389         p++;
390         expon = pg_atoi(p, sizeof(expon), '\0');
391         if (!gotmant)
392             v = 1.0;
393         fact = expon;
394         v *= pow(10.0, fact);
395     } else {
396         /* if no exponent, then nothing */
397         if (c != 0)
398             return (-1);
399     }
400     
401     /* store the result and exit */
402     if (minus)
403         v = -v;
404     *val = v;
405     return (0);
406 }