Advertisement
Guest User

postgresql cash_out proposed fix

a guest
Oct 29th, 2011
266
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.02 KB | None | 0 0
  1. /* cash_out()
  2.  * Function to convert cash to a money representation.
  3.  */
  4. Datum
  5. cash_out(PG_FUNCTION_ARGS)
  6. {
  7.     Cash        value = PG_GETARG_CASH(0);
  8.     char       *result;
  9.     char        buf[CASH_BUFSZ];
  10.     int         count = LAST_DIGIT,
  11.                 dcount = 0;
  12.     int         points,
  13.                 mon_group;
  14.     const char *dsymbol,
  15.                *ssymbol,
  16.                *csymbol,
  17.                *csymbol_sep,
  18.                *signsymbol;
  19.     char        sign_pos,
  20.                 csymbol_precedes;
  21.     struct lconv *lconvert = PGLC_localeconv();
  22.  
  23.     /* see comments about frac_digits in cash_in() */
  24.     points = lconvert->frac_digits;
  25.     if (points < 0 || points > 10)
  26.         points = 2;             /* best guess in this case, I think */
  27.  
  28.     /*
  29.      * As with frac_digits, must apply a range check to mon_grouping to avoid
  30.      * being fooled by variant CHAR_MAX values.
  31.      */
  32.     mon_group = *lconvert->mon_grouping;
  33.     if (mon_group <= 0 || mon_group > 6)
  34.         mon_group = 3;
  35.  
  36.     dsymbol = ((*lconvert->mon_decimal_point != '\0') ? lconvert->mon_decimal_point : ".");
  37. /*
  38.     ssymbol = lconvert->mon_thousands_sep;
  39.     to pass regression test must set "," as the separator when it is empty
  40. */
  41.     if (*lconvert->mon_thousands_sep != '\0')
  42.         ssymbol = lconvert->mon_thousands_sep;
  43.     else
  44.         /* ssymbol should not equal dsymbol */
  45.         ssymbol = (*dsymbol != ',') ? "," : ".";
  46.  
  47.     csymbol = ((*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$");
  48.  
  49.     if (value < 0)
  50.     {
  51.         /* we work with positive amounts */
  52.         value = -value;
  53.         signsymbol = ((*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-");
  54. /*
  55.         csymbol_sep = ((lconvert->n_sep_by_space) ? " " : "");
  56.         to pass regression test must omit the currency symbol separator
  57. */
  58.         csymbol_sep = "";
  59.         csymbol_precedes = lconvert->n_cs_precedes;
  60.         sign_pos = lconvert->n_sign_posn;
  61.     }
  62.     else
  63.     {
  64.         signsymbol = lconvert->positive_sign;
  65. /*
  66.         csymbol_sep = ((lconvert->p_sep_by_space) ? " " : "");
  67.         to pass regression test must omit the currency symbol separator
  68. */
  69.         csymbol_sep = "";
  70.         csymbol_precedes = lconvert->p_cs_precedes;
  71.         sign_pos = lconvert->p_sign_posn;
  72.     }
  73.  
  74.     /* allow for trailing negative strings */
  75.     MemSet(buf, ' ', CASH_BUFSZ);
  76.     buf[TERMINATOR] = buf[LAST_PAREN] = '\0';
  77.  
  78.     while (count >= 0 && (value || dcount <= points))
  79.     {
  80.         if (points && points == dcount)
  81.         {
  82.             if (count < strlen(dsymbol)) break;
  83.             count -= strlen(dsymbol);
  84.             strncpy((buf + count + 1), dsymbol, strlen(dsymbol));
  85.         }
  86.         else if (*ssymbol && dcount > points && (dcount - points) % mon_group == 0)
  87.         {
  88.             if (count < strlen(ssymbol)) break;
  89.             count -= strlen(ssymbol);
  90.             strncpy((buf + count + 1), ssymbol, strlen(ssymbol));
  91.         }
  92.  
  93.         buf[count--] = ((uint64) value % 10) + '0';
  94.         value = ((uint64) value) / 10;
  95.         dcount++;
  96.     }
  97.     count++;
  98.  
  99.     if (!sign_pos) {
  100.         result = palloc(CASH_BUFSZ + 2 - count + 2 + strlen(csymbol) + 1);
  101.         if (csymbol_precedes)
  102.             sprintf(result, "(%s%s%s)", csymbol, csymbol_sep, buf + count);
  103.         else
  104.             sprintf(result, "(%s%s%s)", buf + count, csymbol_sep, csymbol);
  105.     } else {
  106.         result = palloc(CASH_BUFSZ + 2 - count + strlen(signsymbol) + strlen(csymbol) + 1);
  107.         switch (sign_pos)
  108.         {
  109.             case 2:
  110.                 /* sign after the quantity and currency symbol */
  111.                 if (csymbol_precedes)
  112.                     sprintf(result, "%s%s%s%s", csymbol, csymbol_sep, buf + count, signsymbol);
  113.                 else
  114.                     sprintf(result, "%s%s%s%s", buf + count, csymbol_sep, csymbol, signsymbol);
  115.                 break;
  116.             case 3:
  117.                 /* sign right before currency symbol */
  118.                 if (csymbol_precedes)
  119.                     sprintf(result, "%s%s%s%s", signsymbol, csymbol, csymbol_sep, buf + count);
  120.                 else
  121.                     sprintf(result, "%s%s%s%s", buf + count, signsymbol, csymbol_sep, csymbol);
  122.                 break;
  123.             case 4:
  124.                 /* sign right after currency symbol */
  125.                 if (csymbol_precedes)
  126.                     sprintf(result, "%s%s%s%s", csymbol, csymbol_sep, signsymbol, buf + count);
  127.                 else
  128.                     sprintf(result, "%s%s%s%s", buf + count, csymbol_sep, csymbol, signsymbol);
  129.                 break;
  130.             case 1:
  131.                 /* sign before the quantity and currency symbol */
  132.             default:
  133.                 if (csymbol_precedes)
  134.                     sprintf(result, "%s%s%s%s", signsymbol, csymbol, csymbol_sep, buf + count);
  135.                 else
  136.                     sprintf(result, "%s%s%s%s", signsymbol, buf + count, csymbol_sep, csymbol);
  137.                 break;
  138.         }
  139.     }
  140.  
  141.     PG_RETURN_CSTRING(result);
  142. }
  143.  
  144.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement