2 * The Regina Rexx Interpreter
3 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
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.
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.
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.
21 * The functions in this file converts between the different
22 * 'datatypes' that REXX uses, such as decimal number, character
23 * string and hex string. Some of the functions are meant for the
24 * standard library, like c2x, x2c, d2x, x2d, c2d and d2c, and also
25 * the new functions in language level 4.00: b2x and x2b. The routines
26 * in the file might also be used elsewhere for conversion between
27 * char, decimal and hex.
29 * In general, there are two levels, the interface for the functions
30 * in the builtin library (std_c2x, std_c2d, etc) and the low-level
31 * routines that do the actual job. The interface routines 'only' call
32 * the low-level routines in the right order, to preprocess parameters
33 * and to postprocess the result. However, this implementation is not
34 * 100% clean in this respect, since std_b2x() and std_x2b() are
37 * When converting to or from decimal numbers, the decimal number will
38 * trigger an overflow condition if more bits are pushed into the
39 * number than the is allowed by the current setting of NUMERIC
42 * The low-level routines are:
44 * pack_hex() --- packs a hex string into a char string
45 * unpack_hex() --- unpacks a char string into a hex string.
46 * numberize() --- converts a char string to a whole number
48 * In addition, low level routine that operates on whole numbers are
49 * placed in strmath.c. The relevant routines there which are called
50 * from this file are (numberize() is only a frontend to the function
53 * str_binerize() --- converts a whole number into a char string
54 * str_digitize() --- converts a char string into a whole number
56 * The high-level routines in this file are:
58 * std_b2x() --- converts bin string to hex string
59 * std_c2d() --- converts char string to whole number
60 * std_c2x() --- converts char string to hex string
61 * std_d2c() --- converts whole number to char string
62 * std_d2x() --- converts whole number to hex string
63 * std_x2b() --- converts hex string to bin string
64 * std_x2c() --- converts hex string to char string
65 * std_x2d() --- converts hex string to whole number
68 * There are four 'generic' dataformats used in this implementation:
69 * bin string, hex string, char string and whole number.
71 * * CHAR STRING consists of chars (any of the 256, including 0). It
72 * can have any length (including 0). This is the 'normal' strings
73 * in Rexx, but note that in the context of this module, char strings
74 * will often contain unprintable characters, while in normal use
75 * char strings will often just contain printable characters.
76 * To emphsize the difference, it will sometimes be refered to as
79 * * BIN STRING consists of the binary digits 0 and 1, and will be
80 * implicitly padded out to a nibble (4 bit) boundary. They may have
81 * any length, including 0. Optional spaces might be added between
82 * nibble boundaries, but not at the start or end of the string. The
83 * first group of bin digits may have any number of digits, and will
84 * be padded with leading zeros at the left to make it a multiple
87 * * HEX STRING consists of the hex digits 0-9 and A-F (in upper or
88 * lower case). It may have any length (including 0). Optional
89 * spaces might be added between pairs of digits to form groups of
90 * hex digits, but not at the start or end. If the first group does
91 * not contain an even number of hex digits, it is padded to the
94 * * WHOLE NUMBER must be a string which is a valid Rexx whole number,
95 * which is a subset of Rexx numbers. If it has a decimal part, that
96 * must be zero (i.e. 13.0 is a whole number). In addition, it must
97 * have a precition which is sufficient high to identify the number
98 * as a particular integer (i.e. 13E1 is not a whole number, since
99 * it really is 130 plus/minus 5).
101 * All these, except whole numbers, can have zero length, in which
102 * case they are considered the nullstring. When generating these
103 * datatype for output, they will be normalized, which means:
105 * * For whole numbers, bin and hex string, no additional space is
106 * added; neither internal, leading nor trailing.
108 * * Whole numbers will not be in exponential form, and the decimal
109 * part of the number (if any) is truncated.
111 * * Hex string will use upper case alphanumberic characters in stead
112 * of lower case. Bin string will be padded with zeros at the left
113 * to a multiple of four.
124 * The following string is used to convert a nibble value
125 * into its hexadecimal character set representation. Perhaps this
126 * should be placed somewhere else, e.g. in misc.c
128 static const char hexnum
[] = "0123456789ABCDEF" ;
132 /* ---------------------------------------------------------------
133 * Takes a bin string as input, and returns a normalized hex
134 * string representing the same data. The output will have an even
137 * Since we are reading byte values in the range 0-255, we must take
138 * care to use unsigned chars, else we might get some surprises.
139 * Therefore there are some casting in this routine.
141 static streng
*unpack_hex( const tsd_t
*TSD
, const streng
*string
)
143 streng
*result
=NULL
; /* the output string */
144 char *res_ptr
=NULL
; /* ptr to current char in output string */
145 unsigned char *ptr
=NULL
; /* ptr to input string */
146 unsigned char *end_ptr
=NULL
; /* ptr to end+1 of input string */
149 * Allocate the needed space, which is very easy to calculate
151 result
= Str_makeTSD( Str_len( string
)*2 ) ;
152 res_ptr
= result
->value
;
155 * Initialize loop ptr and the end ptr, and loop through each
156 * character in the input string. Write two output hex digits
157 * for each char in the input string
159 end_ptr
= (unsigned char *)(Str_end(string
)) ;
160 ptr
= (unsigned char *)(string
->value
) ;
161 for (; ptr
<end_ptr
; ptr
++ )
163 *res_ptr
++ = hexnum
[ (*ptr
>>4) ] ;
164 *res_ptr
++ = hexnum
[ (*ptr
& 0x0f) ] ;
168 * That's it, set the length and return to caller
170 result
->len
= ( res_ptr
- result
->value
) ;
171 assert( result
->len
<= result
->max
) ;
177 /* -----------------------------------------------------------------
178 * Input is a hex string, which is converted to a char string
179 * representing the same information and returned.
181 * We have to concider the optional grouping of hex digits by spaces at
182 * byte boundaries, and the possibility of having to pad first group
185 * There is one performance problem with this. If the hex string is
186 * normalized and long, we have to loop through the string twice, while
187 * once would suffice. To determine whether or not to pad first group
188 * with a zero, all of first group must be scanned, which is identical
189 * to the whole string if it is normalized.
191 static streng
*pack_hex( tsd_t
*TSD
, const char *bif
, const streng
*string
)
193 streng
*result
=NULL
; /* output char string */
194 const char *ptr
=NULL
; /* current digit in input hex string */
195 const char *end_ptr
=NULL
; /* ptr to end+1 in input hex string */
196 char *res_ptr
=NULL
; /* ptr to current char in output string */
197 int byte_boundary
=0 ; /* boolean, are we at at byte bounary? */
198 int count
; /* used to count positions */
201 * Allow one extra char for padding, ignore that allocated string
202 * might be too long if there is spacing at byte boundaries.
204 result
= Str_makeTSD( (Str_len(string
)+1)/2 +1 ) ;
205 res_ptr
= result
->value
;
208 * Initiate pointers to current char in intput string, and to
209 * end+1 in input string.
211 ptr
= string
->value
;
212 end_ptr
= Str_end(string
) ;
215 * Explicitly check for space at start or end. Illegal space within
216 * the hex string is checked for during the loop.
218 if ((ptr
<end_ptr
) && ((rx_isspace(*ptr
)) || (rx_isspace(*(end_ptr
-1)))))
224 * Find the number of hex digits in the first group of hex digits.
225 * Let the variable 'byte_boundary' be a boolean, indicating if
226 * current char might be a byte boundary. I.e if byte_boundary is
227 * set, spaces are legal.
229 * Also, set the first byte in the output string. That is not
230 * necessary if the first group of hex digits has an even number of
231 * digits, but it is cheaper to do it always that check for it.
233 for (; (ptr
<end_ptr
) && (rx_isxdigit(*ptr
)); ptr
++ ) ;
234 byte_boundary
= !((ptr
-string
->value
)%2) ;
236 /* Does this statement do anything useful? (Proabably, things crash if
242 * Loop through the elements of the input string. Skip over spaces.
243 * Stuff hex digits into the output string, and report error
244 * for any other type of data.
246 for (count
=1,ptr
=string
->value
; ptr
<end_ptr
; ptr
++, count
++)
248 if (rx_isspace(*ptr
))
251 * Just make sure that this space occurs at a byte boundary,
252 * except from that, ignore it.
259 else if (rx_isxdigit(*ptr
))
262 * Stuff it into the output array, either as upper or lower
263 * part of a byte, depending on the value of 'byte_boundary'.
264 * Then toggle the value of 'byte_boundary'.
267 *res_ptr
= (char)( HEXVAL(*ptr
) << 4 ) ;
271 *res_ptr
= (char) (*res_ptr
+ (char) (HEXVAL(*ptr
))) ;
275 byte_boundary
= !byte_boundary
;
284 * Set the length and do 'redundant' check for problems. In
285 * particular, check 'byte_boundary' to verify that the last group
286 * of hex digits ended at a byte boundary; report error if not.
293 result
->len
= res_ptr
- result
->value
;
294 assert( result
->len
<= result
->max
) ;
299 Free_stringTSD( result
);
300 exiterror( ERR_INCORRECT_CALL
, 25, bif
, tmpstr_of( TSD
, string
) );
301 return NULL
; /* not reached */
306 /* ------------------------------------------------------------------
307 * Takes a char string input and concerts it into a whole number of
308 * base 10, which can be signed. Actually, the real work is done in
311 * If length is -1 (i.e. unspecified) it will be interpreted as an
314 * If length is specified, the input string will be interpreted as an
315 * two's complement number having that length. If parameter 'length'
316 * is bigger than the length of parameter string, 'string' is
317 * logically extended with '0' at the left. If parameter length is
318 * smaller than the length of parameter string, only the rightmost
319 * characters of string is significant.
321 * The output string will not contain any leading zeros (unless the
322 * value of the number is zero, in which case '0' is returned). A '0'
323 * will also be returned if 'length' is zero, or if 'string' is the
326 static streng
*numerize( tsd_t
*TSD
, streng
*string
, int length
,
327 const char *bif
, int removeStringOnError
)
329 int start
=0 ; /* character to start reading at */
330 int sign
=0 ; /* is this to be interpreted as signed? */
332 /* The trivial case, either the nullstring, or length=0 */
333 if ((length
==0) || (Str_len(string
)==0))
334 return int_to_streng( TSD
, 0 ) ;
337 * Set the variable 'start' to the most significant byte in 'string'.
338 * That is the first byte if 'length' is either unspecified or
339 * bigger than (or equal to) the length of 'string'.
341 * If 'length' is specified and is less than the length of 'string',
342 * then set 'start' to the the 'length'th byte, counted backward.
344 if ((length
==-1) || (length
>Str_len(string
)))
348 assert((length
>0) && (length
<=Str_len(string
))) ;
349 start
= Str_len(string
) - length
;
351 assert((start
>=0) && (start
<Str_len(string
))) ;
355 * Call the correct routine in the string module. The number will
356 * always be signed if length is specified.
358 return str_digitize( TSD
, string
, start
, sign
, bif
, removeStringOnError
) ;
363 /* ------------------------------------------------------------------
364 * Converts a hex string to a decimal number using two's complement.
365 * This is a high level routine, which just calls the above low level
366 * routines to do the job. First the hex string is converted into
367 * a char string, and then the char string is converted into a whole
370 streng
*std_x2d( tsd_t
*TSD
, cparamboxptr parms
)
372 int length
=0 ; /* the length of the input hex string */
373 streng
*result
=NULL
; /* the output string */
374 streng
*packed
=NULL
; /* tmp variable holding the char string */
377 * First read the parameters, and set length to -1 (meaning
378 * unspecified) if the second parameter was not specified.
380 checkparam( parms
, 1, 2 , "X2D" ) ;
381 if ((parms
->next
)&&(parms
->next
->value
))
382 length
= atozpos( TSD
, parms
->next
->value
, "X2D", 2 ) ;
387 * Convert the hex string into a whole number in two steps
389 * Note that the 'length' variable is the length in hex digits, and
390 * that numerize receives its input as a char string, so we have to
391 * convert the 'length' a bit. Also, that means that we have to
392 * sign extend the number at the left to a byte boundary.
394 packed
= pack_hex( TSD
, "X2D", parms
->value
) ;
395 if ((length
>0) && (length
%2))
398 * The char string was padded with an extra zero nibble in pack_hex()
399 * so we must signextend that nibble. 'msb' is a tmp variable
400 * that points to the most significant byte in packed. Hmmm this
403 int msb
= Str_len(packed
)-(length
/2)-1 ;
404 if (msb
>= 0) /* only if length <= hexchars supplied */
406 if (packed
->value
[msb
] & 0x08)
407 packed
->value
[msb
] |= 0xf0 ;
409 packed
->value
[msb
] &= 0x0f ;
412 result
= numerize( TSD
,
414 ((length
!=-1) ? ((length
+1)/2) : -1),
419 * Clean up and return to caller
421 Free_stringTSD( packed
) ;
428 /* ------------------------------------------------------------------
429 * Converts a char string to a hex string. This a just a box around
430 * one of the low level routines, that processes the parameters.
432 streng
*std_x2c( tsd_t
*TSD
, cparamboxptr parms
)
434 checkparam( parms
, 1, 1 , "X2C" ) ;
435 return pack_hex( TSD
, "X2C", parms
->value
) ;
440 /* ------------------------------------------------------------------
441 * Builtin function that converts a binary string to a normalized
442 * hexstring. The hexstring will be padded to *nibble* boundary,
443 * (note: not byte boundary).
445 * This function should have been implemented as a convertion from
446 * bin string to packed binary string, and then a call to unpack
447 * the binary string to a hex string. Unfortunately, accuracy would
448 * be lost, since packed binary strings are padded to byte boundary.
450 * Therefore, this function converts directly into a hex string. If
451 * more functions are added to Rexx (like b2d() and b2c()) in the
452 * future, it might be more effective to create a nibble format (or
453 * change the packed binary string to nibble array), in order to
454 * decrease the number of lines of code.
456 * The code for this is mostly taken from lexsrc.l, these two pieces
457 * should perhaps be tuned to use the same function.
460 streng
*std_b2x( tsd_t
*TSD
, cparamboxptr parms
)
462 char *ptr
=NULL
; /* loop variable */
463 char *endptr
=NULL
; /* pointer to end+1 of input string */
464 char *res_ptr
=NULL
; /* pointer to result string */
465 streng
*result
=NULL
; /* result string */
466 streng
*string
=NULL
; /* tmp variable to avoid pointer chasing */
467 int first_group
=0 ; /* number of bin digits in first bin group */
468 int cur_bit
=0 ; /* current bit in input string */
469 int nibble
=0 ; /* collects bin digits to nibbles */
472 * Have we been called correctly?
474 checkparam( parms
, 1, 1 , "B2X" ) ;
475 string
= parms
->value
;
478 * Since a bin string can have any number of digits in its first
479 * group, we have to find the number of digits, in order to be able
480 * to pad that group with leading zeros. The number can also be
481 * zero (i.e. the bin string is empty.) The number first_group
482 * contains the number of binary digits in the first group.
484 endptr
= Str_end(string
) ;
485 ptr
= string
->value
;
486 for (; (ptr
<endptr
) && (((*ptr
)=='0') || ((*ptr
)=='1')); ptr
++ ) ;
487 first_group
= ptr
- string
->value
;
490 * If the first group contained zero binary digits, then either does
491 * it contain leading space, or it is the nullstring. The former is
492 * an error, so report it if that is the case.
494 if (Str_len(string
) && ((first_group
==0) || (rx_isspace(*(endptr
-1)))))
497 exiterror( ERR_INCORRECT_CALL
, 24, "B2X", tmpstr_of( TSD
, string
) );
501 * If the string is a proper bin string, we need one hex digit for
502 * each fourth bin digit (after having taken into account that the
503 * first group might have a maximum of three implied zeros.) If it
504 * is not a proper bin string, the error will be caught later.
506 * Actually, this might be more than we need, since there might be
507 * spaces embedded within the bin string, but don't bother about
508 * that since it just takes CPU time to figure out exactly how many
509 * bytes we need. Just allocate enough.
511 result
= Str_makeTSD( (Str_len(string
)+3)/4 ) ;
512 res_ptr
= result
->value
;
515 * Initialize some variables, 'cur_bit' is the current bit within
516 * the current nibble. It must be initialized to the number of
517 * implied leading zeros in the bin string. The following
518 * transformation from 'frist_group%4' to 'cur_bit' has the following
519 * mapping {0,1,2,3}->{0,3,2,1}.
521 cur_bit
= (4 - first_group
%4)%4 ;
525 * Then, loop for each character in the input string, and perform
526 * some action, based on whether it is a space or a binary digit.
527 * If it is neither, report an error.
529 for (ptr
=string
->value
; ptr
<endptr
; ptr
++)
531 if (rx_isspace(*ptr
))
534 * The variable 'cur_bit' is a number containing the relative
535 * position of the current bit within the current group of
536 * binary digits. After reading a complete nibble, it reaches
537 * 4, and is reset to 0. So if this is a nibble boundary, it
538 * better be 0, or else there is space within a nibble.
542 Free_stringTSD( result
);
543 exiterror( ERR_INCORRECT_CALL
, 24, "B2X", tmpstr_of( TSD
, string
) );
547 else if (((*ptr
)=='0')||((*ptr
)=='1'))
550 * If it is a binary digit, shift 'nibble' and add the digit.
551 * If 'cur_bit' (after being incremented) shows 4 (i.e we have
552 * completed processing a nibble), reset it to 0, and and
553 * flush 'nibble' to the result string and reset 'nibble' too.
555 nibble
= nibble
* 2 + ((*ptr
)-'0') ;
558 *(res_ptr
++) = hexnum
[nibble
] ;
565 exiterror( ERR_INCORRECT_CALL
, 24, "B2X", tmpstr_of( TSD
, string
) );
570 * Wow, we're finished, we just have to set the length of 'result'
572 result
->len
= (res_ptr
- result
->value
) ;
573 assert( result
->len
<= result
->max
) ;
580 /* ------------------------------------------------------------------
581 * Function that converts a hex string to a binary string. The hex
582 * string may have spaces at byte boundaries as usual, but the first
583 * group of hex digits may have an odd number of digits, in which
584 * case it is *not* padded with an zero hex digit.
586 * Just like std_b2x(), this function should really use a common data
587 * format, but it does not matter before more rexx gets more functions
588 * that converts to/from bin strings.
591 streng
*std_x2b( tsd_t
*TSD
, cparamboxptr parms
)
593 int space_stat
=0 ; /* state machine: nibble or byte boundary? */
594 char *ptr
=NULL
; /* loop control variable */
595 char *end_ptr
=NULL
; /* points to end+1 of input, endcondition in loop */
596 streng
*result
=NULL
; /* the output streng */
597 char *res_ptr
=NULL
; /* ptr to contents of 'result' */
598 int nibble
=0 ; /* holds a nibble while extracting bin digits */
599 int count
=0 ; /* loop control variable */
600 int pos
=0 ; /* position in string for error reporting */
603 * Check that we got the parameters that we needed. Then initialize
604 * some of the variables.
606 checkparam( parms
, 1, 1 ,"X2B" ) ;
607 ptr
= parms
->value
->value
;
608 end_ptr
= Str_end( parms
->value
) ;
612 * Let us allocate enough space, we could tune some space here
613 * if we actually checked how many hex digits that the input
616 result
= Str_makeTSD( (end_ptr
-ptr
) * 4 ) ;
617 res_ptr
= result
->value
;
620 * Check for leading or trailing space in the hex string.
624 if (rx_isspace(*ptr
) || rx_isspace(*(end_ptr
-1)))
631 * The main loop. For each hex digit, output four bin digits to
632 * the output string, and check for illegal spaces within bytes.
633 * If anything other than spaces or hex digits are found, report
636 for (pos
=1; ptr
<end_ptr
; ptr
++,pos
++)
638 if (rx_isspace(*ptr
))
641 * We have found space in the hex string, eat it up, and keep
642 * the statemachine 'space_state' going. If state is 0 (end
643 * of first group) go to state 2 (at byte boundary). If state
644 * is 1 (inside a byte) report an error, since space may not
651 else if (space_stat
==1)
656 else if (rx_isxdigit(*ptr
))
659 * We have found a hex digit, chop it into four parts, and
660 * stuff them into 'result'. Requires that the character set
661 * value of '1' is one higher than that of '0'.
663 nibble
= HEXVAL( *ptr
) ;
664 for (count
=0; count
<4; count
++)
666 *(res_ptr
++) = (char)(( (nibble
& 0x08) != 0 ) + '0') ;
671 * Remember to toggle the statemachine between states 1 and 2
672 * so we can keep track of byte and nibble boundaries. If in
673 * state 0 (whitin first group), stay there.
676 space_stat
= ((space_stat
==1) ? 2 : 1) ;
685 * Set the length, and get out of here.
687 result
->len
= res_ptr
- result
->value
;
691 Free_stringTSD( result
);
692 exiterror( ERR_INCORRECT_CALL
, 25, "X2B", tmpstr_of( TSD
, parms
->value
) );
693 return NULL
; /* not reached */
699 /* --------------------------------------------------------------------
700 * Converts a char string to a decimal string. Really just a box around
701 * numerize, that only preprocesses the parameters.
703 streng
*std_c2d( tsd_t
*TSD
, cparamboxptr parms
)
705 int length
; /* The length of the input char string */
707 checkparam( parms
, 1, 2 , "C2D" ) ;
708 if ((parms
->next
)&&(parms
->next
->value
))
709 length
= atozpos( TSD
, parms
->next
->value
, "C2D", 2 ) ;
713 return numerize( TSD
, parms
->value
, length
, "C2D", 0 ) ;
719 /* ---------------------------------------------------------------------
720 * Converts a packed binary string to a hexadecimal string
722 streng
*std_c2x( tsd_t
*TSD
, cparamboxptr parms
)
724 checkparam( parms
, 1, 1 , "C2X" ) ;
725 return unpack_hex( TSD
, parms
->value
) ;
728 static void check_wholenum( tsd_t
*TSD
, const char *bif
, const streng
*arg
,
731 if ( !myiswnumber( TSD
, arg
, num
,
732 !get_options_flag( TSD
->currlevel
, EXT_STRICT_ANSI
) ) )
733 exiterror( ERR_INCORRECT_CALL
, 12, bif
, 1, tmpstr_of( TSD
, arg
) );
736 /* ---------------------------------------------------------------------
737 * Converts a whole number into char string. This is just a wrapper
738 * around str_binerize(), which preprocesses the parameters.
740 streng
*std_d2c( tsd_t
*TSD
, cparamboxptr parms
)
742 int length
; /* the length of the output string */
745 checkparam( parms
, 1, 2 , "D2C" );
747 check_wholenum( TSD
, "D2C", parms
->value
, &num
);
748 if ( parms
->next
&& parms
->next
->value
)
749 length
= atozpos( TSD
, parms
->next
->value
, "D2C", 2 );
753 * The strange syntax forces a check for non-negative first arg if the
754 * second doesn't exist.
757 exiterror( ERR_INCORRECT_CALL
, 13, "D2C", 1,
758 tmpstr_of( TSD
, parms
->value
) );
763 return str_binerize( TSD
, num
, length
);
767 /* ------------------------------------------------------------------
768 * Converts a decimal string into a hexadecimal string, using char
769 * string as an intermediate format. Due to the use of intermediate
770 * format, an extra hex digit might slip into the left end of the
771 * answer, and code is added to remove it.
773 streng
*std_d2x( tsd_t
*TSD
, cparamboxptr parms
)
775 int length
; /* holds the requested langth of the result */
776 streng
*result
; /* the output streng */
777 streng
*packed
; /* tmp variable, holds the packed string */
781 * Check the parameters, and set 'length' to the specified length, or
782 * to -1 if the second parameter was not specified.
784 checkparam( parms
, 1, 2 , "D2X" );
786 check_wholenum( TSD
, "D2X", parms
->value
, &num
);
787 if ( parms
->next
&& parms
->next
->value
)
788 length
= atozpos( TSD
, parms
->next
->value
, "D2X", 2 );
792 * The strange syntax forces a check for non-negative first arg if the
793 * second doesn't exist.
796 exiterror( ERR_INCORRECT_CALL
, 13, "D2X", 1,
797 tmpstr_of( TSD
, parms
->value
) );
803 * Convert the whole number into a hex string in a two step operation.
804 * First it is converted into a char string, and then that char string
805 * is converted into a hexstring.
807 packed
= str_binerize( TSD
, num
, ( length
== -1 ) ? -1 : ( length
+1 ) / 2 );
808 result
= unpack_hex( TSD
, packed
);
809 Free_stringTSD( packed
);
812 * Since we used char string as a temporary format, the hex string
813 * will now be padded with one extra zero at the left. If we specified
814 * length, and that length does not match the actual length, we must
815 * strip away the first zero in 'result'.
817 * Here we check for length>0, since we want to catch it if length was
818 * specified, but not if it was 0. In the latter case, the string will
819 * be the nullstring, and we don't need to do anything anyway.
821 if ( ( length
> 0 ) && ( Str_len( result
) != length
) && Str_len( result
) )
823 assert( Str_len( result
) == length
+ 1 );
824 memmove( result
->value
, &result
->value
[1], --result
->len
);
828 * Just to be safe, check that we did get the nullstring if length
831 assert( ( length
!= 0 ) || ( Str_len(result
) == 0 ) );
834 * If length was not specified, there might be leading zeros in the
835 * answer that we might want to get rid of. However, the algoritm
836 * that is used in str_binerize() should ensure that there will not
837 * be more than one leading zero in this case. This part of the code
838 * could easily be merged with the other call to memmove() above,
839 * but have been placed here to improve readability.
841 * If there are more than one leading zero, this will not work. The
842 * situation where the result only consists of one zero, should not
843 * occur, but it will be handled, since the result should then be
846 if ( ( length
== -1 ) && ( result
->value
[0] == '0' ) )
848 assert( Str_len( result
) > 1 );
849 assert( ( result
->value
[0] == '0') && ( ( result
->value
[1] != '0' ) || ( Str_len( result
) == 2 ) ) );
851 memmove( result
->value
, &result
->value
[1], --result
->len
);
855 * That's it, now we just have to get out of here