home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
deccvt.zip
/
deccvt.c
Wrap
Text File
|
1993-12-28
|
16KB
|
183 lines
/***************************************************************************************************/
/* */
/* This is a sample routine which converts the DBM and DB2/2 type DECIMAL to a character string. */
/* Input is a pointer to the sqlvar structure in the sqlda; the data type must be SQL_TYP_DECIMAL */
/* (484) or SQL_TYP_NDECIMAL (485), but is not checked. The output will be placed in the passed */
/* string, which is not length checked. */
/* */
/* DECIMAL strings have the format 0x1234567c for the value 1234567. There are two decimal digits */
/* per byte, and the last nibble is the sign nibble - 0x0b or 0x0b for negative, otherwise it is */
/* positive. */
/* */
/* The length and precision is returned in the sqlvar->sqllen field, in the format DDLL, where D */
/* is the number of digits to the right of the decimal point, and LL is the total length of the */
/* field. */
/* */
/* This routine left adjusts the number in the field, with leading zeros replaced by blanks. The */
/* sign is floating; it is placed immediately before the first digit of the number if the number */
/* is negative. If the number is positive, no sign is placed. If the number in the range of */
/* 1 > number > -1, a 0 is inserted before the decimal point. */
/* */
/* The operation of the routine is as follows: The end of the input is determined and the sign */
/* nibble checked for 0x0b or 0X0d and bNegativeNumber is set to TRUE if the number is negative, */
/* and FALSE otherwise. The location of the decimal point is set into sPointCtr, and the leading */
/* blanks flag bLeadingBlanks is initialized to TRUE. */
/* */
/* A loop is then entered to check each nibble of the input number. On the even numbered count, */
/* the high nibble is used; on the odd number counts, the low nibble is used and the input pointer */
/* pInputPos is incremented to the next byte. The last nibble (the sign bits) is not checked. */
/* */
/* In the loop, we check to see if we are at the decimal point. If so, and we are still inserting */
/* leading blanks, a '-' or a blank is added to the string for the sign. The current digit is */
/* unconditionally inserted, followed by the decimal point. Finally, bLeadingBlank is turned off */
/* to force all other digits to be inserted. */
/* */
/* If we are not at the decimal point location, and bLeadingBlanks is TRUE, we check the current */
/* digit. If zero, we insert a space and continue. If non-zero, we insert the sign (as above) */
/* and the digit, and set bLeadingBlanks to FALSE. If bLeadingBlanks is FALSE, the digit is */
/* inserted unconditionally. In all cases, digit insertion consists of adding '0' (character 0) */
/* to the digit before inserting into the string, and incrementing the string pointer following */
/* the insertion. */
/* */
/* After completion of the loop, a null character is added to terminate the output string. */
/* */
/* */
/* This is example code I have used for courses in DB2/2, and has not been thoroughly checked for */
/* errors. No warrenties are implied, but it has worked for the fields I have tested. */
/* */
/* Copyright (C) 1993 by JDS & Associates, Raleigh, NC. CIS ID: 70363,407 */
/* */
/***************************************************************************************************/
/* Macro definitions */
#define HINIBBLE(x) (((x) & 0XF0) >> 4) /* Return high nibble of a byte */
#define LONIBBLE(x) ((x) & 0X0F) /* Return low nibble of a byte */
char * DecimalToChar (struct sqlvar * sqlvar, PCHAR pOutput)
{
PCHAR PInputPos = sqlvar->sqldata; /* Point at the data area */
PCHAR pOutputPos = pOutput; /* Working pointer for output */
SHORT sDigitCount = LOBYTE(sqlvar->sqllen); /* Total number of digits */
SHORT sPointCtr = sDigitCount - HIBYTE(sqlvar->sqllen); /* Offset of decimal point */
SHORT sDigit = /* One digit from input */
LONIBBLE(*(PInputPos + ((sDigitCount + 1) / 2) - 1)); /* Sign character here */
BOOL bLeadingBlanks = TRUE; /* Blanks instead of leading 0's */
BOOL bNegativeNumber; /* Get sign nibble */
INT i; /* Loop control */
bNegativeNumber = (sDigit == 0X0B) || (sDigit == 0X0D); /* < 0 if sign = 0x0b or 0x0d */
pOutputPos[0] = '\0'; /* Initialize string to empty */
for (i = 0; i < (sDigitCount-1); i++) /* Loop through each except last */
{
sDigit = i % 2 ? /* Even/Odd time through test */
LONIBBLE(*(PInputPos++)) : HINIBBLE(*PInputPos); /* hi/low digit in byte */
if (--sPointCtr == 0) /* If at decimal point */
{
if (bLeadingBlanks) /* If we still have leading zeros*/
*(pOutputPos++) = bNegativeNumber ? '-' : ' '; /* Insert '-' if < 0, ' ' if > 0 */
*(pOutputPos++) = sDigit + '0'; /* Insert leading zero or digit */
*(pOutputPos++) = '.'; /* Insert the decimal point */
bLeadingBlanks = FALSE; /* No more leading blanks */
}
else
if (bLeadingBlanks) /* Suppressing leading blanks? */
if (sDigit) /* If this digit is non-zero */
{
bLeadingBlanks = FALSE; /* No more leading blanks */
*(pOutputPos++) = bNegativeNumber ? '-' : ' '; /* Insert '-' if < 0, ' ' if > 0 */
*(pOutputPos++) = sDigit + '0'; /* Insert the character */
}
else /* Still supressing leading zeros*/
*(pOutputPos++) = ' '; /* Insert a blank */
else
*(pOutputPos++) = sDigit + '0'; /* Add in the digit */
}
*pOutputPos = '\0';
return pOutput;
}
/***************************************************************************************************/
/* */
/* This is a sample routine which converts the DBM and DB2/2 type DECIMAL to a long double. */
/* Input is a pointer to the sqlvar structure in the sqlda; the data type must be SQL_TYP_DECIMAL */
/* (484) or SQL_TYP_NDECIMAL (485), but is not checked. The output is a long double type and is */
/* returned by the function directly. */
/* */
/* DECIMAL strings have the format 0x1234567c for the value 1234567. There are two decimal digits */
/* per byte, and the last nibble is the sign nibble - 0x0b or 0x0b for negative, otherwise it is */
/* positive. */
/* */
/* The length and precision is returned in the sqlvar->sqllen field, in the format DDLL, where D */
/* is the number of digits to the right of the decimal point, and LL is the total length of the */
/* field. */
/* */
/* This routine left adjusts the number in the field, with leading zeros replaced by blanks. The */
/* sign is floating; it is placed immediately before the first digit of the number if the number */
/* is negative. If the number is positive, no sign is placed. If the number in the range of */
/* 1 > number > -1, a 0 is inserted before the decimal point. */
/* */
/* The operation of the routine is as follows: The end of the input is determined and the sign */
/* nibble checked for 0x0b or 0X0d and bNegativeNumber is set to TRUE if the number is negative, */
/* and FALSE otherwise. The location of the decimal point is set into sPointCtr, and the leading */
/* blanks flag bLeadingBlanks is initialized to TRUE. */
/* */
/* A loop is then entered to check each nibble of the input number. On the even numbered count, */
/* the high nibble is used; on the odd number counts, the low nibble is used and the input pointer */
/* pInputPos is incremented to the next byte. The last nibble (the sign bits) is not checked. */
/* */
/* In the loop, we check to see if we are before the decimal point. If so, we multiply ldAccum by */
/* 10 and add the current digit. If we are after the decimal point, we multiply ldDecimalAccum */
/* by 10 and add the digit. At the same time, we multiply ldDivisor by 10 to provide a divisor. */
/* */
/* This method was selected to minimize the errors encountered by floating point variables not */
/* being able to represent exact values for fractions. Computing a new fraction each time through */
/* the loop could introduce truncation errors, which could be compounded at each iteration of the */
/* loop. This method minimizes the risk, but obviously cannot elimitate it altogether. */
/* */
/* After completion of the loop, ldDecimalAccum (the portion to the right of the decimal place) is */
/* divided by ldDivisor and added to ldAccum. The sign is checked, and if negative, the negative */
/* value of the number is returned; otherwise the positive value is returned. */
/* */
/* This is example code I have used for courses in DB2/2, and has not been thoroughly checked for */
/* errors. No warrenties are implied, but it has worked for the fields I have tested. */
/* */
/* Copyright (C) 1993 by JDS & Associates, Raleigh, NC. CIS ID: 70363,407 */
/* */
/***************************************************************************************************/
long double DecimalToLongDouble (struct sqlvar * sqlvar)
{
long double ldAccum = 0; /* Accumulator for output */
long double ldDecimalAccum = 0; /* Accumulator for fractions */
long double ldDivisor = 1; /* Divider for Fractions */
PCHAR PInputPos = sqlvar->sqldata; /* Point at the data area */
SHORT sDigitCount = LOBYTE(sqlvar->sqllen); /* Total number of digits */
SHORT sPointCtr = sDigitCount - HIBYTE(sqlvar->sqllen); /* Offset of decimal point */
SHORT sDigit = /* One digit from input */
LONIBBLE(*(PInputPos + ((sDigitCount + 1) / 2) - 1)); /* Sign character here */
BOOL bNegativeNumber; /* Get sign nibble */
INT i; /* Loop control */
bNegativeNumber = (sDigit == 0X0B) || (sDigit == 0X0D); /* < 0 if sign = 0x0b or 0x0d */
for (i = 0; i < (sDigitCount-1); i++) /* Loop through each except last */
{
sDigit = i % 2 ? /* Even/Odd time through test */
LONIBBLE(*(PInputPos++)) : HINIBBLE(*PInputPos); /* hi/low digit in byte */
if (--sPointCtr >= 0) /* If before decimal point */
{
ldAccum *= 10; /* Multiply existing value by 10 */
ldAccum += sDigit; /* Add in the new digit */
}
else
{
ldDivisor *= 10; /* Multiply final divisor by 10 */
ldDecimalAccum *= 10; /* Multiply current decimal by 10*/
ldDecimalAccum += sDigit; /* Add in new value */
}
}
ldAccum += ldDecimalAccum / ldDivisor; /* Compute fraction and add in */
return bNegativeNumber ? -ldAccum : ldAccum; /* Return sign adjusted number */
}