DSN8DUCY
Formats a given numeric amount with a specified currency symbol and, if specified, one of the following debit/ credit indicators.
/********************************************************************* 00000100
* Module name = DSN8DUCY (DB2 sample program) * 00000200
* * 00000300
* DESCRIPTIVE NAME = General currency formatter (UDF) * 00000400
* * 00000500
* * 00000600
* LICENSED MATERIALS - PROPERTY OF IBM * 00000700
* 5675-DB2 * 00000800
* (C) COPYRIGHT 1998, 2000 IBM CORP. ALL RIGHTS RESERVED. * 00000900
* * 00001000
* STATUS = VERSION 7 * 00001100
* * 00001200
* Function: Formats a given numeric amount with a specified currency * 00001300
* symbol and, if specified, one of the following debit/ * 00001400
* credit indicators. * 00001500
* * 00001600
* +/-: Place a hyphen between the currency symbol and the * 00001700
* amount if the amount is less than 0. * 00001800
* (/): Place a left parenthesis between currency symbol * 00001900
* and the amount and place a right parenthesis to the * 00002000
* right of the amount if the amount is less than 0. * 00002100
* CR/DB: Place CR to the right of the amount if it is less * 00002200
* than 0; otherwise place DB to the right of the * 00002300
* amount. * 00002400
* * 00002500
* Example invocations: * 00002600
* EXEC SQL SET :money = CURRENCY( -123, * 00002700
* "DM" ); * 00002800
* ==> money = DM -123.00 * 00002900
* * 00003000
* * 00003100
* EXEC SQL SET :money = CURRENCY( -123, * 00003200
* "DM", * 00003300
* "(/)" ); * 00003400
* ==> money = DM (123.00) * 00003500
* * 00003600
* Notes: * 00003700
* Dependencies: Requires IBM C/C++ for OS/390 V1R3 or higher * 00003800
* * 00003900
* Restrictions: * 00004000
* * 00004100
* Module type: C program * 00004200
* Processor: IBM C/C++ for OS/390 V1R3 or higher * 00004300
* Module size: See linkedit output * 00004400
* Attributes: Re-entrant and re-usable * 00004500
* * 00004600
* Entry Point: DSN8DUCY * 00004700
* Purpose: See Function * 00004800
* Linkage: DB2SQL * 00004900
* Invoked via SQL UDF call * 00005000
* * 00005100
* Parameters: DSN8DUCY uses the C "main" argument convention of * 00005200
* argv (argument vector) and argc (argument count). * 00005300
* * 00005400
* The location of input and output parameters depends * 00005500
* on whether the CURRENCY UDF is invoked with two * 00005600
* input arguments (amount and currency symbol) or with * 00005700
* three input arguments (amount, currency symbol, and * 00005800
* credit/debit indicator). * 00005900
* * 00006000
* If the CURRENCY UDF is invoked with two arguments * 00006100
* only (an amount and a currency symbol): * 00006200
* - ARGV[0] = (input) pointer to a char[9], null- * 00006300
* terminated string having the name of * 00006400
* this program (DSN8DUCY) * 00006500
* - ARGV[1] = (input) pointer to a double word having * 00006600
* the amount to be formatted as currency. * 00006700
* - ARGV[2] = (input) pointer to a char[3], null- * 00006800
* terminated string having the currency * 00006900
* symbol. * 00007000
* - ARGV[3] = (output) pointer to a char[20], null- * 00007100
* terminated string to receive the cur- * 00007200
* rency result. * 00007300
* - ARGV[4] = (input) pointer to a short integer * 00007400
* having the null indicator for the input * 00007500
* amount * 00007600
* - ARGV[5] = (input) pointer to a short integer * 00007700
* having the null indicator for the cur- * 00007800
* rency symbol * 00007900
* - ARGV[6] = (output) pointer to a short integer * 00008000
* having the null indicator for the result * 00008100
* - ARGV[7] = (output) pointer to a char[6], null- * 00008200
* terminated string to receive the * 00008300
* SQLSTATE * 00008400
* - ARGV[8] = (input) pointer to a char[138], null- * 00008500
* terminated string having the UDF family * 00008600
* name of the function * 00008700
* - ARGV[9] = (input) pointer to a char[129], null- * 00008800
* terminated string having the UDF * 00008900
* specific name of the function * 00009000
* - ARGV[10] = (output) pointer to a char[70], * 00009100
* null- terminated string to receive any * 00009200
* diagnostic message issued by this * 00009300
* function * 00009400
* * 00009500
* If the CURRENCY UDF is invoked with three arguments * 00009600
* (an amount, a currency symbol, and a credit/debit * 00009700
* indicator): * 00009800
* - ARGV[0] = (input) pointer to a char[9], null- * 00009900
* terminated string having the name of * 00010000
* this program (DSN8DUCY) * 00010100
* - ARGV[1] = (input) pointer to a double word having * 00010200
* the amount to be formatted as currency. * 00010300
* - ARGV[2] = (input) pointer to a char[3], null- * 00010400
* terminated string having the currency * 00010500
* symbol. * 00010600
* - ARGV[3] = (input) pointer to a char[6], null- * 00010700
* terminated string having the credit/ * 00010800
* debit indicator (see under "Function:", * 00010900
* above, for valid credit/debit indicators)* 00011000
* - ARGV[4] = (output) pointer to a char[20], null- * 00011100
* terminated string to receive the cur- * 00011200
* rency result. * 00011300
* - ARGV[5] = (input) pointer to a short integer * 00011400
* having the null indicator for the input * 00011500
* amount * 00011600
* - ARGV[6] = (input) pointer to a short integer * 00011700
* having the null indicator for the cur- * 00011800
* rency symbol * 00011900
* - ARGV[7] = (input) pointer to a short integer * 00012000
* having the null indicator for the * 00012100
* credit/debit indicator * 00012200
* - ARGV[8] = (output) pointer to a short integer * 00012300
* having the null indicator for the result * 00012400
* - ARGV[9] = (output) pointer to a char[6], null- * 00012500
* terminated string to receive the * 00012600
* SQLSTATE * 00012700
* - ARGV[10] = (input) pointer to a char[138], null- * 00012800
* terminated string having the UDF family * 00012900
* name of the function * 00013000
* - ARGV[11] = (input) pointer to a char[129], null- * 00013100
* terminated string having the UDF * 00013200
* specific name of the function * 00013300
* - ARGV[12] = (output) pointer to a char[70], * 00013400
* null- terminated string to receive any * 00013500
* diagnostic message issued by this * 00013600
* function * 00013700
* * 00013800
* Normal Exit: Return Code: SQLSTATE = 00000 * 00013900
* - Message: none * 00014000
* * 00014100
* Error Exit: Return Code: SQLSTATE = 38601 * 00014200
* - Message: DSN8DUCY Error: No amount entered * 00014300
* - Message: DSN8DUCY Error: No currency symbol entered * 00014400
* * 00014500
* Return Code: SQLSTATE = 38602 * 00014600
* - Message: DSN8DUCY Error: Error performing * 00014700
* setlocale() * 00014800
* * 00014900
* External References: * 00015000
* - Routines/Services: None * 00015100
* - Data areas : None * 00015200
* - Control blocks : None * 00015300
* * 00015400
* * 00015500
* Pseudocode: * 00015600
* DSN8DUCY: * 00015700
* - Walk down the argv list, locating the input and output parms * 00015800
* - Issue sqlstate 38601 and a diagnostic message if no input * 00015900
* amount was provided. * 00016000
* - Issue sqlstate 38601 and a diagnostic message if no currency * 00016100
* symbol was provided. * 00016200
* - Call formatAmount to assemble the currency expression from the * 00016300
* input amount and the currency symbol and, optionally, the * 00016400
* credit/debit indicator. * 00016500
* - If no errors, unset null indicators, and return SQLSTATE 00000 * 00016600
* else set null indicator and return null time out. * 00016700
* End DSN8DUCY * 00016800
* * 00016900
* formatAmount * 00017000
* - If the amount in is less than zero ... * 00017100
* - if a CR/DB indicator of -/+ has been specified, prefix * 00017200
* the currency expression with a hyphen * 00017300
* - else if a CR/DB of (/) has been specified, prefix the curr- * 00017400
* rency expression with a left parenthesis * 00017500
* - Append the currency symbol to the currency expression * 00017600
* - if the currency symbol is just 1 byte, concatentate a blank * 00017700
* - Call the C function setlocale() to initialize the C function * 00017800
* strfmon(). * 00017900
* - if error, issue SQLSTATE 38602 and a diagnostic message * 00018000
* - Call the C function strfmon() to reformat the input amount * 00018100
* with the currency symbol. * 00018200
* - If the amount in is less than zero ... * 00018300
* - if a CR/DB of (/) has been specified, append a right paren- * 00018400
* thesis to the currency expression. * 00018500
* End formatAmount * 00018600
* * 00018700
* * 00018800
*********************************************************************/ 00018900
/********************** C library definitions ***********************/ 00019000
#include <localdef.h> 00019100
#include <monetary.h> 00019200
#include <stdio.h> 00019300
#include <stdlib.h> 00019400
#include <string.h> 00019500
00019600
/***************************** Equates ******************************/ 00019700
#define NULLCHAR '\0' /* Null character */ 00019800
00019900
#define MATCH 0 /* Comparison status: Equal */ 00020000
#define NOT_OK 0 /* Run status indicator: Error*/ 00020100
#define OK 1 /* Run status indicator: Good */ 00020200
00020300
00020400
/*********************** DSN8DUCY functions *************************/ 00020500
int main /* main routine */ 00020600
( int argc, /* standard argument count */ 00020700
char *argv[] /* standard argument vector */ 00020800
); 00020900
00021000
int formatAmount /* format amountIn as currency*/ 00021100
( char *moneyOut, /* out: formatted amountIn */ 00021200
char *message, /* out: diagnostic message */ 00021300
char *sqlstate, /* out: SQLSTATE */ 00021400
double *amountIn, /* in: value to be formatted */ 00021500
char *currSymbol, /* in: currency symbol */ 00021600
char *CRDBInd /* in: credit/debit indicator */ 00021700
); 00021800
00021900
/********************************************************************/ 00022000
/*************************** main routine ***************************/ 00022100
/********************************************************************/ 00022200
int main /* main routine */ 00022300
( int argc, /* standard argument count */ 00022400
char *argv[] /* standard argument vector */ 00022500
) 00022600
/********************************************************************* 00022700
* * 00022800
*********************************************************************/ 00022900
{ 00023000
00023100
/************************ local variables *************************/ 00023200
short int minus1 = -1; /* default null indic setting */ 00023300
00023400
/* vars for argument vector */ 00023500
double *amountIn; /* in: value to be formatted */ 00023600
char currSymbol[3]; /* in: currency symbol */ 00023700
char CRDBInd[6]; /* in: credit/debit indicator */ 00023800
char *moneyOut; /* out: formatted amountIn */ 00023900
short int *niAmountIn; /* in: indic var, amountIn */ 00024000
short int *niCurrSymbol; /* in: indic var, currSymbol */ 00024100
short int *niCRDBInd; /* in: indic var, CRDBInd */ 00024200
short int *niMoneyOut; /* out: indic var, moneyOut */ 00024300
char *sqlstate; /* out: SQLSTATE */ 00024400
char fnName[138]; /* in: family name of function*/ 00024500
char specificName[129]; /* in: specific name of func */ 00024600
char *message; /* out: diagnostic message */ 00024700
00024800
short int status = OK; /* DSN8DUCY run status */ 00024900
00025000
00025100
00025200
/******************************************************************* 00025300
* Walk down the argv list, locating the input and output parms * 00025400
*******************************************************************/ 00025500
argc--; /* convert argc to base 0 index*/ 00025600
00025700
message = (char *)argv[argc--]; /* out: point to UDF diag msg */ 00025800
00025900
strcpy( specificName, /* in: save UDF specific name */ 00026000
argv[argc--]); 00026100
00026200
strcpy( fnName,argv[argc--] ); /* in: save UDF function name */ 00026300
00026400
sqlstate = (char *)argv[argc--]; /* out: point to UDF sqlstate */ 00026500
00026600
niMoneyOut /* out: point to null indicator*/ 00026700
= (short int *)argv[argc--]; /* variable for result */ 00026800
00026900
if( argc == 7 ) /* if 3 input parms passed */ 00027000
niCRDBInd /* ..in: point to null indic. */ 00027100
= (short int *)argv[argc--]; /* var for CR/DB indic. */ 00027200
else /* otherwise it wasn't passed */ 00027300
niCRDBInd = &minus1; /* ..so define it as null */ 00027400
00027500
niCurrSymbol /* in: point to null indicator */ 00027600
= (short int *)argv[argc--]; /* var for currency symbol */ 00027700
00027800
niAmountIn /* in: point to null indicator */ 00027900
= (short int *)argv[argc--]; /* var for input amount */ 00028000
00028100
moneyOut = (char *)argv[argc--]; /* out: point to UDF result */ 00028200
00028300
if( argc == 3 ) /* if 3 input parms passed */ 00028400
strcpy( CRDBInd, /* ..in: save object location */ 00028500
argv[argc--] ); /* name */ 00028600
else /* otherwise it wasn't passed */ 00028700
CRDBInd[0] = NULLCHAR; /* ..so define it as null */ 00028800
00028900
strcpy( currSymbol,argv[argc--] ); /* in: save currency symbol */ 00029000
00029100
amountIn = (double *)argv[argc]; /* in: save input amount */ 00029200
00029300
00029400
/******************************************************************* 00029500
* Initialize output parms * 00029600
*******************************************************************/ 00029700
message[0] = NULLCHAR; 00029800
strcpy( sqlstate,"00000" ); 00029900
*niMoneyOut = 0; 00030000
moneyOut[0] = NULLCHAR; 00030100
00030200
/******************************************************************* 00030300
* Verify that an amount and a currency symbol have been passed in * 00030400
*******************************************************************/ 00030500
if( *niAmountIn ) 00030600
{ 00030700
status = NOT_OK; 00030800
strcpy( message, 00030900
"DSN8DUCY Error: No amount entered" ); 00031000
strcpy( sqlstate, "38601" ); 00031100
} 00031200
else if( *niCurrSymbol || ( strlen( currSymbol ) == 0 ) ) 00031300
{ 00031400
status = NOT_OK; 00031500
strcpy( message, 00031600
"DSN8DUCY Error: No currency symbol entered" ); 00031700
strcpy( sqlstate, "38601" ); 00031800
} 00031900
00032000
/******************************************************************* 00032100
* Format the amount into currency notation * 00032200
*******************************************************************/ 00032300
if( status == OK ) 00032400
status = formatAmount( moneyOut, message, sqlstate, 00032500
amountIn, currSymbol, CRDBInd ); 00032600
00032700
/******************************************************************* 00032800
* If formatting was successful, clear the message buffer and sql- * 00032900
* state, and unset the SQL null indicator for moneyOut. * 00033000
*******************************************************************/ 00033100
if( status == OK ) 00033200
{ 00033300
*niMoneyOut = 0; 00033400
message[0] = NULLCHAR; 00033500
strcpy( sqlstate,"00000" ); 00033600
} 00033700
/******************************************************************* 00033800
* If errors occurred, clear the moneyOut buff and set the SQL null * 00033900
* indicator. A diagnostic message and the SQLSTATE have been set * 00034000
* where the error was detected. * 00034100
*******************************************************************/ 00034200
else 00034300
{ 00034400
moneyOut[0] = NULLCHAR; 00034500
*niMoneyOut = -1; 00034600
} 00034700
00034800
return( 0 ); 00034900
} /* end main */ 00035000
00035100
/********************************************************************/ 00035200
/***************************** functions ****************************/ 00035300
/********************************************************************/ 00035400
int formatAmount /* format amountIn as currency*/ 00035500
( char *moneyOut, /* out: formatted amountIn */ 00035600
char *message, /* out: diagnostic message */ 00035700
char *sqlstate, /* out: SQLSTATE */ 00035800
double *amountIn, /* in: value to be formatted */ 00035900
char *currSymbol, /* in: currency symbol */ 00036000
char *CRDBInd /* in: credit/debit indicator */ 00036100
) 00036200
/********************************************************************* 00036300
* Converts amountIn to a string, including the currency type in * 00036400
* currSymbol and, if specified, the credit/debit indicator in CRDB- * 00036500
* Symbol. The result is placed in moneyOut. * 00036600
* * 00036700
* currSymbol may be any string of characters, up to 2 bytes long. * 00036800
* CRDBInd is used only its value is: * 00036900
* - "+/-", indicating that moneyOut and its prefix from currSymbol * 00037000
* should be prefixed by a hyphen ("-") if amountIn is negative. * 00037100
* - "(/)", indicating that moneyOut should be enclosed, with the * 00037200
* prefix from currSymbol, in parentheses if amountIn is negative. * 00037300
* - "CR/DB", indicating that moneyOut should be prefixed with DB * 00037400
* if amountIn is negative, otherwise with CR. * 00037500
*********************************************************************/ 00037600
{ 00037700
int i; /* loop control */ 00037800
int negFlag = 0; /* negative currency flag */ 00037900
00038000
double amount; /* work var for amountIn */ 00038100
char moneyStr[200]; /* work string for type conv. */ 00038200
00038300
/******************************************************************* 00038400
* Clear any residual value from moneyOut * 00038500
*******************************************************************/ 00038600
for( i=0;i<strlen(moneyOut);i++) 00038700
moneyOut[i] = NULLCHAR; 00038800
00038900
/******************************************************************* 00039000
* If amountIn is negative, prefix moneyOut with neg curr indicators* 00039100
*******************************************************************/ 00039200
amount = *amountIn; 00039300
if( amount < 0 ) 00039400
{ 00039500
negFlag = 1; 00039600
if( CRDBInd[0] != NULLCHAR ) 00039700
{ 00039800
amount = -amount; 00039900
00040000
if( strcmp( CRDBInd,"+/-" ) == 0 ) 00040100
strcpy( moneyOut,"-" ); 00040200
else if( strcmp( CRDBInd,"(/)" ) == 0 ) 00040300
strcpy( moneyOut,"(" ); 00040400
} 00040500
} 00040600
00040700
/******************************************************************* 00040800
* Append the currency type (currSymbol) to moneyOut. If currSymbol* 00040900
* is more than one byte, place a blank between it and the amount * 00041000
*******************************************************************/ 00041100
strcat( moneyOut,currSymbol ); 00041200
if( strlen( currSymbol ) > 1 ) 00041300
strcat( moneyOut," " ); 00041400
00041500
/******************************************************************* 00041600
* Set the local for the strfmon function * 00041700
*******************************************************************/ 00041800
if( setlocale( LC_ALL, "En_US" ) == NULL ) 00041900
{ 00042000
strcpy( message, 00042100
"DSN8DUCY Error: Error performing setlocale()" ); 00042200
strcpy( sqlstate, "38602" ); 00042300
return( NOT_OK ); 00042400
} 00042500
00042600
/******************************************************************* 00042700
* Reformat amount to a string type with thousands grouping * 00042800
*******************************************************************/ 00042900
strfmon( moneyStr,100,"%!n",amount ); 00043000
strcat( moneyOut,moneyStr ); 00043100
00043200
/******************************************************************* 00043300
* If amount < 0, append negative currency indicators, if passed * 00043400
*******************************************************************/ 00043500
if( CRDBInd[0] != NULLCHAR ) 00043600
{ 00043700
if( negFlag == 1 ) 00043800
{ 00043900
if( strcmp( CRDBInd,"CR/DB" ) == 0 ) 00044000
strcat( moneyOut," DB" ); 00044100
else if( strcmp( CRDBInd,"(/)" ) == 0 ) 00044200
strcat( moneyOut,")" ); 00044300
} 00044400
else 00044500
{ 00044600
if( strcmp( CRDBInd,"CR/DB" ) == 0 ) 00044700
strcat( moneyOut," CR" ); 00044800
} 00044900
} 00045000
00045100
return( OK ); 00045200
} /* end formatAmount */ 00045300