LCOV - code coverage report
Current view: top level - util - amount.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 74.2 % 551 409
Test Date: 2026-09-11 18:55:36 Functions: 76.9 % 39 30

            Line data    Source code
       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           20 : invalidate (struct TALER_Amount *a)
      35              : {
      36           20 :   memset (a,
      37              :           0,
      38              :           sizeof (struct TALER_Amount));
      39           20 : }
      40              : 
      41              : 
      42              : enum GNUNET_GenericReturnValue
      43        74376 : TALER_check_currency (const char *str)
      44              : {
      45        74376 :   size_t len = strlen (str);
      46              : 
      47        74376 :   if (len >= TALER_CURRENCY_LEN)
      48              :   {
      49            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
      50              :                 "Currency code name `%s' is too long\n",
      51              :                 str);
      52            0 :     return GNUNET_SYSERR;
      53              :   }
      54        74376 :   if (len == 0)
      55              :   {
      56            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
      57              :                 "Currency code name must be set\n");
      58            0 :     return GNUNET_SYSERR;
      59              :   }
      60              :   /* validate str has only legal characters in it! */
      61       407620 :   for (unsigned int i = 0; '\0' != str[i]; i++)
      62              :   {
      63       333244 :     if ( ('A' > str[i]) || ('Z' < str[i]) )
      64              :     {
      65            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
      66              :                   "Currency code name `%s' contains illegal characters (only A-Z allowed)\n",
      67              :                   str);
      68            0 :       return GNUNET_SYSERR;
      69              :     }
      70              :   }
      71        74376 :   return GNUNET_OK;
      72              : }
      73              : 
      74              : 
      75              : enum GNUNET_GenericReturnValue
      76        12690 : 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        12692 :   while (isspace ( (unsigned char) str[0]))
      85            2 :     str++;
      86        12690 :   if ('\0' == str[0])
      87              :   {
      88            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
      89              :                 "Null before currency\n");
      90            0 :     invalidate (amount);
      91            0 :     return GNUNET_SYSERR;
      92              :   }
      93              : 
      94              :   /* parse currency */
      95        12690 :   colon = strchr (str, (int) ':');
      96        12690 :   if ( (NULL == colon) ||
      97        12687 :        (colon == str) ||
      98        12687 :        ((colon - str) >= TALER_CURRENCY_LEN) )
      99              :   {
     100            3 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     101              :                 "Invalid currency specified before colon: `%s'\n",
     102              :                 str);
     103            3 :     invalidate (amount);
     104            3 :     return GNUNET_SYSERR;
     105              :   }
     106              : 
     107        12687 :   GNUNET_assert (TALER_CURRENCY_LEN > (colon - str));
     108        12687 :   memcpy (&amount->currency[0],
     109              :           str,
     110        12687 :           colon - str);
     111              :   /* 0-terminate *and* normalize buffer by setting everything to '\0' */
     112        12687 :   memset (&amount->currency [colon - str],
     113              :           0,
     114        12687 :           TALER_CURRENCY_LEN - (colon - str));
     115        12687 :   if (GNUNET_OK !=
     116        12687 :       TALER_check_currency (amount->currency))
     117              :   {
     118            0 :     invalidate (amount);
     119            0 :     return GNUNET_SYSERR;
     120              :   }
     121              :   /* skip colon */
     122        12687 :   value = colon + 1;
     123        12687 :   if ('\0' == value[0])
     124              :   {
     125            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     126              :                 "Actual value missing in amount `%s'\n",
     127              :                 str);
     128            0 :     invalidate (amount);
     129            0 :     return GNUNET_SYSERR;
     130              :   }
     131              : 
     132        12687 :   amount->value = 0;
     133        12687 :   amount->fraction = 0;
     134              : 
     135              :   /* parse value */
     136        27212 :   while ('.' != *value)
     137              :   {
     138              :     int n;
     139              : 
     140        18038 :     if ('\0' == *value)
     141              :     {
     142              :       /* we are done */
     143         3510 :       return GNUNET_OK;
     144              :     }
     145        14528 :     if ( (*value < '0') ||
     146        14528 :          (*value > '9') )
     147              :     {
     148            2 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     149              :                   "Invalid character `%c' in amount `%s'\n",
     150              :                   (int) *value,
     151              :                   str);
     152            2 :       invalidate (amount);
     153            2 :       return GNUNET_SYSERR;
     154              :     }
     155        14526 :     n = *value - '0';
     156        14526 :     if ( (amount->value * 10 < amount->value) ||
     157        14526 :          (amount->value * 10 + n < amount->value) ||
     158        14526 :          (amount->value > TALER_AMOUNT_MAX_VALUE) ||
     159        14526 :          (amount->value * 10 + n > TALER_AMOUNT_MAX_VALUE) )
     160              :     {
     161            1 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     162              :                   "Value specified in amount `%s' is too large\n",
     163              :                   str);
     164            1 :       invalidate (amount);
     165            1 :       return GNUNET_SYSERR;
     166              :     }
     167        14525 :     amount->value = (amount->value * 10) + n;
     168        14525 :     value++;
     169              :   }
     170              : 
     171              :   /* skip the dot */
     172         9174 :   value++;
     173              : 
     174              :   /* parse fraction */
     175         9174 :   if ('\0' == *value)
     176              :   {
     177            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     178              :                 "Amount `%s' ends abruptly after `.'\n",
     179              :                 str);
     180            0 :     invalidate (amount);
     181            0 :     return GNUNET_SYSERR;
     182              :   }
     183         9174 :   b = TALER_AMOUNT_FRAC_BASE / 10;
     184        27215 :   while ('\0' != *value)
     185              :   {
     186              :     int n;
     187              : 
     188        18044 :     if (0 == b)
     189              :     {
     190            1 :       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            1 :       invalidate (amount);
     195            1 :       return GNUNET_SYSERR;
     196              :     }
     197        18043 :     if ( (*value < '0') ||
     198        18043 :          (*value > '9') )
     199              :     {
     200            2 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     201              :                   "Error after dot\n");
     202            2 :       invalidate (amount);
     203            2 :       return GNUNET_SYSERR;
     204              :     }
     205        18041 :     n = *value - '0';
     206        18041 :     amount->fraction += n * b;
     207        18041 :     b /= 10;
     208        18041 :     value++;
     209              :   }
     210         9171 :   return GNUNET_OK;
     211              : }
     212              : 
     213              : 
     214              : enum GNUNET_GenericReturnValue
     215            0 : TALER_string_to_amount_nbo (const char *str,
     216              :                             struct TALER_AmountNBO *amount_nbo)
     217              : {
     218              :   struct TALER_Amount amount;
     219              : 
     220            0 :   if (GNUNET_OK !=
     221            0 :       TALER_string_to_amount (str,
     222              :                               &amount))
     223            0 :     return GNUNET_SYSERR;
     224            0 :   TALER_amount_hton (amount_nbo,
     225              :                      &amount);
     226            0 :   return GNUNET_OK;
     227              : }
     228              : 
     229              : 
     230              : void
     231        21893 : TALER_amount_hton (struct TALER_AmountNBO *res,
     232              :                    const struct TALER_Amount *d)
     233              : {
     234        21893 :   GNUNET_assert (GNUNET_YES ==
     235              :                  TALER_amount_is_valid (d));
     236        21893 :   res->value = GNUNET_htonll (d->value);
     237        21893 :   res->fraction = htonl (d->fraction);
     238       284609 :   for (unsigned int i = 0; i<TALER_CURRENCY_LEN; i++)
     239       262716 :     res->currency[i] = d->currency[i];
     240        21893 : }
     241              : 
     242              : 
     243              : void
     244           55 : TALER_amount_ntoh (struct TALER_Amount *res,
     245              :                    const struct TALER_AmountNBO *dn)
     246              : {
     247           55 :   res->value = GNUNET_ntohll (dn->value);
     248           55 :   res->fraction = ntohl (dn->fraction);
     249           55 :   GNUNET_memcpy (res->currency,
     250              :                  dn->currency,
     251              :                  TALER_CURRENCY_LEN);
     252           55 :   GNUNET_assert (GNUNET_YES ==
     253              :                  TALER_amount_is_valid (res));
     254           55 : }
     255              : 
     256              : 
     257              : enum GNUNET_GenericReturnValue
     258        61072 : 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        61072 :   if (GNUNET_OK !=
     265        61072 :       TALER_check_currency (cur))
     266            0 :     return GNUNET_SYSERR;
     267        61072 :   slen = strlen (cur);
     268              :   /* make a copy of 'cur' to 'tmp' as the memset may clobber cur
     269              :      if cur aliases &amount->currency! */
     270        61072 :   memcpy (tmp,
     271              :           cur,
     272              :           slen);
     273        61072 :   memset (amount,
     274              :           0,
     275              :           sizeof (struct TALER_Amount));
     276       353258 :   for (unsigned int i = 0; i<slen; i++)
     277       292186 :     amount->currency[i] = tmp[i];
     278        61072 :   return GNUNET_OK;
     279              : }
     280              : 
     281              : 
     282              : enum GNUNET_GenericReturnValue
     283       391346 : TALER_amount_is_valid (const struct TALER_Amount *amount)
     284              : {
     285       391346 :   if (amount->value > TALER_AMOUNT_MAX_VALUE)
     286              :   {
     287            2 :     GNUNET_break (0);
     288            2 :     return GNUNET_SYSERR;
     289              :   }
     290       391344 :   return ('\0' != amount->currency[0]) ? GNUNET_OK : GNUNET_NO;
     291              : }
     292              : 
     293              : 
     294              : enum GNUNET_GenericReturnValue
     295            0 : TALER_amount_max (struct TALER_Amount *ma,
     296              :                   const struct TALER_Amount *a1,
     297              :                   const struct TALER_Amount *a2)
     298              : {
     299            0 :   if (GNUNET_OK !=
     300            0 :       TALER_amount_cmp_currency (a1,
     301              :                                  a2))
     302              :   {
     303            0 :     memset (ma,
     304              :             0,
     305              :             sizeof (*ma));
     306            0 :     return GNUNET_SYSERR;
     307              :   }
     308            0 :   if (1 == TALER_amount_cmp (a1,
     309              :                              a2))
     310            0 :     *ma = *a1;
     311              :   else
     312            0 :     *ma = *a2;
     313            0 :   return GNUNET_OK;
     314              : }
     315              : 
     316              : 
     317              : enum GNUNET_GenericReturnValue
     318            0 : TALER_amount_min (struct TALER_Amount *mi,
     319              :                   const struct TALER_Amount *a1,
     320              :                   const struct TALER_Amount *a2)
     321              : {
     322            0 :   if (GNUNET_OK !=
     323            0 :       TALER_amount_cmp_currency (a1,
     324              :                                  a2))
     325              :   {
     326            0 :     memset (mi,
     327              :             0,
     328              :             sizeof (*mi));
     329            0 :     return GNUNET_SYSERR;
     330              :   }
     331            0 :   if (1 == TALER_amount_cmp (a1,
     332              :                              a2))
     333            0 :     *mi = *a2;
     334              :   else
     335            0 :     *mi = *a1;
     336            0 :   return GNUNET_OK;
     337              : }
     338              : 
     339              : 
     340              : bool
     341        65599 : TALER_amount_is_zero (const struct TALER_Amount *amount)
     342              : {
     343        65599 :   if (GNUNET_OK !=
     344        65599 :       TALER_amount_is_valid (amount))
     345            0 :     return false;
     346              :   return
     347        89755 :     (0 == amount->value) &&
     348        24156 :     (0 == amount->fraction);
     349              : }
     350              : 
     351              : 
     352              : enum GNUNET_GenericReturnValue
     353         4456 : TALER_amount_is_currency (const struct TALER_Amount *amount,
     354              :                           const char *currency)
     355              : {
     356         4456 :   if (GNUNET_OK !=
     357         4456 :       TALER_amount_is_valid (amount))
     358            0 :     return GNUNET_SYSERR;
     359         4456 :   return (0 == strcasecmp (currency,
     360         4456 :                            amount->currency))
     361              :          ? GNUNET_OK
     362         4456 :          : 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            0 : test_valid_nbo (const struct TALER_AmountNBO *a)
     375              : {
     376            0 :   return ('\0' != a->currency[0]) ? GNUNET_YES : GNUNET_NO;
     377              : }
     378              : 
     379              : 
     380              : enum GNUNET_GenericReturnValue
     381        58718 : TALER_amount_cmp_currency (const struct TALER_Amount *a1,
     382              :                            const struct TALER_Amount *a2)
     383              : {
     384       117436 :   if ( (GNUNET_NO == TALER_amount_is_valid (a1)) ||
     385        58718 :        (GNUNET_NO == TALER_amount_is_valid (a2)) )
     386            0 :     return GNUNET_SYSERR;
     387        58718 :   if (0 == strcasecmp (a1->currency,
     388        58718 :                        a2->currency))
     389        58716 :     return GNUNET_YES;
     390            2 :   return GNUNET_NO;
     391              : }
     392              : 
     393              : 
     394              : enum GNUNET_GenericReturnValue
     395            0 : TALER_amount_cmp_currency_nbo (const struct TALER_AmountNBO *a1,
     396              :                                const struct TALER_AmountNBO *a2)
     397              : {
     398            0 :   if ( (GNUNET_NO == test_valid_nbo (a1)) ||
     399            0 :        (GNUNET_NO == test_valid_nbo (a2)) )
     400            0 :     return GNUNET_SYSERR;
     401            0 :   if (0 == strcasecmp (a1->currency,
     402            0 :                        a2->currency))
     403            0 :     return GNUNET_YES;
     404            0 :   return GNUNET_NO;
     405              : }
     406              : 
     407              : 
     408              : int
     409        39429 : 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        39429 :   GNUNET_assert (GNUNET_YES ==
     416              :                  TALER_amount_cmp_currency (a1,
     417              :                                             a2));
     418        39429 :   n1 = *a1;
     419        39429 :   n2 = *a2;
     420        39429 :   GNUNET_assert (GNUNET_SYSERR !=
     421              :                  TALER_amount_normalize (&n1));
     422        39429 :   GNUNET_assert (GNUNET_SYSERR !=
     423              :                  TALER_amount_normalize (&n2));
     424        39429 :   if (n1.value == n2.value)
     425              :   {
     426        36956 :     if (n1.fraction < n2.fraction)
     427           90 :       return -1;
     428        36866 :     if (n1.fraction > n2.fraction)
     429        16598 :       return 1;
     430        20268 :     return 0;
     431              :   }
     432         2473 :   if (n1.value < n2.value)
     433          919 :     return -1;
     434         1554 :   return 1;
     435              : }
     436              : 
     437              : 
     438              : int
     439            0 : 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            0 :   TALER_amount_ntoh (&h1,
     446              :                      a1);
     447            0 :   TALER_amount_ntoh (&h2,
     448              :                      a2);
     449            0 :   return TALER_amount_cmp (&h1,
     450              :                            &h2);
     451              : }
     452              : 
     453              : 
     454              : enum TALER_AmountArithmeticResult
     455        17291 : 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        17291 :   if (GNUNET_YES !=
     463        17291 :       TALER_amount_cmp_currency (a1,
     464              :                                  a2))
     465              :   {
     466            1 :     invalidate (diff);
     467            1 :     return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
     468              :   }
     469              :   /* make local copies to avoid aliasing problems between
     470              :      diff and a1/a2 */
     471        17290 :   n1 = *a1;
     472        17290 :   n2 = *a2;
     473        34580 :   if ( (GNUNET_SYSERR == TALER_amount_normalize (&n1)) ||
     474        17290 :        (GNUNET_SYSERR == TALER_amount_normalize (&n2)) )
     475              :   {
     476            0 :     invalidate (diff);
     477            0 :     return TALER_AAR_INVALID_NORMALIZATION_FAILED;
     478              :   }
     479              : 
     480        17290 :   if (n1.fraction < n2.fraction)
     481              :   {
     482          378 :     if (0 == n1.value)
     483              :     {
     484            6 :       invalidate (diff);
     485            6 :       return TALER_AAR_INVALID_NEGATIVE_RESULT;
     486              :     }
     487          372 :     n1.fraction += TALER_AMOUNT_FRAC_BASE;
     488          372 :     n1.value--;
     489              :   }
     490        17284 :   if (n1.value < n2.value)
     491              :   {
     492            1 :     invalidate (diff);
     493            1 :     return TALER_AAR_INVALID_NEGATIVE_RESULT;
     494              :   }
     495        17283 :   GNUNET_assert (GNUNET_OK ==
     496              :                  TALER_amount_set_zero (n1.currency,
     497              :                                         diff));
     498        17283 :   GNUNET_assert (n1.fraction >= n2.fraction);
     499        17283 :   diff->fraction = n1.fraction - n2.fraction;
     500        17283 :   GNUNET_assert (n1.value >= n2.value);
     501        17283 :   diff->value = n1.value - n2.value;
     502        17283 :   if ( (0 == diff->fraction) &&
     503          109 :        (0 == diff->value) )
     504           26 :     return TALER_AAR_RESULT_ZERO;
     505        17257 :   return TALER_AAR_RESULT_POSITIVE;
     506              : }
     507              : 
     508              : 
     509              : enum TALER_AmountArithmeticResult
     510         1866 : 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         1866 :   if (GNUNET_YES !=
     519         1866 :       TALER_amount_cmp_currency (a1,
     520              :                                  a2))
     521              :   {
     522            0 :     invalidate (sum);
     523            0 :     return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
     524              :   }
     525              :   /* make local copies to avoid aliasing problems between
     526              :      diff and a1/a2 */
     527         1866 :   n1 = *a1;
     528         1866 :   n2 = *a2;
     529         1866 :   if ( (GNUNET_SYSERR ==
     530         3732 :         TALER_amount_normalize (&n1)) ||
     531              :        (GNUNET_SYSERR ==
     532         1866 :         TALER_amount_normalize (&n2)) )
     533              :   {
     534            0 :     invalidate (sum);
     535            0 :     return TALER_AAR_INVALID_NORMALIZATION_FAILED;
     536              :   }
     537              : 
     538         1866 :   GNUNET_assert (GNUNET_OK ==
     539              :                  TALER_amount_set_zero (a1->currency,
     540              :                                         &res));
     541         1866 :   res.value = n1.value + n2.value;
     542         1866 :   if (res.value < n1.value)
     543              :   {
     544              :     /* integer overflow */
     545            0 :     invalidate (sum);
     546            0 :     return TALER_AAR_INVALID_RESULT_OVERFLOW;
     547              :   }
     548         1866 :   if (res.value > TALER_AMOUNT_MAX_VALUE)
     549              :   {
     550              :     /* too large to be legal */
     551            0 :     invalidate (sum);
     552            0 :     return TALER_AAR_INVALID_RESULT_OVERFLOW;
     553              :   }
     554         1866 :   res.fraction = n1.fraction + n2.fraction;
     555         1866 :   if (GNUNET_SYSERR ==
     556         1866 :       TALER_amount_normalize (&res))
     557              :   {
     558              :     /* integer overflow via carry from fraction */
     559            1 :     invalidate (sum);
     560            1 :     return TALER_AAR_INVALID_RESULT_OVERFLOW;
     561              :   }
     562         1865 :   *sum = res;
     563         1865 :   if ( (0 == sum->fraction) &&
     564          297 :        (0 == sum->value) )
     565            0 :     return TALER_AAR_RESULT_ZERO;
     566         1865 :   return TALER_AAR_RESULT_POSITIVE;
     567              : }
     568              : 
     569              : 
     570              : enum GNUNET_GenericReturnValue
     571       158711 : TALER_amount_normalize (struct TALER_Amount *amount)
     572              : {
     573              :   uint32_t overflow;
     574              : 
     575       158711 :   if (GNUNET_YES != TALER_amount_is_valid (amount))
     576            3 :     return GNUNET_SYSERR;
     577       158708 :   if (amount->fraction < TALER_AMOUNT_FRAC_BASE)
     578       158645 :     return GNUNET_NO;
     579           63 :   overflow = amount->fraction / TALER_AMOUNT_FRAC_BASE;
     580           63 :   amount->fraction %= TALER_AMOUNT_FRAC_BASE;
     581           63 :   amount->value += overflow;
     582           63 :   if ( (amount->value < overflow) ||
     583           63 :        (amount->value > TALER_AMOUNT_MAX_VALUE) )
     584              :   {
     585            1 :     invalidate (amount);
     586            1 :     return GNUNET_SYSERR;
     587              :   }
     588           62 :   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        20906 : amount_to_tail (const struct TALER_Amount *amount,
     600              :                 char tail[TALER_AMOUNT_FRAC_LEN + 1])
     601              : {
     602        20906 :   uint32_t n = amount->fraction;
     603              :   unsigned int i;
     604              : 
     605       161834 :   for (i = 0; (i < TALER_AMOUNT_FRAC_LEN) && (0 != n); i++)
     606              :   {
     607       140928 :     tail[i] = '0' + (n / (TALER_AMOUNT_FRAC_BASE / 10));
     608       140928 :     n = (n * 10) % (TALER_AMOUNT_FRAC_BASE);
     609              :   }
     610        20906 :   tail[i] = '\0';
     611        20906 : }
     612              : 
     613              : 
     614              : char *
     615         5535 : TALER_amount_to_string (const struct TALER_Amount *amount)
     616              : {
     617              :   char *result;
     618              :   struct TALER_Amount norm;
     619              : 
     620         5535 :   if (GNUNET_YES !=
     621         5535 :       TALER_amount_is_valid (amount))
     622            1 :     return NULL;
     623         5534 :   norm = *amount;
     624         5534 :   if (GNUNET_SYSERR ==
     625         5534 :       TALER_amount_normalize (&norm))
     626              :   {
     627            0 :     GNUNET_break (0);
     628            0 :     return NULL;
     629              :   }
     630         5534 :   if (0 != norm.fraction)
     631              :   {
     632              :     char tail[TALER_AMOUNT_FRAC_LEN + 1];
     633              : 
     634         3796 :     amount_to_tail (&norm,
     635              :                     tail);
     636         3796 :     GNUNET_asprintf (&result,
     637              :                      "%s:%llu.%s",
     638              :                      norm.currency,
     639         3796 :                      (unsigned long long) norm.value,
     640              :                      tail);
     641              :   }
     642              :   else
     643              :   {
     644         1738 :     GNUNET_asprintf (&result,
     645              :                      "%s:%llu",
     646              :                      norm.currency,
     647         1738 :                      (unsigned long long) norm.value);
     648              :   }
     649         5534 :   return result;
     650              : }
     651              : 
     652              : 
     653              : const char *
     654        17582 : 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        17582 :   if (GNUNET_YES !=
     662        17582 :       TALER_amount_is_valid (amount))
     663           12 :     return NULL;
     664        17570 :   norm = *amount;
     665        17570 :   if (GNUNET_SYSERR ==
     666        17570 :       TALER_amount_normalize (&norm))
     667              :   {
     668            0 :     GNUNET_break (0);
     669            0 :     return NULL;
     670              :   }
     671        17570 :   if (0 != norm.fraction)
     672              :   {
     673              :     char tail[TALER_AMOUNT_FRAC_LEN + 1];
     674              : 
     675        17110 :     amount_to_tail (&norm,
     676              :                     tail);
     677        17110 :     GNUNET_snprintf (result,
     678              :                      sizeof (result),
     679              :                      "%s:%llu.%s",
     680              :                      norm.currency,
     681        17110 :                      (unsigned long long) norm.value,
     682              :                      tail);
     683              :   }
     684              :   else
     685              :   {
     686          460 :     GNUNET_snprintf (result,
     687              :                      sizeof (result),
     688              :                      "%s:%llu",
     689              :                      norm.currency,
     690          460 :                      (unsigned long long) norm.value);
     691              :   }
     692        17570 :   return result;
     693              : }
     694              : 
     695              : 
     696              : void
     697            4 : TALER_amount_divide (struct TALER_Amount *result,
     698              :                      const struct TALER_Amount *dividend,
     699              :                      uint32_t divisor)
     700              : {
     701              :   uint64_t modr;
     702              : 
     703            4 :   GNUNET_assert (0 != divisor); /* division by zero is discouraged */
     704            4 :   *result = *dividend;
     705              :   /* in case @a dividend was not yet normalized */
     706            4 :   GNUNET_assert (GNUNET_SYSERR !=
     707              :                  TALER_amount_normalize (result));
     708            4 :   if (1 == divisor)
     709            1 :     return;
     710            3 :   modr = result->value % divisor;
     711            3 :   result->value /= divisor;
     712              :   /* modr fits into 32 bits, so we can safely multiply by (<32-bit) base and add fraction! */
     713            3 :   modr = (modr * TALER_AMOUNT_FRAC_BASE) + result->fraction;
     714            3 :   result->fraction = (uint32_t) (modr / divisor);
     715              :   /* 'fraction' could now be larger than #TALER_AMOUNT_FRAC_BASE, so we must normalize */
     716            3 :   GNUNET_assert (GNUNET_SYSERR !=
     717              :                  TALER_amount_normalize (result));
     718              : }
     719              : 
     720              : 
     721              : int
     722            5 : 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            5 :   if (GNUNET_YES !=
     733            5 :       TALER_amount_cmp_currency (dividend,
     734              :                                  divisor))
     735              :   {
     736            0 :     GNUNET_break (0);
     737            0 :     return -1;
     738              :   }
     739            5 :   if ( (0 == divisor->fraction) &&
     740            2 :        (0 == divisor->value) )
     741            1 :     return INT_MAX;
     742              :   /* first, get rounded approximation */
     743            4 :   d = ((double) dividend->value) * ((double) TALER_AMOUNT_FRAC_BASE)
     744            4 :       + ( (double) dividend->fraction);
     745            4 :   r = ((double) divisor->value) * ((double) TALER_AMOUNT_FRAC_BASE)
     746            4 :       + ( (double) divisor->fraction);
     747            4 :   approx = d / r;
     748            4 :   if (approx > ((double) INT_MAX))
     749            0 :     return INT_MAX; /* 'infinity' */
     750              :   /* round down */
     751            4 :   if (approx < 2)
     752            1 :     ret = 0;
     753              :   else
     754            3 :     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            4 :   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           10 :     GNUNET_assert (0 <=
     765              :                    TALER_amount_add (&nxt,
     766              :                                      &tmp,
     767              :                                      divisor));
     768           10 :     if (1 ==
     769           10 :         TALER_amount_cmp (&nxt,
     770              :                           dividend))
     771            4 :       break; /* nxt > dividend */
     772            6 :     ret++;
     773            6 :     tmp = nxt;
     774              :   }
     775            4 :   return ret;
     776              : }
     777              : 
     778              : 
     779              : enum TALER_AmountArithmeticResult
     780           12 : TALER_amount_multiply (struct TALER_Amount *result,
     781              :                        const struct TALER_Amount *amount,
     782              :                        uint32_t factor)
     783              : {
     784           12 :   struct TALER_Amount in = *amount;
     785              : 
     786           12 :   if (GNUNET_SYSERR ==
     787           12 :       TALER_amount_normalize (&in))
     788              :   {
     789            0 :     invalidate (result);
     790            0 :     return TALER_AAR_INVALID_NORMALIZATION_FAILED;
     791              :   }
     792           12 :   GNUNET_memcpy (result->currency,
     793              :                  amount->currency,
     794              :                  TALER_CURRENCY_LEN);
     795           12 :   if ( (0 == factor) ||
     796           11 :        ( (0 == in.value) &&
     797            1 :          (0 == in.fraction) ) )
     798              :   {
     799            2 :     result->value = 0;
     800            2 :     result->fraction = 0;
     801            2 :     return TALER_AAR_RESULT_ZERO;
     802              :   }
     803           10 :   result->value = in.value * ((uint64_t) factor);
     804           10 :   if (in.value != result->value / factor)
     805              :   {
     806            0 :     invalidate (result);
     807            0 :     return TALER_AAR_INVALID_RESULT_OVERFLOW;
     808              :   }
     809              :   {
     810              :     /* This multiplication cannot overflow since both inputs are 32-bit values */
     811           10 :     uint64_t tmp = ((uint64_t) factor) * ((uint64_t) in.fraction);
     812              :     uint64_t res;
     813              : 
     814           10 :     res = tmp / TALER_AMOUNT_FRAC_BASE;
     815              :     /* check for overflow */
     816           10 :     if (result->value + res < result->value)
     817              :     {
     818            0 :       invalidate (result);
     819            0 :       return TALER_AAR_INVALID_RESULT_OVERFLOW;
     820              :     }
     821           10 :     result->value += res;
     822           10 :     result->fraction = tmp % TALER_AMOUNT_FRAC_BASE;
     823              :   }
     824           10 :   if (result->value > TALER_AMOUNT_MAX_VALUE)
     825              :   {
     826            1 :     invalidate (result);
     827            1 :     return TALER_AAR_INVALID_RESULT_OVERFLOW;
     828              :   }
     829              :   /* This check should be redundant... */
     830            9 :   GNUNET_assert (GNUNET_SYSERR !=
     831              :                  TALER_amount_normalize (result));
     832            9 :   return TALER_AAR_RESULT_POSITIVE;
     833              : }
     834              : 
     835              : 
     836              : enum GNUNET_GenericReturnValue
     837           63 : TALER_amount_round_down (struct TALER_Amount *amount,
     838              :                          const struct TALER_Amount *round_unit)
     839              : {
     840           63 :   if (GNUNET_OK !=
     841           63 :       TALER_amount_cmp_currency (amount,
     842              :                                  round_unit))
     843              :   {
     844            0 :     GNUNET_break (0);
     845            0 :     return GNUNET_SYSERR;
     846              :   }
     847           63 :   if ( (0 != round_unit->fraction) &&
     848           62 :        (0 != round_unit->value) )
     849              :   {
     850            0 :     GNUNET_break (0);
     851            0 :     return GNUNET_SYSERR;
     852              :   }
     853           63 :   if ( (0 == round_unit->fraction) &&
     854            1 :        (0 == round_unit->value) )
     855            0 :     return GNUNET_NO; /* no rounding requested */
     856           63 :   if (0 != round_unit->fraction)
     857              :   {
     858              :     uint32_t delta;
     859              : 
     860           62 :     delta = amount->fraction % round_unit->fraction;
     861           62 :     if (0 == delta)
     862           58 :       return GNUNET_NO;
     863            4 :     amount->fraction -= delta;
     864              :   }
     865            5 :   if (0 != round_unit->value)
     866              :   {
     867              :     uint64_t delta;
     868              : 
     869            1 :     delta = amount->value % round_unit->value;
     870            1 :     if ( (0 == delta) &&
     871            0 :          (0 == amount->fraction) )
     872            0 :       return GNUNET_NO;
     873            1 :     amount->value -= delta;
     874            1 :     amount->fraction = 0;
     875              :   }
     876            5 :   return GNUNET_OK;
     877              : }
     878              : 
     879              : 
     880              : void
     881            0 : TALER_amount_set_free (struct TALER_AmountSet *as)
     882              : {
     883            0 :   GNUNET_array_grow (as->taa,
     884              :                      as->taa_size,
     885              :                      0);
     886            0 : }
     887              : 
     888              : 
     889              : enum TALER_AmountArithmeticResult
     890            0 : TALER_amount_set_add (struct TALER_AmountSet *as,
     891              :                       const struct TALER_Amount *val,
     892              :                       const struct TALER_Amount *cap)
     893              : {
     894            0 :   for (unsigned int i = 0; i<as->taa_size; i++)
     895              :   {
     896            0 :     struct TALER_Amount *ai = &as->taa[i];
     897              :     enum TALER_AmountArithmeticResult aar;
     898              : 
     899            0 :     if (GNUNET_OK !=
     900            0 :         TALER_amount_cmp_currency (ai,
     901              :                                    val))
     902            0 :       continue;
     903            0 :     aar = TALER_amount_add (ai,
     904              :                             ai,
     905              :                             val);
     906              :     /* If we have a cap, we tolerate the overflow */
     907            0 :     if ( (aar < 0) &&
     908            0 :          ( (NULL == cap) ||
     909              :            (TALER_AAR_INVALID_RESULT_OVERFLOW != aar) ) )
     910            0 :       return aar; /* hard error */
     911            0 :     if (TALER_AAR_INVALID_RESULT_OVERFLOW == aar)
     912              :     {
     913            0 :       if (GNUNET_OK !=
     914            0 :           TALER_amount_cmp_currency (val,
     915              :                                      cap))
     916            0 :         return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
     917            0 :       *ai = *cap;
     918            0 :       return (TALER_amount_is_zero (cap))
     919              :         ? TALER_AAR_RESULT_ZERO
     920            0 :         : TALER_AAR_RESULT_POSITIVE;
     921              :     }
     922            0 :     GNUNET_assert (aar >= 0);
     923            0 :     if (NULL != cap)
     924            0 :       GNUNET_assert (GNUNET_OK ==
     925              :                      TALER_amount_min (ai,
     926              :                                        ai,
     927              :                                        cap));
     928            0 :     return (TALER_amount_is_zero (ai))
     929              :       ? TALER_AAR_RESULT_ZERO
     930            0 :       : TALER_AAR_RESULT_POSITIVE;
     931              :   }
     932            0 :   GNUNET_array_append (as->taa,
     933              :                        as->taa_size,
     934              :                        *val);
     935              :   {
     936            0 :     struct TALER_Amount *ai = &as->taa[as->taa_size - 1];
     937              : 
     938            0 :     if (NULL != cap)
     939              :     {
     940            0 :       if (GNUNET_OK !=
     941            0 :           TALER_amount_cmp_currency (val,
     942              :                                      cap))
     943            0 :         return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
     944            0 :       GNUNET_assert (GNUNET_OK ==
     945              :                      TALER_amount_min (ai,
     946              :                                        ai,
     947              :                                        cap));
     948              :     }
     949            0 :     return (TALER_amount_is_zero (ai))
     950              :       ? TALER_AAR_RESULT_ZERO
     951            0 :       : TALER_AAR_RESULT_POSITIVE;
     952              :   }
     953              : }
     954              : 
     955              : 
     956              : bool
     957            0 : TALER_amount_set_test_above (const struct TALER_AmountSet *as,
     958              :                              const struct TALER_Amount *b)
     959              : {
     960            0 :   for (unsigned int i = 0; i<as->taa_size; i++)
     961              :   {
     962            0 :     const struct TALER_Amount *asi = &as->taa[i];
     963              : 
     964            0 :     if (GNUNET_OK !=
     965            0 :         TALER_amount_cmp_currency (b,
     966              :                                    asi))
     967            0 :       continue;
     968            0 :     if (1 !=
     969            0 :         TALER_amount_cmp (b,
     970              :                           asi))
     971            0 :       return true;
     972              :   }
     973            0 :   return false;
     974              : }
     975              : 
     976              : 
     977              : const struct TALER_Amount *
     978            1 : 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            5 :   for (unsigned int i = 0; i<as->taa_size; i++)
     984              :   {
     985            4 :     const struct TALER_Amount *asi = &as->taa[i];
     986              : 
     987            4 :     if (0 == strcasecmp (currency,
     988            4 :                          asi->currency))
     989            0 :       return asi;
     990              :   }
     991            1 :   if (GNUNET_OK !=
     992            1 :       TALER_amount_set_zero (currency,
     993              :                              &z))
     994              :   {
     995            0 :     GNUNET_break (0);
     996            0 :     return NULL;
     997              :   }
     998            1 :   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           20 : TALER_amount_list_free (struct TALER_AmountList *al)
    1014              : {
    1015           20 :   GNUNET_array_grow (al->tal,
    1016              :                      al->tal_len,
    1017              :                      0);
    1018           20 : }
    1019              : 
    1020              : 
    1021              : enum GNUNET_GenericReturnValue
    1022           13 : TALER_string_to_amount_list (const char *str,
    1023              :                              struct TALER_AmountList *al)
    1024              : {
    1025           13 :   struct TALER_AmountList tmp = {
    1026              :     .tal = NULL,
    1027              :     .tal_len = 0
    1028              :   };
    1029           13 :   const char *pos = str;
    1030              : 
    1031              :   /* skip leading whitespace, so that an all-whitespace option
    1032              :      value means "free" and not "malformed" */
    1033           13 :   while (isspace ( (unsigned char) pos[0]))
    1034            0 :     pos++;
    1035           13 :   if ('\0' == pos[0])
    1036              :   {
    1037            2 :     al->tal = NULL;
    1038            2 :     al->tal_len = 0;
    1039            2 :     return GNUNET_OK;
    1040              :   }
    1041              :   while (1)
    1042           13 :   {
    1043           24 :     const char *end = strchr (pos,
    1044              :                               (int) ';');
    1045           24 :     size_t len = (NULL == end)
    1046           10 :       ? strlen (pos)
    1047           24 :       : (size_t) (end - pos);
    1048              :     struct TALER_Amount a;
    1049              :     char *component;
    1050              : 
    1051           24 :     if (0 == len)
    1052              :     {
    1053            2 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1054              :                   "Empty component in amount list `%s'\n",
    1055              :                   str);
    1056            2 :       TALER_amount_list_free (&tmp);
    1057            5 :       return GNUNET_SYSERR;
    1058              :     }
    1059           22 :     component = GNUNET_strndup (pos,
    1060              :                                 len);
    1061           22 :     if (GNUNET_OK !=
    1062           22 :         TALER_string_to_amount (component,
    1063              :                                 &a))
    1064              :     {
    1065            2 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1066              :                   "Invalid amount `%s' in amount list `%s'\n",
    1067              :                   component,
    1068              :                   str);
    1069            2 :       GNUNET_free (component);
    1070            2 :       TALER_amount_list_free (&tmp);
    1071            2 :       return GNUNET_SYSERR;
    1072              :     }
    1073           20 :     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           20 :     if (NULL !=
    1077           20 :         TALER_amount_list_find (&tmp,
    1078              :                                 a.currency))
    1079              :     {
    1080            1 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1081              :                   "Currency `%s' given more than once in amount list `%s'\n",
    1082              :                   a.currency,
    1083              :                   str);
    1084            1 :       TALER_amount_list_free (&tmp);
    1085            1 :       return GNUNET_SYSERR;
    1086              :     }
    1087           19 :     GNUNET_array_append (tmp.tal,
    1088              :                          tmp.tal_len,
    1089              :                          a);
    1090           19 :     if (NULL == end)
    1091            6 :       break;
    1092           13 :     pos = end + 1;
    1093              :   }
    1094            6 :   *al = tmp;
    1095            6 :   return GNUNET_OK;
    1096              : }
    1097              : 
    1098              : 
    1099              : const char *
    1100            6 : 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            6 :   size_t off = 0;
    1106              : 
    1107              :   /* one separator per entry is one too many, which covers the '\0' */
    1108            6 :   need = (al->tal_len + 1) * (AMOUNT_STR_MAX + 1);
    1109            6 :   if (need > result_size)
    1110              :   {
    1111            1 :     GNUNET_free (result);
    1112            1 :     result = GNUNET_malloc (need);
    1113            1 :     result_size = need;
    1114              :   }
    1115            6 :   result[0] = '\0';
    1116           24 :   for (unsigned int i = 0; i<al->tal_len; i++)
    1117              :   {
    1118           18 :     const char *as = TALER_amount2s (&al->tal[i]);
    1119              : 
    1120           18 :     if (NULL == as)
    1121              :     {
    1122            0 :       GNUNET_break (0);
    1123            0 :       return NULL;
    1124              :     }
    1125           18 :     off += GNUNET_snprintf (&result[off],
    1126              :                             result_size - off,
    1127              :                             "%s%s",
    1128              :                             (0 == i) ? "" : ";",
    1129              :                             as);
    1130              :   }
    1131            6 :   return result;
    1132              : }
    1133              : 
    1134              : 
    1135              : const struct TALER_Amount *
    1136           37 : TALER_amount_list_find (const struct TALER_AmountList *al,
    1137              :                         const char *currency)
    1138              : {
    1139           68 :   for (unsigned int i = 0; i<al->tal_len; i++)
    1140              :   {
    1141           41 :     const struct TALER_Amount *ali = &al->tal[i];
    1142              : 
    1143           41 :     if (0 == strcasecmp (currency,
    1144           41 :                          ali->currency))
    1145           10 :       return ali;
    1146              :   }
    1147           27 :   return NULL;
    1148              : }
    1149              : 
    1150              : 
    1151              : enum GNUNET_GenericReturnValue
    1152            4 : TALER_amount_list_check_uniform (const struct TALER_AmountList *al)
    1153              : {
    1154            4 :   bool have_zero = false;
    1155            4 :   bool have_price = false;
    1156              : 
    1157           12 :   for (unsigned int i = 0; i<al->tal_len; i++)
    1158              :   {
    1159            8 :     if (TALER_amount_is_zero (&al->tal[i]))
    1160            3 :       have_zero = true;
    1161              :     else
    1162            5 :       have_price = true;
    1163              :   }
    1164            4 :   if (have_zero && have_price)
    1165            1 :     return GNUNET_SYSERR;
    1166            3 :   if (have_price)
    1167            1 :     return GNUNET_OK;
    1168            2 :   return GNUNET_NO; /* all zero, or empty */
    1169              : }
    1170              : 
    1171              : 
    1172              : bool
    1173            4 : 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            4 :   if (al->tal_len != currencies_len)
    1180            2 :     return false;
    1181            9 :   for (unsigned int i = 0; i<currencies_len; i++)
    1182            8 :     if (NULL ==
    1183            8 :         TALER_amount_list_find (al,
    1184            8 :                                 currencies[i]))
    1185            1 :       return false;
    1186            1 :   return true;
    1187              : }
    1188              : 
    1189              : 
    1190              : enum GNUNET_GenericReturnValue
    1191            5 : TALER_amount_list_multiply (struct TALER_AmountList *al,
    1192              :                             uint32_t n)
    1193              : {
    1194              :   struct TALER_Amount *tmp;
    1195              : 
    1196            5 :   if (0 == n)
    1197              :   {
    1198            1 :     GNUNET_break (0);
    1199            1 :     return GNUNET_SYSERR;
    1200              :   }
    1201            4 :   if ( (1 == n) ||
    1202            3 :        (0 == al->tal_len) )
    1203            2 :     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            2 :   tmp = GNUNET_new_array (al->tal_len,
    1207              :                           struct TALER_Amount);
    1208            7 :   for (unsigned int i = 0; i<al->tal_len; i++)
    1209              :   {
    1210            6 :     if (0 >
    1211            6 :         TALER_amount_multiply (&tmp[i],
    1212            6 :                                &al->tal[i],
    1213              :                                n))
    1214              :     {
    1215            1 :       GNUNET_free (tmp);
    1216            1 :       return GNUNET_SYSERR;
    1217              :     }
    1218              :   }
    1219            1 :   GNUNET_memcpy (al->tal,
    1220              :                  tmp,
    1221              :                  al->tal_len * sizeof (struct TALER_Amount));
    1222            1 :   GNUNET_free (tmp);
    1223            1 :   return GNUNET_OK;
    1224              : }
    1225              : 
    1226              : 
    1227              : void
    1228            1 : TALER_amount_list_copy (struct TALER_AmountList *dst,
    1229              :                         const struct TALER_AmountList *src)
    1230              : {
    1231            1 :   dst->tal_len = src->tal_len;
    1232            1 :   if (0 == src->tal_len)
    1233              :   {
    1234            0 :     dst->tal = NULL;
    1235            0 :     return;
    1236              :   }
    1237            1 :   dst->tal = GNUNET_new_array (src->tal_len,
    1238              :                                struct TALER_Amount);
    1239            1 :   GNUNET_memcpy (dst->tal,
    1240              :                  src->tal,
    1241              :                  src->tal_len * sizeof (struct TALER_Amount));
    1242              : }
    1243              : 
    1244              : 
    1245              : /* end of amount.c */
        

Generated by: LCOV version 2.0-1