aboutsummaryrefslogtreecommitdiff
path: root/src/util/amount.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/amount.c')
-rw-r--r--src/util/amount.c329
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 @@
1/*
2 This file is part of TALER
3 (C) 2014 Christian Grothoff (and other contributing authors)
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, If not, see <http://www.gnu.org/licenses/>
15*/
16
17/**
18 * @file amount.c
19 * @brief Common utility functions to deal with units of currency
20 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
21 * @author Florian Dold
22 * @author Benedikt Mueller
23 */
24#include "platform.h"
25#include "taler_util.h"
26#include <gnunet/gnunet_common.h>
27#include <gnunet/gnunet_util_lib.h>
28#include <gcrypt.h>
29
30#define AMOUNT_FRAC_BASE 1000000
31
32#define AMOUNT_FRAC_LEN 6
33
34
35/**
36 * Parse money amount description, in the format "A:B.C".
37 *
38 * @param str amount description
39 * @param denom amount to write the result to
40 * @return #GNUNET_OK if the string is a valid amount specification,
41 * #GNUNET_SYSERR if it is invalid.
42 */
43int
44TALER_string_to_amount (const char *str,
45 struct TALER_Amount *denom)
46{
47 unsigned int i; // pos in str
48 int n; // number tmp
49 unsigned int c; // currency pos
50 uint32_t b; // base for suffix
51
52 memset (denom, 0, sizeof (struct TALER_Amount));
53
54 i = n = c = 0;
55
56 while (isspace(str[i]))
57 i++;
58
59 if (0 == str[i])
60 {
61 printf("null before currency\n");
62 return GNUNET_SYSERR;
63 }
64
65 while (str[i] != ':')
66 {
67 if (0 == str[i])
68 {
69 printf("null before colon");
70 return GNUNET_SYSERR;
71 }
72 if (c > 3)
73 {
74 printf("currency too long\n");
75 return GNUNET_SYSERR;
76 }
77 denom->currency[c] = str[i];
78 c++;
79 i++;
80 }
81
82 // skip colon
83 i++;
84
85 if (0 == str[i])
86 {
87 printf("null before value\n");
88 return GNUNET_SYSERR;
89 }
90
91 while (str[i] != '.')
92 {
93 if (0 == str[i])
94 {
95 return GNUNET_OK;
96 }
97 n = str[i] - '0';
98 if (n < 0 || n > 9)
99 {
100 printf("invalid character '%c' before comma at %u\n", (char) n, i);
101 return GNUNET_SYSERR;
102 }
103 denom->value = (denom->value * 10) + n;
104 i++;
105 }
106
107 // skip the dot
108 i++;
109
110 if (0 == str[i])
111 {
112 printf("null after dot");
113 return GNUNET_SYSERR;
114 }
115
116 b = 100000;
117
118 while (0 != str[i])
119 {
120 n = str[i] - '0';
121 if (b == 0 || n < 0 || n > 9)
122 {
123 printf("error after comma");
124 return GNUNET_SYSERR;
125 }
126 denom->fraction += n * b;
127 b /= 10;
128 i++;
129 }
130
131 return GNUNET_OK;
132}
133
134
135/**
136 * FIXME
137 */
138struct TALER_AmountNBO
139TALER_amount_hton (struct TALER_Amount d)
140{
141 struct TALER_AmountNBO dn;
142 dn.value = htonl (d.value);
143 dn.fraction = htonl (d.fraction);
144 memcpy (dn.currency, d.currency, TALER_CURRENCY_LEN);
145
146 return dn;
147}
148
149
150/**
151 * FIXME
152 */
153struct TALER_Amount
154TALER_amount_ntoh (struct TALER_AmountNBO dn)
155{
156 struct TALER_Amount d;
157 d.value = ntohl (dn.value);
158 d.fraction = ntohl (dn.fraction);
159 memcpy (d.currency, dn.currency, sizeof(dn.currency));
160
161 return d;
162}
163
164
165/**
166 * Compare the value/fraction of two amounts. Does not compare the currency,
167 * i.e. comparing amounts with the same value and fraction but different
168 * currency would return 0.
169 *
170 * @param a1 first amount
171 * @param a2 second amount
172 * @return result of the comparison
173 */
174int
175TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2)
176{
177 a1 = TALER_amount_normalize (a1);
178 a2 = TALER_amount_normalize (a2);
179 if (a1.value == a2.value)
180 {
181 if (a1.fraction < a2.fraction)
182 return -1;
183 if (a1.fraction > a2.fraction)
184 return 1;
185 return 0;
186 }
187 if (a1.value < a2.value)
188 return -1;
189 return 1;
190}
191
192
193/**
194 * Perform saturating subtraction of amounts.
195 *
196 * @param a1 amount to subtract from
197 * @param a2 amount to subtract
198 * @return (a1-a2) or 0 if a2>=a1
199 */
200struct TALER_Amount
201TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2)
202{
203 a1 = TALER_amount_normalize (a1);
204 a2 = TALER_amount_normalize (a2);
205
206 if (a1.value < a2.value)
207 {
208 a1.value = 0;
209 a1.fraction = 0;
210 return a1;
211 }
212
213 if (a1.fraction < a2.fraction)
214 {
215 if (0 == a1.value)
216 {
217 a1.fraction = 0;
218 return a1;
219 }
220 a1.fraction += AMOUNT_FRAC_BASE;
221 a1.value -= 1;
222 }
223
224 a1.fraction -= a2.fraction;
225 a1.value -= a2.value;
226
227 return a1;
228}
229
230
231/**
232 * Perform saturating addition of amounts.
233 *
234 * @param a1 first amount to add
235 * @param a2 second amount to add
236 * @return sum of a1 and a2
237 */
238struct TALER_Amount
239TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2)
240{
241 a1 = TALER_amount_normalize (a1);
242 a2 = TALER_amount_normalize (a2);
243
244 a1.value += a2.value;
245 a1.fraction += a2.fraction;
246
247 if (0 == a1.currency[0])
248 {
249 memcpy (a2.currency, a1.currency, TALER_CURRENCY_LEN);
250 }
251
252 if (0 == a2.currency[0])
253 {
254 memcpy (a1.currency, a2.currency, TALER_CURRENCY_LEN);
255 }
256
257 if (0 != a1.currency[0] && 0 != memcmp (a1.currency, a2.currency, TALER_CURRENCY_LEN))
258 {
259 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "adding mismatching currencies\n");
260 }
261
262 if (a1.value < a2.value)
263 {
264 a1.value = UINT32_MAX;
265 a2.value = UINT32_MAX;
266 return a1;
267 }
268
269 return TALER_amount_normalize (a1);
270}
271
272
273/**
274 * Normalize the given amount.
275 *
276 * @param amout amount to normalize
277 * @return normalized amount
278 */
279struct TALER_Amount
280TALER_amount_normalize (struct TALER_Amount amount)
281{
282 while (amount.value != UINT32_MAX && amount.fraction >= AMOUNT_FRAC_BASE)
283 {
284 amount.fraction -= AMOUNT_FRAC_BASE;
285 amount.value += 1;
286 }
287 return amount;
288}
289
290
291/**
292 * Convert amount to string.
293 *
294 * @param amount amount to convert to string
295 * @return freshly allocated string representation
296 */
297char *
298TALER_amount_to_string (struct TALER_Amount amount)
299{
300 char tail[AMOUNT_FRAC_LEN + 1] = { 0 };
301 char curr[TALER_CURRENCY_LEN + 1] = { 0 };
302 char *result = NULL;
303 int len;
304
305 memcpy (curr, amount.currency, TALER_CURRENCY_LEN);
306
307 amount = TALER_amount_normalize (amount);
308 if (0 != amount.fraction)
309 {
310 unsigned int i;
311 uint32_t n = amount.fraction;
312 for (i = 0; (i < AMOUNT_FRAC_LEN) && (n != 0); i++)
313 {
314 tail[i] = '0' + (n / (AMOUNT_FRAC_BASE / 10));
315 n = (n * 10) % (AMOUNT_FRAC_BASE);
316 }
317 tail[i] = 0;
318 len = GNUNET_asprintf (&result, "%s:%lu.%s", curr, (unsigned long) amount.value, tail);
319 }
320 else
321 {
322 len = GNUNET_asprintf (&result, "%s:%lu", curr, (unsigned long) amount.value);
323 }
324 GNUNET_assert (len > 0);
325 return result;
326}
327
328
329/* end of amount.c */