File indexing completed on 2024-05-12 05:55:13
0001 /* floatio.c: low level conversion, based on floatnum. */ 0002 /* 0003 Copyright (C) 2007, 2008 Wolf Lammen. 0004 0005 This program is free software; you can redistribute it and/or modify 0006 it under the terms of the GNU General Public License as published by 0007 the Free Software Foundation; either version 2 of the License , or 0008 (at your option) any later version. 0009 0010 This program is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 GNU General Public License for more details. 0014 0015 You should have received a copy of the GNU General Public License 0016 along with this program; see the file COPYING. If not, write to: 0017 0018 The Free Software Foundation, Inc. 0019 59 Temple Place, Suite 330 0020 Boston, MA 02111-1307 USA. 0021 0022 0023 You may contact the author by: 0024 e-mail: ookami1 <at> gmx <dot> de 0025 mail: Wolf Lammen 0026 Oertzweg 45 0027 22307 Hamburg 0028 Germany 0029 0030 *************************************************************************/ 0031 0032 #include "floatio.h" 0033 #include "floatlong.h" 0034 #include <string.h> 0035 0036 typedef enum { NmbNormal, NmbSpecial, NmbBufferOverflow } NmbType; 0037 0038 /* Besides the regular bases 2, 8, 10 and 16, there are 0039 three others (IO_BASE_DEFAULT, IO_BASE_NAN and IO_BASE_ZERO) 0040 used internally to mark special situations. They are called 0041 pseudo-bases, because you cannot use them as parameter to 0042 floatnum functions */ 0043 static char 0044 _isspecial( 0045 signed char base) 0046 { 0047 switch (base) 0048 { 0049 case IO_BASE_NAN: 0050 case IO_BASE_ZERO: 0051 case IO_BASE_DEFAULT: 0052 return 1; 0053 } 0054 return 0; 0055 } 0056 0057 /*-------------- ASCII based functions -------------*/ 0058 0059 static char emptystr = '\0'; 0060 0061 /* sort of alias for (strlen == 0). I don't have access to a 0062 POSIX manual, so I don't know how strlen reacts on NULL.*/ 0063 static char 0064 _isempty( 0065 const char* p) 0066 { 0067 return p == NULL || *p == '\0'; 0068 } 0069 0070 /* copies the null-terminated ASCIIZ string src into the 0071 buffer dest. If the buffer is too small to hold src, 0072 0 is returned */ 0073 static char 0074 _setstr( 0075 p_buffer dest, 0076 const char* src) 0077 { 0078 if (dest->sz > 0) 0079 { 0080 if (src == NULL) 0081 *(dest->buf) = '\0'; 0082 else if (dest->sz < (int)strlen(src) + 1) 0083 return 0; 0084 else 0085 strcpy(dest->buf, src); 0086 } 0087 return 1; 0088 } 0089 0090 /* looks, whether dest begins with the substring in 0091 pattern */ 0092 static int 0093 _match( 0094 const char* dest, 0095 const char* pattern) 0096 { 0097 int lg; 0098 0099 if (_isempty(dest) || _isempty(pattern)) 0100 return 0; 0101 lg = strlen(pattern); 0102 return strncmp(dest, pattern, lg) == 0? lg : 0; 0103 } 0104 0105 /* converts an ASCII encoded hexagesimal digit a 0106 corresponding value < 16 */ 0107 char 0108 _ascii2digit( 0109 char c) 0110 { 0111 if (c >= '0' && c <= '9') 0112 return c - '0'; 0113 if (c >= 'A' && c <= 'F') 0114 return (c - 'A') + 10; 0115 if (c >= 'a' && c <= 'f') 0116 return (c - 'a') + 10; 0117 return NO_DIGIT; 0118 } 0119 0120 static char hexdigits[] = "0123456789ABCDEF"; 0121 0122 /* converts a value 0 <=x < 16 into a hexdigit */ 0123 char 0124 _digit2ascii( 0125 int value) 0126 { 0127 return hexdigits[value]; 0128 } 0129 0130 /* advances the pointer buf until it points to the 0131 first character not being a valid digit of base 0132 base. The return pointer is the initial value 0133 of buf, or NULL if no digit was found */ 0134 static const char* 0135 _scandigits( 0136 const char** buf, 0137 char base) 0138 { 0139 const char* p; 0140 const char* result; 0141 0142 result = *buf; 0143 p = result - 1; 0144 while (_ascii2digit(*++p) < base); 0145 *buf = p; 0146 return p == result? NULL : result; 0147 } 0148 0149 /*-------------------- t_seq_desc ---------------*/ 0150 0151 /* returns the offset6 of the last significant digit */ 0152 static int 0153 _ofslastnz( 0154 p_seq_desc n) 0155 { 0156 return n->digits - n->trailing0 - 1; 0157 } 0158 0159 /* number of significant digits in a number sequence */ 0160 int 0161 _significantdigits( 0162 p_seq_desc n) 0163 { 0164 return n->digits - n->leadingSignDigits - n->trailing0; 0165 } 0166 0167 /* number of digits without leading zeros in a sequence. 0168 If the sequence describes an integer, these are the digits 0169 of this integer */ 0170 static int 0171 _intdigits( 0172 p_seq_desc n) 0173 { 0174 return n->digits - n->leadingSignDigits; 0175 } 0176 0177 /* has a sequence significant digits? */ 0178 static char 0179 _iszero( 0180 p_seq_desc n) 0181 { 0182 return _significantdigits(n) == 0; 0183 } 0184 0185 /* returns a digit from an ASCIIZ string containing 0186 digits only */ 0187 static char 0188 _getseqdigit( 0189 int ofs, 0190 p_seq_desc n) 0191 { 0192 if (ofs < 0 || ofs > _ofslastnz(n)) 0193 return 0; 0194 return _ascii2digit(*((char*)(n->param) + ofs)); 0195 } 0196 0197 /* returns a digit from an ASCIIZ string containing 0198 digits only, but complements them */ 0199 static char 0200 _getcmpldigit( 0201 int ofs, 0202 p_seq_desc n) 0203 { 0204 int lastnz; 0205 char c; 0206 0207 lastnz = _ofslastnz(n); 0208 if (ofs > lastnz) 0209 return 0; 0210 c = n->base - _getseqdigit(ofs, n) - (ofs == lastnz? 0 : 1); 0211 return c == n->base? 1 : c; 0212 } 0213 0214 /* initializes a structure used for copying digit 0215 sequences */ 0216 static void 0217 _clearint( 0218 p_ext_seq_desc n) 0219 { 0220 n->seq.leadingSignDigits = 0; 0221 n->seq.digits = 0; 0222 n->seq.trailing0 = 0; 0223 n->seq.base = IO_BASE_ZERO; 0224 n->seq.param = NULL; 0225 n->getdigit = _getseqdigit; 0226 } 0227 0228 /*---------------------- t_[io]token ------------------*/ 0229 0230 /* initializes a structure used for describing a 0231 floating point number */ 0232 void 0233 _clearnumber( 0234 p_number_desc n) 0235 { 0236 n->prefix.sign = IO_SIGN_NONE; 0237 n->prefix.base = IO_BASE_NAN; 0238 _clearint(&n->intpart); 0239 _clearint(&n->fracpart); 0240 n->exp = 0; 0241 } 0242 0243 /* creates a sequence descriptor from an ASCII digit 0244 sequence, not necessarily terminated by \0. 0245 After maxdigits digits, all following digits are 0246 assumed to be zero, regardless of their true 0247 value. */ 0248 static void 0249 _str2seq( 0250 p_ext_seq_desc n, 0251 const char* digits, 0252 int maxdigits, 0253 signed char base, 0254 char complement) 0255 { 0256 /* pre: n has to be initialized to describe a zero */ 0257 const char* p; 0258 const char* pz; 0259 char leadingdigit; 0260 unsigned char c; 0261 0262 leadingdigit = 0; 0263 if (complement) 0264 { 0265 leadingdigit = base - 1; 0266 n->getdigit = _getcmpldigit; 0267 } 0268 p = digits; 0269 /* skip sign digits (usually 0, in complement mode 0270 F, 7 or 1 */ 0271 for (; _ascii2digit(*p) == leadingdigit; ++p); 0272 n->seq.leadingSignDigits = p - digits; 0273 /* pz is pointer to first trailing zero */ 0274 pz = p; 0275 for (; (c = _ascii2digit(*(p++))) < base;) 0276 { 0277 if (--maxdigits >= 0 && c != 0) 0278 pz = p; 0279 } 0280 n->seq.trailing0 = p - pz - 1; 0281 n->seq.digits = p - digits - 1; 0282 n->seq.param = (void*)digits; 0283 if (complement || _significantdigits(&n->seq) != 0) 0284 n->seq.base = base; 0285 } 0286 0287 /* copy count digits (leading zeros included) from the 0288 digit sequence described by n to an ASCII buffer */ 0289 static Error 0290 _seq2str( 0291 p_buffer dest, 0292 int count, 0293 p_ext_seq_desc n) 0294 { 0295 int ofs; 0296 char* buf; 0297 0298 ofs = 0; 0299 if (count >= dest->sz) 0300 return IOBufferOverflow; 0301 buf = dest->buf; 0302 for (; ofs < count; ++ofs) 0303 *(buf++) = _digit2ascii(n->getdigit(ofs, &n->seq)); 0304 *(buf) = '\0'; 0305 return Success; 0306 } 0307 0308 /* copy all digits (leading zeros included) from the 0309 digit sequence described by n to an ASCII buffer, but 0310 complement the sequence before writing to the buffer */ 0311 static Error 0312 _cmplseq2str( 0313 p_buffer dest, 0314 p_ext_seq_desc n) 0315 { 0316 int bound; 0317 int ofs; 0318 int lastnz; 0319 char* buf; 0320 char c; 0321 0322 buf = dest->buf; 0323 bound = _intdigits(&n->seq); 0324 if (bound + 1 > dest->sz) 0325 return IOBufferOverflow; 0326 lastnz = _ofslastnz(&n->seq); 0327 for (ofs = -1; ++ofs < lastnz;) 0328 { 0329 c = n->seq.base - n->getdigit(ofs, &n->seq) - 1; 0330 *(buf++) = _digit2ascii(c); 0331 } 0332 c = n->getdigit(ofs, &n->seq); 0333 if (c != 1 || _significantdigits(&n->seq) != 1) 0334 *(buf++) = _digit2ascii(n->seq.base - c); 0335 else 0336 { 0337 --bound; 0338 --ofs; 0339 } 0340 for (; ++ofs < bound;) 0341 *(buf++) = _digit2ascii(0); 0342 *(buf) = '\0'; 0343 return Success; 0344 } 0345 0346 /* create a descriptor from a sequence of digits, 0347 assuming the sequence is an integer */ 0348 static Error 0349 str2int( 0350 p_ext_seq_desc n, 0351 const char* value, 0352 p_prefix prefix, 0353 int maxdigits) 0354 { 0355 char complement; 0356 0357 if (prefix->base == IO_BASE_NAN) 0358 return IONoBase; 0359 complement = prefix->sign == IO_SIGN_COMPLEMENT; 0360 if (complement) 0361 { 0362 n->getdigit = _getcmpldigit; 0363 /* necessary, because when value is empty, base = IO_BASE_ZERO */ 0364 n->seq.base = prefix->base; 0365 } 0366 if (value) 0367 _str2seq(n, value, maxdigits, prefix->base, complement); 0368 return Success; 0369 } 0370 0371 /* if base describes a special value (0 or NaN), the normal 0372 conversion routines fail. This routine creates special output 0373 values for these bases, and return 0374 nmbBufferOverflow: if the buffer is too small 0375 nmbSpecial: if it created output 0376 nmbNormal: if base stands for a usual number that the 0377 normal routines should deal with */ 0378 static NmbType 0379 _special2str( 0380 p_otokens tokens, 0381 signed char base) 0382 { 0383 const char* p; 0384 switch (base) 0385 { 0386 case IO_BASE_ZERO: 0387 p = "0"; 0388 break; 0389 case IO_BASE_NAN: 0390 p = "NaN"; 0391 break; 0392 default: 0393 return NmbNormal; 0394 } 0395 return _setstr(&tokens->intpart, p)? NmbSpecial : NmbBufferOverflow; 0396 } 0397 0398 /* create an ASCIIZ sequence of the integer part, 0399 set sign and base. */ 0400 static Error 0401 int2str( 0402 p_otokens tokens, 0403 p_number_desc n, 0404 char complement) 0405 { 0406 tokens->sign = n->prefix.sign; 0407 tokens->base = n->prefix.base; 0408 switch (_special2str(tokens, n->prefix.base)) 0409 { 0410 case NmbSpecial: return Success; 0411 case NmbBufferOverflow: return IOBufferOverflow; 0412 default: break; /* NmbNormal */ 0413 } 0414 /* no special encodings */ 0415 if (complement) 0416 return _cmplseq2str(&tokens->intpart, &n->intpart); 0417 return _seq2str(&tokens->intpart, _intdigits(&n->intpart.seq), 0418 &n->intpart); 0419 } 0420 0421 /* do some sanity checks, create descriptors of integer and fraction 0422 part in tokens, set sign and base */ 0423 static Error 0424 str2fixp( 0425 p_number_desc n, 0426 p_itokens tokens) 0427 { 0428 Error result; 0429 int maxdigits; 0430 0431 maxdigits = tokens->maxdigits; 0432 n->prefix.base = tokens->base; 0433 n->prefix.sign = tokens->sign; 0434 if (tokens->sign == IO_SIGN_COMPLEMENT 0435 && (!_isempty(tokens->fracpart) || tokens->exp)) 0436 return IOInvalidComplement; 0437 result = str2int(&n->intpart, tokens->intpart, &n->prefix, maxdigits); 0438 if (_isspecial(n->prefix.base)) 0439 return result; 0440 if (!_isempty(tokens->fracpart)) 0441 _str2seq(&n->fracpart, tokens->fracpart, 0442 maxdigits - _intdigits(&n->intpart.seq), 0443 n->prefix.base, 0); 0444 if (n->prefix.sign != IO_SIGN_COMPLEMENT 0445 && n->intpart.seq.digits + n->fracpart.seq.digits == 0) 0446 return IONoSignificand; 0447 if (n->prefix.sign != IO_SIGN_COMPLEMENT 0448 && _iszero(&n->intpart.seq) && _iszero(&n->fracpart.seq)) 0449 n->prefix.base = IO_BASE_ZERO; 0450 return Success; 0451 } 0452 0453 /* convert integer and fraction part into ASCIIZ sequences */ 0454 static Error 0455 fixp2str( 0456 p_otokens tokens, 0457 p_number_desc n, 0458 int scale) 0459 { 0460 Error result; 0461 0462 result = int2str(tokens, n, n->prefix.sign == IO_SIGN_COMPLEMENT); 0463 if (result != Success || _isspecial(n->prefix.base)) 0464 return result; 0465 return _seq2str(&tokens->fracpart, scale, &n->fracpart); 0466 } 0467 0468 /* create a descriptor from the digit sequence of the exponent */ 0469 static Error 0470 _exp2desc( 0471 p_number_desc n, 0472 p_itokens tokens) 0473 { 0474 if (tokens->expsign != IO_SIGN_NONE || tokens->exp) 0475 { 0476 unsigned upperLimit; 0477 signed char sign; 0478 switch (tokens->base) 0479 { 0480 case 2 : upperLimit = BITS_IN_BINEXP - 1; break; 0481 case 8 : upperLimit = BITS_IN_OCTEXP - 1; break; 0482 case 16: upperLimit = BITS_IN_HEXEXP - 1; break; 0483 default: upperLimit = BITS_IN_EXP - 1; break; 0484 } 0485 upperLimit = (1 << (upperLimit)) - 1; 0486 sign = tokens->expsign; 0487 switch (sign) 0488 { 0489 case IO_SIGN_COMPLEMENT: 0490 return IOBadExp; 0491 case IO_SIGN_NONE: 0492 sign = IO_SIGN_PLUS; break; 0493 case IO_SIGN_MINUS: 0494 ++upperLimit; break; 0495 default:; 0496 } 0497 if (tokens->exp > upperLimit) 0498 return IOExpOverflow; 0499 if (sign < 0) 0500 n->exp = -(int)(tokens->exp); 0501 else 0502 n->exp = tokens->exp; 0503 } 0504 return Success; 0505 } 0506 0507 /* create a descriptor from the floating point number given in 0508 tokens */ 0509 Error 0510 str2desc( 0511 p_number_desc n, 0512 p_itokens tokens) 0513 { 0514 Error result; 0515 0516 _clearnumber(n); 0517 result = str2fixp(n, tokens); 0518 if (result == Success) 0519 result = _exp2desc(n, tokens); 0520 if (result != Success) 0521 n->prefix.base = IO_BASE_NAN; 0522 return result; 0523 } 0524 0525 Error 0526 desc2str( 0527 p_otokens tokens, 0528 p_number_desc n, 0529 int scale) 0530 { 0531 Error result; 0532 0533 result = fixp2str(tokens, n, scale); 0534 if (result != Success || _isspecial(n->prefix.base)) 0535 return result; 0536 tokens->exp = n->exp; 0537 return Success; 0538 } 0539 0540 Error 0541 exp2str( 0542 p_buffer dest, 0543 int exp, 0544 char base) 0545 { 0546 char tmp[BITS_IN_EXP + 3]; 0547 int idx = 0; 0548 int di = 0; 0549 if (exp < 0) 0550 exp = -exp; 0551 while (exp != 0) 0552 { 0553 tmp[idx++] = hexdigits[exp % base]; 0554 exp /= base; 0555 } 0556 if (idx == 0) 0557 tmp[idx++] = hexdigits[0]; 0558 if (dest->sz <= idx) 0559 return IOBufferOverflow; 0560 for (; --idx >= 0;) 0561 dest->buf[di++] = tmp[idx]; 0562 dest->buf[di] = 0; 0563 return Success; 0564 } 0565 0566 0567 /* ***************** additional stuff, just to get started *************/ 0568 0569 static t_ioparams stdioparams[4] = 0570 { 0571 {10, 10, '.', "0d", "eE(", " )", "", DECPRECISION}, 0572 {16, 10, '.', "0x", "hH(", " )", "sF", HEXPRECISION}, 0573 {2, 10, '.', "0b", "bB(", " )", "s1", BINPRECISION}, 0574 {8, 10, '.', "0o", "oOC(", " )", "s7", OCTPRECISION} 0575 }; 0576 0577 enum {idzero, idx10, idx16, idx2, idx8, idxcount}; 0578 0579 static t_ioparams ioparams[idxcount] = { 0580 {IO_BASE_ZERO, IO_BASE_ZERO, '\0', "", "", "", "", 0x7FFFFFFF}, 0581 {IO_BASE_DEFAULT, IO_BASE_DEFAULT, '\0', "", "", "", "", 0}, 0582 {IO_BASE_DEFAULT, IO_BASE_DEFAULT, '\0', "", "", "", "", 0}, 0583 {IO_BASE_DEFAULT, IO_BASE_DEFAULT, '\0', "", "", "", "", 0}, 0584 {IO_BASE_DEFAULT, IO_BASE_DEFAULT, '\0', "", "", "", "", 0} 0585 }; 0586 0587 static p_ioparams _defaultbase = NULL; 0588 0589 static char 0590 _isvalidioparams( 0591 p_ioparams param) 0592 { 0593 return param != NULL && param->base != IO_BASE_DEFAULT; 0594 } 0595 0596 static void 0597 _invalidateioparams( 0598 p_ioparams param) 0599 { 0600 if (param) 0601 param->base = IO_BASE_DEFAULT; 0602 } 0603 0604 p_ioparams 0605 _base2ioparams( 0606 signed char base) 0607 { 0608 int idx; 0609 0610 switch (base) 0611 { 0612 case 10: 0613 idx = idx10; 0614 break; 0615 case 16: 0616 idx = idx16; 0617 break; 0618 case 2: 0619 idx = idx2; 0620 break; 0621 case 8: 0622 idx = idx8; 0623 break; 0624 case IO_BASE_ZERO: 0625 idx = idzero; 0626 break; 0627 default: 0628 return NULL; 0629 } 0630 return &ioparams[idx]; 0631 } 0632 0633 char 0634 setioparams( 0635 p_ioparams params) 0636 { 0637 p_ioparams dest; 0638 0639 if (!_isvalidioparams(params)) 0640 return 0; 0641 dest = _base2ioparams(params->base); 0642 if (dest == NULL) 0643 return 0; 0644 *dest = *params; 0645 return 1; 0646 } 0647 0648 char 0649 delioparams( 0650 signed char base) 0651 { 0652 p_ioparams dest; 0653 0654 dest = _base2ioparams(base); 0655 _invalidateioparams(dest); 0656 return dest != NULL; 0657 } 0658 0659 p_ioparams 0660 getioparams( 0661 signed char base) 0662 { 0663 p_ioparams result; 0664 0665 if (base == IO_BASE_DEFAULT) 0666 return _defaultbase; 0667 result = _base2ioparams(base); 0668 return _isvalidioparams(result)? result : NULL; 0669 } 0670 0671 static signed char 0672 _getdefaultbase() 0673 { 0674 p_ioparams param; 0675 0676 param = getioparams(IO_BASE_DEFAULT); 0677 return param == NULL? IO_BASE_DEFAULT : param->base; 0678 } 0679 0680 signed char 0681 setdefaultbase( 0682 signed char base) 0683 { 0684 char result; 0685 0686 result = _getdefaultbase(); 0687 _defaultbase = _base2ioparams(base); 0688 return result; 0689 } 0690 0691 void 0692 float_stdconvert() 0693 { 0694 int i; 0695 0696 for (i = 0; i < 4; ++i) 0697 setioparams(&stdioparams[i]); 0698 setdefaultbase(10); 0699 } 0700 0701 const char* basePrefix(char base) 0702 { 0703 return getioparams(base)->basetag; 0704 } 0705 0706 static signed char 0707 _parsesign( 0708 const char** buf) 0709 { 0710 signed char result; 0711 0712 result = IO_SIGN_NONE; 0713 if (!_isempty(*buf)) 0714 switch (**buf) 0715 { 0716 case '-': 0717 result = IO_SIGN_MINUS; 0718 break; 0719 case '+': 0720 result = IO_SIGN_PLUS; 0721 } 0722 if (result != IO_SIGN_NONE) 0723 (*buf)++; 0724 return result; 0725 } 0726 0727 static signed char 0728 _parsebase( 0729 const char** buf, 0730 char defaultbase) 0731 { 0732 signed char base; 0733 int lg, i; 0734 0735 lg = 0; 0736 base = IO_BASE_DEFAULT; 0737 if (!_isempty(*buf)) 0738 for (i = 0; i < idxcount; ++i) 0739 { 0740 lg = _match(*buf, ioparams[i].basetag); 0741 if (lg > 0) 0742 { 0743 base = ioparams[i].base; 0744 break; 0745 } 0746 } 0747 *buf += lg; 0748 return base == IO_BASE_DEFAULT? defaultbase : base; 0749 } 0750 0751 static char 0752 _parsecmpl( 0753 const char** buf, 0754 char base) 0755 { 0756 int lg; 0757 p_ioparams param; 0758 0759 param = getioparams(base); 0760 lg = 0; 0761 if (_isvalidioparams(param)) 0762 lg = _match(*buf, param->cmpltag); 0763 *buf += lg; 0764 return lg > 0; 0765 } 0766 0767 Error 0768 parse( 0769 p_itokens tokens, 0770 const char** buffer) 0771 { 0772 p_ioparams params; 0773 const char* p; 0774 char* expchar; 0775 signed char base; 0776 int idx; 0777 char dot; 0778 char* expbegin; 0779 char* expend; 0780 0781 tokens->fracpart = NULL; 0782 tokens->exp = 0; 0783 tokens->expsign = IO_SIGN_NONE; 0784 tokens->maxdigits = 0; 0785 dot = '.'; 0786 expbegin = "("; 0787 expend = ")"; 0788 p = *buffer; 0789 tokens->sign = _parsesign(&p); 0790 base = _parsebase(&p, _getdefaultbase()); 0791 params = getioparams(base); 0792 if (params != NULL) 0793 { 0794 dot = params->dot; 0795 if (params->expbegin != NULL) 0796 expbegin = params->expbegin; 0797 if (params->expend != NULL) 0798 expend = params->expend; 0799 tokens->maxdigits = params->maxdigits; 0800 } 0801 else 0802 base = 10; 0803 tokens->base = base; 0804 if (tokens->maxdigits <= 0) 0805 tokens->maxdigits = DECPRECISION; 0806 if (_parsecmpl(&p, tokens->base)) 0807 { 0808 if (tokens->sign != IO_SIGN_NONE) 0809 return IOInvalidComplement; 0810 tokens->sign = IO_SIGN_COMPLEMENT; 0811 } 0812 tokens->intpart = _scandigits(&p, base); 0813 if (*p == dot) 0814 { 0815 ++p; 0816 tokens->fracpart = _scandigits(&p, base); 0817 } 0818 if (!tokens->intpart && !tokens->fracpart 0819 && tokens->sign != IO_SIGN_COMPLEMENT) 0820 return IONoSignificand; 0821 expchar = strchr(expbegin, *p); 0822 if (!_isempty(expchar)) 0823 { 0824 const char* expptr; 0825 int i; 0826 int e = 0; 0827 int expbase; 0828 ++p; 0829 idx = expchar - expbegin; 0830 tokens->expsign = _parsesign(&p); 0831 expbase = _parsebase(&p, base); 0832 expptr = _scandigits(&p, expbase); 0833 if (!expptr || (*(expend + idx) != ' ' && *(expend + idx) != *p)) 0834 return IOBadExp; 0835 for (i = 0; i < p-expptr; ++i) 0836 { 0837 if (!_checkmul(&e, expbase) 0838 || !_checkadd(&e, _ascii2digit(*(expptr+i)))) 0839 return IOExpOverflow; 0840 } 0841 tokens->exp = e; 0842 } 0843 *buffer = p; 0844 return Success; 0845 } 0846 0847 static char 0848 _decodesign( 0849 signed char s) 0850 { 0851 switch (s) 0852 { 0853 case IO_SIGN_PLUS: 0854 return '+'; 0855 case IO_SIGN_MINUS: 0856 return '-'; 0857 } 0858 return '\0'; 0859 } 0860 0861 static char* 0862 _decodebase( 0863 signed char base) 0864 { 0865 p_ioparams param; 0866 0867 param = getioparams(base); 0868 if (!_isvalidioparams(param) || _isempty(param->basetag)) 0869 return &emptystr; 0870 return param->basetag; 0871 } 0872 0873 static char* 0874 _decodecomplement( 0875 signed char sign, 0876 signed char base) 0877 { 0878 p_ioparams param; 0879 0880 param = getioparams(base); 0881 if (sign != IO_SIGN_COMPLEMENT || !_isvalidioparams(param) 0882 || _isempty(param->cmpltag)) 0883 return &emptystr; 0884 return param->cmpltag; 0885 } 0886 0887 static void 0888 _cattoken( 0889 char* buf, 0890 char* token, 0891 char enable) 0892 { 0893 if (enable && !_isempty(token)) 0894 strcat(buf, token); 0895 } 0896 0897 int 0898 cattokens( 0899 char* buf, 0900 int bufsz, 0901 p_otokens tokens, 0902 signed char expbase, 0903 unsigned flags) 0904 { 0905 int sz; 0906 int fraclg; 0907 p_ioparams ioparams; 0908 char* expbegin; 0909 char* expend; 0910 char* cmpltag; 0911 char* basetag; 0912 char* expbasetag; 0913 signed char base; 0914 char dot; 0915 char cbuf[2]; 0916 char printsign; 0917 char printbasetag; 0918 char printcmpl; 0919 char printleading0; 0920 char printdot; 0921 char printexp; 0922 char printexpsign = 0; 0923 char printexpbase = 0; 0924 char printexpbegin; 0925 char printexpend; 0926 char exp[BITS_IN_BINEXP+2]; 0927 t_buffer expBuf; 0928 0929 expBuf.sz = sizeof(exp); 0930 expBuf.buf = exp; 0931 cbuf[1] = '\0'; 0932 fraclg = 0; 0933 if (!_isempty(tokens->fracpart.buf)) 0934 { 0935 fraclg = strlen(tokens->fracpart.buf) - 1; 0936 if ((flags & IO_FLAG_SUPPRESS_TRL_ZERO) != 0) 0937 while (fraclg >= 0 && tokens->fracpart.buf[fraclg] == '0') 0938 --fraclg; 0939 ++fraclg; 0940 } 0941 ioparams = getioparams(IO_BASE_DEFAULT); 0942 base = tokens->base; 0943 printbasetag = !_isspecial(base) 0944 && (flags & IO_FLAG_SUPPRESS_BASETAG) == 0 0945 && (ioparams == NULL || ioparams->base != base); 0946 ioparams = getioparams(base); 0947 basetag = _decodebase(base); 0948 cmpltag = _decodecomplement(tokens->sign, base); 0949 expbasetag = NULL; 0950 if (base == IO_BASE_DEFAULT) 0951 flags |= IO_FLAG_SUPPRESS_DOT | IO_FLAG_SUPPRESS_LDG_ZERO; 0952 if ((flags & IO_FLAG_SHOW_BASE) != 0) 0953 printbasetag = 1; 0954 printcmpl = tokens->sign == IO_SIGN_COMPLEMENT 0955 && (flags & IO_FLAG_SUPPRESS_CMPL) == 0; 0956 printsign = !printcmpl 0957 && tokens->sign != IO_SIGN_NONE 0958 && (tokens->sign != IO_SIGN_PLUS 0959 || (flags & IO_FLAG_SUPPRESS_PLUS) == 0); 0960 printleading0 = _isempty(tokens->intpart.buf) 0961 && (flags & IO_FLAG_SUPPRESS_LDG_ZERO) == 0; 0962 printdot = fraclg > 0 || (flags & IO_FLAG_SUPPRESS_DOT) == 0; 0963 printexp = base != IO_BASE_NAN && base != IO_BASE_ZERO 0964 && ((flags & IO_FLAG_SUPPRESS_EXPZERO) == 0 0965 || tokens->exp != 0); 0966 if (printexp) 0967 { 0968 if (expbase < 2) 0969 expbase = ioparams->expbase; 0970 expbasetag = _decodebase(expbase); 0971 printexpsign = tokens->exp < 0 0972 || (flags & IO_FLAG_SUPPRESS_EXPPLUS) == 0; 0973 printexpbase = expbasetag != NULL 0974 && (flags & IO_FLAG_SUPPRESS_EXPBASE) == 0 0975 && (_isempty(basetag) 0976 || strcmp(basetag, expbasetag) != 0); 0977 if ((flags & IO_FLAG_SHOW_EXPBASE) != 0) 0978 printexpbase = 1; 0979 } 0980 dot = '.'; 0981 expbegin = "("; 0982 expend = ")"; 0983 if (ioparams != NULL) 0984 { 0985 dot = ioparams->dot; 0986 expbegin = ioparams->expbegin; 0987 expend = ioparams->expend; 0988 } 0989 printexpbegin = *expbegin != '\0'; 0990 printexpend = *expend != '\0' && *expend != ' '; 0991 sz = 1; 0992 if (printsign) 0993 sz += 1; 0994 if (printbasetag) 0995 sz += strlen(basetag); 0996 if (printcmpl) 0997 sz += strlen(cmpltag); 0998 if (printleading0) 0999 ++sz; 1000 if (!_isempty(tokens->intpart.buf)) 1001 sz += strlen(tokens->intpart.buf); 1002 if (printdot) 1003 sz += 1; 1004 sz += fraclg; 1005 if (printexp) 1006 { 1007 exp2str(&expBuf, tokens->exp, expbase); 1008 if (printexpbegin) 1009 ++sz; 1010 if (printexpsign) 1011 sz += 1; 1012 if (printexpbase) 1013 sz += strlen(expbasetag); 1014 sz += strlen(expBuf.buf); 1015 if (printexpend) 1016 ++sz; 1017 } 1018 if (sz <= bufsz) 1019 { 1020 *buf = '\0'; 1021 cbuf[0] = _decodesign(tokens->sign); 1022 _cattoken(buf, cbuf, printsign); 1023 _cattoken(buf, basetag, printbasetag); 1024 _cattoken(buf, cmpltag, printcmpl); 1025 _cattoken(buf, "0", printleading0); 1026 _cattoken(buf, tokens->intpart.buf, 1); 1027 cbuf[0] = dot; 1028 _cattoken(buf, cbuf, printdot); 1029 if (fraclg > 0) 1030 strncat(buf, tokens->fracpart.buf, fraclg); 1031 if (printexp) 1032 { 1033 cbuf[0] = *expbegin; 1034 _cattoken(buf, cbuf, printexpbegin); 1035 cbuf[0] = _decodesign(tokens->exp < 0? -1:1); 1036 _cattoken(buf, cbuf, printexpsign); 1037 _cattoken(buf, expbasetag, printexpbase); 1038 strcat(buf, expBuf.buf); 1039 cbuf[0] = *expend; 1040 _cattoken(buf, cbuf, printexpend); 1041 } 1042 } 1043 return sz; 1044 }