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