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