1 /*
2  *  Generic Call Interface for Rexx
3  *  Copyright � 2003-2004, Florian Gro�e-Coosmann
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public
16  *  License along with this library; if not, write to the Free
17  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * ----------------------------------------------------------------------------
20  *
21  * This file converts numerical string values to binary values and vice versa.
22  *
23  * Supported datatypes must be configured from outside in the file
24  * gci_convert.h. We need functions for parsing and printing floating points
25  * and integers.
26  *
27  * We support integers with a size of a power of 2 only, typically
28  * 1, 2, 4, 8 and probably 16; every type with a smaller value will be
29  * accepted automatically.
30  *
31  * This is expected by the include file to be defined:
32  * GCI_I_x  signed integer data type with x bytes.
33  * GCI_I_xm minimum value for GCI_I_x.
34  * GCI_I_xM maximum value for GCI_I_x.
35  * GCI_Ir   function for converting GCI_I_x, x largest of all x, which
36  *          converts a string into a binary representation. The function
37  *          must behave as strtol with the fitting data type.
38  * GCI_Iw   function for converting GCI_I_x, x largest of all x, which
39  *          converts a binary representation of a number into a zero
40  *          terminated string. The prototype must fit "GCI_Iw(string,GCI_I)".
41  *          No error throwing is allowed. The maximum number of characters to
42  *          write is 127. The function must return the length of string
43  *          without the terminating '\0'.
44  *
45  *
46  * GCI_U_x
47  * GCI_U_xm
48  * GCI_U_xM
49  * GCI_Ur
50  * GCI_Uw   same as above but for unsigned datatypes.
51  *
52  * GCI_F_x
53  * GCI_F_xm
54  * GCI_F_xM
55  * GCI_Fr
56  * GCI_Fw   same as above but for floating point data types. GCI_Fw may
57  *          write a maximum of 127 characters and may use "NaN", etc to
58  *          present anomal numbers.
59  *
60  *
61  * One can take advantage of strtobigl and strtobigul for GCI_Ir and GCI_Ur
62  * is NEED_STRTOBIGL or NEED_STRTOBIGUL are defined. They are slow but work.
63  *
64  * strtobigf can be used for GCI_Fr if NEED_STRTOBIGF is defined. In this case,
65  * F_SCAN must be defined and should be the scanf() compatible mask for parsing
66  * a GCI_F_x value. Most systems need a '#define F_SCAN "%Lf"' in this case.
67  */
68 
69 #include "gci_convert.h"
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <assert.h>
74 #include <errno.h>
75 #include <ctype.h>
76 
77 #undef GCI_I
78 #undef GCI_Imax
79 #undef GCI_U
80 #undef GCI_Umax
81 #undef GCI_F
82 #undef GCI_Fmax
83 #undef GCI_max
84 
85 /*
86  * Determine the maximum size for each family.
87  */
88 #if   defined(GCI_I_16)
89 # define GCI_I    GCI_I_16
90 # define GCI_Imax 16
91 # define GCI_Im   GCI_I_16m
92 # define GCI_IM   GCI_I_16M
93 #elif defined(GCI_I_8)
94 # define GCI_I    GCI_I_8
95 # define GCI_Imax 8
96 # define GCI_Im   GCI_I_8m
97 # define GCI_IM   GCI_I_8M
98 #else
99 # define GCI_I    GCI_I_4
100 # define GCI_Imax 4
101 # define GCI_Im   GCI_I_4m
102 # define GCI_IM   GCI_I_4M
103 #endif
104 
105 #if   defined(GCI_U_16)
106 # define GCI_U    GCI_U_16
107 # define GCI_Umax 16
108 # define GCI_UM   GCI_U_16M
109 #elif defined(GCI_U_8)
110 # define GCI_U    GCI_U_8
111 # define GCI_Umax 8
112 # define GCI_UM   GCI_U_8M
113 #else
114 # define GCI_U    GCI_U_4
115 # define GCI_Umax 4
116 # define GCI_UM   GCI_U_4M
117 #endif
118 
119 #if   defined(GCI_F_16)
120 # define GCI_F    GCI_F_16
121 # define GCI_Fmax 16
122 #elif defined(GCI_F_12)
123 # define GCI_F    GCI_F_12
124 # define GCI_Fmax 12
125 #elif defined(GCI_F_10)
126 # define GCI_F    GCI_F_10
127 # define GCI_Fmax 10
128 #elif defined(GCI_F_8)
129 # define GCI_F    GCI_F_8
130 # define GCI_Fmax 8
131 #elif defined(GCI_F_4)
132 # define GCI_F    GCI_F_4
133 # define GCI_Fmax 4
134 #else
135 # define GCI_Fmax 0
136 #endif
137 
138 #if   ( GCI_Imax >= GCI_Umax ) && ( GCI_Imax >= GCI_Fmax )
139 # define GCI_max GCI_Imax
140 #elif ( GCI_Umax >= GCI_Imax ) && ( GCI_Umax >= GCI_Fmax )
141 # define GCI_max GCI_Umax
142 #else
143 # define GCI_max GCI_Fmax
144 #endif
145 
146 /*
147  * Create a table for conversion functions. We know the maximum entry
148  * count now.
149  */
150 static struct {
151    GCI_result (*s2ifunc)( void *hidden, const char *str, int strsize,
152                           void *target );
153    GCI_result (*s2ufunc)( void *hidden, const char *str, int strsize,
154                           void *target );
155    GCI_result (*s2ffunc)( void *hidden, const char *str, int strsize,
156                           void *target );
157    GCI_result (*i2sfunc)( void *hidden, const void *data, char *str,
158                           int *strsize );
159    GCI_result (*u2sfunc)( void *hidden, const void *data, char *str,
160                           int *strsize );
161    GCI_result (*f2sfunc)( void *hidden, const void *data, char *str,
162                           int *strsize );
163 } functable[GCI_max+1] = {
164    {NULL, },
165 };
166 static int functable_assigned = 0;
167 
168 #ifdef NEED_STRTOBIGL
strtobigl(void * hidden,const char * nptr,char ** end,int base)169 static GCI_I strtobigl( void *hidden, const char *nptr, char **end, int base )
170 {
171    int neg = 0;
172    char *run = (char *) nptr;
173    GCI_I retval = 0;
174 
175    (hidden = hidden);
176 
177    assert( base == 10 );
178 
179    while ( GCI_isspace( *run ) )
180       run++;
181 
182    if ( *run == '-' )
183    {
184       neg = 1;
185       run++;
186    }
187    if ( !GCI_isdigit( *run ) )
188    {
189       *end = (char *) nptr;
190       return 0;
191    }
192 
193    while ( GCI_isdigit( *run ) )
194    {
195       if ( neg )
196       {
197          if ( retval <= GCI_Im / 10 )
198          {
199             if ( retval == GCI_Im / 10 )
200             {
201                if ( (char ) -( GCI_Im - 10 * retval ) < ( *run - '0' ) )
202                {
203                   retval = GCI_Im;
204                   errno = ERANGE;
205                }
206                else
207                {
208                   retval *= 10;
209                   retval -= ( GCI_I ) ( *run - '0' );
210                }
211             }
212             else
213             {
214                retval = GCI_Im;
215                errno = ERANGE;
216             }
217          }
218          else
219          {
220             retval *= 10;
221             retval -= ( GCI_I ) ( *run - '0' );
222          }
223       }
224       else
225       {
226          if ( retval >= GCI_IM / 10 )
227          {
228             if ( retval == GCI_IM / 10 )
229             {
230                if ( (char ) ( GCI_IM - 10 * retval ) < ( *run - '0' ) )
231                {
232                   retval = GCI_IM;
233                   errno = ERANGE;
234                }
235                else
236                {
237                   retval *= 10;
238                   retval += ( GCI_I ) ( *run - '0' );
239                }
240             }
241             else
242             {
243                retval = GCI_IM;
244                errno = ERANGE;
245             }
246          }
247          else
248          {
249             retval *= 10;
250             retval += ( GCI_I ) ( *run - '0' );
251          }
252       }
253       run++;
254    }
255 
256    *end = run;
257 
258    return retval;
259 }
260 #endif
261 
262 #ifdef NEED_STRTOBIGUL
strtobigul(void * hidden,const char * nptr,char ** end,int base)263 static GCI_U strtobigul( void *hidden, const char *nptr, char **end, int base )
264 {
265    char *run = (char *) nptr;
266    GCI_U retval = 0;
267 
268    (hidden = hidden);
269 
270    assert( base == 10 );
271 
272    while ( GCI_isspace( *run ) )
273       run++;
274 
275    if ( !GCI_isdigit( *run ) )
276    {
277       *end = (char *) nptr;
278       return 0;
279    }
280 
281    while ( GCI_isdigit( *run ) )
282    {
283       if ( retval >= GCI_UM / 10 )
284       {
285          if ( retval == GCI_UM / 10 )
286          {
287             if ( (char ) ( GCI_UM - 10 * retval ) < ( *run - '0' ) )
288             {
289                retval = GCI_UM;
290                errno = ERANGE;
291             }
292             else
293             {
294                retval *= 10;
295                retval += ( GCI_U ) ( *run - '0' );
296             }
297          }
298          else
299          {
300             retval = GCI_UM;
301             errno = ERANGE;
302          }
303       }
304       else
305       {
306          retval *= 10;
307          retval += ( GCI_U ) ( *run - '0' );
308       }
309       run++;
310    }
311 
312    *end = run;
313 
314    return retval;
315 }
316 #endif
317 
318 #ifdef NEED_STRTOBIGF
strtobigf(const char * nptr,char ** end)319 static GCI_F strtobigf( const char *nptr, char **end )
320 {
321    char c;
322    GCI_F f;
323    int rc;
324 
325    errno = 0;
326    rc = sscanf( nptr, F_SCAN " %c", &f, &c );
327    if ( rc <= 0 )
328    {
329       *end = (char *) nptr;
330       if ( !errno )
331          errno = ERANGE;
332       return f; /* pro forma */
333    }
334 
335    if ( rc == 2 )
336    {
337       if ( ( *end = strrchr( nptr, c ) ) == NULL )
338          *end = (char *) nptr;
339    }
340    else
341       *end = (char *) nptr + strlen( nptr );
342 
343    return f;
344 }
345 #endif
346 
347 /*
348  * preparenum chops off leading and trailing whitespaces from *str with the
349  * initial length of *size. Leading zeros will be cut off, too.
350  * *str and *size represent the final string after the stripping.
351  * A resulting length of 0 may occur only if the complete string contain
352  * whitespaces, only.
353  */
preparenum(void * hidden,const char ** str,int * size)354 static void preparenum( void *hidden,
355                         const char **str,
356                         int *size )
357 {
358    const char *s = *str;
359    int len = *size;
360 
361    /*
362     * We prepare the number by hand and strip away blanks and useless zeros.
363     */
364    while ( len && GCI_isspace( *s ) )
365    {
366       s++;
367       len--;
368    }
369    if ( !len )
370    {
371       *size = 0;
372       return;
373    }
374 
375    /*
376     * We know from the previous test that at least one non-space exists.
377     */
378    while ( GCI_isspace( s[len - 1] ) )
379    {
380       len--;
381    }
382 
383    /*
384     * At least one non-space exist. Strip leading zeros; if no character
385     * remains, we have cut off one or more zeros. Undo one step then.
386     */
387    while ( len && ( *s == '0' ) )
388    {
389       s++;
390       len--;
391    }
392    if ( !len )
393    {
394       s--;
395       len = 1;
396    }
397 
398    *str = s;
399    *size = len;
400 }
401 
402 /*
403  * iswhole returns 1 exactly if all characters in str are decimal digits,
404  * 0 otherwise.
405  */
iswhole(void * hidden,const char * str,int size)406 static int iswhole( void *hidden,
407                     const char *str,
408                     int size )
409 {
410    while ( size && GCI_isdigit( *str ) )
411    {
412       str++;
413       size--;
414    }
415    return !size;
416 }
417 
418 /*
419  * string2int is the basic routine which implements GCI_Ir. size characters
420  * of str (not strongly 0-terminated) are converted and the number is placed
421  * in *retval.
422  *
423  * The string may contain garbage whitespace.
424  *
425  * The return code may be GCI_OK, GCI_WrongInput, GCI_NumberRange.
426  */
string2int(void * hidden,const char * str,int size,GCI_I * retval)427 static GCI_result string2int( void *hidden,
428                               const char *str,
429                               int size,
430                               GCI_I *retval )
431 {
432    char buf[80]; /* enough even for 256 bit numbers */
433    char *p;
434    int rc;
435 
436    preparenum( hidden, &str, &size );
437    if ( !size || ( size > (int) sizeof( buf ) - 1 ) )
438       return GCI_WrongInput;
439 
440    if ( ( *str == '-' ) || ( *str == '+' ) )
441       rc = iswhole( hidden, str + 1, size - 1 );
442    else
443       rc = iswhole( hidden, str, size );
444    if ( !rc )
445       return GCI_WrongInput;
446 
447    memcpy( buf, str, size );
448    buf[size] = '\0';
449 
450    /*
451     * Carefully try to detect an overflow. We have to set errno for that
452     * cases where MAX_??? is given in str.
453     */
454    errno = 0;
455    *retval = GCI_Ir( buf, &p, 10 );
456    if ( ( *p != '\0' ) || errno )
457       return GCI_NumberRange;
458 
459    return GCI_OK;
460 }
461 
462 /*
463  * int2string is the basic routine which implements GCI_Iw. bin is converted
464  * into a string which is placed into str. strsize must hold the buffer width
465  * of str and must be greater than 79.
466  *
467  * The return code will be GCI_OK.
468  *
469  * *strsize is set to the resulting length without the terminator.
470  */
int2string(void * hidden,GCI_I bin,char * str,int * strsize)471 static GCI_result int2string( void *hidden,
472                               GCI_I bin,
473                               char *str,
474                               int *strsize )
475 {
476    assert( *strsize >= 80 );
477 
478    *strsize = GCI_Iw( str, bin );
479    return GCI_OK;
480 }
481 
482 /*
483  * string2uint is the basic routine which implements GCI_Ur. size characters
484  * of str (not strongly 0-terminated) are converted and the number is placed
485  * in *retval.
486  *
487  * The string may contain garbage whitespace.
488  *
489  * The return code may be GCI_OK, GCI_WrongInput, GCI_NumberRange.
490  */
string2uint(void * hidden,const char * str,int size,GCI_U * retval)491 static GCI_result string2uint( void *hidden,
492                                const char *str,
493                                int size,
494                                GCI_U *retval )
495 {
496    char buf[80]; /* enough even for 256 bit numbers */
497    char *p;
498 
499    preparenum( hidden, &str, &size );
500    if ( !size ||
501         ( size > (int) sizeof( buf ) - 1 ) ||
502         !iswhole( hidden, str, size ) )
503       return GCI_WrongInput;
504 
505    memcpy( buf, str, size );
506    buf[size] = '\0';
507 
508    /*
509     * Carefully try to detect an overflow. We have to set errno for that
510     * cases where MAX_??? is given in str.
511     */
512    errno = 0;
513    *retval = GCI_Ur( buf, &p, 10 );
514    if ( ( *p != '\0' ) || errno )
515       return GCI_NumberRange;
516 
517    return GCI_OK;
518 }
519 
520 /*
521  * uint2string is the basic routine which implements GCI_Uw. bin is converted
522  * into a string which is placed into str. strsize must hold the buffer width
523  * of str and must be greater than 79.
524  *
525  * The return code will be GCI_OK.
526  *
527  * *strsize is set to the resulting length without the terminator.
528  */
uint2string(void * hidden,GCI_U bin,char * str,int * strsize)529 static GCI_result uint2string( void *hidden,
530                                GCI_U bin,
531                                char *str,
532                                int *strsize )
533 {
534    assert( *strsize >= 80 );
535 
536    *strsize = GCI_Uw( str, bin );
537    return GCI_OK;
538 }
539 
540 #ifdef GCI_F
541 /*
542  * string2float is the basic routine which implements GCI_Fr. size characters
543  * of str (not strongly 0-terminated) are converted and the number is placed
544  * in *retval.
545  *
546  * The string may contain garbage whitespace.
547  *
548  * The return code may be GCI_OK, GCI_NoMemory, GCI_WrongInput,
549  * GCI_NumberRange.
550  */
string2float(void * hidden,const char * str,int size,GCI_F * retval)551 static GCI_result string2float( void *hidden,
552                                 const char *str,
553                                 int size,
554                                 GCI_F *retval )
555 {
556    char *buf;
557    char *p;
558 
559    preparenum( hidden, &str, &size );
560    if ( !size )
561       return GCI_WrongInput;
562 
563    if ( ( buf = (char *) GCI_malloc( hidden, size + 1 ) ) == NULL )
564       return GCI_NoMemory;
565 
566    memcpy( buf, str, size );
567    buf[size] = '\0';
568 
569    /*
570     * Carefully try to detect an overflow. We have to set errno for that
571     * cases where MAX_??? is given in str.
572     */
573    errno = 0;
574    *retval = GCI_Fr( buf, &p );
575    while ( GCI_isspace( *p ) )
576       p++;
577 
578    if ( *p != '\0' )
579    {
580       GCI_free( hidden, buf );
581       return GCI_WrongInput;
582    }
583 
584    if ( errno )
585    {
586       GCI_free( hidden, buf );
587       return GCI_NumberRange;
588    }
589 
590    GCI_free( hidden, buf );
591    return GCI_OK;
592 }
593 
594 /*
595  * float2string is the basic routine which implements GCI_Uw. bin is converted
596  * into a string which is placed into str. *strsize must hold the buffer width
597  * of str and must be greater than 127.
598  *
599  * The return code will be GCI_OK or GCI_UnsupportedNumber if the generated
600  * number cannot be represented by digits (e.g. NaN).
601  *
602  * *strsize is set to the resulting length without the terminator.
603  */
float2string(void * hidden,GCI_F bin,char * str,int * strsize)604 static GCI_result float2string( void *hidden,
605                                 GCI_F bin,
606                                 char *str,
607                                 int *strsize )
608 {
609    assert( *strsize >= 128 );
610 
611    *strsize = GCI_Fw( str, bin );
612    if ( ( *str == '-' ) || ( *str == '+' ) )
613       str++;
614    if ( !GCI_isdigit( *str ) )
615       return GCI_UnsupportedNumber;
616    return GCI_OK;
617 }
618 #endif /* ifdef GCI_F */
619 
620 /*
621  * We define a set of functions which bases on string2int and int2string.
622  * Each function will either convert to a smaller sized number or display a
623  * smaller sized number.
624  *
625  * usage: AUTOIFUNC(x) create the two functions s2ifuncx and i2sfuncx.
626  */
627 #define AUTOIFUNC(size) static GCI_result s2ifunc##size( void *hidden,    \
628                                                          const char *str, \
629                                                          int strsize,     \
630                                                          void *target )   \
631 {                                                                         \
632    GCI_result rc;                                                         \
633    GCI_I val;                                                             \
634    if ( ( rc = string2int( hidden, str, strsize, &val ) ) != GCI_OK )     \
635       return rc;                                                          \
636                                                                           \
637    if ( ( (GCI_I) val < GCI_I_##size##m ) ||                              \
638         ( (GCI_I) val > GCI_I_##size##M ) )                               \
639       return GCI_NumberRange;                                             \
640                                                                           \
641    *((GCI_I_##size *) target) = (GCI_I_##size) val;                       \
642    return GCI_OK;                                                         \
643 }                                                                         \
644 static GCI_result i2sfunc##size( void *hidden,                            \
645                                  const void *data,                        \
646                                  char *str,                               \
647                                  int *strsize)                            \
648 {                                                                         \
649    GCI_I val;                                                             \
650    val = (GCI_I) *( (GCI_I_##size *) data );                              \
651    return int2string( hidden, val, str, strsize );                        \
652 }
653 
654 #ifdef GCI_I_1
655 AUTOIFUNC(1)
656 #endif
657 
658 #ifdef GCI_I_2
659 AUTOIFUNC(2)
660 #endif
661 
662 #ifdef GCI_I_4
663 AUTOIFUNC(4)
664 #endif
665 
666 #ifdef GCI_I_8
667 AUTOIFUNC(8)
668 #endif
669 
670 #ifdef GCI_I_16
671 AUTOIFUNC(16)
672 #endif
673 
674 /*
675  * We define a set of functions which bases on string2uint and uint2string.
676  * Each function will either convert to a smaller sized number or display a
677  * smaller sized number.
678  *
679  * usage: AUTOUFUNC(x) create the two functions s2ufuncx and u2sfuncx.
680  */
681 #define AUTOUFUNC(size) static GCI_result s2ufunc##size( void *hidden,    \
682                                                          const char *str, \
683                                                          int strsize,     \
684                                                          void *target )   \
685 {                                                                         \
686    GCI_result rc;                                                         \
687    GCI_U val;                                                             \
688    if ( ( rc = string2uint( hidden, str, strsize, &val ) ) != GCI_OK )    \
689       return rc;                                                          \
690                                                                           \
691    if ( (GCI_U) val > GCI_U_##size##M )                                   \
692       return GCI_NumberRange;                                             \
693                                                                           \
694    *((GCI_U_##size *) target) = (GCI_U_##size) val;                       \
695    return GCI_OK;                                                         \
696 }                                                                         \
697 static GCI_result u2sfunc##size( void *hidden,                            \
698                                  const void *data,                        \
699                                  char *str,                               \
700                                  int *strsize)                            \
701 {                                                                         \
702    GCI_U val;                                                             \
703    val = (GCI_U) *( (GCI_U_##size *) data );                              \
704    return uint2string( hidden, val, str, strsize );                       \
705 }
706 
707 
708 #ifdef GCI_U_1
709 AUTOUFUNC(1)
710 #endif
711 
712 #ifdef GCI_U_2
713 AUTOUFUNC(2)
714 #endif
715 
716 #ifdef GCI_U_4
717 AUTOUFUNC(4)
718 #endif
719 
720 #ifdef GCI_U_8
721 AUTOUFUNC(8)
722 #endif
723 
724 #ifdef GCI_U_16
725 AUTOUFUNC(16)
726 #endif
727 
728 #ifdef GCI_F
729 /*
730  * We define a set of functions which bases on string2float and float2string.
731  * Each function will either convert to a smaller sized number or display a
732  * smaller sized number.
733  *
734  * usage: AUTOFFUNC(x) create the two functions s2ffuncx and f2sfuncx.
735  */
736 #define AUTOFFUNC(size) static GCI_result s2ffunc##size( void *hidden,    \
737                                                          const char *str, \
738                                                          int strsize,     \
739                                                          void *target )   \
740 {                                                                         \
741    GCI_result rc;                                                         \
742    GCI_F val;                                                             \
743    if ( ( rc = string2float( hidden, str, strsize, &val ) ) != GCI_OK )   \
744       return rc;                                                          \
745                                                                           \
746    if ( ( (GCI_F) val < GCI_F_##size##m ) ||                              \
747         ( (GCI_F) val > GCI_F_##size##M ) )                               \
748       return GCI_NumberRange;                                             \
749                                                                           \
750    *((GCI_F_##size *) target) = (GCI_F_##size) val;                       \
751    return GCI_OK;                                                         \
752 }                                                                         \
753 static GCI_result f2sfunc##size( void *hidden,                            \
754                                  const void *data,                        \
755                                  char *str,                               \
756                                  int *strsize)                            \
757 {                                                                         \
758    GCI_F val;                                                             \
759    val = (GCI_F) *( (GCI_F_##size *) data );                              \
760    return float2string( hidden, val, str, strsize );                      \
761 }
762 
763 #ifdef GCI_F_4
764 AUTOFFUNC(4)
765 #endif
766 
767 #ifdef GCI_F_8
768 AUTOFFUNC(8)
769 #endif
770 
771 #ifdef GCI_F_10
772 AUTOFFUNC(10)
773 #endif
774 
775 #ifdef GCI_F_12
776 AUTOFFUNC(12)
777 #endif
778 
779 #ifdef GCI_F_16
780 AUTOFFUNC(16)
781 #endif
782 #endif /* ifdef GCI_F */
783 
784 /*
785  * setup_functable initializes the functable table without setting illegal
786  * values.
787  * This allows simultaneous access without locking in multi-threading systems.
788  */
setup_functable(void)789 static void setup_functable( void )
790 {
791    int i;
792 
793    if ( functable_assigned )
794       return;
795 
796    for ( i = 0; i <= GCI_max; i++)
797    {
798       switch ( i )
799       {
800          case 1:
801 #ifdef GCI_I_1
802             functable[i].s2ifunc = s2ifunc1;
803             functable[i].i2sfunc = i2sfunc1;
804 #else
805             functable[i].s2ifunc = NULL;
806             functable[i].i2sfunc = NULL;
807 #endif
808 #ifdef GCI_U_1
809             functable[i].s2ufunc = s2ufunc1;
810             functable[i].u2sfunc = u2sfunc1;
811 #else
812             functable[i].s2ufunc = NULL;
813             functable[i].u2sfunc = NULL;
814 #endif
815             functable[i].s2ffunc = NULL;
816             functable[i].f2sfunc = NULL;
817             break;
818 
819          case 2:
820 #ifdef GCI_I_2
821             functable[i].s2ifunc = s2ifunc2;
822             functable[i].i2sfunc = i2sfunc2;
823 #else
824             functable[i].s2ifunc = NULL;
825             functable[i].i2sfunc = NULL;
826 #endif
827 #ifdef GCI_U_2
828             functable[i].s2ufunc = s2ufunc2;
829             functable[i].u2sfunc = u2sfunc2;
830 #else
831             functable[i].s2ufunc = NULL;
832             functable[i].u2sfunc = NULL;
833 #endif
834             functable[i].s2ffunc = NULL;
835             functable[i].f2sfunc = NULL;
836             break;
837 
838          case 4:
839 #ifdef GCI_I_4
840             functable[i].s2ifunc = s2ifunc4;
841             functable[i].i2sfunc = i2sfunc4;
842 #else
843             functable[i].s2ifunc = NULL;
844             functable[i].i2sfunc = NULL;
845 #endif
846 #ifdef GCI_U_4
847             functable[i].s2ufunc = s2ufunc4;
848             functable[i].u2sfunc = u2sfunc4;
849 #else
850             functable[i].s2ufunc = NULL;
851             functable[i].u2sfunc = NULL;
852 #endif
853 #ifdef GCI_F_4
854             functable[i].s2ffunc = s2ffunc4;
855             functable[i].f2sfunc = f2sfunc4;
856 #else
857             functable[i].s2ffunc = NULL;
858             functable[i].f2sfunc = NULL;
859 #endif
860             break;
861 
862          case 8:
863 #ifdef GCI_I_8
864             functable[i].s2ifunc = s2ifunc8;
865             functable[i].i2sfunc = i2sfunc8;
866 #else
867             functable[i].s2ifunc = NULL;
868             functable[i].i2sfunc = NULL;
869 #endif
870 #ifdef GCI_U_8
871             functable[i].s2ufunc = s2ufunc8;
872             functable[i].u2sfunc = u2sfunc8;
873 #else
874             functable[i].s2ufunc = NULL;
875             functable[i].u2sfunc = NULL;
876 #endif
877 #ifdef GCI_F_8
878             functable[i].s2ffunc = s2ffunc8;
879             functable[i].f2sfunc = f2sfunc8;
880 #else
881             functable[i].s2ffunc = NULL;
882             functable[i].f2sfunc = NULL;
883 #endif
884             break;
885 
886          case 10:
887             functable[i].s2ifunc = NULL;
888             functable[i].i2sfunc = NULL;
889             functable[i].s2ufunc = NULL;
890             functable[i].u2sfunc = NULL;
891 #ifdef GCI_F_10
892             functable[i].s2ffunc = s2ffunc10;
893             functable[i].f2sfunc = f2sfunc10;
894 #else
895             functable[i].s2ffunc = NULL;
896             functable[i].f2sfunc = NULL;
897 #endif
898             break;
899 
900          case 12:
901             functable[i].s2ifunc = NULL;
902             functable[i].i2sfunc = NULL;
903             functable[i].s2ufunc = NULL;
904             functable[i].u2sfunc = NULL;
905 #ifdef GCI_F_12
906             functable[i].s2ffunc = s2ffunc12;
907             functable[i].f2sfunc = f2sfunc12;
908 #else
909             functable[i].s2ffunc = NULL;
910             functable[i].f2sfunc = NULL;
911 #endif
912             break;
913 
914          case 16:
915 #ifdef GCI_I_16
916             functable[i].s2ifunc = s2ifunc16;
917             functable[i].i2sfunc = i2sfunc16;
918 #else
919             functable[i].s2ifunc = NULL;
920             functable[i].i2sfunc = NULL;
921 #endif
922 #ifdef GCI_U_16
923             functable[i].s2ufunc = s2ufunc16;
924             functable[i].u2sfunc = u2sfunc16;
925 #else
926             functable[i].s2ufunc = NULL;
927             functable[i].u2sfunc = NULL;
928 #endif
929 #ifdef GCI_F_16
930             functable[i].s2ffunc = s2ffunc16;
931             functable[i].f2sfunc = f2sfunc16;
932 #else
933             functable[i].s2ffunc = NULL;
934             functable[i].f2sfunc = NULL;
935 #endif
936             break;
937 
938          default:
939             functable[i].s2ifunc = NULL;
940             functable[i].i2sfunc = NULL;
941             functable[i].s2ufunc = NULL;
942             functable[i].u2sfunc = NULL;
943             functable[i].s2ffunc = NULL;
944             functable[i].f2sfunc = NULL;
945             break;
946       }
947    }
948 
949    functable_assigned = 1;
950 }
951 
952 /*****************************************************************************
953  *****************************************************************************
954  ** GLOBAL FUNCTIONS *********************************************************
955  *****************************************************************************
956  *****************************************************************************/
957 
958 /*
959  * GCI_string2bin converts size characters of the not strongly 0-terminated
960  * string in str to a number.
961  * The desired datatype is taken from type. It must be GCI_integer,
962  * GCI_unsigned, GCI_float or GCI_char.
963  * destbyte contains the number of bytes of the desired type.
964  * Exactly destbyte bytes will be written to *dest on success. No checks for
965  * alignment errors are done.
966  *
967  * The return code may be
968  * GCI_OK              Everything is perfect.
969  * GCI_NoMemory        Out of memory when converting a floating point number.
970  * GCI_WrongInput      Strange characters occur in the input string.
971  * GCI_NumberRange     Number to small or big to fit into the desired type
972  *                     with the desired destbyte-size.
973  * GCI_UnsupportedType The combination of destbyte/type is unknown or not
974  *                     supported.
975  */
GCI_string2bin(void * hidden,const char * str,int size,void * dest,int destbyte,GCI_basetype type)976 GCI_result GCI_string2bin( void *hidden,
977                            const char *str,
978                            int size,
979                            void *dest,
980                            int destbyte,
981                            GCI_basetype type )
982 {
983    if ( !functable_assigned )
984       setup_functable();
985 
986    if ( ( destbyte < 0 ) || ( destbyte >= (int) elements( functable ) ) )
987       return GCI_UnsupportedType;
988 
989    switch ( type )
990    {
991       case GCI_integer:
992          if ( functable[destbyte].s2ifunc == NULL )
993             return GCI_UnsupportedType;
994          return functable[destbyte].s2ifunc( hidden, str, size, dest );
995 
996       case GCI_unsigned:
997          if ( functable[destbyte].s2ufunc == NULL )
998             return GCI_UnsupportedType;
999          return functable[destbyte].s2ufunc( hidden, str, size, dest );
1000 
1001       case GCI_float:
1002          if ( functable[destbyte].s2ffunc == NULL )
1003             return GCI_UnsupportedType;
1004          return functable[destbyte].s2ffunc( hidden, str, size, dest );
1005 
1006       case GCI_char:
1007          if ( destbyte != 1 )
1008             return GCI_UnsupportedType;
1009          if ( size != 1 )
1010             return GCI_WrongInput;
1011          *((char *) dest) = *str;
1012          return GCI_OK;
1013 
1014       default:
1015          break;
1016    }
1017    return GCI_UnsupportedType;
1018 }
1019 
1020 /*
1021  * GCI_bin2string converts size byte of base into a 0-terminated string with
1022  * a maximum target size of *strsize including the terminator.
1023  * The desired datatype is taken from type. It must be GCI_integer,
1024  * GCI_unsigned, GCI_float or GCI_char. GCI_string is not handled.
1025  * size contains the number of bytes of the desired type.
1026  * Exactly size bytes will be taken from *base. No checks for alignment errors
1027  * are done.
1028  * *strsize is set to the new size of the resulting string without the
1029  * terminator.
1030  *
1031  * The return code may be
1032  * GCI_OK                Everything is perfect.
1033  * GCI_UnsupportedNumber The floating point value in base is not a number
1034  *                       which can be displayed by digits (e.g. NaN).
1035  * GCI_BufferTooSmall    The target buffer size strsize is less than 128.
1036  * GCI_UnsupportedType   The combination of size/type is unknown or not
1037  *                       supported.
1038  */
GCI_bin2string(void * hidden,const void * base,int size,char * str,int * strsize,GCI_basetype type)1039 GCI_result GCI_bin2string( void *hidden,
1040                            const void *base,
1041                            int size,
1042                            char *str,
1043                            int *strsize,
1044                            GCI_basetype type )
1045 {
1046    if ( !functable_assigned )
1047       setup_functable();
1048 
1049    if ( ( size < 0 ) || ( size >= (int) elements( functable ) ) )
1050       return GCI_UnsupportedType;
1051 
1052    if ( *strsize < 128 )
1053       return GCI_BufferTooSmall;
1054 
1055    switch ( type )
1056    {
1057       case GCI_integer:
1058          if ( functable[size].i2sfunc == NULL )
1059             return GCI_UnsupportedType;
1060          return functable[size].i2sfunc( hidden, base, str, strsize );
1061 
1062       case GCI_unsigned:
1063          if ( functable[size].u2sfunc == NULL )
1064             return GCI_UnsupportedType;
1065          return functable[size].u2sfunc( hidden, base, str, strsize );
1066 
1067       case GCI_float:
1068          if ( functable[size].f2sfunc == NULL )
1069             return GCI_UnsupportedType;
1070          return functable[size].f2sfunc( hidden, base, str, strsize );
1071 
1072       case GCI_char:
1073          if ( size == 0 )
1074             return GCI_BufferTooSmall;
1075          if ( size > 1 )
1076             return GCI_UnsupportedType;
1077          str[0] = *((char *) base);
1078          str[1] = '\0';
1079          *strsize = 1;
1080          return GCI_OK;
1081 
1082       default:
1083          break;
1084    }
1085    return GCI_UnsupportedType;
1086 }
1087 
1088 /*
1089  * GCI_validate tests whether a specific type is supported by both conversion
1090  * routines. If basetype is set, an additional test is done for a base type.
1091  *
1092  * The return code is
1093  * GCI_OK                Everything is perfect.
1094  * GCI_UnsupportedType   The combination of size/type is unknown or not
1095  *                       supported.
1096  * GCI_NoBaseType        The type won't fit the requirements for basic types.
1097  */
GCI_validate(int size,GCI_basetype type,int basetype)1098 GCI_result GCI_validate( int size,
1099                          GCI_basetype type,
1100                          int basetype )
1101 {
1102    if ( !functable_assigned )
1103       setup_functable();
1104 
1105    if ( size < 0 )
1106       return GCI_UnsupportedType;
1107 
1108    if ( ( type == GCI_string ) ||
1109         ( type == GCI_raw ) ||
1110         ( type == GCI_container ) ||
1111         ( type == GCI_array ) )
1112       return ( basetype ) ? GCI_NoBaseType : GCI_OK;
1113 
1114    if ( size >= (int) elements( functable ) )
1115       return GCI_UnsupportedType;
1116 
1117    switch ( type )
1118    {
1119       case GCI_integer:
1120          if ( ( functable[size].i2sfunc == NULL ) ||
1121               ( functable[size].s2ifunc == NULL ) )
1122             return GCI_UnsupportedType;
1123          return GCI_OK;
1124 
1125       case GCI_unsigned:
1126          if ( ( functable[size].u2sfunc == NULL ) ||
1127               ( functable[size].s2ufunc == NULL ) )
1128             return GCI_UnsupportedType;
1129          return GCI_OK;
1130 
1131       case GCI_float:
1132          if ( ( functable[size].f2sfunc == NULL ) ||
1133               ( functable[size].s2ffunc == NULL ) )
1134             return GCI_UnsupportedType;
1135          return GCI_OK;
1136 
1137       case GCI_char:
1138          if ( size != 1 ) /* we don't support unicode or other MBCS */
1139             return GCI_UnsupportedType;
1140          return GCI_OK;
1141 
1142       default:
1143          break;
1144    }
1145    return GCI_UnsupportedType;
1146 }
1147