Commit | Line | Data |
---|---|---|
0e23f538 TJ |
1 | /* |
2 | The software in this package is distributed under the GNU General | |
3 | Public License version 2 (with a special exception described below). | |
4 | ||
5 | A copy of GNU General Public License (GPL) is included in this distribution, | |
6 | in the file COPYING.GPL. | |
7 | ||
8 | As a special exception, if other files instantiate templates or use macros | |
9 | or inline functions from this file, or you compile this file and link it | |
10 | with other works to produce a work based on this file, this file | |
11 | does not by itself cause the resulting work to be covered | |
12 | by the GNU General Public License. | |
13 | ||
14 | However the source code for this file must still be made available | |
15 | in accordance with section (3) of the GNU General Public License. | |
16 | ||
17 | This exception does not invalidate any other reasons why a work based | |
18 | on this file might be covered by the GNU General Public License. | |
19 | */ | |
0c7e72d7 TJ |
20 | #include <week.hpp> |
21 | ||
22 | #include <sstream> | |
23 | #include <stdexcept> | |
24 | ||
25 | #include <i18n.h> | |
26 | ||
27 | using namespace std; | |
28 | ||
29 | namespace I2n { | |
30 | namespace Time { | |
31 | ||
32 | /** | |
33 | * Constructor | |
34 | * @param daystring Active days as string. 0 is Sunday. Call is_sane() afterwards. | |
35 | */ | |
36 | Week::Week(const std::string& daystring) | |
37 | { | |
38 | IsValid = set(daystring); | |
39 | } | |
40 | ||
41 | /** | |
42 | * Constructor | |
43 | * @param days Active days as bitset. 0 is Sunday | |
44 | */ | |
45 | Week::Week(const std::bitset<7> &days) | |
46 | : Days(days) | |
47 | , IsValid(true) | |
48 | { | |
49 | } | |
50 | ||
51 | /** | |
52 | * Default constructor | |
53 | */ | |
54 | Week::Week() | |
55 | : IsValid(true) | |
56 | { | |
57 | } | |
58 | ||
59 | /** | |
60 | * Check if this Week object is valid, f.e. after set(). | |
61 | * @return True if valid, false otherwise | |
62 | */ | |
63 | bool Week::is_valid() const | |
64 | { | |
65 | return IsValid; | |
66 | } | |
67 | ||
68 | /** | |
69 | * Clear all active days | |
70 | */ | |
71 | void Week::clear() | |
72 | { | |
8047e088 | 73 | Days.reset(); |
0c7e72d7 TJ |
74 | IsValid = true; |
75 | } | |
76 | ||
77 | /** | |
78 | * Set active days as string. Clears unset values. | |
79 | * Active days will remain untouched if there's an error | |
80 | * which you can query via is_valid(). | |
81 | * @param daystring Active days as string | |
82 | * @return True if all is fine, false otherwise | |
83 | */ | |
84 | bool Week::set(const std::string& daystring) | |
85 | { | |
86 | bitset<7> new_days; | |
87 | IsValid = true; | |
88 | ||
89 | string::size_type len=daystring.length(); | |
90 | for (string::size_type p=0; p < len; p++) | |
91 | { | |
92 | char nr[2]; | |
93 | nr[0]=daystring[p]; | |
94 | nr[1]=0; | |
95 | istringstream c(nr); | |
12963590 TJ |
96 | unsigned int wnr=7; |
97 | if (!(c >> wnr) || wnr > 6) | |
0c7e72d7 TJ |
98 | { |
99 | IsValid = false; | |
100 | return IsValid; | |
101 | } | |
102 | ||
8047e088 | 103 | new_days.set(wnr); |
0c7e72d7 TJ |
104 | } |
105 | // Atomic switch-over | |
106 | Days = new_days; | |
107 | ||
108 | return IsValid; | |
109 | } | |
110 | ||
111 | /** | |
112 | * Set or disable one weekday. | |
113 | * @param day Day to modify | |
114 | * @param value True for active, false to disable | |
115 | * @return True if all is fine, false otherwise | |
116 | */ | |
117 | bool Week::set(const WeekDay day, bool value) | |
118 | { | |
12963590 | 119 | if (day >= _WeekDay_END) |
0c7e72d7 TJ |
120 | { |
121 | IsValid = false; | |
122 | return IsValid; | |
123 | } | |
124 | ||
8047e088 | 125 | Days.set(static_cast<size_t>(day), value); |
12963590 | 126 | |
0c7e72d7 TJ |
127 | return IsValid; |
128 | } | |
129 | ||
130 | /** | |
131 | * Check if a particular day is active | |
3438e43a | 132 | * @param day Day to check |
0c7e72d7 TJ |
133 | * @return True if day is active, false otherwise |
134 | */ | |
135 | bool Week::get(WeekDay day) const | |
136 | { | |
12963590 | 137 | return Days.test(static_cast<size_t>(day)); |
0c7e72d7 TJ |
138 | } |
139 | ||
140 | /** | |
141 | * Check if a particular day is active | |
3438e43a | 142 | * @param day Day to check |
0c7e72d7 TJ |
143 | * @return True if day is active, false otherwise |
144 | */ | |
145 | bool Week::is_set(WeekDay day) const | |
146 | { | |
12963590 | 147 | return Days.test(static_cast<size_t>(day)); |
0c7e72d7 TJ |
148 | } |
149 | ||
150 | /** | |
151 | * Check if all days are active | |
152 | * @return True if all days are active, false otherwise | |
153 | */ | |
154 | bool Week::all_set() const | |
155 | { | |
156 | return (Days.count()==7); | |
157 | } | |
158 | ||
159 | /** | |
160 | * Check if no days is active | |
161 | * @return True if no day is active, false otherwise | |
162 | */ | |
163 | bool Week::none_set() const | |
164 | { | |
165 | return Days.none(); | |
166 | } | |
167 | ||
168 | /** | |
169 | @brief returns the number of days till the next weekday which is set | |
170 | @param start weekday to start checking | |
171 | @note returns 0 if the start-day is set | |
172 | */ | |
12963590 | 173 | unsigned int Week::days_till_set(WeekDay start) const |
0c7e72d7 TJ |
174 | { |
175 | if (none_set()) | |
12963590 | 176 | return 0; |
0c7e72d7 TJ |
177 | |
178 | for (unsigned int days=0; days < 8; days++) | |
179 | { | |
180 | unsigned int check=start+days; | |
181 | if (check > 6) | |
182 | check-=7; | |
183 | if (is_set(static_cast<WeekDay>(check))) | |
184 | return days; | |
185 | } | |
186 | ||
187 | throw logic_error("can't find next weekday"); | |
188 | ||
189 | // fake | |
12963590 | 190 | return 0; //lint !e527 |
0c7e72d7 TJ |
191 | } |
192 | ||
193 | /** | |
194 | @brief returns the number of days since the previous weekday which is set | |
195 | @param start weekday to start checking | |
196 | @note returns 0 if the start-day is set | |
197 | */ | |
12963590 | 198 | unsigned int Week::days_since_set(WeekDay start) const |
0c7e72d7 TJ |
199 | { |
200 | if (none_set()) | |
12963590 | 201 | return 0; |
0c7e72d7 TJ |
202 | |
203 | for (unsigned int days=0; days < 8; days++) | |
204 | { | |
12963590 | 205 | int check=start-static_cast<int>(days); |
0c7e72d7 TJ |
206 | if (check < 0) |
207 | check+=7; | |
208 | if (is_set(static_cast<WeekDay>(check))) | |
209 | return days; | |
210 | } | |
211 | ||
212 | throw logic_error("can't find next weekday"); | |
213 | ||
214 | // fake | |
12963590 | 215 | return 0; //lint !e527 |
0c7e72d7 TJ |
216 | } |
217 | ||
218 | /** | |
219 | * Get days as number string compatible for set() like "345". | |
220 | * @return Days as string | |
221 | */ | |
222 | std::string Week::get_daystring() const | |
223 | { | |
224 | ostringstream out; | |
225 | ||
12963590 | 226 | for (unsigned int i = 0; i < 7; i++) |
0c7e72d7 TJ |
227 | if (Days[i]) |
228 | out << i; | |
229 | ||
230 | return out.str(); | |
231 | } | |
232 | ||
233 | /** | |
234 | * Get days as string presentable to the user | |
235 | * @return Days as string | |
236 | */ | |
237 | std::string Week::get_displaystring() const | |
238 | { | |
239 | string weekdays_str; | |
240 | ||
8047e088 TJ |
241 | // We want to display from Monday to Sunday so reorder |
242 | // the bitset and make monday bit 0 and sunday bit 6. | |
243 | bitset<7> reordered = Days >> 1; | |
244 | reordered.set(6, Days[0]); | |
0c7e72d7 | 245 | |
8047e088 | 246 | for (unsigned int i = 0; i < 7; ++i) |
0c7e72d7 | 247 | { |
8047e088 TJ |
248 | // day active? |
249 | if (!reordered.test(i)) | |
250 | continue; | |
251 | ||
0c7e72d7 TJ |
252 | if (!weekdays_str.empty()) |
253 | weekdays_str += ", "; | |
254 | ||
8047e088 TJ |
255 | // get day string (revert the reorder) |
256 | weekdays_str += get_day_display(i == 6 ? Su : static_cast<WeekDay>(i+1)); | |
257 | ||
258 | // check if we can group two or more days | |
259 | unsigned int group_days = i; | |
260 | while (group_days < 6 && reordered.test(group_days+1)) | |
261 | group_days++; | |
262 | ||
263 | // Were we able to group two or more days? | |
264 | if (group_days > i+1) | |
265 | { | |
266 | i = group_days; | |
267 | weekdays_str += "-" + get_day_display(i == 6 ? Su : static_cast<WeekDay>(i+1)); | |
268 | } | |
269 | } /*lint --e(850) */ | |
0c7e72d7 TJ |
270 | |
271 | return weekdays_str; | |
272 | } | |
273 | ||
274 | /** | |
275 | * Get days as string suitable for netfilter rules | |
276 | * @return | |
277 | */ | |
278 | std::string Week::get_netfilterstring() const | |
279 | { | |
280 | string out; | |
281 | ||
12963590 | 282 | for (unsigned int i = 0; i < 7; i++) |
0c7e72d7 TJ |
283 | if (Days[i]) |
284 | { | |
285 | if (!out.empty()) | |
286 | out+=","; | |
287 | out+=get_english_display(static_cast<WeekDay>(i));; | |
288 | } | |
289 | ||
290 | return out; | |
291 | } | |
292 | ||
293 | /** | |
294 | * Convert WeekDay to readable string | |
295 | * @param day WeekDay to convert | |
296 | * @return Weekday as string | |
297 | */ | |
298 | std::string Week::get_day_display(WeekDay day) | |
299 | { | |
300 | string weekday_str; | |
301 | ||
12963590 TJ |
302 | switch (day) |
303 | { | |
0c7e72d7 TJ |
304 | case Mo: |
305 | weekday_str = i18n("Mon"); | |
306 | break; | |
307 | case Tu: | |
308 | weekday_str = i18n("Tue"); | |
309 | break; | |
310 | case We: | |
311 | weekday_str = i18n("Wed"); | |
312 | break; | |
313 | case Th: | |
314 | weekday_str = i18n("Thu"); | |
315 | break; | |
316 | case Fr: | |
317 | weekday_str = i18n("Fri"); | |
318 | break; | |
319 | case Sa: | |
320 | weekday_str = i18n("Sat"); | |
321 | break; | |
322 | case Su: | |
323 | weekday_str = i18n("Sun"); | |
324 | break; | |
325 | default: | |
326 | break; | |
12963590 | 327 | } //lint !e788: Don't complain about unused _WeekDay_END |
0c7e72d7 TJ |
328 | |
329 | return weekday_str; | |
330 | } | |
331 | ||
332 | /** | |
333 | * Convert WeekDay to readable string without i18n | |
334 | * @param day WeekDay to convert | |
335 | * @return WeekDay as string in English | |
336 | */ | |
337 | std::string Week::get_english_display(WeekDay day) | |
338 | { | |
339 | string weekday_str; | |
340 | ||
12963590 TJ |
341 | switch (day) |
342 | { | |
0c7e72d7 TJ |
343 | case Mo: |
344 | weekday_str = "Mon"; | |
345 | break; | |
346 | case Tu: | |
347 | weekday_str = "Tue"; | |
348 | break; | |
349 | case We: | |
350 | weekday_str = "Wed"; | |
351 | break; | |
352 | case Th: | |
353 | weekday_str = "Thu"; | |
354 | break; | |
355 | case Fr: | |
356 | weekday_str = "Fri"; | |
357 | break; | |
358 | case Sa: | |
359 | weekday_str = "Sat"; | |
360 | break; | |
361 | case Su: | |
362 | weekday_str = "Sun"; | |
363 | break; | |
364 | default: | |
365 | break; | |
12963590 | 366 | } //lint !e788: Don't complain about unused _WeekDay_END |
0c7e72d7 TJ |
367 | |
368 | return weekday_str; | |
369 | } | |
370 | ||
371 | } | |
372 | } |