1 /* $XConsortium: reprevtick.c /main/6 1996/11/21 19:46:55 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.
9 #define XOS_USE_NO_LOCKING
10 #define X_INCLUDE_TIME_H
11 #include <X11/Xos_r.h>
22 static Tick DoMinute(const Tick, const Tick, const RepeatEvent *,
24 static Tick DoDay(const Tick, const Tick, const RepeatEvent *,
26 static Tick DoWeek(const Tick, const Tick, const RepeatEvent *,
28 static Tick DoMonthDay(const Tick, const Tick, const RepeatEvent *,
30 static Tick DoMonthPos(const Tick, const Tick, const RepeatEvent *,
32 static Tick DoYearByMonth(const Tick, const Tick, const RepeatEvent *,
34 static Tick DoYearByDay(const Tick, const Tick, const RepeatEvent *,
37 static Tick PrevDayTick(const Tick, const int, const int, const RepeatEvent *,
39 static Tick PrevWeekTick(const struct tm *, const struct tm *,
40 const RepeatEvent *, const DayTime *,
41 const MoveIndicator, RepeatEventState *);
42 static Tick PrevMonthTick(const struct tm *, const RepeatEvent *,
43 const WeekDayTime *, const MoveIndicator,
45 extern void FillInRepeatEvent(const Tick, RepeatEvent *);
49 const Duration res_dur,
50 const Duration re_dur)
52 if (re_dur == RE_INFINITY || re_dur == RE_NOTSET) return TRUE;
63 const Tick start_time,
65 RepeatEventState *res)
70 if (!re) return (Tick)NULL;
73 FillInRepeatEvent(cur_time, re);
75 FillInRepeatEvent(start_time, re);
77 if (!DurationCheck(res->res_duration, re->re_duration)) return (Tick)0;
79 switch (re->re_type) {
81 next_time = DoMinute(cur_time, start_time, re, res);
84 next_time = DoDay(cur_time, start_time, re, res);
87 next_time = DoWeek(cur_time, start_time, re, res);
89 case RT_MONTHLY_POSITION:
90 next_time = DoMonthPos(cur_time, start_time, re, res);
93 next_time = DoMonthDay(cur_time, start_time, re, res);
96 next_time = DoYearByMonth(cur_time, start_time, re, res);
99 next_time = DoYearByDay(cur_time, start_time, re, res);
104 * If the duration was not set (thus strictly using the end date)
105 * reset the RepeatEventState duration back to not-set. This is
106 * cleaner than having conditionals through out the code checking
107 * to see if the duration needs to be updated.
109 if (re->re_duration == RE_NOTSET)
110 res->res_duration = RE_NOTSET;
117 * If DoMinute is called, RT_MINUTE must be on top of res stack.
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 dd_ntime = RE_DAILY(re)->dd_ntime,
139 res_time = RES_DSTATE(res).res_time;
142 /* Last event was on the first time for this day. Now must
143 * move to the previous day/interval - latest hour.
145 if (RES_DSTATE(res).res_time == 0) {
146 prev_time = PrevDayTick(cur_time,
147 RE_DAILY(re)->dd_time[dd_ntime - 1]/100,
148 RE_DAILY(re)->dd_time[dd_ntime - 1]%100,
150 RES_DSTATE(res).res_time = dd_ntime - 1;
153 _Xltimeparams localtime_buf;
155 /* There is an earlier valid time on this day, use it */
156 tm = _XLocaltime(&cur_time, localtime_buf);
159 dd_time[--RES_DSTATE(res).res_time] / 100; tm->tm_min =
160 RE_DAILY(re)->dd_time[RES_DSTATE(res).res_time]
163 prev_time = mktime(tm);
167 _Xltimeparams localtime_buf;
169 /* No alternate times for this day/move to the previous
173 start_tm = _XLocaltime(&start_time, localtime_buf);
175 start_tm = _XLocaltime(&cur_time, localtime_buf);
176 prev_time = PrevDayTick(cur_time, start_tm->tm_hour,
177 start_tm->tm_min, re, res);
180 /* We can not move before the start time. */
181 if (prev_time < start_time) {
182 res->res_duration = res_duration;
183 RES_DSTATE(res).res_time = res_time;
193 const Tick start_time,
194 const RepeatEvent *re,
195 RepeatEventState *res)
197 unsigned int res_daytime = RES_WSTATE(res).res_daytime,
198 res_time = RES_WSTATE(res).res_time,
200 re_ndaytime = RE_WEEKLY(re)->wd_ndaytime;
201 Duration res_duration = res->res_duration;
204 DayTime *daytime = RE_WEEKLY(re)->wd_daytime;
206 _Xltimeparams localtime_buf;
208 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
210 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
214 re_ntime = daytime[0].dt_ntime;
216 /* If this is 0 then we are at the first time for this day. */
218 /* If this is 0 then we are at the first day for this week. */
221 /* Beginning of week - move to an earlier week */
222 RES_WSTATE(res).res_daytime = re_ndaytime - 1;
223 RES_WSTATE(res).res_time = re_ntime - 1;
224 prev_time = PrevWeekTick(&cur_tm, &start_tm, re,
225 daytime, NextInterval, res);
227 /* Move to the prev day event (same week), use
230 RES_WSTATE(res).res_time = re_ntime - 1;
231 RES_WSTATE(res).res_daytime--;
232 prev_time = PrevWeekTick(&cur_tm, &start_tm, re,
233 daytime, SameInterval, res);
236 /* Move to an earlier time, same day. */
237 RES_WSTATE(res).res_time--;
238 prev_time = PrevWeekTick(&cur_tm, &start_tm, re, daytime,
242 /* We can not move before the start time. */
243 if (prev_time < start_time) {
244 res->res_duration = res_duration;
245 RES_WSTATE(res).res_time = res_time;
246 RES_WSTATE(res).res_daytime = res_daytime;
256 const Tick start_time,
257 const RepeatEvent *re,
258 RepeatEventState *res)
260 unsigned int *md_days = RE_MONTHLY(re)->md_days,
261 md_nitems = RE_MONTHLY(re)->md_nitems,
262 res_day = RES_MSTATE(res).res_day;
263 Duration res_duration = res->res_duration;
266 int next_interval = FALSE;
267 _Xltimeparams localtime_buf;
269 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
271 /* Check each event day in the month, move to the previous interval
272 * when we run out of event days for the month. Make sure the event
273 * day * exists in that month. e.g. the 31st of June does not exist.
276 if (!RES_MSTATE(res).res_day) {
277 cur_tm.tm_mon -= 1 * re->re_interval;
278 RES_MSTATE(res).res_day = md_nitems - 1;
279 next_interval = TRUE;
281 RES_MSTATE(res).res_day--;
283 cur_tm.tm_isdst = -1;
285 _cur_time = mktime(&cur_tm);
286 cur_tm = *_XLocaltime((const time_t *)&_cur_time, localtime_buf);
287 } while (!DayExists(md_days[RES_MSTATE(res).res_day], cur_tm.tm_mon,
290 cur_tm.tm_mday = DayOfMonth(md_days[RES_MSTATE(res).res_day],
291 cur_tm.tm_mon, cur_tm.tm_year);
292 cur_tm.tm_isdst = -1;
293 _cur_time = mktime(&cur_tm);
295 if (next_interval) res->res_duration++;
297 /* We can not move before the start time. */
298 if (_cur_time < start_time) {
299 res->res_duration = res_duration;
300 RES_MSTATE(res).res_day = res_day;
310 const Tick start_time,
311 const RepeatEvent *re,
312 RepeatEventState *res)
314 WeekDayTime *wdt_list = RE_MONTHLY(re)->md_weektime;
316 Duration res_duration = res->res_duration;
318 unsigned int md_nitems = RE_MONTHLY(re)->md_nitems,
319 res_weektime = RES_MSTATE(res).res_weektime,
320 res_wday = RES_MSTATE(res).res_wday,
321 res_wtime = RES_MSTATE(res).res_wtime,
322 res_wweek = RES_MSTATE(res).res_wweek;
323 _Xltimeparams localtime_buf;
325 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
327 /* XXX: This assumes rules of this form only: MP<n> 1+ WE #4 */
331 RES_MSTATE(res).res_weektime = md_nitems - 1;
332 RES_MSTATE(res).res_wday =
333 wdt_list[md_nitems - 1].wdt_nday - 1;
334 RES_MSTATE(res).res_wtime =
335 wdt_list[md_nitems - 1].wdt_ntime - 1;
336 RES_MSTATE(res).res_wweek =
337 wdt_list[md_nitems - 1].wdt_nweek - 1;
338 _cur_time = PrevMonthTick(&cur_tm, re, wdt_list,
350 /* We can not move before the start time. */
351 if (_cur_time < start_time) {
352 res->res_duration = res_duration;
353 RES_MSTATE(res).res_weektime = res_weektime;
354 RES_MSTATE(res).res_wday = res_wday;
355 RES_MSTATE(res).res_wtime = res_wtime;
356 RES_MSTATE(res).res_wweek = res_wweek;
366 const Tick start_time,
367 const RepeatEvent *re,
368 RepeatEventState *res)
372 Duration res_duration = res->res_duration;
374 unsigned int *month_list = RE_YEARLY(re)->yd_items,
375 nitems = RE_YEARLY(re)->yd_nitems,
376 res_month = RES_YSTATE(res).res_daymonth;
377 _Xltimeparams localtime_buf;
379 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
381 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
382 cur_tm.tm_mday = start_tm.tm_mday;
383 cur_tm.tm_hour = start_tm.tm_hour;
384 cur_tm.tm_min = start_tm.tm_min;
385 cur_tm.tm_sec = start_tm.tm_sec;
389 /* If this equals 0 then we are at the first event slot of the year,
390 * we must move backward one interval/year.
393 cur_tm.tm_year -= re->re_interval;
394 cur_tm.tm_mon = month_list[nitems - 1] - 1; /* 0 = January */
395 RES_YSTATE(res).res_daymonth = nitems - 1;
398 /* Take the next month in the month_list, same year */
399 cur_tm.tm_mon = month_list[--RES_YSTATE(res).res_daymonth] - 1;
402 cur_tm.tm_isdst = -1;
403 _cur_time = mktime(&cur_tm);
405 /* We can not move before the start time. */
406 if (_cur_time < start_time) {
407 res->res_duration = res_duration;
408 RES_YSTATE(res).res_daymonth = res_month;
418 const Tick start_time,
419 const RepeatEvent *re,
420 RepeatEventState *res)
424 Duration res_duration = res->res_duration;
426 unsigned int *day_list = RE_YEARLY(re)->yd_items,
427 nitems = RE_YEARLY(re)->yd_nitems,
428 res_month = RES_YSTATE(res).res_daymonth;
429 _Xltimeparams localtime_buf;
431 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
433 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
437 cur_tm.tm_mday = start_tm.tm_mday;
438 cur_tm.tm_hour = start_tm.tm_hour;
439 cur_tm.tm_min = start_tm.tm_min;
440 cur_tm.tm_sec = start_tm.tm_sec;
442 cur_tm.tm_isdst = -1;
444 /* If this equals 0 then we are at the first event slot of the year,
445 * we must move backward one interval/year.
448 cur_tm.tm_year -= re->re_interval;
449 cur_tm.tm_mday = day_list[nitems - 1];
450 RES_YSTATE(res).res_daymonth = nitems - 1;
453 /* Take the next day in the day_list, same year */
454 cur_tm.tm_mday = day_list[--RES_YSTATE(res).res_daymonth];
457 _cur_time = mktime(&cur_tm);
459 /* We can not move before the start time. */
460 if (_cur_time < start_time) {
461 res->res_duration = res_duration;
462 RES_YSTATE(res).res_daymonth = res_month;
474 const RepeatEvent *re,
475 RepeatEventState *res)
478 _Xltimeparams localtime_buf;
482 tm = _XLocaltime(&tick, localtime_buf);
484 tm->tm_mday -= re->re_interval;
493 const struct tm *current_tm,
494 const struct tm *start_tm,
495 const RepeatEvent *re,
496 const DayTime *wd_daytime,
497 const MoveIndicator move,
498 RepeatEventState *res)
500 struct tm *cur_tm = (struct tm *)current_tm;
501 unsigned int res_daytime = RES_WSTATE(res).res_daytime;
502 unsigned int res_time = RES_WSTATE(res).res_time;
504 /* Move backward to the previous interval (at least another week) */
505 if (move == (const MoveIndicator)NextInterval) {
506 /* Normalize the date to the beginning of the week. */
507 cur_tm->tm_mday -= cur_tm->tm_wday;
508 cur_tm->tm_sec = cur_tm->tm_min = cur_tm->tm_hour = 0;
509 cur_tm->tm_isdst = -1;
511 /* Subtract an interval */
512 cur_tm->tm_mday -= re->re_interval * 7;
514 /* Put it on the correct day. */
515 cur_tm->tm_mday += wd_daytime[res_daytime].dt_day;
517 /* Put it on the correct time. */
518 if (wd_daytime[res_daytime].dt_time) {
520 wd_daytime[res_daytime].dt_time[res_time] / 100;
522 wd_daytime[res_daytime].dt_time[res_time] % 100;
524 /* Use the time from the first appt */
525 cur_tm->tm_hour = start_tm->tm_hour;
526 cur_tm->tm_min = start_tm->tm_min;
531 return (mktime(cur_tm));
536 /* Move the appropriate number of days forward */
537 cur_tm->tm_mday -= GetWDayDiff(
538 RE_WEEKLY(re)->wd_daytime[res_daytime].dt_day,
541 /* Use the indicated time if available */
542 if (wd_daytime[res_daytime].dt_time) {
543 cur_tm->tm_hour = wd_daytime[res_daytime].dt_time[res_time]
545 cur_tm->tm_min = wd_daytime[res_daytime].dt_time[res_time]
548 /* Use the time from the first appt */
549 cur_tm->tm_hour = start_tm->tm_hour;
550 cur_tm->tm_min = start_tm->tm_min;
553 cur_tm->tm_isdst = -1;
554 return (mktime(cur_tm));
559 const struct tm *current_tm,
560 const RepeatEvent *re,
561 const WeekDayTime *wdt_list,
562 const MoveIndicator move,
563 RepeatEventState *res)
565 struct tm *cur_tm = (struct tm *)current_tm;
566 unsigned int res_weektime = RES_MSTATE(res).res_weektime,
567 res_wweek = RES_MSTATE(res).res_wweek,
568 res_wday = RES_MSTATE(res).res_wday;
571 /* Move backward to the previous interval (at least another month) */
572 if (move == (const MoveIndicator)NextInterval) {
576 /* Add an interval */
577 cur_tm->tm_mon -= re->re_interval;
578 cur_tm->tm_isdst = -1;
580 } while (!(next_time = WeekNumberToDay(mktime(cur_tm),
581 wdt_list[res_weektime].wdt_week[res_wweek],
582 wdt_list[res_weektime].wdt_day[res_wday])));