1 1.1 mrg /* Packed decimal conversion module for the decNumber C Library. 2 1.12 mrg Copyright (C) 2007-2022 Free Software Foundation, Inc. 3 1.1 mrg Contributed by IBM Corporation. Author Mike Cowlishaw. 4 1.1 mrg 5 1.1 mrg This file is part of GCC. 6 1.1 mrg 7 1.1 mrg GCC is free software; you can redistribute it and/or modify it under 8 1.1 mrg the terms of the GNU General Public License as published by the Free 9 1.1 mrg Software Foundation; either version 3, or (at your option) any later 10 1.1 mrg version. 11 1.1 mrg 12 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 1.1 mrg for more details. 16 1.1 mrg 17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 18 1.1 mrg permissions described in the GCC Runtime Library Exception, version 19 1.1 mrg 3.1, as published by the Free Software Foundation. 20 1.1 mrg 21 1.1 mrg You should have received a copy of the GNU General Public License and 22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 1.1 mrg <http://www.gnu.org/licenses/>. */ 25 1.1 mrg 26 1.1 mrg /* ------------------------------------------------------------------ */ 27 1.1 mrg /* Packed Decimal conversion module */ 28 1.1 mrg /* ------------------------------------------------------------------ */ 29 1.1 mrg /* This module comprises the routines for Packed Decimal format */ 30 1.1 mrg /* numbers. Conversions are supplied to and from decNumber, which in */ 31 1.1 mrg /* turn supports: */ 32 1.1 mrg /* conversions to and from string */ 33 1.1 mrg /* arithmetic routines */ 34 1.1 mrg /* utilities. */ 35 1.1 mrg /* Conversions from decNumber to and from densely packed decimal */ 36 1.1 mrg /* formats are provided by the decimal32 through decimal128 modules. */ 37 1.1 mrg /* ------------------------------------------------------------------ */ 38 1.1 mrg 39 1.1 mrg #include <string.h> /* for NULL */ 40 1.1 mrg #include "decNumber.h" /* base number library */ 41 1.1 mrg #include "decPacked.h" /* packed decimal */ 42 1.1 mrg #include "decNumberLocal.h" /* decNumber local types, etc. */ 43 1.1 mrg 44 1.1 mrg /* ------------------------------------------------------------------ */ 45 1.1 mrg /* decPackedFromNumber -- convert decNumber to BCD Packed Decimal */ 46 1.1 mrg /* */ 47 1.1 mrg /* bcd is the BCD bytes */ 48 1.1 mrg /* length is the length of the BCD array */ 49 1.1 mrg /* scale is the scale result */ 50 1.1 mrg /* dn is the decNumber */ 51 1.1 mrg /* returns bcd, or NULL if error */ 52 1.1 mrg /* */ 53 1.1 mrg /* The number is converted to a BCD packed decimal byte array, */ 54 1.1 mrg /* right aligned in the bcd array, whose length is indicated by the */ 55 1.1 mrg /* second parameter. The final 4-bit nibble in the array will be a */ 56 1.1 mrg /* sign nibble, C (1100) for + and D (1101) for -. Unused bytes and */ 57 1.1 mrg /* nibbles to the left of the number are set to 0. */ 58 1.1 mrg /* */ 59 1.1 mrg /* scale is set to the scale of the number (this is the exponent, */ 60 1.1 mrg /* negated). To force the number to a specified scale, first use the */ 61 1.1 mrg /* decNumberRescale routine, which will round and change the exponent */ 62 1.1 mrg /* as necessary. */ 63 1.1 mrg /* */ 64 1.1 mrg /* If there is an error (that is, the decNumber has too many digits */ 65 1.1 mrg /* to fit in length bytes, or it is a NaN or Infinity), NULL is */ 66 1.1 mrg /* returned and the bcd and scale results are unchanged. Otherwise */ 67 1.1 mrg /* bcd is returned. */ 68 1.1 mrg /* ------------------------------------------------------------------ */ 69 1.1 mrg uByte * decPackedFromNumber(uByte *bcd, Int length, Int *scale, 70 1.1 mrg const decNumber *dn) { 71 1.1 mrg const Unit *up=dn->lsu; /* Unit array pointer */ 72 1.1 mrg uByte obyte, *out; /* current output byte, and where it goes */ 73 1.1 mrg Int indigs=dn->digits; /* digits processed */ 74 1.1 mrg uInt cut=DECDPUN; /* downcounter per Unit */ 75 1.1 mrg uInt u=*up; /* work */ 76 1.1 mrg uInt nib; /* .. */ 77 1.1 mrg #if DECDPUN<=4 78 1.1 mrg uInt temp; /* .. */ 79 1.1 mrg #endif 80 1.1 mrg 81 1.1 mrg if (dn->digits>length*2-1 /* too long .. */ 82 1.1 mrg ||(dn->bits & DECSPECIAL)) return NULL; /* .. or special -- hopeless */ 83 1.1 mrg 84 1.1 mrg if (dn->bits&DECNEG) obyte=DECPMINUS; /* set the sign .. */ 85 1.1 mrg else obyte=DECPPLUS; 86 1.1 mrg *scale=-dn->exponent; /* .. and scale */ 87 1.1 mrg 88 1.1 mrg /* loop from lowest (rightmost) byte */ 89 1.1 mrg out=bcd+length-1; /* -> final byte */ 90 1.1 mrg for (; out>=bcd; out--) { 91 1.1 mrg if (indigs>0) { 92 1.1 mrg if (cut==0) { 93 1.1 mrg up++; 94 1.1 mrg u=*up; 95 1.1 mrg cut=DECDPUN; 96 1.1 mrg } 97 1.1 mrg #if DECDPUN<=4 98 1.1 mrg temp=(u*6554)>>16; /* fast /10 */ 99 1.1 mrg nib=u-X10(temp); 100 1.1 mrg u=temp; 101 1.1 mrg #else 102 1.1 mrg nib=u%10; /* cannot use *6554 trick :-( */ 103 1.1 mrg u=u/10; 104 1.1 mrg #endif 105 1.1 mrg obyte|=(nib<<4); 106 1.1 mrg indigs--; 107 1.1 mrg cut--; 108 1.1 mrg } 109 1.1 mrg *out=obyte; 110 1.1 mrg obyte=0; /* assume 0 */ 111 1.1 mrg if (indigs>0) { 112 1.1 mrg if (cut==0) { 113 1.1 mrg up++; 114 1.1 mrg u=*up; 115 1.1 mrg cut=DECDPUN; 116 1.1 mrg } 117 1.1 mrg #if DECDPUN<=4 118 1.1 mrg temp=(u*6554)>>16; /* as above */ 119 1.1 mrg obyte=(uByte)(u-X10(temp)); 120 1.1 mrg u=temp; 121 1.1 mrg #else 122 1.1 mrg obyte=(uByte)(u%10); 123 1.1 mrg u=u/10; 124 1.1 mrg #endif 125 1.1 mrg indigs--; 126 1.1 mrg cut--; 127 1.1 mrg } 128 1.1 mrg } /* loop */ 129 1.1 mrg 130 1.1 mrg return bcd; 131 1.1 mrg } /* decPackedFromNumber */ 132 1.1 mrg 133 1.1 mrg /* ------------------------------------------------------------------ */ 134 1.1 mrg /* decPackedToNumber -- convert BCD Packed Decimal to a decNumber */ 135 1.1 mrg /* */ 136 1.1 mrg /* bcd is the BCD bytes */ 137 1.1 mrg /* length is the length of the BCD array */ 138 1.1 mrg /* scale is the scale associated with the BCD integer */ 139 1.1 mrg /* dn is the decNumber [with space for length*2 digits] */ 140 1.1 mrg /* returns dn, or NULL if error */ 141 1.1 mrg /* */ 142 1.1 mrg /* The BCD packed decimal byte array, together with an associated */ 143 1.1 mrg /* scale, is converted to a decNumber. The BCD array is assumed full */ 144 1.1 mrg /* of digits, and must be ended by a 4-bit sign nibble in the least */ 145 1.1 mrg /* significant four bits of the final byte. */ 146 1.1 mrg /* */ 147 1.1 mrg /* The scale is used (negated) as the exponent of the decNumber. */ 148 1.1 mrg /* Note that zeros may have a sign and/or a scale. */ 149 1.1 mrg /* */ 150 1.1 mrg /* The decNumber structure is assumed to have sufficient space to */ 151 1.1 mrg /* hold the converted number (that is, up to length*2-1 digits), so */ 152 1.1 mrg /* no error is possible unless the adjusted exponent is out of range, */ 153 1.1 mrg /* no sign nibble was found, or a sign nibble was found before the */ 154 1.1 mrg /* final nibble. In these error cases, NULL is returned and the */ 155 1.1 mrg /* decNumber will be 0. */ 156 1.1 mrg /* ------------------------------------------------------------------ */ 157 1.1 mrg decNumber * decPackedToNumber(const uByte *bcd, Int length, 158 1.1 mrg const Int *scale, decNumber *dn) { 159 1.1 mrg const uByte *last=bcd+length-1; /* -> last byte */ 160 1.1 mrg const uByte *first; /* -> first non-zero byte */ 161 1.1 mrg uInt nib; /* work nibble */ 162 1.1 mrg Unit *up=dn->lsu; /* output pointer */ 163 1.1 mrg Int digits; /* digits count */ 164 1.1 mrg Int cut=0; /* phase of output */ 165 1.1 mrg 166 1.1 mrg decNumberZero(dn); /* default result */ 167 1.1 mrg last=&bcd[length-1]; 168 1.1 mrg nib=*last & 0x0f; /* get the sign */ 169 1.1 mrg if (nib==DECPMINUS || nib==DECPMINUSALT) dn->bits=DECNEG; 170 1.1 mrg else if (nib<=9) return NULL; /* not a sign nibble */ 171 1.1 mrg 172 1.1 mrg /* skip leading zero bytes [final byte is always non-zero, due to sign] */ 173 1.1 mrg for (first=bcd; *first==0;) first++; 174 1.1 mrg digits=(last-first)*2+1; /* calculate digits .. */ 175 1.1 mrg if ((*first & 0xf0)==0) digits--; /* adjust for leading zero nibble */ 176 1.1 mrg if (digits!=0) dn->digits=digits; /* count of actual digits [if 0, */ 177 1.1 mrg /* leave as 1] */ 178 1.1 mrg 179 1.1 mrg /* check the adjusted exponent; note that scale could be unbounded */ 180 1.1 mrg dn->exponent=-*scale; /* set the exponent */ 181 1.1 mrg if (*scale>=0) { /* usual case */ 182 1.1 mrg if ((dn->digits-*scale-1)<-DECNUMMAXE) { /* underflow */ 183 1.1 mrg decNumberZero(dn); 184 1.1 mrg return NULL;} 185 1.1 mrg } 186 1.1 mrg else { /* -ve scale; +ve exponent */ 187 1.1 mrg /* need to be careful to avoid wrap, here, also BADINT case */ 188 1.1 mrg if ((*scale<-DECNUMMAXE) /* overflow even without digits */ 189 1.1 mrg || ((dn->digits-*scale-1)>DECNUMMAXE)) { /* overflow */ 190 1.1 mrg decNumberZero(dn); 191 1.1 mrg return NULL;} 192 1.1 mrg } 193 1.1 mrg if (digits==0) return dn; /* result was zero */ 194 1.1 mrg 195 1.1 mrg /* copy the digits to the number's units, starting at the lsu */ 196 1.1 mrg /* [unrolled] */ 197 1.1 mrg for (;;) { /* forever */ 198 1.1 mrg /* left nibble first */ 199 1.1 mrg nib=(unsigned)(*last & 0xf0)>>4; 200 1.1 mrg /* got a digit, in nib */ 201 1.1 mrg if (nib>9) {decNumberZero(dn); return NULL;} 202 1.1 mrg 203 1.1 mrg if (cut==0) *up=(Unit)nib; 204 1.1 mrg else *up=(Unit)(*up+nib*DECPOWERS[cut]); 205 1.1 mrg digits--; 206 1.1 mrg if (digits==0) break; /* got them all */ 207 1.1 mrg cut++; 208 1.1 mrg if (cut==DECDPUN) { 209 1.1 mrg up++; 210 1.1 mrg cut=0; 211 1.1 mrg } 212 1.1 mrg last--; /* ready for next */ 213 1.1 mrg nib=*last & 0x0f; /* get right nibble */ 214 1.1 mrg if (nib>9) {decNumberZero(dn); return NULL;} 215 1.1 mrg 216 1.1 mrg /* got a digit, in nib */ 217 1.1 mrg if (cut==0) *up=(Unit)nib; 218 1.1 mrg else *up=(Unit)(*up+nib*DECPOWERS[cut]); 219 1.1 mrg digits--; 220 1.1 mrg if (digits==0) break; /* got them all */ 221 1.1 mrg cut++; 222 1.1 mrg if (cut==DECDPUN) { 223 1.1 mrg up++; 224 1.1 mrg cut=0; 225 1.1 mrg } 226 1.1 mrg } /* forever */ 227 1.1 mrg 228 1.1 mrg return dn; 229 1.1 mrg } /* decPackedToNumber */ 230 1.1 mrg 231