exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

amount.c (31703B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2021 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file util/amount.c
     18  * @brief Common utility functions to deal with units of currency
     19  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
     20  * @author Florian Dold
     21  * @author Benedikt Mueller
     22  * @author Christian Grothoff
     23  */
     24 #include "platform.h"
     25 #include "taler/taler_util.h"
     26 
     27 
     28 /**
     29  * Set @a a to "invalid".
     30  *
     31  * @param[out] a amount to set to invalid
     32  */
     33 static void
     34 invalidate (struct TALER_Amount *a)
     35 {
     36   memset (a,
     37           0,
     38           sizeof (struct TALER_Amount));
     39 }
     40 
     41 
     42 enum GNUNET_GenericReturnValue
     43 TALER_check_currency (const char *str)
     44 {
     45   size_t len = strlen (str);
     46 
     47   if (len >= TALER_CURRENCY_LEN)
     48   {
     49     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     50                 "Currency code name `%s' is too long\n",
     51                 str);
     52     return GNUNET_SYSERR;
     53   }
     54   if (len == 0)
     55   {
     56     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     57                 "Currency code name must be set\n");
     58     return GNUNET_SYSERR;
     59   }
     60   /* validate str has only legal characters in it! */
     61   for (unsigned int i = 0; '\0' != str[i]; i++)
     62   {
     63     if ( ('A' > str[i]) || ('Z' < str[i]) )
     64     {
     65       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     66                   "Currency code name `%s' contains illegal characters (only A-Z allowed)\n",
     67                   str);
     68       return GNUNET_SYSERR;
     69     }
     70   }
     71   return GNUNET_OK;
     72 }
     73 
     74 
     75 enum GNUNET_GenericReturnValue
     76 TALER_string_to_amount (const char *str,
     77                         struct TALER_Amount *amount)
     78 {
     79   uint32_t b;
     80   const char *colon;
     81   const char *value;
     82 
     83   /* skip leading whitespace */
     84   while (isspace ( (unsigned char) str[0]))
     85     str++;
     86   if ('\0' == str[0])
     87   {
     88     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     89                 "Null before currency\n");
     90     invalidate (amount);
     91     return GNUNET_SYSERR;
     92   }
     93 
     94   /* parse currency */
     95   colon = strchr (str, (int) ':');
     96   if ( (NULL == colon) ||
     97        (colon == str) ||
     98        ((colon - str) >= TALER_CURRENCY_LEN) )
     99   {
    100     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    101                 "Invalid currency specified before colon: `%s'\n",
    102                 str);
    103     invalidate (amount);
    104     return GNUNET_SYSERR;
    105   }
    106 
    107   GNUNET_assert (TALER_CURRENCY_LEN > (colon - str));
    108   memcpy (&amount->currency[0],
    109           str,
    110           colon - str);
    111   /* 0-terminate *and* normalize buffer by setting everything to '\0' */
    112   memset (&amount->currency [colon - str],
    113           0,
    114           TALER_CURRENCY_LEN - (colon - str));
    115   if (GNUNET_OK !=
    116       TALER_check_currency (amount->currency))
    117   {
    118     invalidate (amount);
    119     return GNUNET_SYSERR;
    120   }
    121   /* skip colon */
    122   value = colon + 1;
    123   if ('\0' == value[0])
    124   {
    125     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    126                 "Actual value missing in amount `%s'\n",
    127                 str);
    128     invalidate (amount);
    129     return GNUNET_SYSERR;
    130   }
    131 
    132   amount->value = 0;
    133   amount->fraction = 0;
    134 
    135   /* parse value */
    136   while ('.' != *value)
    137   {
    138     int n;
    139 
    140     if ('\0' == *value)
    141     {
    142       /* we are done */
    143       return GNUNET_OK;
    144     }
    145     if ( (*value < '0') ||
    146          (*value > '9') )
    147     {
    148       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    149                   "Invalid character `%c' in amount `%s'\n",
    150                   (int) *value,
    151                   str);
    152       invalidate (amount);
    153       return GNUNET_SYSERR;
    154     }
    155     n = *value - '0';
    156     if ( (amount->value * 10 < amount->value) ||
    157          (amount->value * 10 + n < amount->value) ||
    158          (amount->value > TALER_AMOUNT_MAX_VALUE) ||
    159          (amount->value * 10 + n > TALER_AMOUNT_MAX_VALUE) )
    160     {
    161       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    162                   "Value specified in amount `%s' is too large\n",
    163                   str);
    164       invalidate (amount);
    165       return GNUNET_SYSERR;
    166     }
    167     amount->value = (amount->value * 10) + n;
    168     value++;
    169   }
    170 
    171   /* skip the dot */
    172   value++;
    173 
    174   /* parse fraction */
    175   if ('\0' == *value)
    176   {
    177     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    178                 "Amount `%s' ends abruptly after `.'\n",
    179                 str);
    180     invalidate (amount);
    181     return GNUNET_SYSERR;
    182   }
    183   b = TALER_AMOUNT_FRAC_BASE / 10;
    184   while ('\0' != *value)
    185   {
    186     int n;
    187 
    188     if (0 == b)
    189     {
    190       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    191                   "Fractional value too small (only %u digits supported) in amount `%s'\n",
    192                   (unsigned int) TALER_AMOUNT_FRAC_LEN,
    193                   str);
    194       invalidate (amount);
    195       return GNUNET_SYSERR;
    196     }
    197     if ( (*value < '0') ||
    198          (*value > '9') )
    199     {
    200       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    201                   "Error after dot\n");
    202       invalidate (amount);
    203       return GNUNET_SYSERR;
    204     }
    205     n = *value - '0';
    206     amount->fraction += n * b;
    207     b /= 10;
    208     value++;
    209   }
    210   return GNUNET_OK;
    211 }
    212 
    213 
    214 enum GNUNET_GenericReturnValue
    215 TALER_string_to_amount_nbo (const char *str,
    216                             struct TALER_AmountNBO *amount_nbo)
    217 {
    218   struct TALER_Amount amount;
    219 
    220   if (GNUNET_OK !=
    221       TALER_string_to_amount (str,
    222                               &amount))
    223     return GNUNET_SYSERR;
    224   TALER_amount_hton (amount_nbo,
    225                      &amount);
    226   return GNUNET_OK;
    227 }
    228 
    229 
    230 void
    231 TALER_amount_hton (struct TALER_AmountNBO *res,
    232                    const struct TALER_Amount *d)
    233 {
    234   GNUNET_assert (GNUNET_YES ==
    235                  TALER_amount_is_valid (d));
    236   res->value = GNUNET_htonll (d->value);
    237   res->fraction = htonl (d->fraction);
    238   for (unsigned int i = 0; i<TALER_CURRENCY_LEN; i++)
    239     res->currency[i] = d->currency[i];
    240 }
    241 
    242 
    243 void
    244 TALER_amount_ntoh (struct TALER_Amount *res,
    245                    const struct TALER_AmountNBO *dn)
    246 {
    247   res->value = GNUNET_ntohll (dn->value);
    248   res->fraction = ntohl (dn->fraction);
    249   GNUNET_memcpy (res->currency,
    250                  dn->currency,
    251                  TALER_CURRENCY_LEN);
    252   GNUNET_assert (GNUNET_YES ==
    253                  TALER_amount_is_valid (res));
    254 }
    255 
    256 
    257 enum GNUNET_GenericReturnValue
    258 TALER_amount_set_zero (const char *cur,
    259                        struct TALER_Amount *amount)
    260 {
    261   char tmp[TALER_CURRENCY_LEN];
    262   size_t slen;
    263 
    264   if (GNUNET_OK !=
    265       TALER_check_currency (cur))
    266     return GNUNET_SYSERR;
    267   slen = strlen (cur);
    268   /* make a copy of 'cur' to 'tmp' as the memset may clobber cur
    269      if cur aliases &amount->currency! */
    270   memcpy (tmp,
    271           cur,
    272           slen);
    273   memset (amount,
    274           0,
    275           sizeof (struct TALER_Amount));
    276   for (unsigned int i = 0; i<slen; i++)
    277     amount->currency[i] = tmp[i];
    278   return GNUNET_OK;
    279 }
    280 
    281 
    282 enum GNUNET_GenericReturnValue
    283 TALER_amount_is_valid (const struct TALER_Amount *amount)
    284 {
    285   if (amount->value > TALER_AMOUNT_MAX_VALUE)
    286   {
    287     GNUNET_break (0);
    288     return GNUNET_SYSERR;
    289   }
    290   return ('\0' != amount->currency[0]) ? GNUNET_OK : GNUNET_NO;
    291 }
    292 
    293 
    294 enum GNUNET_GenericReturnValue
    295 TALER_amount_max (struct TALER_Amount *ma,
    296                   const struct TALER_Amount *a1,
    297                   const struct TALER_Amount *a2)
    298 {
    299   if (GNUNET_OK !=
    300       TALER_amount_cmp_currency (a1,
    301                                  a2))
    302   {
    303     memset (ma,
    304             0,
    305             sizeof (*ma));
    306     return GNUNET_SYSERR;
    307   }
    308   if (1 == TALER_amount_cmp (a1,
    309                              a2))
    310     *ma = *a1;
    311   else
    312     *ma = *a2;
    313   return GNUNET_OK;
    314 }
    315 
    316 
    317 enum GNUNET_GenericReturnValue
    318 TALER_amount_min (struct TALER_Amount *mi,
    319                   const struct TALER_Amount *a1,
    320                   const struct TALER_Amount *a2)
    321 {
    322   if (GNUNET_OK !=
    323       TALER_amount_cmp_currency (a1,
    324                                  a2))
    325   {
    326     memset (mi,
    327             0,
    328             sizeof (*mi));
    329     return GNUNET_SYSERR;
    330   }
    331   if (1 == TALER_amount_cmp (a1,
    332                              a2))
    333     *mi = *a2;
    334   else
    335     *mi = *a1;
    336   return GNUNET_OK;
    337 }
    338 
    339 
    340 bool
    341 TALER_amount_is_zero (const struct TALER_Amount *amount)
    342 {
    343   if (GNUNET_OK !=
    344       TALER_amount_is_valid (amount))
    345     return false;
    346   return
    347     (0 == amount->value) &&
    348     (0 == amount->fraction);
    349 }
    350 
    351 
    352 enum GNUNET_GenericReturnValue
    353 TALER_amount_is_currency (const struct TALER_Amount *amount,
    354                           const char *currency)
    355 {
    356   if (GNUNET_OK !=
    357       TALER_amount_is_valid (amount))
    358     return GNUNET_SYSERR;
    359   return (0 == strcasecmp (currency,
    360                            amount->currency))
    361          ? GNUNET_OK
    362          : GNUNET_NO;
    363 }
    364 
    365 
    366 /**
    367  * Test if @a a is valid, NBO variant.
    368  *
    369  * @param a amount to test
    370  * @return #GNUNET_YES if valid,
    371  *         #GNUNET_NO if invalid
    372  */
    373 static enum GNUNET_GenericReturnValue
    374 test_valid_nbo (const struct TALER_AmountNBO *a)
    375 {
    376   return ('\0' != a->currency[0]) ? GNUNET_YES : GNUNET_NO;
    377 }
    378 
    379 
    380 enum GNUNET_GenericReturnValue
    381 TALER_amount_cmp_currency (const struct TALER_Amount *a1,
    382                            const struct TALER_Amount *a2)
    383 {
    384   if ( (GNUNET_NO == TALER_amount_is_valid (a1)) ||
    385        (GNUNET_NO == TALER_amount_is_valid (a2)) )
    386     return GNUNET_SYSERR;
    387   if (0 == strcasecmp (a1->currency,
    388                        a2->currency))
    389     return GNUNET_YES;
    390   return GNUNET_NO;
    391 }
    392 
    393 
    394 enum GNUNET_GenericReturnValue
    395 TALER_amount_cmp_currency_nbo (const struct TALER_AmountNBO *a1,
    396                                const struct TALER_AmountNBO *a2)
    397 {
    398   if ( (GNUNET_NO == test_valid_nbo (a1)) ||
    399        (GNUNET_NO == test_valid_nbo (a2)) )
    400     return GNUNET_SYSERR;
    401   if (0 == strcasecmp (a1->currency,
    402                        a2->currency))
    403     return GNUNET_YES;
    404   return GNUNET_NO;
    405 }
    406 
    407 
    408 int
    409 TALER_amount_cmp (const struct TALER_Amount *a1,
    410                   const struct TALER_Amount *a2)
    411 {
    412   struct TALER_Amount n1;
    413   struct TALER_Amount n2;
    414 
    415   GNUNET_assert (GNUNET_YES ==
    416                  TALER_amount_cmp_currency (a1,
    417                                             a2));
    418   n1 = *a1;
    419   n2 = *a2;
    420   GNUNET_assert (GNUNET_SYSERR !=
    421                  TALER_amount_normalize (&n1));
    422   GNUNET_assert (GNUNET_SYSERR !=
    423                  TALER_amount_normalize (&n2));
    424   if (n1.value == n2.value)
    425   {
    426     if (n1.fraction < n2.fraction)
    427       return -1;
    428     if (n1.fraction > n2.fraction)
    429       return 1;
    430     return 0;
    431   }
    432   if (n1.value < n2.value)
    433     return -1;
    434   return 1;
    435 }
    436 
    437 
    438 int
    439 TALER_amount_cmp_nbo (const struct TALER_AmountNBO *a1,
    440                       const struct TALER_AmountNBO *a2)
    441 {
    442   struct TALER_Amount h1;
    443   struct TALER_Amount h2;
    444 
    445   TALER_amount_ntoh (&h1,
    446                      a1);
    447   TALER_amount_ntoh (&h2,
    448                      a2);
    449   return TALER_amount_cmp (&h1,
    450                            &h2);
    451 }
    452 
    453 
    454 enum TALER_AmountArithmeticResult
    455 TALER_amount_subtract (struct TALER_Amount *diff,
    456                        const struct TALER_Amount *a1,
    457                        const struct TALER_Amount *a2)
    458 {
    459   struct TALER_Amount n1;
    460   struct TALER_Amount n2;
    461 
    462   if (GNUNET_YES !=
    463       TALER_amount_cmp_currency (a1,
    464                                  a2))
    465   {
    466     invalidate (diff);
    467     return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
    468   }
    469   /* make local copies to avoid aliasing problems between
    470      diff and a1/a2 */
    471   n1 = *a1;
    472   n2 = *a2;
    473   if ( (GNUNET_SYSERR == TALER_amount_normalize (&n1)) ||
    474        (GNUNET_SYSERR == TALER_amount_normalize (&n2)) )
    475   {
    476     invalidate (diff);
    477     return TALER_AAR_INVALID_NORMALIZATION_FAILED;
    478   }
    479 
    480   if (n1.fraction < n2.fraction)
    481   {
    482     if (0 == n1.value)
    483     {
    484       invalidate (diff);
    485       return TALER_AAR_INVALID_NEGATIVE_RESULT;
    486     }
    487     n1.fraction += TALER_AMOUNT_FRAC_BASE;
    488     n1.value--;
    489   }
    490   if (n1.value < n2.value)
    491   {
    492     invalidate (diff);
    493     return TALER_AAR_INVALID_NEGATIVE_RESULT;
    494   }
    495   GNUNET_assert (GNUNET_OK ==
    496                  TALER_amount_set_zero (n1.currency,
    497                                         diff));
    498   GNUNET_assert (n1.fraction >= n2.fraction);
    499   diff->fraction = n1.fraction - n2.fraction;
    500   GNUNET_assert (n1.value >= n2.value);
    501   diff->value = n1.value - n2.value;
    502   if ( (0 == diff->fraction) &&
    503        (0 == diff->value) )
    504     return TALER_AAR_RESULT_ZERO;
    505   return TALER_AAR_RESULT_POSITIVE;
    506 }
    507 
    508 
    509 enum TALER_AmountArithmeticResult
    510 TALER_amount_add (struct TALER_Amount *sum,
    511                   const struct TALER_Amount *a1,
    512                   const struct TALER_Amount *a2)
    513 {
    514   struct TALER_Amount n1;
    515   struct TALER_Amount n2;
    516   struct TALER_Amount res;
    517 
    518   if (GNUNET_YES !=
    519       TALER_amount_cmp_currency (a1,
    520                                  a2))
    521   {
    522     invalidate (sum);
    523     return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
    524   }
    525   /* make local copies to avoid aliasing problems between
    526      diff and a1/a2 */
    527   n1 = *a1;
    528   n2 = *a2;
    529   if ( (GNUNET_SYSERR ==
    530         TALER_amount_normalize (&n1)) ||
    531        (GNUNET_SYSERR ==
    532         TALER_amount_normalize (&n2)) )
    533   {
    534     invalidate (sum);
    535     return TALER_AAR_INVALID_NORMALIZATION_FAILED;
    536   }
    537 
    538   GNUNET_assert (GNUNET_OK ==
    539                  TALER_amount_set_zero (a1->currency,
    540                                         &res));
    541   res.value = n1.value + n2.value;
    542   if (res.value < n1.value)
    543   {
    544     /* integer overflow */
    545     invalidate (sum);
    546     return TALER_AAR_INVALID_RESULT_OVERFLOW;
    547   }
    548   if (res.value > TALER_AMOUNT_MAX_VALUE)
    549   {
    550     /* too large to be legal */
    551     invalidate (sum);
    552     return TALER_AAR_INVALID_RESULT_OVERFLOW;
    553   }
    554   res.fraction = n1.fraction + n2.fraction;
    555   if (GNUNET_SYSERR ==
    556       TALER_amount_normalize (&res))
    557   {
    558     /* integer overflow via carry from fraction */
    559     invalidate (sum);
    560     return TALER_AAR_INVALID_RESULT_OVERFLOW;
    561   }
    562   *sum = res;
    563   if ( (0 == sum->fraction) &&
    564        (0 == sum->value) )
    565     return TALER_AAR_RESULT_ZERO;
    566   return TALER_AAR_RESULT_POSITIVE;
    567 }
    568 
    569 
    570 enum GNUNET_GenericReturnValue
    571 TALER_amount_normalize (struct TALER_Amount *amount)
    572 {
    573   uint32_t overflow;
    574 
    575   if (GNUNET_YES != TALER_amount_is_valid (amount))
    576     return GNUNET_SYSERR;
    577   if (amount->fraction < TALER_AMOUNT_FRAC_BASE)
    578     return GNUNET_NO;
    579   overflow = amount->fraction / TALER_AMOUNT_FRAC_BASE;
    580   amount->fraction %= TALER_AMOUNT_FRAC_BASE;
    581   amount->value += overflow;
    582   if ( (amount->value < overflow) ||
    583        (amount->value > TALER_AMOUNT_MAX_VALUE) )
    584   {
    585     invalidate (amount);
    586     return GNUNET_SYSERR;
    587   }
    588   return GNUNET_OK;
    589 }
    590 
    591 
    592 /**
    593  * Convert the fraction of @a amount to a string in decimals.
    594  *
    595  * @param amount value to convert
    596  * @param[out] tail where to write the result
    597  */
    598 static void
    599 amount_to_tail (const struct TALER_Amount *amount,
    600                 char tail[TALER_AMOUNT_FRAC_LEN + 1])
    601 {
    602   uint32_t n = amount->fraction;
    603   unsigned int i;
    604 
    605   for (i = 0; (i < TALER_AMOUNT_FRAC_LEN) && (0 != n); i++)
    606   {
    607     tail[i] = '0' + (n / (TALER_AMOUNT_FRAC_BASE / 10));
    608     n = (n * 10) % (TALER_AMOUNT_FRAC_BASE);
    609   }
    610   tail[i] = '\0';
    611 }
    612 
    613 
    614 char *
    615 TALER_amount_to_string (const struct TALER_Amount *amount)
    616 {
    617   char *result;
    618   struct TALER_Amount norm;
    619 
    620   if (GNUNET_YES !=
    621       TALER_amount_is_valid (amount))
    622     return NULL;
    623   norm = *amount;
    624   if (GNUNET_SYSERR ==
    625       TALER_amount_normalize (&norm))
    626   {
    627     GNUNET_break (0);
    628     return NULL;
    629   }
    630   if (0 != norm.fraction)
    631   {
    632     char tail[TALER_AMOUNT_FRAC_LEN + 1];
    633 
    634     amount_to_tail (&norm,
    635                     tail);
    636     GNUNET_asprintf (&result,
    637                      "%s:%llu.%s",
    638                      norm.currency,
    639                      (unsigned long long) norm.value,
    640                      tail);
    641   }
    642   else
    643   {
    644     GNUNET_asprintf (&result,
    645                      "%s:%llu",
    646                      norm.currency,
    647                      (unsigned long long) norm.value);
    648   }
    649   return result;
    650 }
    651 
    652 
    653 const char *
    654 TALER_amount2s (const struct TALER_Amount *amount)
    655 {
    656   /* 24 is sufficient for a uint64_t value in decimal; 3 is for ":.\0" */
    657   static TALER_THREAD_LOCAL char result[TALER_AMOUNT_FRAC_LEN
    658                                         + TALER_CURRENCY_LEN + 3 + 24];
    659   struct TALER_Amount norm;
    660 
    661   if (GNUNET_YES !=
    662       TALER_amount_is_valid (amount))
    663     return NULL;
    664   norm = *amount;
    665   if (GNUNET_SYSERR ==
    666       TALER_amount_normalize (&norm))
    667   {
    668     GNUNET_break (0);
    669     return NULL;
    670   }
    671   if (0 != norm.fraction)
    672   {
    673     char tail[TALER_AMOUNT_FRAC_LEN + 1];
    674 
    675     amount_to_tail (&norm,
    676                     tail);
    677     GNUNET_snprintf (result,
    678                      sizeof (result),
    679                      "%s:%llu.%s",
    680                      norm.currency,
    681                      (unsigned long long) norm.value,
    682                      tail);
    683   }
    684   else
    685   {
    686     GNUNET_snprintf (result,
    687                      sizeof (result),
    688                      "%s:%llu",
    689                      norm.currency,
    690                      (unsigned long long) norm.value);
    691   }
    692   return result;
    693 }
    694 
    695 
    696 void
    697 TALER_amount_divide (struct TALER_Amount *result,
    698                      const struct TALER_Amount *dividend,
    699                      uint32_t divisor)
    700 {
    701   uint64_t modr;
    702 
    703   GNUNET_assert (0 != divisor); /* division by zero is discouraged */
    704   *result = *dividend;
    705   /* in case @a dividend was not yet normalized */
    706   GNUNET_assert (GNUNET_SYSERR !=
    707                  TALER_amount_normalize (result));
    708   if (1 == divisor)
    709     return;
    710   modr = result->value % divisor;
    711   result->value /= divisor;
    712   /* modr fits into 32 bits, so we can safely multiply by (<32-bit) base and add fraction! */
    713   modr = (modr * TALER_AMOUNT_FRAC_BASE) + result->fraction;
    714   result->fraction = (uint32_t) (modr / divisor);
    715   /* 'fraction' could now be larger than #TALER_AMOUNT_FRAC_BASE, so we must normalize */
    716   GNUNET_assert (GNUNET_SYSERR !=
    717                  TALER_amount_normalize (result));
    718 }
    719 
    720 
    721 int
    722 TALER_amount_divide2 (const struct TALER_Amount *dividend,
    723                       const struct TALER_Amount *divisor)
    724 {
    725   double approx;
    726   double d;
    727   double r;
    728   int ret;
    729   struct TALER_Amount tmp;
    730   struct TALER_Amount nxt;
    731 
    732   if (GNUNET_YES !=
    733       TALER_amount_cmp_currency (dividend,
    734                                  divisor))
    735   {
    736     GNUNET_break (0);
    737     return -1;
    738   }
    739   if ( (0 == divisor->fraction) &&
    740        (0 == divisor->value) )
    741     return INT_MAX;
    742   /* first, get rounded approximation */
    743   d = ((double) dividend->value) * ((double) TALER_AMOUNT_FRAC_BASE)
    744       + ( (double) dividend->fraction);
    745   r = ((double) divisor->value) * ((double) TALER_AMOUNT_FRAC_BASE)
    746       + ( (double) divisor->fraction);
    747   approx = d / r;
    748   if (approx > ((double) INT_MAX))
    749     return INT_MAX; /* 'infinity' */
    750   /* round down */
    751   if (approx < 2)
    752     ret = 0;
    753   else
    754     ret = (int) approx - 2;
    755   /* Now do *exact* calculation, using well rounded-down factor as starting
    756      point to avoid having to do too many steps. */
    757   GNUNET_assert (0 <=
    758                  TALER_amount_multiply (&tmp,
    759                                         divisor,
    760                                         ret));
    761   /* in practice, this loop will only run for one or two iterations */
    762   while (1)
    763   {
    764     enum TALER_AmountArithmeticResult aar;
    765 
    766     aar = TALER_amount_add (&nxt,
    767                             &tmp,
    768                             divisor);
    769     if (TALER_AAR_INVALID_RESULT_OVERFLOW == aar)
    770       break; /* nxt would exceed TALER_AMOUNT_MAX_VALUE, and thus
    771                 certainly the (presumed valid) dividend */
    772     GNUNET_assert (0 <= aar);
    773     if (1 ==
    774         TALER_amount_cmp (&nxt,
    775                           dividend))
    776       break; /* nxt > dividend */
    777     ret++;
    778     tmp = nxt;
    779   }
    780   return ret;
    781 }
    782 
    783 
    784 enum TALER_AmountArithmeticResult
    785 TALER_amount_multiply (struct TALER_Amount *result,
    786                        const struct TALER_Amount *amount,
    787                        uint32_t factor)
    788 {
    789   struct TALER_Amount in = *amount;
    790 
    791   if (GNUNET_SYSERR ==
    792       TALER_amount_normalize (&in))
    793   {
    794     invalidate (result);
    795     return TALER_AAR_INVALID_NORMALIZATION_FAILED;
    796   }
    797   GNUNET_memcpy (result->currency,
    798                  amount->currency,
    799                  TALER_CURRENCY_LEN);
    800   if ( (0 == factor) ||
    801        ( (0 == in.value) &&
    802          (0 == in.fraction) ) )
    803   {
    804     result->value = 0;
    805     result->fraction = 0;
    806     return TALER_AAR_RESULT_ZERO;
    807   }
    808   result->value = in.value * ((uint64_t) factor);
    809   if (in.value != result->value / factor)
    810   {
    811     invalidate (result);
    812     return TALER_AAR_INVALID_RESULT_OVERFLOW;
    813   }
    814   {
    815     /* This multiplication cannot overflow since both inputs are 32-bit values */
    816     uint64_t tmp = ((uint64_t) factor) * ((uint64_t) in.fraction);
    817     uint64_t res;
    818 
    819     res = tmp / TALER_AMOUNT_FRAC_BASE;
    820     /* check for overflow */
    821     if (result->value + res < result->value)
    822     {
    823       invalidate (result);
    824       return TALER_AAR_INVALID_RESULT_OVERFLOW;
    825     }
    826     result->value += res;
    827     result->fraction = tmp % TALER_AMOUNT_FRAC_BASE;
    828   }
    829   if (result->value > TALER_AMOUNT_MAX_VALUE)
    830   {
    831     invalidate (result);
    832     return TALER_AAR_INVALID_RESULT_OVERFLOW;
    833   }
    834   /* This check should be redundant... */
    835   GNUNET_assert (GNUNET_SYSERR !=
    836                  TALER_amount_normalize (result));
    837   return TALER_AAR_RESULT_POSITIVE;
    838 }
    839 
    840 
    841 enum GNUNET_GenericReturnValue
    842 TALER_amount_round_down (struct TALER_Amount *amount,
    843                          const struct TALER_Amount *round_unit)
    844 {
    845   if (GNUNET_OK !=
    846       TALER_amount_cmp_currency (amount,
    847                                  round_unit))
    848   {
    849     GNUNET_break (0);
    850     return GNUNET_SYSERR;
    851   }
    852   if ( (0 != round_unit->fraction) &&
    853        (0 != round_unit->value) )
    854   {
    855     GNUNET_break (0);
    856     return GNUNET_SYSERR;
    857   }
    858   if ( (0 == round_unit->fraction) &&
    859        (0 == round_unit->value) )
    860     return GNUNET_NO; /* no rounding requested */
    861   if (0 != round_unit->fraction)
    862   {
    863     uint32_t delta;
    864 
    865     delta = amount->fraction % round_unit->fraction;
    866     if (0 == delta)
    867       return GNUNET_NO;
    868     amount->fraction -= delta;
    869   }
    870   if (0 != round_unit->value)
    871   {
    872     uint64_t delta;
    873 
    874     delta = amount->value % round_unit->value;
    875     if ( (0 == delta) &&
    876          (0 == amount->fraction) )
    877       return GNUNET_NO;
    878     amount->value -= delta;
    879     amount->fraction = 0;
    880   }
    881   return GNUNET_OK;
    882 }
    883 
    884 
    885 void
    886 TALER_amount_set_free (struct TALER_AmountSet *as)
    887 {
    888   GNUNET_array_grow (as->taa,
    889                      as->taa_size,
    890                      0);
    891 }
    892 
    893 
    894 enum TALER_AmountArithmeticResult
    895 TALER_amount_set_add (struct TALER_AmountSet *as,
    896                       const struct TALER_Amount *val,
    897                       const struct TALER_Amount *cap)
    898 {
    899   for (unsigned int i = 0; i<as->taa_size; i++)
    900   {
    901     struct TALER_Amount *ai = &as->taa[i];
    902     enum TALER_AmountArithmeticResult aar;
    903 
    904     if (GNUNET_OK !=
    905         TALER_amount_cmp_currency (ai,
    906                                    val))
    907       continue;
    908     aar = TALER_amount_add (ai,
    909                             ai,
    910                             val);
    911     /* If we have a cap, we tolerate the overflow */
    912     if ( (aar < 0) &&
    913          ( (NULL == cap) ||
    914            (TALER_AAR_INVALID_RESULT_OVERFLOW != aar) ) )
    915       return aar; /* hard error */
    916     if (TALER_AAR_INVALID_RESULT_OVERFLOW == aar)
    917     {
    918       if (GNUNET_OK !=
    919           TALER_amount_cmp_currency (val,
    920                                      cap))
    921         return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
    922       *ai = *cap;
    923       return (TALER_amount_is_zero (cap))
    924         ? TALER_AAR_RESULT_ZERO
    925         : TALER_AAR_RESULT_POSITIVE;
    926     }
    927     GNUNET_assert (aar >= 0);
    928     if (NULL != cap)
    929       GNUNET_assert (GNUNET_OK ==
    930                      TALER_amount_min (ai,
    931                                        ai,
    932                                        cap));
    933     return (TALER_amount_is_zero (ai))
    934       ? TALER_AAR_RESULT_ZERO
    935       : TALER_AAR_RESULT_POSITIVE;
    936   }
    937   GNUNET_array_append (as->taa,
    938                        as->taa_size,
    939                        *val);
    940   {
    941     struct TALER_Amount *ai = &as->taa[as->taa_size - 1];
    942 
    943     if (NULL != cap)
    944     {
    945       if (GNUNET_OK !=
    946           TALER_amount_cmp_currency (val,
    947                                      cap))
    948         return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
    949       GNUNET_assert (GNUNET_OK ==
    950                      TALER_amount_min (ai,
    951                                        ai,
    952                                        cap));
    953     }
    954     return (TALER_amount_is_zero (ai))
    955       ? TALER_AAR_RESULT_ZERO
    956       : TALER_AAR_RESULT_POSITIVE;
    957   }
    958 }
    959 
    960 
    961 bool
    962 TALER_amount_set_test_above (const struct TALER_AmountSet *as,
    963                              const struct TALER_Amount *b)
    964 {
    965   for (unsigned int i = 0; i<as->taa_size; i++)
    966   {
    967     const struct TALER_Amount *asi = &as->taa[i];
    968 
    969     if (GNUNET_OK !=
    970         TALER_amount_cmp_currency (b,
    971                                    asi))
    972       continue;
    973     if (1 !=
    974         TALER_amount_cmp (b,
    975                           asi))
    976       return true;
    977   }
    978   return false;
    979 }
    980 
    981 
    982 const struct TALER_Amount *
    983 TALER_amount_set_find (const char *currency,
    984                        const struct TALER_AmountSet *as)
    985 {
    986   static TALER_THREAD_LOCAL struct TALER_Amount z;
    987 
    988   for (unsigned int i = 0; i<as->taa_size; i++)
    989   {
    990     const struct TALER_Amount *asi = &as->taa[i];
    991 
    992     if (0 == strcasecmp (currency,
    993                          asi->currency))
    994       return asi;
    995   }
    996   if (GNUNET_OK !=
    997       TALER_amount_set_zero (currency,
    998                              &z))
    999   {
   1000     GNUNET_break (0);
   1001     return NULL;
   1002   }
   1003   return &z;
   1004 }
   1005 
   1006 
   1007 /**
   1008  * Upper bound on the length of the string representation of a
   1009  * single amount: the currency, the ':', the value, the '.', the
   1010  * fraction and the '\0'.  24 is sufficient for a uint64_t value
   1011  * in decimal.
   1012  */
   1013 #define AMOUNT_STR_MAX (TALER_AMOUNT_FRAC_LEN     \
   1014                         + TALER_CURRENCY_LEN + 3 + 24)
   1015 
   1016 
   1017 void
   1018 TALER_amount_list_free (struct TALER_AmountList *al)
   1019 {
   1020   GNUNET_array_grow (al->tal,
   1021                      al->tal_len,
   1022                      0);
   1023 }
   1024 
   1025 
   1026 enum GNUNET_GenericReturnValue
   1027 TALER_string_to_amount_list (const char *str,
   1028                              struct TALER_AmountList *al)
   1029 {
   1030   struct TALER_AmountList tmp = {
   1031     .tal = NULL,
   1032     .tal_len = 0
   1033   };
   1034   const char *pos = str;
   1035 
   1036   /* skip leading whitespace, so that an all-whitespace option
   1037      value means "free" and not "malformed" */
   1038   while (isspace ( (unsigned char) pos[0]))
   1039     pos++;
   1040   if ('\0' == pos[0])
   1041   {
   1042     al->tal = NULL;
   1043     al->tal_len = 0;
   1044     return GNUNET_OK;
   1045   }
   1046   while (1)
   1047   {
   1048     const char *end = strchr (pos,
   1049                               (int) ';');
   1050     size_t len = (NULL == end)
   1051       ? strlen (pos)
   1052       : (size_t) (end - pos);
   1053     struct TALER_Amount a;
   1054     char *component;
   1055 
   1056     if (0 == len)
   1057     {
   1058       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1059                   "Empty component in amount list `%s'\n",
   1060                   str);
   1061       TALER_amount_list_free (&tmp);
   1062       return GNUNET_SYSERR;
   1063     }
   1064     component = GNUNET_strndup (pos,
   1065                                 len);
   1066     if (GNUNET_OK !=
   1067         TALER_string_to_amount (component,
   1068                                 &a))
   1069     {
   1070       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1071                   "Invalid amount `%s' in amount list `%s'\n",
   1072                   component,
   1073                   str);
   1074       GNUNET_free (component);
   1075       TALER_amount_list_free (&tmp);
   1076       return GNUNET_SYSERR;
   1077     }
   1078     GNUNET_free (component);
   1079     /* A repeated currency is a typo, not an accumulation: which of
   1080        the two prices would apply is anyone's guess. */
   1081     if (NULL !=
   1082         TALER_amount_list_find (&tmp,
   1083                                 a.currency))
   1084     {
   1085       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1086                   "Currency `%s' given more than once in amount list `%s'\n",
   1087                   a.currency,
   1088                   str);
   1089       TALER_amount_list_free (&tmp);
   1090       return GNUNET_SYSERR;
   1091     }
   1092     GNUNET_array_append (tmp.tal,
   1093                          tmp.tal_len,
   1094                          a);
   1095     if (NULL == end)
   1096       break;
   1097     pos = end + 1;
   1098   }
   1099   *al = tmp;
   1100   return GNUNET_OK;
   1101 }
   1102 
   1103 
   1104 const char *
   1105 TALER_amount_list2s (const struct TALER_AmountList *al)
   1106 {
   1107   static TALER_THREAD_LOCAL char *result;
   1108   static TALER_THREAD_LOCAL size_t result_size;
   1109   size_t need;
   1110   size_t off = 0;
   1111 
   1112   /* one separator per entry is one too many, which covers the '\0' */
   1113   need = (al->tal_len + 1) * (AMOUNT_STR_MAX + 1);
   1114   if (need > result_size)
   1115   {
   1116     GNUNET_free (result);
   1117     result = GNUNET_malloc (need);
   1118     result_size = need;
   1119   }
   1120   result[0] = '\0';
   1121   for (unsigned int i = 0; i<al->tal_len; i++)
   1122   {
   1123     const char *as = TALER_amount2s (&al->tal[i]);
   1124 
   1125     if (NULL == as)
   1126     {
   1127       GNUNET_break (0);
   1128       return NULL;
   1129     }
   1130     off += GNUNET_snprintf (&result[off],
   1131                             result_size - off,
   1132                             "%s%s",
   1133                             (0 == i) ? "" : ";",
   1134                             as);
   1135   }
   1136   return result;
   1137 }
   1138 
   1139 
   1140 const struct TALER_Amount *
   1141 TALER_amount_list_find (const struct TALER_AmountList *al,
   1142                         const char *currency)
   1143 {
   1144   for (unsigned int i = 0; i<al->tal_len; i++)
   1145   {
   1146     const struct TALER_Amount *ali = &al->tal[i];
   1147 
   1148     if (0 == strcasecmp (currency,
   1149                          ali->currency))
   1150       return ali;
   1151   }
   1152   return NULL;
   1153 }
   1154 
   1155 
   1156 enum GNUNET_GenericReturnValue
   1157 TALER_amount_list_check_uniform (const struct TALER_AmountList *al)
   1158 {
   1159   bool have_zero = false;
   1160   bool have_price = false;
   1161 
   1162   for (unsigned int i = 0; i<al->tal_len; i++)
   1163   {
   1164     if (TALER_amount_is_zero (&al->tal[i]))
   1165       have_zero = true;
   1166     else
   1167       have_price = true;
   1168   }
   1169   if (have_zero && have_price)
   1170     return GNUNET_SYSERR;
   1171   if (have_price)
   1172     return GNUNET_OK;
   1173   return GNUNET_NO; /* all zero, or empty */
   1174 }
   1175 
   1176 
   1177 bool
   1178 TALER_amount_list_covers (const struct TALER_AmountList *al,
   1179                           const char *const *currencies,
   1180                           unsigned int currencies_len)
   1181 {
   1182   /* @a al has no duplicates, so equal length plus each currency
   1183      being present is enough to conclude the two agree exactly */
   1184   if (al->tal_len != currencies_len)
   1185     return false;
   1186   for (unsigned int i = 0; i<currencies_len; i++)
   1187     if (NULL ==
   1188         TALER_amount_list_find (al,
   1189                                 currencies[i]))
   1190       return false;
   1191   return true;
   1192 }
   1193 
   1194 
   1195 enum GNUNET_GenericReturnValue
   1196 TALER_amount_list_multiply (struct TALER_AmountList *al,
   1197                             uint32_t n)
   1198 {
   1199   struct TALER_Amount *tmp;
   1200 
   1201   if (0 == n)
   1202   {
   1203     GNUNET_break (0);
   1204     return GNUNET_SYSERR;
   1205   }
   1206   if ( (1 == n) ||
   1207        (0 == al->tal_len) )
   1208     return GNUNET_OK;
   1209   /* compute into a scratch array first, so that an overflow in a
   1210      late currency does not leave the early ones multiplied */
   1211   tmp = GNUNET_new_array (al->tal_len,
   1212                           struct TALER_Amount);
   1213   for (unsigned int i = 0; i<al->tal_len; i++)
   1214   {
   1215     if (0 >
   1216         TALER_amount_multiply (&tmp[i],
   1217                                &al->tal[i],
   1218                                n))
   1219     {
   1220       GNUNET_free (tmp);
   1221       return GNUNET_SYSERR;
   1222     }
   1223   }
   1224   GNUNET_memcpy (al->tal,
   1225                  tmp,
   1226                  al->tal_len * sizeof (struct TALER_Amount));
   1227   GNUNET_free (tmp);
   1228   return GNUNET_OK;
   1229 }
   1230 
   1231 
   1232 void
   1233 TALER_amount_list_copy (struct TALER_AmountList *dst,
   1234                         const struct TALER_AmountList *src)
   1235 {
   1236   dst->tal_len = src->tal_len;
   1237   if (0 == src->tal_len)
   1238   {
   1239     dst->tal = NULL;
   1240     return;
   1241   }
   1242   dst->tal = GNUNET_new_array (src->tal_len,
   1243                                struct TALER_Amount);
   1244   GNUNET_memcpy (dst->tal,
   1245                  src->tal,
   1246                  src->tal_len * sizeof (struct TALER_Amount));
   1247 }
   1248 
   1249 
   1250 /* end of amount.c */