Replace inet_aton() with inet_pton() to parse IPs correctly (#8825)
[libi2ncommon] / src / week.cpp
... / ...
CommitLineData
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
20#include <week.hpp>
21
22#include <sstream>
23#include <stdexcept>
24
25#include <i18n.h>
26
27using namespace std;
28
29namespace I2n {
30namespace Time {
31
32/**
33 * Constructor
34 * @param daystring Active days as string. 0 is Sunday. Call is_sane() afterwards.
35 */
36Week::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 */
45Week::Week(const std::bitset<7> &days)
46 : Days(days)
47 , IsValid(true)
48{
49}
50
51/**
52 * Default constructor
53 */
54Week::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 */
63bool Week::is_valid() const
64{
65 return IsValid;
66}
67
68/**
69 * Clear all active days
70 */
71void Week::clear()
72{
73 Days.reset();
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 */
84bool 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);
96 unsigned int wnr=7;
97 if (!(c >> wnr) || wnr > 6)
98 {
99 IsValid = false;
100 return IsValid;
101 }
102
103 new_days.set(wnr);
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 */
117bool Week::set(const WeekDay day, bool value)
118{
119 if (day >= _WeekDay_END)
120 {
121 IsValid = false;
122 return IsValid;
123 }
124
125 Days.set(static_cast<size_t>(day), value);
126
127 return IsValid;
128}
129
130/**
131 * Check if a particular day is active
132 * @param day Day to check
133 * @return True if day is active, false otherwise
134 */
135bool Week::get(WeekDay day) const
136{
137 return Days.test(static_cast<size_t>(day));
138}
139
140/**
141 * Check if a particular day is active
142 * @param day Day to check
143 * @return True if day is active, false otherwise
144 */
145bool Week::is_set(WeekDay day) const
146{
147 return Days.test(static_cast<size_t>(day));
148}
149
150/**
151 * Check if all days are active
152 * @return True if all days are active, false otherwise
153 */
154bool 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 */
163bool 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*/
173unsigned int Week::days_till_set(WeekDay start) const
174{
175 if (none_set())
176 return 0;
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
190 return 0; //lint !e527
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*/
198unsigned int Week::days_since_set(WeekDay start) const
199{
200 if (none_set())
201 return 0;
202
203 for (unsigned int days=0; days < 8; days++)
204 {
205 int check=start-static_cast<int>(days);
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
215 return 0; //lint !e527
216}
217
218/**
219 * Get days as number string compatible for set() like "345".
220 * @return Days as string
221 */
222std::string Week::get_daystring() const
223{
224 ostringstream out;
225
226 for (unsigned int i = 0; i < 7; i++)
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 */
237std::string Week::get_displaystring() const
238{
239 string weekdays_str;
240
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]);
245
246 for (unsigned int i = 0; i < 7; ++i)
247 {
248 // day active?
249 if (!reordered.test(i))
250 continue;
251
252 if (!weekdays_str.empty())
253 weekdays_str += ", ";
254
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) */
270
271 return weekdays_str;
272}
273
274/**
275 * Get days as string suitable for netfilter rules
276 * @return
277 */
278std::string Week::get_netfilterstring() const
279{
280 string out;
281
282 for (unsigned int i = 0; i < 7; i++)
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 */
298std::string Week::get_day_display(WeekDay day)
299{
300 string weekday_str;
301
302 switch (day)
303 {
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;
327 } //lint !e788: Don't complain about unused _WeekDay_END
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 */
337std::string Week::get_english_display(WeekDay day)
338{
339 string weekday_str;
340
341 switch (day)
342 {
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;
366 } //lint !e788: Don't complain about unused _WeekDay_END
367
368 return weekday_str;
369}
370
371}
372}