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