exchange

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

amount.c (31506B)


      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     GNUNET_assert (0 <=
    765                    TALER_amount_add (&nxt,
    766                                      &tmp,
    767                                      divisor));
    768     if (1 ==
    769         TALER_amount_cmp (&nxt,
    770                           dividend))
    771       break; /* nxt > dividend */
    772     ret++;
    773     tmp = nxt;
    774   }
    775   return ret;
    776 }
    777 
    778 
    779 enum TALER_AmountArithmeticResult
    780 TALER_amount_multiply (struct TALER_Amount *result,
    781                        const struct TALER_Amount *amount,
    782                        uint32_t factor)
    783 {
    784   struct TALER_Amount in = *amount;
    785 
    786   if (GNUNET_SYSERR ==
    787       TALER_amount_normalize (&in))
    788   {
    789     invalidate (result);
    790     return TALER_AAR_INVALID_NORMALIZATION_FAILED;
    791   }
    792   GNUNET_memcpy (result->currency,
    793                  amount->currency,
    794                  TALER_CURRENCY_LEN);
    795   if ( (0 == factor) ||
    796        ( (0 == in.value) &&
    797          (0 == in.fraction) ) )
    798   {
    799     result->value = 0;
    800     result->fraction = 0;
    801     return TALER_AAR_RESULT_ZERO;
    802   }
    803   result->value = in.value * ((uint64_t) factor);
    804   if (in.value != result->value / factor)
    805   {
    806     invalidate (result);
    807     return TALER_AAR_INVALID_RESULT_OVERFLOW;
    808   }
    809   {
    810     /* This multiplication cannot overflow since both inputs are 32-bit values */
    811     uint64_t tmp = ((uint64_t) factor) * ((uint64_t) in.fraction);
    812     uint64_t res;
    813 
    814     res = tmp / TALER_AMOUNT_FRAC_BASE;
    815     /* check for overflow */
    816     if (result->value + res < result->value)
    817     {
    818       invalidate (result);
    819       return TALER_AAR_INVALID_RESULT_OVERFLOW;
    820     }
    821     result->value += res;
    822     result->fraction = tmp % TALER_AMOUNT_FRAC_BASE;
    823   }
    824   if (result->value > TALER_AMOUNT_MAX_VALUE)
    825   {
    826     invalidate (result);
    827     return TALER_AAR_INVALID_RESULT_OVERFLOW;
    828   }
    829   /* This check should be redundant... */
    830   GNUNET_assert (GNUNET_SYSERR !=
    831                  TALER_amount_normalize (result));
    832   return TALER_AAR_RESULT_POSITIVE;
    833 }
    834 
    835 
    836 enum GNUNET_GenericReturnValue
    837 TALER_amount_round_down (struct TALER_Amount *amount,
    838                          const struct TALER_Amount *round_unit)
    839 {
    840   if (GNUNET_OK !=
    841       TALER_amount_cmp_currency (amount,
    842                                  round_unit))
    843   {
    844     GNUNET_break (0);
    845     return GNUNET_SYSERR;
    846   }
    847   if ( (0 != round_unit->fraction) &&
    848        (0 != round_unit->value) )
    849   {
    850     GNUNET_break (0);
    851     return GNUNET_SYSERR;
    852   }
    853   if ( (0 == round_unit->fraction) &&
    854        (0 == round_unit->value) )
    855     return GNUNET_NO; /* no rounding requested */
    856   if (0 != round_unit->fraction)
    857   {
    858     uint32_t delta;
    859 
    860     delta = amount->fraction % round_unit->fraction;
    861     if (0 == delta)
    862       return GNUNET_NO;
    863     amount->fraction -= delta;
    864   }
    865   if (0 != round_unit->value)
    866   {
    867     uint64_t delta;
    868 
    869     delta = amount->value % round_unit->value;
    870     if ( (0 == delta) &&
    871          (0 == amount->fraction) )
    872       return GNUNET_NO;
    873     amount->value -= delta;
    874     amount->fraction = 0;
    875   }
    876   return GNUNET_OK;
    877 }
    878 
    879 
    880 void
    881 TALER_amount_set_free (struct TALER_AmountSet *as)
    882 {
    883   GNUNET_array_grow (as->taa,
    884                      as->taa_size,
    885                      0);
    886 }
    887 
    888 
    889 enum TALER_AmountArithmeticResult
    890 TALER_amount_set_add (struct TALER_AmountSet *as,
    891                       const struct TALER_Amount *val,
    892                       const struct TALER_Amount *cap)
    893 {
    894   for (unsigned int i = 0; i<as->taa_size; i++)
    895   {
    896     struct TALER_Amount *ai = &as->taa[i];
    897     enum TALER_AmountArithmeticResult aar;
    898 
    899     if (GNUNET_OK !=
    900         TALER_amount_cmp_currency (ai,
    901                                    val))
    902       continue;
    903     aar = TALER_amount_add (ai,
    904                             ai,
    905                             val);
    906     /* If we have a cap, we tolerate the overflow */
    907     if ( (aar < 0) &&
    908          ( (NULL == cap) ||
    909            (TALER_AAR_INVALID_RESULT_OVERFLOW != aar) ) )
    910       return aar; /* hard error */
    911     if (TALER_AAR_INVALID_RESULT_OVERFLOW == aar)
    912     {
    913       if (GNUNET_OK !=
    914           TALER_amount_cmp_currency (val,
    915                                      cap))
    916         return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
    917       *ai = *cap;
    918       return (TALER_amount_is_zero (cap))
    919         ? TALER_AAR_RESULT_ZERO
    920         : TALER_AAR_RESULT_POSITIVE;
    921     }
    922     GNUNET_assert (aar >= 0);
    923     if (NULL != cap)
    924       GNUNET_assert (GNUNET_OK ==
    925                      TALER_amount_min (ai,
    926                                        ai,
    927                                        cap));
    928     return (TALER_amount_is_zero (ai))
    929       ? TALER_AAR_RESULT_ZERO
    930       : TALER_AAR_RESULT_POSITIVE;
    931   }
    932   GNUNET_array_append (as->taa,
    933                        as->taa_size,
    934                        *val);
    935   {
    936     struct TALER_Amount *ai = &as->taa[as->taa_size - 1];
    937 
    938     if (NULL != cap)
    939     {
    940       if (GNUNET_OK !=
    941           TALER_amount_cmp_currency (val,
    942                                      cap))
    943         return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
    944       GNUNET_assert (GNUNET_OK ==
    945                      TALER_amount_min (ai,
    946                                        ai,
    947                                        cap));
    948     }
    949     return (TALER_amount_is_zero (ai))
    950       ? TALER_AAR_RESULT_ZERO
    951       : TALER_AAR_RESULT_POSITIVE;
    952   }
    953 }
    954 
    955 
    956 bool
    957 TALER_amount_set_test_above (const struct TALER_AmountSet *as,
    958                              const struct TALER_Amount *b)
    959 {
    960   for (unsigned int i = 0; i<as->taa_size; i++)
    961   {
    962     const struct TALER_Amount *asi = &as->taa[i];
    963 
    964     if (GNUNET_OK !=
    965         TALER_amount_cmp_currency (b,
    966                                    asi))
    967       continue;
    968     if (1 !=
    969         TALER_amount_cmp (b,
    970                           asi))
    971       return true;
    972   }
    973   return false;
    974 }
    975 
    976 
    977 const struct TALER_Amount *
    978 TALER_amount_set_find (const char *currency,
    979                        const struct TALER_AmountSet *as)
    980 {
    981   static TALER_THREAD_LOCAL struct TALER_Amount z;
    982 
    983   for (unsigned int i = 0; i<as->taa_size; i++)
    984   {
    985     const struct TALER_Amount *asi = &as->taa[i];
    986 
    987     if (0 == strcasecmp (currency,
    988                          asi->currency))
    989       return asi;
    990   }
    991   if (GNUNET_OK !=
    992       TALER_amount_set_zero (currency,
    993                              &z))
    994   {
    995     GNUNET_break (0);
    996     return NULL;
    997   }
    998   return &z;
    999 }
   1000 
   1001 
   1002 /**
   1003  * Upper bound on the length of the string representation of a
   1004  * single amount: the currency, the ':', the value, the '.', the
   1005  * fraction and the '\0'.  24 is sufficient for a uint64_t value
   1006  * in decimal.
   1007  */
   1008 #define AMOUNT_STR_MAX (TALER_AMOUNT_FRAC_LEN     \
   1009                         + TALER_CURRENCY_LEN + 3 + 24)
   1010 
   1011 
   1012 void
   1013 TALER_amount_list_free (struct TALER_AmountList *al)
   1014 {
   1015   GNUNET_array_grow (al->tal,
   1016                      al->tal_len,
   1017                      0);
   1018 }
   1019 
   1020 
   1021 enum GNUNET_GenericReturnValue
   1022 TALER_string_to_amount_list (const char *str,
   1023                              struct TALER_AmountList *al)
   1024 {
   1025   struct TALER_AmountList tmp = {
   1026     .tal = NULL,
   1027     .tal_len = 0
   1028   };
   1029   const char *pos = str;
   1030 
   1031   /* skip leading whitespace, so that an all-whitespace option
   1032      value means "free" and not "malformed" */
   1033   while (isspace ( (unsigned char) pos[0]))
   1034     pos++;
   1035   if ('\0' == pos[0])
   1036   {
   1037     al->tal = NULL;
   1038     al->tal_len = 0;
   1039     return GNUNET_OK;
   1040   }
   1041   while (1)
   1042   {
   1043     const char *end = strchr (pos,
   1044                               (int) ';');
   1045     size_t len = (NULL == end)
   1046       ? strlen (pos)
   1047       : (size_t) (end - pos);
   1048     struct TALER_Amount a;
   1049     char *component;
   1050 
   1051     if (0 == len)
   1052     {
   1053       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1054                   "Empty component in amount list `%s'\n",
   1055                   str);
   1056       TALER_amount_list_free (&tmp);
   1057       return GNUNET_SYSERR;
   1058     }
   1059     component = GNUNET_strndup (pos,
   1060                                 len);
   1061     if (GNUNET_OK !=
   1062         TALER_string_to_amount (component,
   1063                                 &a))
   1064     {
   1065       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1066                   "Invalid amount `%s' in amount list `%s'\n",
   1067                   component,
   1068                   str);
   1069       GNUNET_free (component);
   1070       TALER_amount_list_free (&tmp);
   1071       return GNUNET_SYSERR;
   1072     }
   1073     GNUNET_free (component);
   1074     /* A repeated currency is a typo, not an accumulation: which of
   1075        the two prices would apply is anyone's guess. */
   1076     if (NULL !=
   1077         TALER_amount_list_find (&tmp,
   1078                                 a.currency))
   1079     {
   1080       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1081                   "Currency `%s' given more than once in amount list `%s'\n",
   1082                   a.currency,
   1083                   str);
   1084       TALER_amount_list_free (&tmp);
   1085       return GNUNET_SYSERR;
   1086     }
   1087     GNUNET_array_append (tmp.tal,
   1088                          tmp.tal_len,
   1089                          a);
   1090     if (NULL == end)
   1091       break;
   1092     pos = end + 1;
   1093   }
   1094   *al = tmp;
   1095   return GNUNET_OK;
   1096 }
   1097 
   1098 
   1099 const char *
   1100 TALER_amount_list2s (const struct TALER_AmountList *al)
   1101 {
   1102   static TALER_THREAD_LOCAL char *result;
   1103   static TALER_THREAD_LOCAL size_t result_size;
   1104   size_t need;
   1105   size_t off = 0;
   1106 
   1107   /* one separator per entry is one too many, which covers the '\0' */
   1108   need = (al->tal_len + 1) * (AMOUNT_STR_MAX + 1);
   1109   if (need > result_size)
   1110   {
   1111     GNUNET_free (result);
   1112     result = GNUNET_malloc (need);
   1113     result_size = need;
   1114   }
   1115   result[0] = '\0';
   1116   for (unsigned int i = 0; i<al->tal_len; i++)
   1117   {
   1118     const char *as = TALER_amount2s (&al->tal[i]);
   1119 
   1120     if (NULL == as)
   1121     {
   1122       GNUNET_break (0);
   1123       return NULL;
   1124     }
   1125     off += GNUNET_snprintf (&result[off],
   1126                             result_size - off,
   1127                             "%s%s",
   1128                             (0 == i) ? "" : ";",
   1129                             as);
   1130   }
   1131   return result;
   1132 }
   1133 
   1134 
   1135 const struct TALER_Amount *
   1136 TALER_amount_list_find (const struct TALER_AmountList *al,
   1137                         const char *currency)
   1138 {
   1139   for (unsigned int i = 0; i<al->tal_len; i++)
   1140   {
   1141     const struct TALER_Amount *ali = &al->tal[i];
   1142 
   1143     if (0 == strcasecmp (currency,
   1144                          ali->currency))
   1145       return ali;
   1146   }
   1147   return NULL;
   1148 }
   1149 
   1150 
   1151 enum GNUNET_GenericReturnValue
   1152 TALER_amount_list_check_uniform (const struct TALER_AmountList *al)
   1153 {
   1154   bool have_zero = false;
   1155   bool have_price = false;
   1156 
   1157   for (unsigned int i = 0; i<al->tal_len; i++)
   1158   {
   1159     if (TALER_amount_is_zero (&al->tal[i]))
   1160       have_zero = true;
   1161     else
   1162       have_price = true;
   1163   }
   1164   if (have_zero && have_price)
   1165     return GNUNET_SYSERR;
   1166   if (have_price)
   1167     return GNUNET_OK;
   1168   return GNUNET_NO; /* all zero, or empty */
   1169 }
   1170 
   1171 
   1172 bool
   1173 TALER_amount_list_covers (const struct TALER_AmountList *al,
   1174                           const char *const *currencies,
   1175                           unsigned int currencies_len)
   1176 {
   1177   /* @a al has no duplicates, so equal length plus each currency
   1178      being present is enough to conclude the two agree exactly */
   1179   if (al->tal_len != currencies_len)
   1180     return false;
   1181   for (unsigned int i = 0; i<currencies_len; i++)
   1182     if (NULL ==
   1183         TALER_amount_list_find (al,
   1184                                 currencies[i]))
   1185       return false;
   1186   return true;
   1187 }
   1188 
   1189 
   1190 enum GNUNET_GenericReturnValue
   1191 TALER_amount_list_multiply (struct TALER_AmountList *al,
   1192                             uint32_t n)
   1193 {
   1194   struct TALER_Amount *tmp;
   1195 
   1196   if (0 == n)
   1197   {
   1198     GNUNET_break (0);
   1199     return GNUNET_SYSERR;
   1200   }
   1201   if ( (1 == n) ||
   1202        (0 == al->tal_len) )
   1203     return GNUNET_OK;
   1204   /* compute into a scratch array first, so that an overflow in a
   1205      late currency does not leave the early ones multiplied */
   1206   tmp = GNUNET_new_array (al->tal_len,
   1207                           struct TALER_Amount);
   1208   for (unsigned int i = 0; i<al->tal_len; i++)
   1209   {
   1210     if (0 >
   1211         TALER_amount_multiply (&tmp[i],
   1212                                &al->tal[i],
   1213                                n))
   1214     {
   1215       GNUNET_free (tmp);
   1216       return GNUNET_SYSERR;
   1217     }
   1218   }
   1219   GNUNET_memcpy (al->tal,
   1220                  tmp,
   1221                  al->tal_len * sizeof (struct TALER_Amount));
   1222   GNUNET_free (tmp);
   1223   return GNUNET_OK;
   1224 }
   1225 
   1226 
   1227 void
   1228 TALER_amount_list_copy (struct TALER_AmountList *dst,
   1229                         const struct TALER_AmountList *src)
   1230 {
   1231   dst->tal_len = src->tal_len;
   1232   if (0 == src->tal_len)
   1233   {
   1234     dst->tal = NULL;
   1235     return;
   1236   }
   1237   dst->tal = GNUNET_new_array (src->tal_len,
   1238                                struct TALER_Amount);
   1239   GNUNET_memcpy (dst->tal,
   1240                  src->tal,
   1241                  src->tal_len * sizeof (struct TALER_Amount));
   1242 }
   1243 
   1244 
   1245 /* end of amount.c */