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
36 #include <X11/Xos_r.h>
38 #include <EUSCompat.h>
45 static int InitialEventsToExclude(time_t, RepeatEvent *);
46 static int EventsPerMonth(RepeatEvent *);
47 static int DoBruteForce(const time_t, RepeatEvent *);
50 * Give a start time, a parsed rule and a list of exception dates, determine
51 * the number of events that will be generated.
57 CSA_date_time_entry *dte)
61 int excluded_days = 0;
62 unsigned int nevents1 = (unsigned int)-1,
63 nevents2 = (unsigned int)-1;
65 if (!re || !start_time) return RE_ERROR;
67 if (!re->re_end_date && re->re_duration == RE_INFINITY)
71 * Count the number of times an excluded time hits an event time
72 * generated by the rule.
74 for (; dte; dte = dte->next) {
75 RepeatEventState *res;
77 if (_csa_iso8601_to_tick(dte->date_time, &exclude_time) == -1)
80 if (!(close_time = ClosestTick(exclude_time, start_time, re,
84 last_time = LastTick(start_time, re);
85 if (last_time == exclude_time)
88 if (close_time == exclude_time)
92 _DtCm_free_re_state(res);
96 * If there is an end date, then we must calculate the total number
97 * of events via the brute force method.
99 if (re->re_end_date) {
100 nevents1 = DoBruteForce(start_time, re) - excluded_days;
103 if (re->re_duration == RE_NOTSET)
106 switch (re->re_type) {
110 nevents2 = re->re_duration;
113 if (!RE_WEEKLY(re)->wd_ndaytime)
114 nevents2 = re->re_duration;
116 nevents2 = re->re_duration *
117 RE_WEEKLY(re)->wd_ndaytime;
119 nevents2 -= InitialEventsToExclude(start_time, re);
121 case RT_MONTHLY_POSITION: {
122 int events_per_month = EventsPerMonth(re);
124 if (!events_per_month) {
125 nevents2 = DoBruteForce(start_time, re);
127 nevents2 = re->re_duration * events_per_month -
128 InitialEventsToExclude(start_time, re);
132 case RT_MONTHLY_DAY: {
133 int ndays = RE_MONTHLY(re)->md_nitems;
135 _Xltimeparams localtime_buf;
137 start_tm = _XLocaltime((const time_t *)&start_time, localtime_buf);
139 * Need to do this by brute force if they want days that may
140 * not exist in a given month.
142 if (((!ndays) && start_tm->tm_mday > 28) ||
143 (ndays && RE_MONTHLY(re)->md_days[ndays - 1] > 28)) {
144 nevents2 = DoBruteForce(start_time, re);
147 nevents2 = re->re_duration;
149 nevents2 = re->re_duration * ndays;
151 nevents2 -= InitialEventsToExclude(start_time, re);
155 case RT_YEARLY_MONTH:
156 if (!RE_YEARLY(re)->yd_nitems)
157 nevents2 = re->re_duration;
159 nevents2 = re->re_duration *
160 RE_YEARLY(re)->yd_nitems;
161 nevents2 -= InitialEventsToExclude(start_time, re);
164 if (!RE_YEARLY(re)->yd_nitems)
165 nevents2 = re->re_duration;
167 nevents2 = re->re_duration *
168 RE_YEARLY(re)->yd_nitems;
169 nevents2 -= InitialEventsToExclude(start_time, re);
173 nevents2 -= excluded_days;
176 * If both a duration and and enddate are set the policy is to use
177 * the lesser of the two.
179 if (nevents1 < nevents2)
186 * If the rule is a weekly or monthly style with specific weekdays listed,
187 * such as W1 MO WE FR and the start_time indicates the rule starts on say a
188 * WE, then the first MO would not count as an event day so it must be
189 * excluded from the total count.
192 InitialEventsToExclude(
197 _Xltimeparams localtime_buf;
199 start_tm = _XLocaltime((const time_t *)&start_time, localtime_buf);
201 if (re->re_type == RT_WEEKLY) {
202 DayTime *daytime = (DayTime *)RE_WEEKLY(re)->wd_daytime;
203 int nevent_days = RE_WEEKLY(re)->wd_ndaytime,
206 if (!nevent_days) return 0;
208 for (i = 0; i < nevent_days; i++) {
209 if (daytime[i].dt_day >= start_tm->tm_wday)
212 return (nevent_days);
213 } else if (re->re_type == RT_MONTHLY_POSITION) {
214 WeekDayTime *wdt = (WeekDayTime *)RE_MONTHLY(re)->md_weektime;
218 for (i = 0; i < RE_MONTHLY(re)->md_nitems; i++) {
223 j < RE_MONTHLY(re)->md_weektime[i].wdt_nweek;
227 k < RE_MONTHLY(re)->md_weektime[i].wdt_nday;
230 date = WeekNumberToDay(start_time,
231 RE_MONTHLY(re)->md_weektime[i].
233 RE_MONTHLY(re)->md_weektime[i].
235 if (!date || date < start_time)
241 } else if (re->re_type == RT_MONTHLY_DAY) {
244 if (!RE_MONTHLY(re)->md_nitems) return 0;
246 for (i = 0; i < RE_MONTHLY(re)->md_nitems; i++) {
247 if (RE_MONTHLY(re)->md_days[i] >= start_tm->tm_mday)
250 return (RE_MONTHLY(re)->md_nitems);
251 } else if (re->re_type == RT_YEARLY_MONTH) {
254 if (!RE_YEARLY(re)->yd_nitems) return 0;
256 for (i = 0; i < RE_YEARLY(re)->yd_nitems; i++) {
257 if (RE_YEARLY(re)->yd_items[i] >= (start_tm->tm_mon +1))
260 return (RE_YEARLY(re)->yd_nitems);
261 } else if (re->re_type == RT_YEARLY_DAY) {
264 if (!RE_YEARLY(re)->yd_nitems) return 0;
266 for (i = 0; i < RE_YEARLY(re)->yd_nitems; i++) {
267 if (RE_YEARLY(re)->yd_items[i] >=
268 (start_tm->tm_yday + 1))
271 return (RE_YEARLY(re)->yd_nitems);
278 * Given a parsed MP rule determine the number of events it would generate
279 * in a month. If the rule suggests events should occure on the 5th week
280 * which means the number of events generated in a given month is not
281 * constant, we return 0.
290 for (i = 0, nevents = 0; i < RE_MONTHLY(re)->md_nitems; i++) {
293 /* If 5+ or 5- is used, we must compute count by brute force */
294 for (j = 0; j < RE_MONTHLY(re)->md_weektime[i].wdt_nweek; j++) {
295 if ((RE_MONTHLY(re)->md_weektime[i].wdt_week[j] ==
297 (RE_MONTHLY(re)->md_weektime[i].wdt_week[j] ==
302 nevents += RE_MONTHLY(re)->md_weektime[i].wdt_nday *
303 RE_MONTHLY(re)->md_weektime[i].wdt_nweek;
310 * Given a start time and a parsed rule determine the number events generated
311 * by walking the event stream until we reach the end.
315 const time_t start_time,
318 RepeatEventState *res;
323 if (!(cur_time = ClosestTick(start_time, start_time, re, &res)))
328 while ((cur_time = NextTick(cur_time, start_time, re, res))) {
332 _DtCm_free_re_state(res);