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