2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: recount.c /main/6 1996/11/21 19:45:46 drk $ */
25 * (c) Copyright 1993, 1994 Hewlett-Packard Company
26 * (c) Copyright 1993, 1994 International Business Machines Corp.
27 * (c) Copyright 1993, 1994 Novell, Inc.
28 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
31 #define XOS_USE_NO_LOCKING
32 #define X_INCLUDE_TIME_H
33 #include <X11/Xos_r.h>
35 #include <EUSCompat.h>
42 static int InitialEventsToExclude(time_t, RepeatEvent *);
43 static int EventsPerMonth(RepeatEvent *);
44 static int DoBruteForce(const time_t, RepeatEvent *);
47 * Give a start time, a parsed rule and a list of exception dates, determine
48 * the number of events that will be generated.
54 CSA_date_time_entry *dte)
58 int excluded_days = 0;
59 unsigned int nevents1 = (unsigned int)-1,
60 nevents2 = (unsigned int)-1;
62 if (!re || !start_time) return RE_ERROR;
64 if (!re->re_end_date && re->re_duration == RE_INFINITY)
68 * Count the number of times an excluded time hits an event time
69 * generated by the rule.
71 for (; dte; dte = dte->next) {
72 RepeatEventState *res;
74 if (_csa_iso8601_to_tick(dte->date_time, &exclude_time) == -1)
77 if (!(close_time = ClosestTick(exclude_time, start_time, re,
81 last_time = LastTick(start_time, re);
82 if (last_time == exclude_time)
85 if (close_time == exclude_time)
89 _DtCm_free_re_state(res);
93 * If there is an end date, then we must calculate the total number
94 * of events via the brute force method.
96 if (re->re_end_date) {
97 nevents1 = DoBruteForce(start_time, re) - excluded_days;
100 if (re->re_duration == RE_NOTSET)
103 switch (re->re_type) {
107 nevents2 = re->re_duration;
110 if (!RE_WEEKLY(re)->wd_ndaytime)
111 nevents2 = re->re_duration;
113 nevents2 = re->re_duration *
114 RE_WEEKLY(re)->wd_ndaytime;
116 nevents2 -= InitialEventsToExclude(start_time, re);
118 case RT_MONTHLY_POSITION: {
119 int events_per_month = EventsPerMonth(re);
121 if (!events_per_month) {
122 nevents2 = DoBruteForce(start_time, re);
124 nevents2 = re->re_duration * events_per_month -
125 InitialEventsToExclude(start_time, re);
129 case RT_MONTHLY_DAY: {
130 int ndays = RE_MONTHLY(re)->md_nitems;
132 _Xltimeparams localtime_buf;
134 start_tm = _XLocaltime((const time_t *)&start_time, localtime_buf);
136 * Need to do this by brute force if they want days that may
137 * not exist in a given month.
139 if (((!ndays) && start_tm->tm_mday > 28) ||
140 (ndays && RE_MONTHLY(re)->md_days[ndays - 1] > 28)) {
141 nevents2 = DoBruteForce(start_time, re);
144 nevents2 = re->re_duration;
146 nevents2 = re->re_duration * ndays;
148 nevents2 -= InitialEventsToExclude(start_time, re);
152 case RT_YEARLY_MONTH:
153 if (!RE_YEARLY(re)->yd_nitems)
154 nevents2 = re->re_duration;
156 nevents2 = re->re_duration *
157 RE_YEARLY(re)->yd_nitems;
158 nevents2 -= InitialEventsToExclude(start_time, re);
161 if (!RE_YEARLY(re)->yd_nitems)
162 nevents2 = re->re_duration;
164 nevents2 = re->re_duration *
165 RE_YEARLY(re)->yd_nitems;
166 nevents2 -= InitialEventsToExclude(start_time, re);
170 nevents2 -= excluded_days;
173 * If both a duration and and enddate are set the policy is to use
174 * the lesser of the two.
176 if (nevents1 < nevents2)
183 * If the rule is a weekly or monthly style with specific weekdays listed,
184 * such as W1 MO WE FR and the start_time indicates the rule starts on say a
185 * WE, then the first MO would not count as an event day so it must be
186 * excluded from the total count.
189 InitialEventsToExclude(
194 _Xltimeparams localtime_buf;
196 start_tm = _XLocaltime((const time_t *)&start_time, localtime_buf);
198 if (re->re_type == RT_WEEKLY) {
199 DayTime *daytime = (DayTime *)RE_WEEKLY(re)->wd_daytime;
200 int nevent_days = RE_WEEKLY(re)->wd_ndaytime,
203 if (!nevent_days) return 0;
205 for (i = 0; i < nevent_days; i++) {
206 if (daytime[i].dt_day >= start_tm->tm_wday)
209 return (nevent_days);
210 } else if (re->re_type == RT_MONTHLY_POSITION) {
211 WeekDayTime *wdt = (WeekDayTime *)RE_MONTHLY(re)->md_weektime;
215 for (i = 0; i < RE_MONTHLY(re)->md_nitems; i++) {
220 j < RE_MONTHLY(re)->md_weektime[i].wdt_nweek;
224 k < RE_MONTHLY(re)->md_weektime[i].wdt_nday;
227 date = WeekNumberToDay(start_time,
228 RE_MONTHLY(re)->md_weektime[i].
230 RE_MONTHLY(re)->md_weektime[i].
232 if (!date || date < start_time)
238 } else if (re->re_type == RT_MONTHLY_DAY) {
241 if (!RE_MONTHLY(re)->md_nitems) return 0;
243 for (i = 0; i < RE_MONTHLY(re)->md_nitems; i++) {
244 if (RE_MONTHLY(re)->md_days[i] >= start_tm->tm_mday)
247 return (RE_MONTHLY(re)->md_nitems);
248 } else if (re->re_type == RT_YEARLY_MONTH) {
251 if (!RE_YEARLY(re)->yd_nitems) return 0;
253 for (i = 0; i < RE_YEARLY(re)->yd_nitems; i++) {
254 if (RE_YEARLY(re)->yd_items[i] >= (start_tm->tm_mon +1))
257 return (RE_YEARLY(re)->yd_nitems);
258 } else if (re->re_type == RT_YEARLY_DAY) {
261 if (!RE_YEARLY(re)->yd_nitems) return 0;
263 for (i = 0; i < RE_YEARLY(re)->yd_nitems; i++) {
264 if (RE_YEARLY(re)->yd_items[i] >=
265 (start_tm->tm_yday + 1))
268 return (RE_YEARLY(re)->yd_nitems);
275 * Given a parsed MP rule determine the number of events it would generate
276 * in a month. If the rule suggests events should occure on the 5th week
277 * which means the number of events generated in a given month is not
278 * constant, we return 0.
287 for (i = 0, nevents = 0; i < RE_MONTHLY(re)->md_nitems; i++) {
290 /* If 5+ or 5- is used, we must compute count by brute force */
291 for (j = 0; j < RE_MONTHLY(re)->md_weektime[i].wdt_nweek; j++) {
292 if ((RE_MONTHLY(re)->md_weektime[i].wdt_week[j] ==
294 (RE_MONTHLY(re)->md_weektime[i].wdt_week[j] ==
299 nevents += RE_MONTHLY(re)->md_weektime[i].wdt_nday *
300 RE_MONTHLY(re)->md_weektime[i].wdt_nweek;
307 * Given a start time and a parsed rule determine the number events generated
308 * by walking the event stream until we reach the end.
312 const time_t start_time,
315 RepeatEventState *res;
320 if (!(cur_time = ClosestTick(start_time, start_time, re, &res)))
325 while ((cur_time = NextTick(cur_time, start_time, re, res))) {
329 _DtCm_free_re_state(res);