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: renexttick.c /main/5 1996/11/21 19:46:22 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.
32 #define XOS_USE_NO_LOCKING
33 #define X_INCLUDE_TIME_H
34 #include <X11/Xos_r.h>
45 static Tick DoMinute(const Tick, const Tick, const RepeatEvent *,
47 static Tick DoDay(const Tick, const Tick, const RepeatEvent *,
49 static Tick DoWeek(const Tick, const Tick, const RepeatEvent *,
51 static Tick DoMonthDay(const Tick, const Tick, const RepeatEvent *,
53 static Tick DoMonthPos(const Tick, const Tick, const RepeatEvent *,
55 static Tick DoYearByMonth(const Tick, const Tick, const RepeatEvent *,
57 static Tick DoYearByDay(const Tick, const Tick, const RepeatEvent *,
60 static Tick NextDayTick(const Tick, const Tick, const RepeatEvent *,
62 static Tick NextWeekTick(const struct tm *, const struct tm *,
63 const RepeatEvent *, const DayTime *,
64 const MoveIndicator, RepeatEventState *);
65 static Tick NextMonthTick(const struct tm *, const RepeatEvent *,
66 const WeekDayTime *, const MoveIndicator,
68 extern void FillInRepeatEvent(const Tick, RepeatEvent *);
73 const Tick start_time,
75 RepeatEventState *res)
79 if (!re) return (Tick)NULL;
81 FillInRepeatEvent(start_time, re);
83 switch (re->re_type) {
85 next_time = DoMinute(cur_time, start_time, re, res);
88 next_time = DoDay(cur_time, start_time, re, res);
91 next_time = DoWeek(cur_time, start_time, re, res);
93 case RT_MONTHLY_POSITION:
94 next_time = DoMonthPos(cur_time, start_time, re, res);
97 next_time = DoMonthDay(cur_time, start_time, re, res);
100 next_time = DoYearByMonth(cur_time, start_time, re, res);
103 next_time = DoYearByDay(cur_time, start_time, re, res);
108 * If the duration was not set (thus strictly using the end date)
109 * reset the RepeatEventState duration back to not-set. This is
110 * cleaner than having conditionals through out the code checking
111 * to see if the duration needs to be updated.
113 if (re->re_duration == RE_NOTSET)
114 res->res_duration = RE_NOTSET;
122 const Tick start_time,
123 const RepeatEvent *re,
124 RepeatEventState *res)
132 const Tick start_time,
133 const RepeatEvent *re,
134 RepeatEventState *res)
137 Duration res_duration = res->res_duration;
138 unsigned int res_time = RES_DSTATE(res).res_time;
140 if (RE_DAILY(re)->dd_ntime) {
141 /* Last event was on the last time for this day. Now must
142 * move to the next day/interval.
144 if (RES_DSTATE(res).res_time == RE_DAILY(re)->dd_ntime - 1) {
145 next_time = NextDayTick(cur_time, start_time, re, res);
146 RES_DSTATE(res).res_time = 0;
149 _Xltimeparams localtime_buf;
151 /* There is a later valid time on this day, use it */
152 tm = _XLocaltime(&cur_time, localtime_buf);
155 dd_time[++RES_DSTATE(res).res_time] / 100;
157 RE_DAILY(re)->dd_time[RES_DSTATE(res).res_time]
160 next_time = mktime(tm);
163 /* No alternate times for this day/move to the next interval. */
164 next_time = NextDayTick(cur_time, start_time, re, res);
167 /* If we went beyond the end date then restore the state info, ret 0 */
168 if (re->re_end_date && re->re_end_date < next_time) {
169 res->res_duration = res_duration;
170 RES_DSTATE(res).res_time = res_time;
180 const Tick start_time,
181 const RepeatEvent *re,
182 RepeatEventState *res)
184 unsigned int res_daytime = RES_WSTATE(res).res_daytime,
185 res_time = RES_WSTATE(res).res_time,
187 re_ndaytime = RE_WEEKLY(re)->wd_ndaytime;
188 Duration res_duration = res->res_duration;
191 DayTime *daytime = RE_WEEKLY(re)->wd_daytime;
193 _Xltimeparams localtime_buf;
195 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
196 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
198 re_ntime = daytime[0].dt_ntime;
201 * We want to stop when the duration == 1 and we have handled all
202 * the days in the rule for that week.
204 if ((res->res_duration == 0) || ((res->res_duration == 1) &&
205 ((re_ndaytime - 1) == RES_WSTATE(res).res_daytime)))
208 /* If these are equal then we are at the end of the time
209 * slots for this day */
210 if ((re_ntime - 1) == res_time) {
211 /* If these are equal then we used up all the
212 * days for this week */
213 if ((re_ndaytime - 1) == res_daytime) {
216 RES_WSTATE(res).res_daytime = 0;
217 RES_WSTATE(res).res_time = 0;
218 next_time = NextWeekTick(&cur_tm, &start_tm, re,
219 daytime, NextInterval, res);
221 /* Move to the next day event (same week), use
224 RES_WSTATE(res).res_time = 0;
225 RES_WSTATE(res).res_daytime++;
226 next_time = NextWeekTick(&cur_tm, &start_tm, re,
227 daytime, SameInterval, res);
230 /* Move to the next time, same day. */
231 RES_WSTATE(res).res_time++;
232 next_time = NextWeekTick(&cur_tm, &start_tm, re, daytime,
236 /* If we went beyond the end date then restore the state info, ret 0 */
237 if (re->re_end_date && re->re_end_date < next_time) {
238 res->res_duration = res_duration;
239 RES_WSTATE(res).res_time = res_time;
240 RES_WSTATE(res).res_daytime = res_daytime;
250 const Tick start_time,
251 const RepeatEvent *re,
252 RepeatEventState *res)
254 unsigned int *md_days = RE_MONTHLY(re)->md_days,
255 md_nitems = RE_MONTHLY(re)->md_nitems,
256 res_day = RES_MSTATE(res).res_day;
257 Duration res_duration = res->res_duration;
261 int next_interval = FALSE;
262 _Xltimeparams localtime_buf;
264 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
265 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
268 * We want to stop when the duration == 1 and we have handled all
269 * the days listed in the rule for that month.
271 if ((res->res_duration == 0) || ((res->res_duration == 1) &&
272 ((md_nitems - 1) == RES_MSTATE(res).res_day)))
275 /* Check each event day in the month, move to the next interval when
276 * we run out of event days for the month. Make sure the event day
277 * exists in that month. e.g. the 31st of June does not exist.
280 if ((md_nitems - 1) == RES_MSTATE(res).res_day) {
281 cur_tm.tm_mon += 1 * re->re_interval;
282 RES_MSTATE(res).res_day = 0;
283 next_interval = TRUE;
285 RES_MSTATE(res).res_day++;
287 cur_tm.tm_isdst = -1;
289 _cur_time = mktime(&cur_tm);
290 cur_tm = *_XLocaltime((const time_t *)&_cur_time, localtime_buf);
291 } while (!DayExists(md_days[RES_MSTATE(res).res_day], cur_tm.tm_mon,
294 cur_tm.tm_mday = DayOfMonth(md_days[RES_MSTATE(res).res_day],
295 cur_tm.tm_mon, cur_tm.tm_year);
296 cur_tm.tm_isdst = -1;
297 _cur_time = mktime(&cur_tm);
299 if (next_interval) res->res_duration--;
301 /* If we went beyond the end date then restore the state info, ret 0 */
302 if (re->re_end_date && re->re_end_date < _cur_time) {
303 res->res_duration = res_duration;
304 RES_MSTATE(res).res_day = res_day;
314 const Tick start_time,
315 const RepeatEvent *re,
316 RepeatEventState *res)
318 WeekDayTime *wdt_list = RE_MONTHLY(re)->md_weektime;
322 Duration res_duration = res->res_duration;
323 unsigned int md_nitems = RE_MONTHLY(re)->md_nitems,
324 wdt_nday = wdt_list[md_nitems-1].wdt_nday,
325 wdt_nweek = wdt_list[md_nitems-1].wdt_nweek,
326 res_weektime = RES_MSTATE(res).res_weektime,
327 res_wday = RES_MSTATE(res).res_wday,
328 res_wtime = RES_MSTATE(res).res_wtime,
329 res_wweek = RES_MSTATE(res).res_wweek;
330 _Xltimeparams localtime_buf;
332 if (res->res_duration == 0)
335 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
336 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
338 /* XXX: This assumes rules of this form only: MP<n> 1+ WE #4 */
339 if ((wdt_list[res_weektime].wdt_nday - 1) == res_wday) {
340 if ((wdt_list[res_weektime].wdt_nweek - 1) == res_wweek) {
341 if ((md_nitems - 1) == res_weektime) {
342 RES_MSTATE(res).res_weektime = 0;
343 RES_MSTATE(res).res_wday = 0;
344 RES_MSTATE(res).res_wtime = 0;
345 RES_MSTATE(res).res_wweek = 0;
346 _cur_time = NextMonthTick(&cur_tm, re, wdt_list,
358 /* If we went beyond the end date then restore the state info, ret 0 */
359 if (re->re_end_date && re->re_end_date < _cur_time) {
360 res->res_duration = res_duration;
361 RES_MSTATE(res).res_weektime = res_weektime;
362 RES_MSTATE(res).res_wday = res_wday;
363 RES_MSTATE(res).res_wtime = res_wtime;
364 RES_MSTATE(res).res_wweek = res_wweek;
374 const Tick start_time,
375 const RepeatEvent *re,
376 RepeatEventState *res)
381 Duration res_duration = res->res_duration;
382 unsigned int *month_list = RE_YEARLY(re)->yd_items,
383 nitems = RE_YEARLY(re)->yd_nitems,
384 res_month = RES_YSTATE(res).res_daymonth;
385 _Xltimeparams localtime_buf;
387 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
388 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
391 * We want to stop when the duration == 1 and we have handled all
392 * the months listed in the rule for that year.
394 if ((res->res_duration == 0) || ((res->res_duration == 1) &&
395 ((nitems - 1) == RES_YSTATE(res).res_daymonth)))
398 cur_tm.tm_mday = start_tm.tm_mday;
399 cur_tm.tm_hour = start_tm.tm_hour;
400 cur_tm.tm_min = start_tm.tm_min;
401 cur_tm.tm_sec = start_tm.tm_sec;
403 /* If these equal then we used up all the months for this year.
404 * We must now move to the next interval.
406 if ((nitems - 1) == res_month) {
407 cur_tm.tm_year += re->re_interval;
408 cur_tm.tm_mon = month_list[0] - 1; /* 0 = January */
409 RES_YSTATE(res).res_daymonth = 0;
412 /* Take the next month in the month_list, same year */
413 cur_tm.tm_mon = month_list[++RES_YSTATE(res).res_daymonth] - 1;
416 cur_tm.tm_isdst = -1;
417 _cur_time = mktime(&cur_tm);
419 /* If we went beyond the end date then restore the state info, ret 0 */
420 if (re->re_end_date && re->re_end_date < _cur_time) {
421 res->res_duration = res_duration;
422 RES_YSTATE(res).res_daymonth = res_month;
432 const Tick start_time,
433 const RepeatEvent *re,
434 RepeatEventState *res)
439 Duration res_duration = res->res_duration;
440 unsigned int *day_list = RE_YEARLY(re)->yd_items,
441 nitems = RE_YEARLY(re)->yd_nitems,
442 res_month = RES_YSTATE(res).res_daymonth;
443 _Xltimeparams localtime_buf;
445 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
446 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
449 * We want to stop when the duration == 1 and we have handled all
450 * the days listed in the rule for that year.
452 if ((res->res_duration == 0) || ((res->res_duration == 1) &&
453 ((nitems - 1) == RES_YSTATE(res).res_daymonth)))
456 cur_tm.tm_mday = start_tm.tm_mday;
457 cur_tm.tm_hour = start_tm.tm_hour;
458 cur_tm.tm_min = start_tm.tm_min;
459 cur_tm.tm_sec = start_tm.tm_sec;
461 cur_tm.tm_isdst = -1;
463 /* If these equal then we used up all the days for this year.
464 * We must now move to the next interval.
466 if ((nitems - 1) == res_month) {
467 cur_tm.tm_year += re->re_interval;
468 cur_tm.tm_mday = day_list[0];
469 RES_YSTATE(res).res_daymonth = 0;
472 /* Take the next day in the day_list, same year */
473 cur_tm.tm_mday = day_list[++RES_YSTATE(res).res_daymonth];
476 _cur_time = mktime(&cur_tm);
478 /* If we went beyond the end date then restore the state info, ret 0 */
479 if (re->re_end_date && re->re_end_date < _cur_time) {
480 res->res_duration = res_duration;
481 RES_YSTATE(res).res_daymonth = res_month;
491 const Tick start_time,
492 const RepeatEvent *re,
493 RepeatEventState *res)
497 _Xltimeparams localtime_buf;
499 if (res->res_duration == 0) return (Tick)0;
503 start_tm = *_XLocaltime(&start_time, localtime_buf);
504 tm = _XLocaltime(&cur_time, localtime_buf);
506 tm->tm_mday += re->re_interval;
507 tm->tm_hour = start_tm.tm_hour;
508 tm->tm_min = start_tm.tm_min;
516 const struct tm *current_tm,
517 const struct tm *start_tm,
518 const RepeatEvent *re,
519 const DayTime *wd_daytime,
520 const MoveIndicator move,
521 RepeatEventState *res)
523 struct tm *cur_tm = (struct tm *)current_tm;
524 unsigned int res_daytime = RES_WSTATE(res).res_daytime;
525 unsigned int res_time = RES_WSTATE(res).res_time;
527 /* Move forward to the next interval (at least another week) */
528 if (move == (const MoveIndicator) NextInterval) {
529 /* Normalize the date to the beginning of the week. */
530 cur_tm->tm_mday -= cur_tm->tm_wday;
531 cur_tm->tm_sec = cur_tm->tm_min = cur_tm->tm_hour = 0;
532 cur_tm->tm_isdst = -1;
534 /* Add an interval */
535 cur_tm->tm_mday += re->re_interval * 7;
537 /* Put it on the correct day. */
538 cur_tm->tm_mday += wd_daytime[0].dt_day;
539 /* Put it on the correct time. */
540 cur_tm->tm_hour = wd_daytime[0].dt_time[0] / 100;
541 cur_tm->tm_min = wd_daytime[0].dt_time[0] % 100;
545 return (mktime(cur_tm));
550 /* Move the appropriate number of days forward */
551 cur_tm->tm_mday += GetWDayDiff(cur_tm->tm_wday,
552 wd_daytime[res_daytime].dt_day);
554 /* Use the indicated time if available */
555 if (RE_WEEKLY(re)->wd_daytime[res_daytime].dt_time) {
556 cur_tm->tm_hour = wd_daytime[res_daytime].dt_time[res_time]
558 cur_tm->tm_min = wd_daytime[res_daytime].dt_time[res_time]
561 /* Use the time from the first appt */
562 cur_tm->tm_hour = start_tm->tm_hour;
563 cur_tm->tm_min = start_tm->tm_min;
566 cur_tm->tm_isdst = -1;
567 return (mktime(cur_tm));
572 const struct tm *current_time,
573 const RepeatEvent *re,
574 const WeekDayTime *wdt_list,
575 const MoveIndicator move,
576 RepeatEventState *res)
578 struct tm *cur_tm = (struct tm *)current_time;
579 unsigned int res_weektime = RES_MSTATE(res).res_weektime,
580 res_wweek = RES_MSTATE(res).res_wweek,
581 res_wday = RES_MSTATE(res).res_wday;
584 /* Move forward to the next interval (at least another month) */
585 if (move == (const MoveIndicator) NextInterval) {
589 /* Add an interval */
590 cur_tm->tm_mon += re->re_interval;
591 cur_tm->tm_isdst = -1;
593 } while (!(next_time = WeekNumberToDay(mktime(cur_tm),
594 wdt_list[res_weektime].wdt_week[res_wweek],
595 wdt_list[res_weektime].wdt_day[res_wday])));