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