1 /* Iterator for inserting thousands separators into numbers.
2 Copyright (C) 2022-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <grouping_iterator.h>
23 #include <locale/localeinfo.h>
27 /* Initializes *IT with no grouping information for a string of length
28 DIGITS, and return false to indicate no grouping. */
30 __grouping_iterator_init_none (struct grouping_iterator
*it
,
33 memset (it
, 0, sizeof (*it
));
34 it
->remaining_in_current_group
= digits
;
35 it
->remaining
= digits
;
40 grouping_iterator_setup (struct grouping_iterator
*it
, unsigned int digits
,
43 /* We treat all negative values like CHAR_MAX. */
45 if (*grouping
== CHAR_MAX
|| *grouping
<= 0)
46 /* No grouping should be done. */
47 return __grouping_iterator_init_none (it
, digits
);
49 unsigned int remaining_to_group
= digits
;
50 unsigned int non_repeating_groups
= 0;
51 unsigned int groups
= 0;
54 non_repeating_groups
+= *grouping
;
55 if (remaining_to_group
<= (unsigned int) *grouping
)
59 remaining_to_group
-= *grouping
++;
61 if (*grouping
== CHAR_MAX
66 /* No more grouping should be done. */
68 else if (*grouping
== 0)
70 /* Same grouping repeats. */
72 non_repeating_groups
-= *grouping
; /* Over-counted. */
73 unsigned int repeats
= (remaining_to_group
- 1) / *grouping
;
75 remaining_to_group
-= repeats
* *grouping
;
80 it
->remaining_in_current_group
= remaining_to_group
;
81 it
->remaining
= digits
;
82 it
->groupings
= grouping
;
83 it
->non_repeating_groups
= non_repeating_groups
;
84 it
->separators
= groups
;
85 return it
->separators
> 0;
88 /* Returns the appropriate grouping item in LOC depending on CATEGORY
89 (which must be LC_MONETARY or LC_NUMERIC). */
91 get_grouping (int category
, locale_t loc
)
93 return _nl_lookup (loc
, category
,
94 category
== LC_MONETARY
? MON_GROUPING
: GROUPING
);
99 __grouping_iterator_init (struct grouping_iterator
*it
,
100 int category
, locale_t loc
, unsigned int digits
)
103 return __grouping_iterator_init_none (it
, digits
);
105 return grouping_iterator_setup (it
, digits
, get_grouping (category
, loc
));
109 __grouping_iterator_next (struct grouping_iterator
*it
)
111 assert (it
->remaining
> 0);
114 if (it
->remaining_in_current_group
> 0)
116 --it
->remaining_in_current_group
;
120 /* If we are in the non-repeating part, switch group. */
121 if (it
->remaining
< it
->non_repeating_groups
)
124 it
->remaining_in_current_group
= *it
->groupings
- 1;