|  | /* Packed decimal conversion module for the decNumber C Library. | 
|  | Copyright (C) 2007-2018 Free Software Foundation, Inc. | 
|  | Contributed by IBM Corporation.  Author Mike Cowlishaw. | 
|  |  | 
|  | This file is part of GCC. | 
|  |  | 
|  | GCC is free software; you can redistribute it and/or modify it under | 
|  | the terms of the GNU General Public License as published by the Free | 
|  | Software Foundation; either version 3, or (at your option) any later | 
|  | version. | 
|  |  | 
|  | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | 
|  | WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|  | FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|  | for more details. | 
|  |  | 
|  | Under Section 7 of GPL version 3, you are granted additional | 
|  | permissions described in the GCC Runtime Library Exception, version | 
|  | 3.1, as published by the Free Software Foundation. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License and | 
|  | a copy of the GCC Runtime Library Exception along with this program; | 
|  | see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see | 
|  | <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | /* ------------------------------------------------------------------ */ | 
|  | /* Packed Decimal conversion module				      */ | 
|  | /* ------------------------------------------------------------------ */ | 
|  | /* This module comprises the routines for Packed Decimal format       */ | 
|  | /* numbers.  Conversions are supplied to and from decNumber, which in */ | 
|  | /* turn supports:						      */ | 
|  | /*   conversions to and from string				      */ | 
|  | /*   arithmetic routines					      */ | 
|  | /*   utilities. 						      */ | 
|  | /* Conversions from decNumber to and from densely packed decimal      */ | 
|  | /* formats are provided by the decimal32 through decimal128 modules.  */ | 
|  | /* ------------------------------------------------------------------ */ | 
|  |  | 
|  | #include <string.h>	      /* for NULL */ | 
|  | #include "decNumber.h"	      /* base number library */ | 
|  | #include "decPacked.h"	      /* packed decimal */ | 
|  | #include "decNumberLocal.h"   /* decNumber local types, etc. */ | 
|  |  | 
|  | /* ------------------------------------------------------------------ */ | 
|  | /* decPackedFromNumber -- convert decNumber to BCD Packed Decimal     */ | 
|  | /*								      */ | 
|  | /*   bcd    is the BCD bytes					      */ | 
|  | /*   length is the length of the BCD array			      */ | 
|  | /*   scale  is the scale result 				      */ | 
|  | /*   dn     is the decNumber					      */ | 
|  | /*   returns bcd, or NULL if error				      */ | 
|  | /*								      */ | 
|  | /* The number is converted to a BCD packed decimal byte array,	      */ | 
|  | /* right aligned in the bcd array, whose length is indicated by the   */ | 
|  | /* second parameter.  The final 4-bit nibble in the array will be a   */ | 
|  | /* sign nibble, C (1100) for + and D (1101) for -.  Unused bytes and  */ | 
|  | /* nibbles to the left of the number are set to 0.		      */ | 
|  | /*								      */ | 
|  | /* scale is set to the scale of the number (this is the exponent,     */ | 
|  | /* negated).  To force the number to a specified scale, first use the */ | 
|  | /* decNumberRescale routine, which will round and change the exponent */ | 
|  | /* as necessary.						      */ | 
|  | /*								      */ | 
|  | /* If there is an error (that is, the decNumber has too many digits   */ | 
|  | /* to fit in length bytes, or it is a NaN or Infinity), NULL is       */ | 
|  | /* returned and the bcd and scale results are unchanged.  Otherwise   */ | 
|  | /* bcd is returned.						      */ | 
|  | /* ------------------------------------------------------------------ */ | 
|  | uByte * decPackedFromNumber(uByte *bcd, Int length, Int *scale, | 
|  | const decNumber *dn) { | 
|  | const Unit *up=dn->lsu;     /* Unit array pointer */ | 
|  | uByte obyte, *out;	      /* current output byte, and where it goes */ | 
|  | Int indigs=dn->digits;      /* digits processed */ | 
|  | uInt cut=DECDPUN;	      /* downcounter per Unit */ | 
|  | uInt u=*up;		      /* work */ | 
|  | uInt nib;		      /* .. */ | 
|  | #if DECDPUN<=4 | 
|  | uInt temp;		      /* .. */ | 
|  | #endif | 
|  |  | 
|  | if (dn->digits>length*2-1		     /* too long .. */ | 
|  | ||(dn->bits & DECSPECIAL)) return NULL;   /* .. or special -- hopeless */ | 
|  |  | 
|  | if (dn->bits&DECNEG) obyte=DECPMINUS;      /* set the sign .. */ | 
|  | else 	       obyte=DECPPLUS; | 
|  | *scale=-dn->exponent; 		     /* .. and scale */ | 
|  |  | 
|  | /* loop from lowest (rightmost) byte */ | 
|  | out=bcd+length-1;			     /* -> final byte */ | 
|  | for (; out>=bcd; out--) { | 
|  | if (indigs>0) { | 
|  | if (cut==0) { | 
|  | up++; | 
|  | u=*up; | 
|  | cut=DECDPUN; | 
|  | } | 
|  | #if DECDPUN<=4 | 
|  | temp=(u*6554)>>16;	   /* fast /10 */ | 
|  | nib=u-X10(temp); | 
|  | u=temp; | 
|  | #else | 
|  | nib=u%10;		   /* cannot use *6554 trick :-( */ | 
|  | u=u/10; | 
|  | #endif | 
|  | obyte|=(nib<<4); | 
|  | indigs--; | 
|  | cut--; | 
|  | } | 
|  | *out=obyte; | 
|  | obyte=0;			   /* assume 0 */ | 
|  | if (indigs>0) { | 
|  | if (cut==0) { | 
|  | up++; | 
|  | u=*up; | 
|  | cut=DECDPUN; | 
|  | } | 
|  | #if DECDPUN<=4 | 
|  | temp=(u*6554)>>16;	   /* as above */ | 
|  | obyte=(uByte)(u-X10(temp)); | 
|  | u=temp; | 
|  | #else | 
|  | obyte=(uByte)(u%10); | 
|  | u=u/10; | 
|  | #endif | 
|  | indigs--; | 
|  | cut--; | 
|  | } | 
|  | } /* loop */ | 
|  |  | 
|  | return bcd; | 
|  | } /* decPackedFromNumber */ | 
|  |  | 
|  | /* ------------------------------------------------------------------ */ | 
|  | /* decPackedToNumber -- convert BCD Packed Decimal to a decNumber     */ | 
|  | /*								      */ | 
|  | /*   bcd    is the BCD bytes					      */ | 
|  | /*   length is the length of the BCD array			      */ | 
|  | /*   scale  is the scale associated with the BCD integer	      */ | 
|  | /*   dn     is the decNumber [with space for length*2 digits]	      */ | 
|  | /*   returns dn, or NULL if error				      */ | 
|  | /*								      */ | 
|  | /* The BCD packed decimal byte array, together with an associated     */ | 
|  | /* scale, is converted to a decNumber.	The BCD array is assumed full */ | 
|  | /* of digits, and must be ended by a 4-bit sign nibble in the least   */ | 
|  | /* significant four bits of the final byte.			      */ | 
|  | /*								      */ | 
|  | /* The scale is used (negated) as the exponent of the decNumber.      */ | 
|  | /* Note that zeros may have a sign and/or a scale.		      */ | 
|  | /*								      */ | 
|  | /* The decNumber structure is assumed to have sufficient space to     */ | 
|  | /* hold the converted number (that is, up to length*2-1 digits), so   */ | 
|  | /* no error is possible unless the adjusted exponent is out of range, */ | 
|  | /* no sign nibble was found, or a sign nibble was found before the    */ | 
|  | /* final nibble.  In these error cases, NULL is returned and the      */ | 
|  | /* decNumber will be 0. 					      */ | 
|  | /* ------------------------------------------------------------------ */ | 
|  | decNumber * decPackedToNumber(const uByte *bcd, Int length, | 
|  | const Int *scale, decNumber *dn) { | 
|  | const uByte *last=bcd+length-1;  /* -> last byte */ | 
|  | const uByte *first;		   /* -> first non-zero byte */ | 
|  | uInt	nib;			   /* work nibble */ | 
|  | Unit	*up=dn->lsu;		   /* output pointer */ | 
|  | Int	digits; 		   /* digits count */ | 
|  | Int	cut=0;			   /* phase of output */ | 
|  |  | 
|  | decNumberZero(dn);		   /* default result */ | 
|  | last=&bcd[length-1]; | 
|  | nib=*last & 0x0f;		   /* get the sign */ | 
|  | if (nib==DECPMINUS || nib==DECPMINUSALT) dn->bits=DECNEG; | 
|  | else if (nib<=9) return NULL;   /* not a sign nibble */ | 
|  |  | 
|  | /* skip leading zero bytes [final byte is always non-zero, due to sign] */ | 
|  | for (first=bcd; *first==0;) first++; | 
|  | digits=(last-first)*2+1;		/* calculate digits .. */ | 
|  | if ((*first & 0xf0)==0) digits--;	/* adjust for leading zero nibble */ | 
|  | if (digits!=0) dn->digits=digits;	/* count of actual digits [if 0, */ | 
|  | /* leave as 1] */ | 
|  |  | 
|  | /* check the adjusted exponent; note that scale could be unbounded */ | 
|  | dn->exponent=-*scale; 		/* set the exponent */ | 
|  | if (*scale>=0) {			/* usual case */ | 
|  | if ((dn->digits-*scale-1)<-DECNUMMAXE) {	  /* underflow */ | 
|  | decNumberZero(dn); | 
|  | return NULL;} | 
|  | } | 
|  | else { /* -ve scale; +ve exponent */ | 
|  | /* need to be careful to avoid wrap, here, also BADINT case */ | 
|  | if ((*scale<-DECNUMMAXE)		/* overflow even without digits */ | 
|  | || ((dn->digits-*scale-1)>DECNUMMAXE)) { /* overflow */ | 
|  | decNumberZero(dn); | 
|  | return NULL;} | 
|  | } | 
|  | if (digits==0) return dn;		/* result was zero */ | 
|  |  | 
|  | /* copy the digits to the number's units, starting at the lsu */ | 
|  | /* [unrolled] */ | 
|  | for (;;) {				/* forever */ | 
|  | /* left nibble first */ | 
|  | nib=(unsigned)(*last & 0xf0)>>4; | 
|  | /* got a digit, in nib */ | 
|  | if (nib>9) {decNumberZero(dn); return NULL;} | 
|  |  | 
|  | if (cut==0) *up=(Unit)nib; | 
|  | else *up=(Unit)(*up+nib*DECPOWERS[cut]); | 
|  | digits--; | 
|  | if (digits==0) break;		/* got them all */ | 
|  | cut++; | 
|  | if (cut==DECDPUN) { | 
|  | up++; | 
|  | cut=0; | 
|  | } | 
|  | last--;				/* ready for next */ | 
|  | nib=*last & 0x0f;			/* get right nibble */ | 
|  | if (nib>9) {decNumberZero(dn); return NULL;} | 
|  |  | 
|  | /* got a digit, in nib */ | 
|  | if (cut==0) *up=(Unit)nib; | 
|  | else *up=(Unit)(*up+nib*DECPOWERS[cut]); | 
|  | digits--; | 
|  | if (digits==0) break;		/* got them all */ | 
|  | cut++; | 
|  | if (cut==DECDPUN) { | 
|  | up++; | 
|  | cut=0; | 
|  | } | 
|  | } /* forever */ | 
|  |  | 
|  | return dn; | 
|  | } /* decPackedToNumber */ | 
|  |  |