LCOV - code coverage report
Current view: top level - util - amount.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 75.0 % 555 416
Test Date: 2026-10-29 19:05:17 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           21 : invalidate (struct TALER_Amount *a)
      35              : {
      36           21 :   memset (a,
      37              :           0,
      38              :           sizeof (struct TALER_Amount));
      39           21 : }
      40              : 
      41              : 
      42              : enum GNUNET_GenericReturnValue
      43        86173 : TALER_check_currency (const char *str)
      44              : {
      45        86173 :   size_t len = strlen (str);
      46              : 
      47        86173 :   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        86173 :   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       454934 :   for (unsigned int i = 0; '\0' != str[i]; i++)
      62              :   {
      63       368761 :     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        86173 :   return GNUNET_OK;
      72              : }
      73              : 
      74              : 
      75              : enum GNUNET_GenericReturnValue
      76        15126 : 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        15128 :   while (isspace ( (unsigned char) str[0]))
      85            2 :     str++;
      86        15126 :   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        15126 :   colon = strchr (str, (int) ':');
      96        15126 :   if ( (NULL == colon) ||
      97        15123 :        (colon == str) ||
      98        15123 :        ((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        15123 :   GNUNET_assert (TALER_CURRENCY_LEN > (colon - str));
     108        15123 :   memcpy (&amount->currency[0],
     109              :           str,
     110        15123 :           colon - str);
     111              :   /* 0-terminate *and* normalize buffer by setting everything to '\0' */
     112        15123 :   memset (&amount->currency [colon - str],
     113              :           0,
     114        15123 :           TALER_CURRENCY_LEN - (colon - str));
     115        15123 :   if (GNUNET_OK !=
     116        15123 :       TALER_check_currency (amount->currency))
     117              :   {
     118            0 :     invalidate (amount);
     119            0 :     return GNUNET_SYSERR;
     120              :   }
     121              :   /* skip colon */
     122        15123 :   value = colon + 1;
     123        15123 :   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        15123 :   amount->value = 0;
     133        15123 :   amount->fraction = 0;
     134              : 
     135              :   /* parse value */
     136        32246 :   while ('.' != *value)
     137              :   {
     138              :     int n;
     139              : 
     140        21271 :     if ('\0' == *value)
     141              :     {
     142              :       /* we are done */
     143         4145 :       return GNUNET_OK;
     144              :     }
     145        17126 :     if ( (*value < '0') ||
     146        17126 :          (*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        17124 :     n = *value - '0';
     156        17124 :     if ( (amount->value * 10 < amount->value) ||
     157        17124 :          (amount->value * 10 + n < amount->value) ||
     158        17124 :          (amount->value > TALER_AMOUNT_MAX_VALUE) ||
     159        17124 :          (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        17123 :     amount->value = (amount->value * 10) + n;
     168        17123 :     value++;
     169              :   }
     170              : 
     171              :   /* skip the dot */
     172        10975 :   value++;
     173              : 
     174              :   /* parse fraction */
     175        10975 :   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        10975 :   b = TALER_AMOUNT_FRAC_BASE / 10;
     184        32529 :   while ('\0' != *value)
     185              :   {
     186              :     int n;
     187              : 
     188        21557 :     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        21556 :     if ( (*value < '0') ||
     198        21556 :          (*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        21554 :     n = *value - '0';
     206        21554 :     amount->fraction += n * b;
     207        21554 :     b /= 10;
     208        21554 :     value++;
     209              :   }
     210        10972 :   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        46037 : TALER_amount_hton (struct TALER_AmountNBO *res,
     232              :                    const struct TALER_Amount *d)
     233              : {
     234        46037 :   GNUNET_assert (GNUNET_YES ==
     235              :                  TALER_amount_is_valid (d));
     236        46037 :   res->value = GNUNET_htonll (d->value);
     237        46037 :   res->fraction = htonl (d->fraction);
     238       598481 :   for (unsigned int i = 0; i<TALER_CURRENCY_LEN; i++)
     239       552444 :     res->currency[i] = d->currency[i];
     240        46037 : }
     241              : 
     242              : 
     243              : void
     244           59 : TALER_amount_ntoh (struct TALER_Amount *res,
     245              :                    const struct TALER_AmountNBO *dn)
     246              : {
     247           59 :   res->value = GNUNET_ntohll (dn->value);
     248           59 :   res->fraction = ntohl (dn->fraction);
     249           59 :   GNUNET_memcpy (res->currency,
     250              :                  dn->currency,
     251              :                  TALER_CURRENCY_LEN);
     252           59 :   GNUNET_assert (GNUNET_YES ==
     253              :                  TALER_amount_is_valid (res));
     254           59 : }
     255              : 
     256              : 
     257              : enum GNUNET_GenericReturnValue
     258        70187 : 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        70187 :   if (GNUNET_OK !=
     265        70187 :       TALER_check_currency (cur))
     266            0 :     return GNUNET_SYSERR;
     267        70187 :   slen = strlen (cur);
     268              :   /* make a copy of 'cur' to 'tmp' as the memset may clobber cur
     269              :      if cur aliases &amount->currency! */
     270        70187 :   memcpy (tmp,
     271              :           cur,
     272              :           slen);
     273        70187 :   memset (amount,
     274              :           0,
     275              :           sizeof (struct TALER_Amount));
     276       389724 :   for (unsigned int i = 0; i<slen; i++)
     277       319537 :     amount->currency[i] = tmp[i];
     278        70187 :   return GNUNET_OK;
     279              : }
     280              : 
     281              : 
     282              : enum GNUNET_GenericReturnValue
     283       448217 : TALER_amount_is_valid (const struct TALER_Amount *amount)
     284              : {
     285       448217 :   if (amount->value > TALER_AMOUNT_MAX_VALUE)
     286              :   {
     287            2 :     GNUNET_break (0);
     288            2 :     return GNUNET_SYSERR;
     289              :   }
     290       448215 :   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        65632 : TALER_amount_is_zero (const struct TALER_Amount *amount)
     342              : {
     343        65632 :   if (GNUNET_OK !=
     344        65632 :       TALER_amount_is_valid (amount))
     345            0 :     return false;
     346              :   return
     347        89815 :     (0 == amount->value) &&
     348        24183 :     (0 == amount->fraction);
     349              : }
     350              : 
     351              : 
     352              : enum GNUNET_GenericReturnValue
     353         5308 : TALER_amount_is_currency (const struct TALER_Amount *amount,
     354              :                           const char *currency)
     355              : {
     356         5308 :   if (GNUNET_OK !=
     357         5308 :       TALER_amount_is_valid (amount))
     358            0 :     return GNUNET_SYSERR;
     359         5308 :   return (0 == strcasecmp (currency,
     360         5308 :                            amount->currency))
     361              :          ? GNUNET_OK
     362         5308 :          : 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        63408 : TALER_amount_cmp_currency (const struct TALER_Amount *a1,
     382              :                            const struct TALER_Amount *a2)
     383              : {
     384       126816 :   if ( (GNUNET_NO == TALER_amount_is_valid (a1)) ||
     385        63408 :        (GNUNET_NO == TALER_amount_is_valid (a2)) )
     386            0 :     return GNUNET_SYSERR;
     387        63408 :   if (0 == strcasecmp (a1->currency,
     388        63408 :                        a2->currency))
     389        63406 :     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        41635 : 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        41635 :   GNUNET_assert (GNUNET_YES ==
     416              :                  TALER_amount_cmp_currency (a1,
     417              :                                             a2));
     418        41635 :   n1 = *a1;
     419        41635 :   n2 = *a2;
     420        41635 :   GNUNET_assert (GNUNET_SYSERR !=
     421              :                  TALER_amount_normalize (&n1));
     422        41635 :   GNUNET_assert (GNUNET_SYSERR !=
     423              :                  TALER_amount_normalize (&n2));
     424        41635 :   if (n1.value == n2.value)
     425              :   {
     426        38101 :     if (n1.fraction < n2.fraction)
     427          134 :       return -1;
     428        37967 :     if (n1.fraction > n2.fraction)
     429        16652 :       return 1;
     430        21315 :     return 0;
     431              :   }
     432         3534 :   if (n1.value < n2.value)
     433         1641 :     return -1;
     434         1893 :   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        17670 : 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        17670 :   if (GNUNET_YES !=
     463        17670 :       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        17669 :   n1 = *a1;
     472        17669 :   n2 = *a2;
     473        35338 :   if ( (GNUNET_SYSERR == TALER_amount_normalize (&n1)) ||
     474        17669 :        (GNUNET_SYSERR == TALER_amount_normalize (&n2)) )
     475              :   {
     476            0 :     invalidate (diff);
     477            0 :     return TALER_AAR_INVALID_NORMALIZATION_FAILED;
     478              :   }
     479              : 
     480        17669 :   if (n1.fraction < n2.fraction)
     481              :   {
     482          474 :     if (0 == n1.value)
     483              :     {
     484            6 :       invalidate (diff);
     485            6 :       return TALER_AAR_INVALID_NEGATIVE_RESULT;
     486              :     }
     487          468 :     n1.fraction += TALER_AMOUNT_FRAC_BASE;
     488          468 :     n1.value--;
     489              :   }
     490        17663 :   if (n1.value < n2.value)
     491              :   {
     492            1 :     invalidate (diff);
     493            1 :     return TALER_AAR_INVALID_NEGATIVE_RESULT;
     494              :   }
     495        17662 :   GNUNET_assert (GNUNET_OK ==
     496              :                  TALER_amount_set_zero (n1.currency,
     497              :                                         diff));
     498        17662 :   GNUNET_assert (n1.fraction >= n2.fraction);
     499        17662 :   diff->fraction = n1.fraction - n2.fraction;
     500        17662 :   GNUNET_assert (n1.value >= n2.value);
     501        17662 :   diff->value = n1.value - n2.value;
     502        17662 :   if ( (0 == diff->fraction) &&
     503          216 :        (0 == diff->value) )
     504           62 :     return TALER_AAR_RESULT_ZERO;
     505        17600 :   return TALER_AAR_RESULT_POSITIVE;
     506              : }
     507              : 
     508              : 
     509              : enum TALER_AmountArithmeticResult
     510         3508 : 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         3508 :   if (GNUNET_YES !=
     519         3508 :       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         3508 :   n1 = *a1;
     528         3508 :   n2 = *a2;
     529         3508 :   if ( (GNUNET_SYSERR ==
     530         7016 :         TALER_amount_normalize (&n1)) ||
     531              :        (GNUNET_SYSERR ==
     532         3508 :         TALER_amount_normalize (&n2)) )
     533              :   {
     534            0 :     invalidate (sum);
     535            0 :     return TALER_AAR_INVALID_NORMALIZATION_FAILED;
     536              :   }
     537              : 
     538         3508 :   GNUNET_assert (GNUNET_OK ==
     539              :                  TALER_amount_set_zero (a1->currency,
     540              :                                         &res));
     541         3508 :   res.value = n1.value + n2.value;
     542         3508 :   if (res.value < n1.value)
     543              :   {
     544              :     /* integer overflow */
     545            0 :     invalidate (sum);
     546            0 :     return TALER_AAR_INVALID_RESULT_OVERFLOW;
     547              :   }
     548         3508 :   if (res.value > TALER_AMOUNT_MAX_VALUE)
     549              :   {
     550              :     /* too large to be legal */
     551            1 :     invalidate (sum);
     552            1 :     return TALER_AAR_INVALID_RESULT_OVERFLOW;
     553              :   }
     554         3507 :   res.fraction = n1.fraction + n2.fraction;
     555         3507 :   if (GNUNET_SYSERR ==
     556         3507 :       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         3506 :   *sum = res;
     563         3506 :   if ( (0 == sum->fraction) &&
     564          940 :        (0 == sum->value) )
     565          126 :     return TALER_AAR_RESULT_ZERO;
     566         3380 :   return TALER_AAR_RESULT_POSITIVE;
     567              : }
     568              : 
     569              : 
     570              : enum GNUNET_GenericReturnValue
     571       174940 : TALER_amount_normalize (struct TALER_Amount *amount)
     572              : {
     573              :   uint32_t overflow;
     574              : 
     575       174940 :   if (GNUNET_YES != TALER_amount_is_valid (amount))
     576            3 :     return GNUNET_SYSERR;
     577       174937 :   if (amount->fraction < TALER_AMOUNT_FRAC_BASE)
     578       174831 :     return GNUNET_NO;
     579          106 :   overflow = amount->fraction / TALER_AMOUNT_FRAC_BASE;
     580          106 :   amount->fraction %= TALER_AMOUNT_FRAC_BASE;
     581          106 :   amount->value += overflow;
     582          106 :   if ( (amount->value < overflow) ||
     583          106 :        (amount->value > TALER_AMOUNT_MAX_VALUE) )
     584              :   {
     585            1 :     invalidate (amount);
     586            1 :     return GNUNET_SYSERR;
     587              :   }
     588          105 :   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        24985 : amount_to_tail (const struct TALER_Amount *amount,
     600              :                 char tail[TALER_AMOUNT_FRAC_LEN + 1])
     601              : {
     602        24985 :   uint32_t n = amount->fraction;
     603              :   unsigned int i;
     604              : 
     605       174001 :   for (i = 0; (i < TALER_AMOUNT_FRAC_LEN) && (0 != n); i++)
     606              :   {
     607       149016 :     tail[i] = '0' + (n / (TALER_AMOUNT_FRAC_BASE / 10));
     608       149016 :     n = (n * 10) % (TALER_AMOUNT_FRAC_BASE);
     609              :   }
     610        24985 :   tail[i] = '\0';
     611        24985 : }
     612              : 
     613              : 
     614              : char *
     615        10990 : TALER_amount_to_string (const struct TALER_Amount *amount)
     616              : {
     617              :   char *result;
     618              :   struct TALER_Amount norm;
     619              : 
     620        10990 :   if (GNUNET_YES !=
     621        10990 :       TALER_amount_is_valid (amount))
     622            1 :     return NULL;
     623        10989 :   norm = *amount;
     624        10989 :   if (GNUNET_SYSERR ==
     625        10989 :       TALER_amount_normalize (&norm))
     626              :   {
     627            0 :     GNUNET_break (0);
     628            0 :     return NULL;
     629              :   }
     630        10989 :   if (0 != norm.fraction)
     631              :   {
     632              :     char tail[TALER_AMOUNT_FRAC_LEN + 1];
     633              : 
     634         7501 :     amount_to_tail (&norm,
     635              :                     tail);
     636         7501 :     GNUNET_asprintf (&result,
     637              :                      "%s:%llu.%s",
     638              :                      norm.currency,
     639         7501 :                      (unsigned long long) norm.value,
     640              :                      tail);
     641              :   }
     642              :   else
     643              :   {
     644         3488 :     GNUNET_asprintf (&result,
     645              :                      "%s:%llu",
     646              :                      norm.currency,
     647         3488 :                      (unsigned long long) norm.value);
     648              :   }
     649        10989 :   return result;
     650              : }
     651              : 
     652              : 
     653              : const char *
     654        18260 : 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        18260 :   if (GNUNET_YES !=
     662        18260 :       TALER_amount_is_valid (amount))
     663           12 :     return NULL;
     664        18248 :   norm = *amount;
     665        18248 :   if (GNUNET_SYSERR ==
     666        18248 :       TALER_amount_normalize (&norm))
     667              :   {
     668            0 :     GNUNET_break (0);
     669            0 :     return NULL;
     670              :   }
     671        18248 :   if (0 != norm.fraction)
     672              :   {
     673              :     char tail[TALER_AMOUNT_FRAC_LEN + 1];
     674              : 
     675        17484 :     amount_to_tail (&norm,
     676              :                     tail);
     677        17484 :     GNUNET_snprintf (result,
     678              :                      sizeof (result),
     679              :                      "%s:%llu.%s",
     680              :                      norm.currency,
     681        17484 :                      (unsigned long long) norm.value,
     682              :                      tail);
     683              :   }
     684              :   else
     685              :   {
     686          764 :     GNUNET_snprintf (result,
     687              :                      sizeof (result),
     688              :                      "%s:%llu",
     689              :                      norm.currency,
     690          764 :                      (unsigned long long) norm.value);
     691              :   }
     692        18248 :   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            6 : 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            6 :   if (GNUNET_YES !=
     733            6 :       TALER_amount_cmp_currency (dividend,
     734              :                                  divisor))
     735              :   {
     736            0 :     GNUNET_break (0);
     737            0 :     return -1;
     738              :   }
     739            6 :   if ( (0 == divisor->fraction) &&
     740            3 :        (0 == divisor->value) )
     741            1 :     return INT_MAX;
     742              :   /* first, get rounded approximation */
     743            5 :   d = ((double) dividend->value) * ((double) TALER_AMOUNT_FRAC_BASE)
     744            5 :       + ( (double) dividend->fraction);
     745            5 :   r = ((double) divisor->value) * ((double) TALER_AMOUNT_FRAC_BASE)
     746            5 :       + ( (double) divisor->fraction);
     747            5 :   approx = d / r;
     748            5 :   if (approx > ((double) INT_MAX))
     749            0 :     return INT_MAX; /* 'infinity' */
     750              :   /* round down */
     751            5 :   if (approx < 2)
     752            1 :     ret = 0;
     753              :   else
     754            4 :     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            5 :   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            8 :   {
     764              :     enum TALER_AmountArithmeticResult aar;
     765              : 
     766           13 :     aar = TALER_amount_add (&nxt,
     767              :                             &tmp,
     768              :                             divisor);
     769           13 :     if (TALER_AAR_INVALID_RESULT_OVERFLOW == aar)
     770            1 :       break; /* nxt would exceed TALER_AMOUNT_MAX_VALUE, and thus
     771              :                 certainly the (presumed valid) dividend */
     772           12 :     GNUNET_assert (0 <= aar);
     773           12 :     if (1 ==
     774           12 :         TALER_amount_cmp (&nxt,
     775              :                           dividend))
     776            4 :       break; /* nxt > dividend */
     777            8 :     ret++;
     778            8 :     tmp = nxt;
     779              :   }
     780            5 :   return ret;
     781              : }
     782              : 
     783              : 
     784              : enum TALER_AmountArithmeticResult
     785           13 : TALER_amount_multiply (struct TALER_Amount *result,
     786              :                        const struct TALER_Amount *amount,
     787              :                        uint32_t factor)
     788              : {
     789           13 :   struct TALER_Amount in = *amount;
     790              : 
     791           13 :   if (GNUNET_SYSERR ==
     792           13 :       TALER_amount_normalize (&in))
     793              :   {
     794            0 :     invalidate (result);
     795            0 :     return TALER_AAR_INVALID_NORMALIZATION_FAILED;
     796              :   }
     797           13 :   GNUNET_memcpy (result->currency,
     798              :                  amount->currency,
     799              :                  TALER_CURRENCY_LEN);
     800           13 :   if ( (0 == factor) ||
     801           11 :        ( (0 == in.value) &&
     802            1 :          (0 == in.fraction) ) )
     803              :   {
     804            3 :     result->value = 0;
     805            3 :     result->fraction = 0;
     806            3 :     return TALER_AAR_RESULT_ZERO;
     807              :   }
     808           10 :   result->value = in.value * ((uint64_t) factor);
     809           10 :   if (in.value != result->value / factor)
     810              :   {
     811            0 :     invalidate (result);
     812            0 :     return TALER_AAR_INVALID_RESULT_OVERFLOW;
     813              :   }
     814              :   {
     815              :     /* This multiplication cannot overflow since both inputs are 32-bit values */
     816           10 :     uint64_t tmp = ((uint64_t) factor) * ((uint64_t) in.fraction);
     817              :     uint64_t res;
     818              : 
     819           10 :     res = tmp / TALER_AMOUNT_FRAC_BASE;
     820              :     /* check for overflow */
     821           10 :     if (result->value + res < result->value)
     822              :     {
     823            0 :       invalidate (result);
     824            0 :       return TALER_AAR_INVALID_RESULT_OVERFLOW;
     825              :     }
     826           10 :     result->value += res;
     827           10 :     result->fraction = tmp % TALER_AMOUNT_FRAC_BASE;
     828              :   }
     829           10 :   if (result->value > TALER_AMOUNT_MAX_VALUE)
     830              :   {
     831            1 :     invalidate (result);
     832            1 :     return TALER_AAR_INVALID_RESULT_OVERFLOW;
     833              :   }
     834              :   /* This check should be redundant... */
     835            9 :   GNUNET_assert (GNUNET_SYSERR !=
     836              :                  TALER_amount_normalize (result));
     837            9 :   return TALER_AAR_RESULT_POSITIVE;
     838              : }
     839              : 
     840              : 
     841              : enum GNUNET_GenericReturnValue
     842           95 : TALER_amount_round_down (struct TALER_Amount *amount,
     843              :                          const struct TALER_Amount *round_unit)
     844              : {
     845           95 :   if (GNUNET_OK !=
     846           95 :       TALER_amount_cmp_currency (amount,
     847              :                                  round_unit))
     848              :   {
     849            0 :     GNUNET_break (0);
     850            0 :     return GNUNET_SYSERR;
     851              :   }
     852           95 :   if ( (0 != round_unit->fraction) &&
     853           94 :        (0 != round_unit->value) )
     854              :   {
     855            0 :     GNUNET_break (0);
     856            0 :     return GNUNET_SYSERR;
     857              :   }
     858           95 :   if ( (0 == round_unit->fraction) &&
     859            1 :        (0 == round_unit->value) )
     860            0 :     return GNUNET_NO; /* no rounding requested */
     861           95 :   if (0 != round_unit->fraction)
     862              :   {
     863              :     uint32_t delta;
     864              : 
     865           94 :     delta = amount->fraction % round_unit->fraction;
     866           94 :     if (0 == delta)
     867           90 :       return GNUNET_NO;
     868            4 :     amount->fraction -= delta;
     869              :   }
     870            5 :   if (0 != round_unit->value)
     871              :   {
     872              :     uint64_t delta;
     873              : 
     874            1 :     delta = amount->value % round_unit->value;
     875            1 :     if ( (0 == delta) &&
     876            0 :          (0 == amount->fraction) )
     877            0 :       return GNUNET_NO;
     878            1 :     amount->value -= delta;
     879            1 :     amount->fraction = 0;
     880              :   }
     881            5 :   return GNUNET_OK;
     882              : }
     883              : 
     884              : 
     885              : void
     886            0 : TALER_amount_set_free (struct TALER_AmountSet *as)
     887              : {
     888            0 :   GNUNET_array_grow (as->taa,
     889              :                      as->taa_size,
     890              :                      0);
     891            0 : }
     892              : 
     893              : 
     894              : enum TALER_AmountArithmeticResult
     895            0 : TALER_amount_set_add (struct TALER_AmountSet *as,
     896              :                       const struct TALER_Amount *val,
     897              :                       const struct TALER_Amount *cap)
     898              : {
     899            0 :   for (unsigned int i = 0; i<as->taa_size; i++)
     900              :   {
     901            0 :     struct TALER_Amount *ai = &as->taa[i];
     902              :     enum TALER_AmountArithmeticResult aar;
     903              : 
     904            0 :     if (GNUNET_OK !=
     905            0 :         TALER_amount_cmp_currency (ai,
     906              :                                    val))
     907            0 :       continue;
     908            0 :     aar = TALER_amount_add (ai,
     909              :                             ai,
     910              :                             val);
     911              :     /* If we have a cap, we tolerate the overflow */
     912            0 :     if ( (aar < 0) &&
     913            0 :          ( (NULL == cap) ||
     914              :            (TALER_AAR_INVALID_RESULT_OVERFLOW != aar) ) )
     915            0 :       return aar; /* hard error */
     916            0 :     if (TALER_AAR_INVALID_RESULT_OVERFLOW == aar)
     917              :     {
     918            0 :       if (GNUNET_OK !=
     919            0 :           TALER_amount_cmp_currency (val,
     920              :                                      cap))
     921            0 :         return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
     922            0 :       *ai = *cap;
     923            0 :       return (TALER_amount_is_zero (cap))
     924              :         ? TALER_AAR_RESULT_ZERO
     925            0 :         : TALER_AAR_RESULT_POSITIVE;
     926              :     }
     927            0 :     GNUNET_assert (aar >= 0);
     928            0 :     if (NULL != cap)
     929            0 :       GNUNET_assert (GNUNET_OK ==
     930              :                      TALER_amount_min (ai,
     931              :                                        ai,
     932              :                                        cap));
     933            0 :     return (TALER_amount_is_zero (ai))
     934              :       ? TALER_AAR_RESULT_ZERO
     935            0 :       : TALER_AAR_RESULT_POSITIVE;
     936              :   }
     937            0 :   GNUNET_array_append (as->taa,
     938              :                        as->taa_size,
     939              :                        *val);
     940              :   {
     941            0 :     struct TALER_Amount *ai = &as->taa[as->taa_size - 1];
     942              : 
     943            0 :     if (NULL != cap)
     944              :     {
     945            0 :       if (GNUNET_OK !=
     946            0 :           TALER_amount_cmp_currency (val,
     947              :                                      cap))
     948            0 :         return TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE;
     949            0 :       GNUNET_assert (GNUNET_OK ==
     950              :                      TALER_amount_min (ai,
     951              :                                        ai,
     952              :                                        cap));
     953              :     }
     954            0 :     return (TALER_amount_is_zero (ai))
     955              :       ? TALER_AAR_RESULT_ZERO
     956            0 :       : TALER_AAR_RESULT_POSITIVE;
     957              :   }
     958              : }
     959              : 
     960              : 
     961              : bool
     962            0 : TALER_amount_set_test_above (const struct TALER_AmountSet *as,
     963              :                              const struct TALER_Amount *b)
     964              : {
     965            0 :   for (unsigned int i = 0; i<as->taa_size; i++)
     966              :   {
     967            0 :     const struct TALER_Amount *asi = &as->taa[i];
     968              : 
     969            0 :     if (GNUNET_OK !=
     970            0 :         TALER_amount_cmp_currency (b,
     971              :                                    asi))
     972            0 :       continue;
     973            0 :     if (1 !=
     974            0 :         TALER_amount_cmp (b,
     975              :                           asi))
     976            0 :       return true;
     977              :   }
     978            0 :   return false;
     979              : }
     980              : 
     981              : 
     982              : const struct TALER_Amount *
     983            1 : TALER_amount_set_find (const char *currency,
     984              :                        const struct TALER_AmountSet *as)
     985              : {
     986              :   static TALER_THREAD_LOCAL struct TALER_Amount z;
     987              : 
     988            5 :   for (unsigned int i = 0; i<as->taa_size; i++)
     989              :   {
     990            4 :     const struct TALER_Amount *asi = &as->taa[i];
     991              : 
     992            4 :     if (0 == strcasecmp (currency,
     993            4 :                          asi->currency))
     994            0 :       return asi;
     995              :   }
     996            1 :   if (GNUNET_OK !=
     997            1 :       TALER_amount_set_zero (currency,
     998              :                              &z))
     999              :   {
    1000            0 :     GNUNET_break (0);
    1001            0 :     return NULL;
    1002              :   }
    1003            1 :   return &z;
    1004              : }
    1005              : 
    1006              : 
    1007              : /**
    1008              :  * Upper bound on the length of the string representation of a
    1009              :  * single amount: the currency, the ':', the value, the '.', the
    1010              :  * fraction and the '\0'.  24 is sufficient for a uint64_t value
    1011              :  * in decimal.
    1012              :  */
    1013              : #define AMOUNT_STR_MAX (TALER_AMOUNT_FRAC_LEN     \
    1014              :                         + TALER_CURRENCY_LEN + 3 + 24)
    1015              : 
    1016              : 
    1017              : void
    1018           20 : TALER_amount_list_free (struct TALER_AmountList *al)
    1019              : {
    1020           20 :   GNUNET_array_grow (al->tal,
    1021              :                      al->tal_len,
    1022              :                      0);
    1023           20 : }
    1024              : 
    1025              : 
    1026              : enum GNUNET_GenericReturnValue
    1027           13 : TALER_string_to_amount_list (const char *str,
    1028              :                              struct TALER_AmountList *al)
    1029              : {
    1030           13 :   struct TALER_AmountList tmp = {
    1031              :     .tal = NULL,
    1032              :     .tal_len = 0
    1033              :   };
    1034           13 :   const char *pos = str;
    1035              : 
    1036              :   /* skip leading whitespace, so that an all-whitespace option
    1037              :      value means "free" and not "malformed" */
    1038           13 :   while (isspace ( (unsigned char) pos[0]))
    1039            0 :     pos++;
    1040           13 :   if ('\0' == pos[0])
    1041              :   {
    1042            2 :     al->tal = NULL;
    1043            2 :     al->tal_len = 0;
    1044            2 :     return GNUNET_OK;
    1045              :   }
    1046              :   while (1)
    1047           13 :   {
    1048           24 :     const char *end = strchr (pos,
    1049              :                               (int) ';');
    1050           24 :     size_t len = (NULL == end)
    1051           10 :       ? strlen (pos)
    1052           24 :       : (size_t) (end - pos);
    1053              :     struct TALER_Amount a;
    1054              :     char *component;
    1055              : 
    1056           24 :     if (0 == len)
    1057              :     {
    1058            2 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1059              :                   "Empty component in amount list `%s'\n",
    1060              :                   str);
    1061            2 :       TALER_amount_list_free (&tmp);
    1062            5 :       return GNUNET_SYSERR;
    1063              :     }
    1064           22 :     component = GNUNET_strndup (pos,
    1065              :                                 len);
    1066           22 :     if (GNUNET_OK !=
    1067           22 :         TALER_string_to_amount (component,
    1068              :                                 &a))
    1069              :     {
    1070            2 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1071              :                   "Invalid amount `%s' in amount list `%s'\n",
    1072              :                   component,
    1073              :                   str);
    1074            2 :       GNUNET_free (component);
    1075            2 :       TALER_amount_list_free (&tmp);
    1076            2 :       return GNUNET_SYSERR;
    1077              :     }
    1078           20 :     GNUNET_free (component);
    1079              :     /* A repeated currency is a typo, not an accumulation: which of
    1080              :        the two prices would apply is anyone's guess. */
    1081           20 :     if (NULL !=
    1082           20 :         TALER_amount_list_find (&tmp,
    1083              :                                 a.currency))
    1084              :     {
    1085            1 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1086              :                   "Currency `%s' given more than once in amount list `%s'\n",
    1087              :                   a.currency,
    1088              :                   str);
    1089            1 :       TALER_amount_list_free (&tmp);
    1090            1 :       return GNUNET_SYSERR;
    1091              :     }
    1092           19 :     GNUNET_array_append (tmp.tal,
    1093              :                          tmp.tal_len,
    1094              :                          a);
    1095           19 :     if (NULL == end)
    1096            6 :       break;
    1097           13 :     pos = end + 1;
    1098              :   }
    1099            6 :   *al = tmp;
    1100            6 :   return GNUNET_OK;
    1101              : }
    1102              : 
    1103              : 
    1104              : const char *
    1105            6 : TALER_amount_list2s (const struct TALER_AmountList *al)
    1106              : {
    1107              :   static TALER_THREAD_LOCAL char *result;
    1108              :   static TALER_THREAD_LOCAL size_t result_size;
    1109              :   size_t need;
    1110            6 :   size_t off = 0;
    1111              : 
    1112              :   /* one separator per entry is one too many, which covers the '\0' */
    1113            6 :   need = (al->tal_len + 1) * (AMOUNT_STR_MAX + 1);
    1114            6 :   if (need > result_size)
    1115              :   {
    1116            1 :     GNUNET_free (result);
    1117            1 :     result = GNUNET_malloc (need);
    1118            1 :     result_size = need;
    1119              :   }
    1120            6 :   result[0] = '\0';
    1121           24 :   for (unsigned int i = 0; i<al->tal_len; i++)
    1122              :   {
    1123           18 :     const char *as = TALER_amount2s (&al->tal[i]);
    1124              : 
    1125           18 :     if (NULL == as)
    1126              :     {
    1127            0 :       GNUNET_break (0);
    1128            0 :       return NULL;
    1129              :     }
    1130           18 :     off += GNUNET_snprintf (&result[off],
    1131              :                             result_size - off,
    1132              :                             "%s%s",
    1133              :                             (0 == i) ? "" : ";",
    1134              :                             as);
    1135              :   }
    1136            6 :   return result;
    1137              : }
    1138              : 
    1139              : 
    1140              : const struct TALER_Amount *
    1141           37 : TALER_amount_list_find (const struct TALER_AmountList *al,
    1142              :                         const char *currency)
    1143              : {
    1144           68 :   for (unsigned int i = 0; i<al->tal_len; i++)
    1145              :   {
    1146           41 :     const struct TALER_Amount *ali = &al->tal[i];
    1147              : 
    1148           41 :     if (0 == strcasecmp (currency,
    1149           41 :                          ali->currency))
    1150           10 :       return ali;
    1151              :   }
    1152           27 :   return NULL;
    1153              : }
    1154              : 
    1155              : 
    1156              : enum GNUNET_GenericReturnValue
    1157            4 : TALER_amount_list_check_uniform (const struct TALER_AmountList *al)
    1158              : {
    1159            4 :   bool have_zero = false;
    1160            4 :   bool have_price = false;
    1161              : 
    1162           12 :   for (unsigned int i = 0; i<al->tal_len; i++)
    1163              :   {
    1164            8 :     if (TALER_amount_is_zero (&al->tal[i]))
    1165            3 :       have_zero = true;
    1166              :     else
    1167            5 :       have_price = true;
    1168              :   }
    1169            4 :   if (have_zero && have_price)
    1170            1 :     return GNUNET_SYSERR;
    1171            3 :   if (have_price)
    1172            1 :     return GNUNET_OK;
    1173            2 :   return GNUNET_NO; /* all zero, or empty */
    1174              : }
    1175              : 
    1176              : 
    1177              : bool
    1178            4 : TALER_amount_list_covers (const struct TALER_AmountList *al,
    1179              :                           const char *const *currencies,
    1180              :                           unsigned int currencies_len)
    1181              : {
    1182              :   /* @a al has no duplicates, so equal length plus each currency
    1183              :      being present is enough to conclude the two agree exactly */
    1184            4 :   if (al->tal_len != currencies_len)
    1185            2 :     return false;
    1186            9 :   for (unsigned int i = 0; i<currencies_len; i++)
    1187            8 :     if (NULL ==
    1188            8 :         TALER_amount_list_find (al,
    1189            8 :                                 currencies[i]))
    1190            1 :       return false;
    1191            1 :   return true;
    1192              : }
    1193              : 
    1194              : 
    1195              : enum GNUNET_GenericReturnValue
    1196            5 : TALER_amount_list_multiply (struct TALER_AmountList *al,
    1197              :                             uint32_t n)
    1198              : {
    1199              :   struct TALER_Amount *tmp;
    1200              : 
    1201            5 :   if (0 == n)
    1202              :   {
    1203            1 :     GNUNET_break (0);
    1204            1 :     return GNUNET_SYSERR;
    1205              :   }
    1206            4 :   if ( (1 == n) ||
    1207            3 :        (0 == al->tal_len) )
    1208            2 :     return GNUNET_OK;
    1209              :   /* compute into a scratch array first, so that an overflow in a
    1210              :      late currency does not leave the early ones multiplied */
    1211            2 :   tmp = GNUNET_new_array (al->tal_len,
    1212              :                           struct TALER_Amount);
    1213            7 :   for (unsigned int i = 0; i<al->tal_len; i++)
    1214              :   {
    1215            6 :     if (0 >
    1216            6 :         TALER_amount_multiply (&tmp[i],
    1217            6 :                                &al->tal[i],
    1218              :                                n))
    1219              :     {
    1220            1 :       GNUNET_free (tmp);
    1221            1 :       return GNUNET_SYSERR;
    1222              :     }
    1223              :   }
    1224            1 :   GNUNET_memcpy (al->tal,
    1225              :                  tmp,
    1226              :                  al->tal_len * sizeof (struct TALER_Amount));
    1227            1 :   GNUNET_free (tmp);
    1228            1 :   return GNUNET_OK;
    1229              : }
    1230              : 
    1231              : 
    1232              : void
    1233            1 : TALER_amount_list_copy (struct TALER_AmountList *dst,
    1234              :                         const struct TALER_AmountList *src)
    1235              : {
    1236            1 :   dst->tal_len = src->tal_len;
    1237            1 :   if (0 == src->tal_len)
    1238              :   {
    1239            0 :     dst->tal = NULL;
    1240            0 :     return;
    1241              :   }
    1242            1 :   dst->tal = GNUNET_new_array (src->tal_len,
    1243              :                                struct TALER_Amount);
    1244            1 :   GNUNET_memcpy (dst->tal,
    1245              :                  src->tal,
    1246              :                  src->tal_len * sizeof (struct TALER_Amount));
    1247              : }
    1248              : 
    1249              : 
    1250              : /* end of amount.c */
        

Generated by: LCOV version 2.0-1