diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-01-27 16:18:33 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-01-27 16:18:33 +0100 |
commit | 2cda5ea7ee7e0e87b875ce54b483fdde86ed0dac (patch) | |
tree | dd8bfcc5cb1a8c7b77687de8863b2b330abb9309 /src/util/amount.c | |
parent | 610b7b62c09cb19410dc283f0629e4b24c343b57 (diff) | |
download | exchange-2cda5ea7ee7e0e87b875ce54b483fdde86ed0dac.tar.xz |
rework taler lib, moving some code to GNUnet, cleaner refresh encrypt/decypt API
Diffstat (limited to 'src/util/amount.c')
-rw-r--r-- | src/util/amount.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/src/util/amount.c b/src/util/amount.c new file mode 100644 index 000000000..8bd899bf5 --- /dev/null +++ b/src/util/amount.c @@ -0,0 +1,329 @@ +/* + This file is part of TALER + (C) 2014 Christian Grothoff (and other contributing authors) + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file amount.c + * @brief Common utility functions to deal with units of currency + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + * @author Florian Dold + * @author Benedikt Mueller + */ +#include "platform.h" +#include "taler_util.h" +#include <gnunet/gnunet_common.h> +#include <gnunet/gnunet_util_lib.h> +#include <gcrypt.h> + +#define AMOUNT_FRAC_BASE 1000000 + +#define AMOUNT_FRAC_LEN 6 + + +/** + * Parse money amount description, in the format "A:B.C". + * + * @param str amount description + * @param denom amount to write the result to + * @return #GNUNET_OK if the string is a valid amount specification, + * #GNUNET_SYSERR if it is invalid. + */ +int +TALER_string_to_amount (const char *str, + struct TALER_Amount *denom) +{ + unsigned int i; // pos in str + int n; // number tmp + unsigned int c; // currency pos + uint32_t b; // base for suffix + + memset (denom, 0, sizeof (struct TALER_Amount)); + + i = n = c = 0; + + while (isspace(str[i])) + i++; + + if (0 == str[i]) + { + printf("null before currency\n"); + return GNUNET_SYSERR; + } + + while (str[i] != ':') + { + if (0 == str[i]) + { + printf("null before colon"); + return GNUNET_SYSERR; + } + if (c > 3) + { + printf("currency too long\n"); + return GNUNET_SYSERR; + } + denom->currency[c] = str[i]; + c++; + i++; + } + + // skip colon + i++; + + if (0 == str[i]) + { + printf("null before value\n"); + return GNUNET_SYSERR; + } + + while (str[i] != '.') + { + if (0 == str[i]) + { + return GNUNET_OK; + } + n = str[i] - '0'; + if (n < 0 || n > 9) + { + printf("invalid character '%c' before comma at %u\n", (char) n, i); + return GNUNET_SYSERR; + } + denom->value = (denom->value * 10) + n; + i++; + } + + // skip the dot + i++; + + if (0 == str[i]) + { + printf("null after dot"); + return GNUNET_SYSERR; + } + + b = 100000; + + while (0 != str[i]) + { + n = str[i] - '0'; + if (b == 0 || n < 0 || n > 9) + { + printf("error after comma"); + return GNUNET_SYSERR; + } + denom->fraction += n * b; + b /= 10; + i++; + } + + return GNUNET_OK; +} + + +/** + * FIXME + */ +struct TALER_AmountNBO +TALER_amount_hton (struct TALER_Amount d) +{ + struct TALER_AmountNBO dn; + dn.value = htonl (d.value); + dn.fraction = htonl (d.fraction); + memcpy (dn.currency, d.currency, TALER_CURRENCY_LEN); + + return dn; +} + + +/** + * FIXME + */ +struct TALER_Amount +TALER_amount_ntoh (struct TALER_AmountNBO dn) +{ + struct TALER_Amount d; + d.value = ntohl (dn.value); + d.fraction = ntohl (dn.fraction); + memcpy (d.currency, dn.currency, sizeof(dn.currency)); + + return d; +} + + +/** + * Compare the value/fraction of two amounts. Does not compare the currency, + * i.e. comparing amounts with the same value and fraction but different + * currency would return 0. + * + * @param a1 first amount + * @param a2 second amount + * @return result of the comparison + */ +int +TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2) +{ + a1 = TALER_amount_normalize (a1); + a2 = TALER_amount_normalize (a2); + if (a1.value == a2.value) + { + if (a1.fraction < a2.fraction) + return -1; + if (a1.fraction > a2.fraction) + return 1; + return 0; + } + if (a1.value < a2.value) + return -1; + return 1; +} + + +/** + * Perform saturating subtraction of amounts. + * + * @param a1 amount to subtract from + * @param a2 amount to subtract + * @return (a1-a2) or 0 if a2>=a1 + */ +struct TALER_Amount +TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2) +{ + a1 = TALER_amount_normalize (a1); + a2 = TALER_amount_normalize (a2); + + if (a1.value < a2.value) + { + a1.value = 0; + a1.fraction = 0; + return a1; + } + + if (a1.fraction < a2.fraction) + { + if (0 == a1.value) + { + a1.fraction = 0; + return a1; + } + a1.fraction += AMOUNT_FRAC_BASE; + a1.value -= 1; + } + + a1.fraction -= a2.fraction; + a1.value -= a2.value; + + return a1; +} + + +/** + * Perform saturating addition of amounts. + * + * @param a1 first amount to add + * @param a2 second amount to add + * @return sum of a1 and a2 + */ +struct TALER_Amount +TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2) +{ + a1 = TALER_amount_normalize (a1); + a2 = TALER_amount_normalize (a2); + + a1.value += a2.value; + a1.fraction += a2.fraction; + + if (0 == a1.currency[0]) + { + memcpy (a2.currency, a1.currency, TALER_CURRENCY_LEN); + } + + if (0 == a2.currency[0]) + { + memcpy (a1.currency, a2.currency, TALER_CURRENCY_LEN); + } + + if (0 != a1.currency[0] && 0 != memcmp (a1.currency, a2.currency, TALER_CURRENCY_LEN)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "adding mismatching currencies\n"); + } + + if (a1.value < a2.value) + { + a1.value = UINT32_MAX; + a2.value = UINT32_MAX; + return a1; + } + + return TALER_amount_normalize (a1); +} + + +/** + * Normalize the given amount. + * + * @param amout amount to normalize + * @return normalized amount + */ +struct TALER_Amount +TALER_amount_normalize (struct TALER_Amount amount) +{ + while (amount.value != UINT32_MAX && amount.fraction >= AMOUNT_FRAC_BASE) + { + amount.fraction -= AMOUNT_FRAC_BASE; + amount.value += 1; + } + return amount; +} + + +/** + * Convert amount to string. + * + * @param amount amount to convert to string + * @return freshly allocated string representation + */ +char * +TALER_amount_to_string (struct TALER_Amount amount) +{ + char tail[AMOUNT_FRAC_LEN + 1] = { 0 }; + char curr[TALER_CURRENCY_LEN + 1] = { 0 }; + char *result = NULL; + int len; + + memcpy (curr, amount.currency, TALER_CURRENCY_LEN); + + amount = TALER_amount_normalize (amount); + if (0 != amount.fraction) + { + unsigned int i; + uint32_t n = amount.fraction; + for (i = 0; (i < AMOUNT_FRAC_LEN) && (n != 0); i++) + { + tail[i] = '0' + (n / (AMOUNT_FRAC_BASE / 10)); + n = (n * 10) % (AMOUNT_FRAC_BASE); + } + tail[i] = 0; + len = GNUNET_asprintf (&result, "%s:%lu.%s", curr, (unsigned long) amount.value, tail); + } + else + { + len = GNUNET_asprintf (&result, "%s:%lu", curr, (unsigned long) amount.value); + } + GNUNET_assert (len > 0); + return result; +} + + +/* end of amount.c */ |