1 /* $XConsortium: renexttick.c /main/5 1996/11/21 19:46:22 drk $ */
3 * (c) Copyright 1993, 1994 Hewlett-Packard Company
4 * (c) Copyright 1993, 1994 International Business Machines Corp.
5 * (c) Copyright 1993, 1994 Novell, Inc.
6 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
10 #define XOS_USE_NO_LOCKING
11 #define X_INCLUDE_TIME_H
12 #include <X11/Xos_r.h>
23 static Tick DoMinute(const Tick, const Tick, const RepeatEvent *,
25 static Tick DoDay(const Tick, const Tick, const RepeatEvent *,
27 static Tick DoWeek(const Tick, const Tick, const RepeatEvent *,
29 static Tick DoMonthDay(const Tick, const Tick, const RepeatEvent *,
31 static Tick DoMonthPos(const Tick, const Tick, const RepeatEvent *,
33 static Tick DoYearByMonth(const Tick, const Tick, const RepeatEvent *,
35 static Tick DoYearByDay(const Tick, const Tick, const RepeatEvent *,
38 static Tick NextDayTick(const Tick, const Tick, const RepeatEvent *,
40 static Tick NextWeekTick(const struct tm *, const struct tm *,
41 const RepeatEvent *, const DayTime *,
42 const MoveIndicator, RepeatEventState *);
43 static Tick NextMonthTick(const struct tm *, const RepeatEvent *,
44 const WeekDayTime *, const MoveIndicator,
46 extern void FillInRepeatEvent(const Tick, RepeatEvent *);
51 const Tick start_time,
53 RepeatEventState *res)
57 if (!re) return (Tick)NULL;
59 FillInRepeatEvent(start_time, re);
61 switch (re->re_type) {
63 next_time = DoMinute(cur_time, start_time, re, res);
66 next_time = DoDay(cur_time, start_time, re, res);
69 next_time = DoWeek(cur_time, start_time, re, res);
71 case RT_MONTHLY_POSITION:
72 next_time = DoMonthPos(cur_time, start_time, re, res);
75 next_time = DoMonthDay(cur_time, start_time, re, res);
78 next_time = DoYearByMonth(cur_time, start_time, re, res);
81 next_time = DoYearByDay(cur_time, start_time, re, res);
86 * If the duration was not set (thus strictly using the end date)
87 * reset the RepeatEventState duration back to not-set. This is
88 * cleaner than having conditionals through out the code checking
89 * to see if the duration needs to be updated.
91 if (re->re_duration == RE_NOTSET)
92 res->res_duration = RE_NOTSET;
100 const Tick start_time,
101 const RepeatEvent *re,
102 RepeatEventState *res)
110 const Tick start_time,
111 const RepeatEvent *re,
112 RepeatEventState *res)
115 Duration res_duration = res->res_duration;
116 unsigned int res_time = RES_DSTATE(res).res_time;
118 if (RE_DAILY(re)->dd_ntime) {
119 /* Last event was on the last time for this day. Now must
120 * move to the next day/interval.
122 if (RES_DSTATE(res).res_time == RE_DAILY(re)->dd_ntime - 1) {
123 next_time = NextDayTick(cur_time, start_time, re, res);
124 RES_DSTATE(res).res_time = 0;
127 _Xltimeparams localtime_buf;
129 /* There is a later valid time on this day, use it */
130 tm = _XLocaltime(&cur_time, localtime_buf);
133 dd_time[++RES_DSTATE(res).res_time] / 100;
135 RE_DAILY(re)->dd_time[RES_DSTATE(res).res_time]
138 next_time = mktime(tm);
141 /* No alternate times for this day/move to the next interval. */
142 next_time = NextDayTick(cur_time, start_time, re, res);
145 /* If we went beyond the end date then restore the state info, ret 0 */
146 if (re->re_end_date && re->re_end_date < next_time) {
147 res->res_duration = res_duration;
148 RES_DSTATE(res).res_time = res_time;
158 const Tick start_time,
159 const RepeatEvent *re,
160 RepeatEventState *res)
162 unsigned int res_daytime = RES_WSTATE(res).res_daytime,
163 res_time = RES_WSTATE(res).res_time,
165 re_ndaytime = RE_WEEKLY(re)->wd_ndaytime;
166 Duration res_duration = res->res_duration;
169 DayTime *daytime = RE_WEEKLY(re)->wd_daytime;
171 _Xltimeparams localtime_buf;
173 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
174 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
176 re_ntime = daytime[0].dt_ntime;
179 * We want to stop when the duration == 1 and we have handled all
180 * the days in the rule for that week.
182 if ((res->res_duration == 0) || ((res->res_duration == 1) &&
183 ((re_ndaytime - 1) == RES_WSTATE(res).res_daytime)))
186 /* If these are equal then we are at the end of the time
187 * slots for this day */
188 if ((re_ntime - 1) == res_time) {
189 /* If these are equal then we used up all the
190 * days for this week */
191 if ((re_ndaytime - 1) == res_daytime) {
194 RES_WSTATE(res).res_daytime = 0;
195 RES_WSTATE(res).res_time = 0;
196 next_time = NextWeekTick(&cur_tm, &start_tm, re,
197 daytime, NextInterval, res);
199 /* Move to the next day event (same week), use
202 RES_WSTATE(res).res_time = 0;
203 RES_WSTATE(res).res_daytime++;
204 next_time = NextWeekTick(&cur_tm, &start_tm, re,
205 daytime, SameInterval, res);
208 /* Move to the next time, same day. */
209 RES_WSTATE(res).res_time++;
210 next_time = NextWeekTick(&cur_tm, &start_tm, re, daytime,
214 /* If we went beyond the end date then restore the state info, ret 0 */
215 if (re->re_end_date && re->re_end_date < next_time) {
216 res->res_duration = res_duration;
217 RES_WSTATE(res).res_time = res_time;
218 RES_WSTATE(res).res_daytime = res_daytime;
228 const Tick start_time,
229 const RepeatEvent *re,
230 RepeatEventState *res)
232 unsigned int *md_days = RE_MONTHLY(re)->md_days,
233 md_nitems = RE_MONTHLY(re)->md_nitems,
234 res_day = RES_MSTATE(res).res_day;
235 Duration res_duration = res->res_duration;
239 int next_interval = FALSE;
240 _Xltimeparams localtime_buf;
242 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
243 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
246 * We want to stop when the duration == 1 and we have handled all
247 * the days listed in the rule for that month.
249 if ((res->res_duration == 0) || ((res->res_duration == 1) &&
250 ((md_nitems - 1) == RES_MSTATE(res).res_day)))
253 /* Check each event day in the month, move to the next interval when
254 * we run out of event days for the month. Make sure the event day
255 * exists in that month. e.g. the 31st of June does not exist.
258 if ((md_nitems - 1) == RES_MSTATE(res).res_day) {
259 cur_tm.tm_mon += 1 * re->re_interval;
260 RES_MSTATE(res).res_day = 0;
261 next_interval = TRUE;
263 RES_MSTATE(res).res_day++;
265 cur_tm.tm_isdst = -1;
267 _cur_time = mktime(&cur_tm);
268 cur_tm = *_XLocaltime((const time_t *)&_cur_time, localtime_buf);
269 } while (!DayExists(md_days[RES_MSTATE(res).res_day], cur_tm.tm_mon,
272 cur_tm.tm_mday = DayOfMonth(md_days[RES_MSTATE(res).res_day],
273 cur_tm.tm_mon, cur_tm.tm_year);
274 cur_tm.tm_isdst = -1;
275 _cur_time = mktime(&cur_tm);
277 if (next_interval) res->res_duration--;
279 /* If we went beyond the end date then restore the state info, ret 0 */
280 if (re->re_end_date && re->re_end_date < _cur_time) {
281 res->res_duration = res_duration;
282 RES_MSTATE(res).res_day = res_day;
292 const Tick start_time,
293 const RepeatEvent *re,
294 RepeatEventState *res)
296 WeekDayTime *wdt_list = RE_MONTHLY(re)->md_weektime;
300 Duration res_duration = res->res_duration;
301 unsigned int md_nitems = RE_MONTHLY(re)->md_nitems,
302 wdt_nday = wdt_list[md_nitems-1].wdt_nday,
303 wdt_nweek = wdt_list[md_nitems-1].wdt_nweek,
304 res_weektime = RES_MSTATE(res).res_weektime,
305 res_wday = RES_MSTATE(res).res_wday,
306 res_wtime = RES_MSTATE(res).res_wtime,
307 res_wweek = RES_MSTATE(res).res_wweek;
308 _Xltimeparams localtime_buf;
310 if (res->res_duration == 0)
313 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
314 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
316 /* XXX: This assumes rules of this form only: MP<n> 1+ WE #4 */
317 if ((wdt_list[res_weektime].wdt_nday - 1) == res_wday) {
318 if ((wdt_list[res_weektime].wdt_nweek - 1) == res_wweek) {
319 if ((md_nitems - 1) == res_weektime) {
320 RES_MSTATE(res).res_weektime = 0;
321 RES_MSTATE(res).res_wday = 0;
322 RES_MSTATE(res).res_wtime = 0;
323 RES_MSTATE(res).res_wweek = 0;
324 _cur_time = NextMonthTick(&cur_tm, re, wdt_list,
336 /* If we went beyond the end date then restore the state info, ret 0 */
337 if (re->re_end_date && re->re_end_date < _cur_time) {
338 res->res_duration = res_duration;
339 RES_MSTATE(res).res_weektime = res_weektime;
340 RES_MSTATE(res).res_wday = res_wday;
341 RES_MSTATE(res).res_wtime = res_wtime;
342 RES_MSTATE(res).res_wweek = res_wweek;
352 const Tick start_time,
353 const RepeatEvent *re,
354 RepeatEventState *res)
359 Duration res_duration = res->res_duration;
360 unsigned int *month_list = RE_YEARLY(re)->yd_items,
361 nitems = RE_YEARLY(re)->yd_nitems,
362 res_month = RES_YSTATE(res).res_daymonth;
363 _Xltimeparams localtime_buf;
365 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
366 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
369 * We want to stop when the duration == 1 and we have handled all
370 * the months listed in the rule for that year.
372 if ((res->res_duration == 0) || ((res->res_duration == 1) &&
373 ((nitems - 1) == RES_YSTATE(res).res_daymonth)))
376 cur_tm.tm_mday = start_tm.tm_mday;
377 cur_tm.tm_hour = start_tm.tm_hour;
378 cur_tm.tm_min = start_tm.tm_min;
379 cur_tm.tm_sec = start_tm.tm_sec;
381 /* If these equal then we used up all the months for this year.
382 * We must now move to the next interval.
384 if ((nitems - 1) == res_month) {
385 cur_tm.tm_year += re->re_interval;
386 cur_tm.tm_mon = month_list[0] - 1; /* 0 = January */
387 RES_YSTATE(res).res_daymonth = 0;
390 /* Take the next month in the month_list, same year */
391 cur_tm.tm_mon = month_list[++RES_YSTATE(res).res_daymonth] - 1;
394 cur_tm.tm_isdst = -1;
395 _cur_time = mktime(&cur_tm);
397 /* If we went beyond the end date then restore the state info, ret 0 */
398 if (re->re_end_date && re->re_end_date < _cur_time) {
399 res->res_duration = res_duration;
400 RES_YSTATE(res).res_daymonth = res_month;
410 const Tick start_time,
411 const RepeatEvent *re,
412 RepeatEventState *res)
417 Duration res_duration = res->res_duration;
418 unsigned int *day_list = RE_YEARLY(re)->yd_items,
419 nitems = RE_YEARLY(re)->yd_nitems,
420 res_month = RES_YSTATE(res).res_daymonth;
421 _Xltimeparams localtime_buf;
423 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
424 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
427 * We want to stop when the duration == 1 and we have handled all
428 * the days listed in the rule for that year.
430 if ((res->res_duration == 0) || ((res->res_duration == 1) &&
431 ((nitems - 1) == RES_YSTATE(res).res_daymonth)))
434 cur_tm.tm_mday = start_tm.tm_mday;
435 cur_tm.tm_hour = start_tm.tm_hour;
436 cur_tm.tm_min = start_tm.tm_min;
437 cur_tm.tm_sec = start_tm.tm_sec;
439 cur_tm.tm_isdst = -1;
441 /* If these equal then we used up all the days for this year.
442 * We must now move to the next interval.
444 if ((nitems - 1) == res_month) {
445 cur_tm.tm_year += re->re_interval;
446 cur_tm.tm_mday = day_list[0];
447 RES_YSTATE(res).res_daymonth = 0;
450 /* Take the next day in the day_list, same year */
451 cur_tm.tm_mday = day_list[++RES_YSTATE(res).res_daymonth];
454 _cur_time = mktime(&cur_tm);
456 /* If we went beyond the end date then restore the state info, ret 0 */
457 if (re->re_end_date && re->re_end_date < _cur_time) {
458 res->res_duration = res_duration;
459 RES_YSTATE(res).res_daymonth = res_month;
469 const Tick start_time,
470 const RepeatEvent *re,
471 RepeatEventState *res)
475 _Xltimeparams localtime_buf;
477 if (res->res_duration == 0) return (Tick)0;
481 start_tm = *_XLocaltime(&start_time, localtime_buf);
482 tm = _XLocaltime(&cur_time, localtime_buf);
484 tm->tm_mday += re->re_interval;
485 tm->tm_hour = start_tm.tm_hour;
486 tm->tm_min = start_tm.tm_min;
494 const struct tm *current_tm,
495 const struct tm *start_tm,
496 const RepeatEvent *re,
497 const DayTime *wd_daytime,
498 const MoveIndicator move,
499 RepeatEventState *res)
501 struct tm *cur_tm = (struct tm *)current_tm;
502 unsigned int res_daytime = RES_WSTATE(res).res_daytime;
503 unsigned int res_time = RES_WSTATE(res).res_time;
505 /* Move forward to the next interval (at least another week) */
506 if (move == (const MoveIndicator) NextInterval) {
507 /* Normalize the date to the beginning of the week. */
508 cur_tm->tm_mday -= cur_tm->tm_wday;
509 cur_tm->tm_sec = cur_tm->tm_min = cur_tm->tm_hour = 0;
510 cur_tm->tm_isdst = -1;
512 /* Add an interval */
513 cur_tm->tm_mday += re->re_interval * 7;
515 /* Put it on the correct day. */
516 cur_tm->tm_mday += wd_daytime[0].dt_day;
517 /* Put it on the correct time. */
518 cur_tm->tm_hour = wd_daytime[0].dt_time[0] / 100;
519 cur_tm->tm_min = wd_daytime[0].dt_time[0] % 100;
523 return (mktime(cur_tm));
528 /* Move the appropriate number of days forward */
529 cur_tm->tm_mday += GetWDayDiff(cur_tm->tm_wday,
530 wd_daytime[res_daytime].dt_day);
532 /* Use the indicated time if available */
533 if (RE_WEEKLY(re)->wd_daytime[res_daytime].dt_time) {
534 cur_tm->tm_hour = wd_daytime[res_daytime].dt_time[res_time]
536 cur_tm->tm_min = wd_daytime[res_daytime].dt_time[res_time]
539 /* Use the time from the first appt */
540 cur_tm->tm_hour = start_tm->tm_hour;
541 cur_tm->tm_min = start_tm->tm_min;
544 cur_tm->tm_isdst = -1;
545 return (mktime(cur_tm));
550 const struct tm *current_time,
551 const RepeatEvent *re,
552 const WeekDayTime *wdt_list,
553 const MoveIndicator move,
554 RepeatEventState *res)
556 struct tm *cur_tm = (struct tm *)current_time;
557 unsigned int res_weektime = RES_MSTATE(res).res_weektime,
558 res_wweek = RES_MSTATE(res).res_wweek,
559 res_wday = RES_MSTATE(res).res_wday;
562 /* Move forward to the next interval (at least another month) */
563 if (move == (const MoveIndicator) NextInterval) {
567 /* Add an interval */
568 cur_tm->tm_mon += re->re_interval;
569 cur_tm->tm_isdst = -1;
571 } while (!(next_time = WeekNumberToDay(mktime(cur_tm),
572 wdt_list[res_weektime].wdt_week[res_wweek],
573 wdt_list[res_weektime].wdt_day[res_wday])));