LCOV - code coverage report
Current view: top level - util - amount.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 183 224 81.7 %
Date: 2017-11-25 11:31:41 Functions: 16 17 94.1 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014 GNUnet e.V.
       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             : #if HAVE_GNUNET_GNUNET_UTIL_LIB_H
      26             : #include "taler_util.h"
      27             : #elif HAVE_GNUNET_GNUNET_UTIL_TALER_WALLET_LIB_H
      28             : #include "taler_util_wallet.h"
      29             : #endif
      30             : #include <gcrypt.h>
      31             : 
      32             : /**
      33             :  * Maximum legal 'value' for an amount, based on IEEE double (for JavaScript compatibility).
      34             :  */
      35             : #define MAX_AMOUNT_VALUE (1LLU << 52)
      36             : 
      37             : 
      38             : /**
      39             :  * Set @a a to "invalid".
      40             :  *
      41             :  * @param a amount to set to invalid
      42             :  */
      43             : static void
      44         412 : invalidate (struct TALER_Amount *a)
      45             : {
      46         412 :   memset (a,
      47             :           0,
      48             :           sizeof (struct TALER_Amount));
      49         412 : }
      50             : 
      51             : 
      52             : /**
      53             :  * Parse money amount description, in the format "A:B.C".
      54             :  *
      55             :  * @param str amount description
      56             :  * @param denom amount to write the result to
      57             :  * @return #GNUNET_OK if the string is a valid amount specification,
      58             :  *         #GNUNET_SYSERR if it is invalid.
      59             :  */
      60             : int
      61         404 : TALER_string_to_amount (const char *str,
      62             :                         struct TALER_Amount *denom)
      63             : {
      64             :   size_t i;
      65             :   int n;
      66             :   uint32_t b;
      67             :   const char *colon;
      68             :   const char *value;
      69             : 
      70         404 :   invalidate (denom);
      71             :   /* skip leading whitespace */
      72         810 :   while (isspace( (unsigned char) str[0]))
      73           2 :     str++;
      74         404 :   if ('\0' == str[0])
      75             :   {
      76           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
      77             :                 "Null before currency\n");
      78           0 :     return GNUNET_SYSERR;
      79             :   }
      80             :   /* parse currency */
      81         404 :   colon = strchr (str, (int) ':');
      82         808 :   if ( (NULL == colon) ||
      83         404 :        ((colon - str) >= TALER_CURRENCY_LEN) )
      84             :   {
      85           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
      86             :                 "Invalid currency specified before colon: `%s'",
      87             :                 str);
      88           0 :     goto fail;
      89             :   }
      90         404 :   memcpy (denom->currency,
      91             :           str,
      92         404 :           colon - str);
      93             :   /* skip colon */
      94         404 :   value = colon + 1;
      95         404 :   if ('\0' == value[0])
      96             :   {
      97           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
      98             :                 "Null before value\n");
      99           0 :     goto fail;
     100             :   }
     101             : 
     102             :   /* parse value */
     103         404 :   i = 0;
     104        1263 :   while ('.' != value[i])
     105             :   {
     106         511 :     if ('\0' == value[i])
     107             :     {
     108          54 :       return GNUNET_OK;
     109             :     }
     110         457 :     if ( (value[i] < '0') || (value[i] > '9') )
     111             :     {
     112           1 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     113             :                   "Invalid character `%c'\n",
     114             :                   value[i]);
     115           1 :       goto fail;
     116             :     }
     117         456 :     n = value[i] - '0';
     118         456 :     if (denom->value * 10 + n < denom->value)
     119             :     {
     120           1 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     121             :                   "Value too large\n");
     122           1 :       goto fail;
     123             :     }
     124         455 :     denom->value = (denom->value * 10) + n;
     125         455 :     i++;
     126             :   }
     127             : 
     128             :   /* skip the dot */
     129         348 :   i++;
     130             : 
     131             :   /* parse fraction */
     132         348 :   if ('\0' == value[i])
     133             :   {
     134           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     135             :                 "Null after dot\n");
     136           0 :     goto fail;
     137             :   }
     138         348 :   b = TALER_AMOUNT_FRAC_BASE / 10;
     139        1436 :   while ('\0' != value[i])
     140             :   {
     141         744 :     if (0 == b)
     142             :     {
     143           1 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     144             :                   "Fractional value too small (only %u digits supported)\n",
     145             :                   (unsigned int) TALER_AMOUNT_FRAC_LEN);
     146           1 :       goto fail;
     147             :     }
     148         743 :     if ( (value[i] < '0') || (value[i] > '9') )
     149             :     {
     150           3 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     151             :                   "Error after dot\n");
     152           3 :       goto fail;
     153             :     }
     154         740 :     n = value[i] - '0';
     155         740 :     denom->fraction += n * b;
     156         740 :     b /= 10;
     157         740 :     i++;
     158             :   }
     159         344 :   if (denom->value > MAX_AMOUNT_VALUE)
     160             :   {
     161             :     /* too large to be legal */
     162           0 :     invalidate (denom);
     163           0 :     return GNUNET_SYSERR;
     164             :   }
     165         344 :   return GNUNET_OK;
     166             : 
     167             :  fail:
     168             :   /* set currency to 'invalid' to prevent accidental use */
     169           6 :   memset (denom->currency,
     170             :           0,
     171             :           TALER_CURRENCY_LEN);
     172           6 :   return GNUNET_SYSERR;
     173             : }
     174             : 
     175             : 
     176             : /**
     177             :  * Parse denomination description, in the format "T:V.F".
     178             :  *
     179             :  * @param str denomination description
     180             :  * @param denom denomination to write the result to, in NBO
     181             :  * @return #GNUNET_OK if the string is a valid denomination specification,
     182             :  *         #GNUNET_SYSERR if it is invalid.
     183             :  */
     184             : int
     185           5 : TALER_string_to_amount_nbo (const char *str,
     186             :                             struct TALER_AmountNBO *denom)
     187             : {
     188             :   struct TALER_Amount amount;
     189             : 
     190           5 :   if (GNUNET_OK !=
     191           5 :       TALER_string_to_amount (str,
     192             :                               &amount))
     193           0 :     return GNUNET_SYSERR;
     194           5 :   TALER_amount_hton (denom,
     195             :                      &amount);
     196           5 :   return GNUNET_OK;
     197             : }
     198             : 
     199             : 
     200             : /**
     201             :  * Convert amount from host to network representation.
     202             :  *
     203             :  * @param res where to store amount in network representation
     204             :  * @param d amount in host representation
     205             :  */
     206             : void
     207        2077 : TALER_amount_hton (struct TALER_AmountNBO *res,
     208             :                    const struct TALER_Amount *d)
     209             : {
     210        2077 :   res->value = GNUNET_htonll (d->value);
     211        2077 :   res->fraction = htonl (d->fraction);
     212        2077 :   memcpy (res->currency,
     213        2077 :           d->currency,
     214             :           TALER_CURRENCY_LEN);
     215        2077 : }
     216             : 
     217             : 
     218             : /**
     219             :  * Convert amount from network to host representation.
     220             :  *
     221             :  * @param res where to store amount in host representation
     222             :  * @param dn amount in network representation
     223             :  */
     224             : void
     225         737 : TALER_amount_ntoh (struct TALER_Amount *res,
     226             :                    const struct TALER_AmountNBO *dn)
     227             : {
     228         737 :   res->value = GNUNET_ntohll (dn->value);
     229         737 :   res->fraction = ntohl (dn->fraction);
     230         737 :   memcpy (res->currency,
     231         737 :           dn->currency,
     232             :           TALER_CURRENCY_LEN);
     233         737 : }
     234             : 
     235             : 
     236             : /**
     237             :  * Get the value of "zero" in a particular currency.
     238             :  *
     239             :  * @param cur currency description
     240             :  * @param denom denomination to write the result to
     241             :  * @return #GNUNET_OK if @a cur is a valid currency specification,
     242             :  *         #GNUNET_SYSERR if it is invalid.
     243             :  */
     244             : int
     245         395 : TALER_amount_get_zero (const char *cur,
     246             :                        struct TALER_Amount *denom)
     247             : {
     248             :   size_t slen;
     249             : 
     250         395 :   slen = strlen (cur);
     251         395 :   if (slen >= TALER_CURRENCY_LEN)
     252           0 :     return GNUNET_SYSERR;
     253         395 :   memset (denom,
     254             :           0,
     255             :           sizeof (struct TALER_Amount));
     256         395 :   memcpy (denom->currency,
     257             :           cur,
     258             :           slen);
     259         395 :   return GNUNET_OK;
     260             : }
     261             : 
     262             : 
     263             : /**
     264             :  * Test if the given amount is valid.
     265             :  *
     266             :  * @param amount amount to check
     267             :  * @return #GNUNET_OK if @a amount is valid
     268             :  */
     269             : int
     270        3329 : TALER_amount_is_valid (const struct TALER_Amount *amount)
     271             : {
     272        3329 :   return ('\0' != amount->currency[0]);
     273             : }
     274             : 
     275             : 
     276             : /**
     277             :  * Test if @a a is valid, NBO variant.
     278             :  *
     279             :  * @param a amount to test
     280             :  * @return #GNUNET_YES if valid,
     281             :  *         #GNUNET_NO if invalid
     282             :  */
     283             : static int
     284         304 : test_valid_nbo (const struct TALER_AmountNBO *a)
     285             : {
     286         304 :   return ('\0' != a->currency[0]);
     287             : }
     288             : 
     289             : 
     290             : /**
     291             :  * Test if @a a1 and @a a2 are the same currency.
     292             :  *
     293             :  * @param a1 amount to test
     294             :  * @param a2 amount to test
     295             :  * @return #GNUNET_YES if @a a1 and @a a2 are the same currency
     296             :  *         #GNUNET_NO if the currencies are different,
     297             :  *         #GNUNET_SYSERR if either amount is invalid
     298             :  */
     299             : int
     300         647 : TALER_amount_cmp_currency (const struct TALER_Amount *a1,
     301             :                            const struct TALER_Amount *a2)
     302             : {
     303        1294 :   if ( (GNUNET_NO == TALER_amount_is_valid (a1)) ||
     304         647 :        (GNUNET_NO == TALER_amount_is_valid (a2)) )
     305           0 :     return GNUNET_SYSERR;
     306         647 :   if (0 == strcasecmp (a1->currency,
     307         647 :                        a2->currency))
     308         645 :     return GNUNET_YES;
     309           2 :   return GNUNET_NO;
     310             : }
     311             : 
     312             : 
     313             : /**
     314             :  * Test if @a a1 and @a a2 are the same currency, NBO variant.
     315             :  *
     316             :  * @param a1 amount to test
     317             :  * @param a2 amount to test
     318             :  * @return #GNUNET_YES if @a a1 and @a a2 are the same currency
     319             :  *         #GNUNET_NO if the currencies are different,
     320             :  *         #GNUNET_SYSERR if either amount is invalid
     321             :  */
     322             : int
     323         152 : TALER_amount_cmp_currency_nbo (const struct TALER_AmountNBO *a1,
     324             :                                const struct TALER_AmountNBO *a2)
     325             : {
     326         304 :   if ( (GNUNET_NO == test_valid_nbo (a1)) ||
     327         152 :        (GNUNET_NO == test_valid_nbo (a2)) )
     328           0 :     return GNUNET_SYSERR;
     329         152 :   if (0 == strcasecmp (a1->currency,
     330         152 :                        a2->currency))
     331         152 :     return GNUNET_YES;
     332           0 :   return GNUNET_NO;
     333             : }
     334             : 
     335             : 
     336             : /**
     337             :  * Compare the value/fraction of two amounts.  Does not compare the currency.
     338             :  * Comparing amounts of different currencies will cause the program to abort().
     339             :  * If unsure, check with #TALER_amount_cmp_currency() first to be sure that
     340             :  * the currencies of the two amounts are identical.
     341             :  *
     342             :  * @param a1 first amount
     343             :  * @param a2 second amount
     344             :  * @return result of the comparison,
     345             :  *         -1 if `a1 < a2`
     346             :  *          1 if `a1 > a2`
     347             :  *          0 if `a1 == a2`.
     348             :  */
     349             : int
     350         276 : TALER_amount_cmp (const struct TALER_Amount *a1,
     351             :                   const struct TALER_Amount *a2)
     352             : {
     353             :   struct TALER_Amount n1;
     354             :   struct TALER_Amount n2;
     355             : 
     356         276 :   GNUNET_assert (GNUNET_YES ==
     357             :                  TALER_amount_cmp_currency (a1, a2));
     358         276 :   n1 = *a1;
     359         276 :   n2 = *a2;
     360         276 :   GNUNET_assert (GNUNET_SYSERR !=
     361             :                  TALER_amount_normalize (&n1));
     362         276 :   GNUNET_assert (GNUNET_SYSERR !=
     363             :                  TALER_amount_normalize (&n2));
     364         276 :   if (n1.value == n2.value)
     365             :   {
     366         196 :     if (n1.fraction < n2.fraction)
     367          17 :       return -1;
     368         179 :     if (n1.fraction > n2.fraction)
     369           0 :       return 1;
     370         179 :     return 0;
     371             :   }
     372          80 :   if (n1.value < n2.value)
     373          46 :     return -1;
     374          34 :   return 1;
     375             : }
     376             : 
     377             : 
     378             : /**
     379             :  * Perform saturating subtraction of amounts.
     380             :  *
     381             :  * @param diff where to store (@a a1 - @a a2), or invalid if @a a2 > @a a1
     382             :  * @param a1 amount to subtract from
     383             :  * @param a2 amount to subtract
     384             :  * @return #GNUNET_OK if the subtraction worked,
     385             :  *         #GNUNET_NO if @a a1 = @a a2
     386             :  *         #GNUNET_SYSERR if @a a2 > @a a1 or currencies are incompatible;
     387             :  *                        @a diff is set to invalid
     388             :  */
     389             : int
     390         144 : TALER_amount_subtract (struct TALER_Amount *diff,
     391             :                        const struct TALER_Amount *a1,
     392             :                        const struct TALER_Amount *a2)
     393             : {
     394             :   struct TALER_Amount n1;
     395             :   struct TALER_Amount n2;
     396             : 
     397         144 :   if (GNUNET_YES !=
     398         144 :       TALER_amount_cmp_currency (a1, a2))
     399             :   {
     400           1 :     invalidate (diff);
     401           1 :     return GNUNET_SYSERR;
     402             :   }
     403         143 :   n1 = *a1;
     404         143 :   n2 = *a2;
     405         286 :   if ( (GNUNET_SYSERR == TALER_amount_normalize (&n1)) ||
     406         143 :        (GNUNET_SYSERR == TALER_amount_normalize (&n2)) )
     407             :   {
     408           0 :     invalidate (diff);
     409           0 :     return GNUNET_SYSERR;
     410             :   }
     411             : 
     412         143 :   if (n1.fraction < n2.fraction)
     413             :   {
     414          38 :     if (0 == n1.value)
     415             :     {
     416           4 :       invalidate (diff);
     417           4 :       return GNUNET_SYSERR;
     418             :     }
     419          34 :     n1.fraction += TALER_AMOUNT_FRAC_BASE;
     420          34 :     n1.value--;
     421             :   }
     422         139 :   if (n1.value < n2.value)
     423             :   {
     424           1 :     invalidate (diff);
     425           1 :     return GNUNET_SYSERR;
     426             :   }
     427         138 :   GNUNET_assert (GNUNET_OK ==
     428             :                  TALER_amount_get_zero (n1.currency,
     429             :                                         diff));
     430         138 :   GNUNET_assert (n1.fraction >= n2.fraction);
     431         138 :   diff->fraction = n1.fraction - n2.fraction;
     432         138 :   GNUNET_assert (n1.value >= n2.value);
     433         138 :   diff->value = n1.value - n2.value;
     434         174 :   if ( (0 == diff->fraction) &&
     435          36 :        (0 == diff->value) )
     436          15 :     return GNUNET_NO;
     437         123 :   return GNUNET_OK;
     438             : }
     439             : 
     440             : 
     441             : /**
     442             :  * Perform addition of amounts.
     443             :  *
     444             :  * @param sum where to store @a a1 + @a a2, set to "invalid" on overflow
     445             :  * @param a1 first amount to add
     446             :  * @param a2 second amount to add
     447             :  * @return #GNUNET_OK if the addition worked,
     448             :  *         #GNUNET_SYSERR on overflow
     449             :  */
     450             : int
     451         211 : TALER_amount_add (struct TALER_Amount *sum,
     452             :                   const struct TALER_Amount *a1,
     453             :                   const struct TALER_Amount *a2)
     454             : {
     455             :   struct TALER_Amount n1;
     456             :   struct TALER_Amount n2;
     457             :   struct TALER_Amount res;
     458             : 
     459         211 :   if (GNUNET_YES !=
     460         211 :       TALER_amount_cmp_currency (a1, a2))
     461             :   {
     462           0 :     invalidate (sum);
     463           0 :     return GNUNET_SYSERR;
     464             :   }
     465         211 :   n1 = *a1;
     466         211 :   n2 = *a2;
     467         422 :   if ( (GNUNET_SYSERR == TALER_amount_normalize (&n1)) ||
     468         211 :        (GNUNET_SYSERR == TALER_amount_normalize (&n2)) )
     469             :   {
     470           0 :     invalidate (sum);
     471           0 :     return GNUNET_SYSERR;
     472             :   }
     473             : 
     474         211 :   GNUNET_assert (GNUNET_OK ==
     475             :                  TALER_amount_get_zero (a1->currency,
     476             :                                         &res));
     477         211 :   res.value = n1.value + n2.value;
     478         211 :   if (res.value < n1.value)
     479             :   {
     480             :     /* integer overflow */
     481           0 :     invalidate (sum);
     482           0 :     return GNUNET_SYSERR;
     483             :   }
     484         211 :   if (res.value > MAX_AMOUNT_VALUE)
     485             :   {
     486             :     /* too large to be legal */
     487           1 :     invalidate (sum);
     488           1 :     return GNUNET_SYSERR;
     489             :   }
     490         210 :   res.fraction = n1.fraction + n2.fraction;
     491         210 :   if (GNUNET_SYSERR ==
     492         210 :       TALER_amount_normalize (&res))
     493             :   {
     494             :     /* integer overflow via carry from fraction */
     495           0 :     invalidate (sum);
     496           0 :     return GNUNET_SYSERR;
     497             :   }
     498         210 :   *sum = res;
     499         210 :   return GNUNET_OK;
     500             : }
     501             : 
     502             : 
     503             : /**
     504             :  * Normalize the given amount.
     505             :  *
     506             :  * @param amount amount to normalize
     507             :  * @return #GNUNET_OK if normalization worked
     508             :  *         #GNUNET_NO if value was already normalized
     509             :  *         #GNUNET_SYSERR if value was invalid or could not be normalized
     510             :  */
     511             : int
     512        1858 : TALER_amount_normalize (struct TALER_Amount *amount)
     513             : {
     514             :   int ret;
     515             : 
     516        1858 :   if (GNUNET_YES != TALER_amount_is_valid (amount))
     517           2 :     return GNUNET_SYSERR;
     518        1856 :   ret = GNUNET_NO;
     519        5582 :   while ( (amount->value != UINT64_MAX) &&
     520        1862 :           (amount->fraction >= TALER_AMOUNT_FRAC_BASE) )
     521             :   {
     522           8 :     amount->fraction -= TALER_AMOUNT_FRAC_BASE;
     523           8 :     amount->value++;
     524           8 :     ret = GNUNET_OK;
     525             :   }
     526        1856 :   if (amount->fraction >= TALER_AMOUNT_FRAC_BASE)
     527             :   {
     528             :     /* failed to normalize, adding up fractions caused
     529             :        main value to overflow! */
     530           1 :     invalidate (amount);
     531           1 :     return GNUNET_SYSERR;
     532             :   }
     533        1855 :   return ret;
     534             : }
     535             : 
     536             : 
     537             : /**
     538             :  * Convert amount to string.
     539             :  *
     540             :  * @param amount amount to convert to string
     541             :  * @return freshly allocated string representation
     542             :  */
     543             : char *
     544         177 : TALER_amount_to_string (const struct TALER_Amount *amount)
     545             : {
     546             :   char *result;
     547             :   unsigned int i;
     548             :   uint32_t n;
     549             :   char tail[TALER_AMOUNT_FRAC_LEN + 1];
     550             :   struct TALER_Amount norm;
     551             : 
     552         177 :   if (GNUNET_YES != TALER_amount_is_valid (amount))
     553           1 :     return NULL;
     554         176 :   norm = *amount;
     555         176 :   GNUNET_break (GNUNET_SYSERR !=
     556             :                 TALER_amount_normalize (&norm));
     557         176 :   if (0 != (n = norm.fraction))
     558             :   {
     559         321 :     for (i = 0; (i < TALER_AMOUNT_FRAC_LEN) && (0 != n); i++)
     560             :     {
     561         202 :       tail[i] = '0' + (n / (TALER_AMOUNT_FRAC_BASE / 10));
     562         202 :       n = (n * 10) % (TALER_AMOUNT_FRAC_BASE);
     563             :     }
     564         119 :     tail[i] = '\0';
     565         119 :     GNUNET_asprintf (&result,
     566             :                      "%s:%llu.%s",
     567             :                      norm.currency,
     568         119 :                      (unsigned long long) norm.value,
     569             :                      tail);
     570             :   }
     571             :   else
     572             :   {
     573          57 :     GNUNET_asprintf (&result,
     574             :                      "%s:%llu",
     575             :                      norm.currency,
     576          57 :                      (unsigned long long) norm.value);
     577             :   }
     578         176 :   return result;
     579             : }
     580             : 
     581             : 
     582             : /**
     583             :  * Convert amount to string.
     584             :  *
     585             :  * @param amount amount to convert to string
     586             :  * @return statically allocated buffer with string representation,
     587             :  *         NULL if the @a amount was invalid
     588             :  */
     589             : const char *
     590           0 : TALER_amount2s (const struct TALER_Amount *amount)
     591             : {
     592             :   static char result[TALER_AMOUNT_FRAC_LEN + TALER_CURRENCY_LEN + 3 + 12];
     593             :   unsigned int i;
     594             :   uint32_t n;
     595             :   char tail[TALER_AMOUNT_FRAC_LEN + 1];
     596             :   struct TALER_Amount norm;
     597             : 
     598           0 :   if (GNUNET_YES != TALER_amount_is_valid (amount))
     599           0 :     return NULL;
     600           0 :   norm = *amount;
     601           0 :   GNUNET_break (GNUNET_SYSERR !=
     602             :                 TALER_amount_normalize (&norm));
     603           0 :   if (0 != (n = norm.fraction))
     604             :   {
     605           0 :     for (i = 0; (i < TALER_AMOUNT_FRAC_LEN) && (0 != n); i++)
     606             :     {
     607           0 :       tail[i] = '0' + (n / (TALER_AMOUNT_FRAC_BASE / 10));
     608           0 :       n = (n * 10) % (TALER_AMOUNT_FRAC_BASE);
     609             :     }
     610           0 :     tail[i] = '\0';
     611           0 :     GNUNET_snprintf (result,
     612             :                      sizeof (result),
     613             :                      "%s:%llu.%s",
     614             :                      norm.currency,
     615           0 :                      (unsigned long long) norm.value,
     616             :                      tail);
     617             :   }
     618             :   else
     619             :   {
     620           0 :     GNUNET_snprintf (result,
     621             :                      sizeof (result),
     622             :                      "%s:%llu",
     623             :                      norm.currency,
     624           0 :                      (unsigned long long) norm.value);
     625             :   }
     626           0 :   return result;
     627             : }
     628             : 
     629             : 
     630             : /**
     631             :  * Divide an amount by a float.  Note that this function
     632             :  * may introduce a rounding error!
     633             :  *
     634             :  * @param result where to store @a dividend / @a divisor
     635             :  * @param dividend amount to divide
     636             :  * @param divisor by what to divide, must be positive
     637             :  */
     638             : void
     639           4 : TALER_amount_divide (struct TALER_Amount *result,
     640             :                      const struct TALER_Amount *dividend,
     641             :                      uint32_t divisor)
     642             : {
     643             :   uint64_t modr;
     644             : 
     645           4 :   GNUNET_assert (0 != divisor);
     646           4 :   *result = *dividend;
     647           4 :   if (1 == divisor)
     648           1 :     return;
     649           3 :   modr = result->value % divisor;
     650           3 :   result->value /= divisor;
     651             :   /* modr is a 32-bit value, so we can safely multiply by (<32-bit) base and add fraction! */
     652           3 :   modr = (modr * TALER_AMOUNT_FRAC_BASE) + result->fraction;
     653           3 :   GNUNET_assert (modr < TALER_AMOUNT_FRAC_BASE * divisor);
     654           3 :   result->fraction = (uint32_t) (modr / divisor);
     655             : }
     656             : 
     657             : 
     658             : /* end of amount.c */

Generated by: LCOV version 1.13