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: reprevtick.c /main/6 1996/11/21 19:46:55 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>
47 static Tick DoMinute(const Tick, const Tick, const RepeatEvent *,
49 static Tick DoDay(const Tick, const Tick, const RepeatEvent *,
51 static Tick DoWeek(const Tick, const Tick, const RepeatEvent *,
53 static Tick DoMonthDay(const Tick, const Tick, const RepeatEvent *,
55 static Tick DoMonthPos(const Tick, const Tick, const RepeatEvent *,
57 static Tick DoYearByMonth(const Tick, const Tick, const RepeatEvent *,
59 static Tick DoYearByDay(const Tick, const Tick, const RepeatEvent *,
62 static Tick PrevDayTick(const Tick, const int, const int, const RepeatEvent *,
64 static Tick PrevWeekTick(const struct tm *, const struct tm *,
65 const RepeatEvent *, const DayTime *,
66 const MoveIndicator, RepeatEventState *);
67 static Tick PrevMonthTick(const struct tm *, const RepeatEvent *,
68 const WeekDayTime *, const MoveIndicator,
70 extern void FillInRepeatEvent(const Tick, RepeatEvent *);
74 const Duration res_dur,
75 const Duration re_dur)
77 if (re_dur == RE_INFINITY || re_dur == RE_NOTSET) return TRUE;
88 const Tick start_time,
90 RepeatEventState *res)
95 if (!re) return (Tick)NULL;
98 FillInRepeatEvent(cur_time, re);
100 FillInRepeatEvent(start_time, re);
102 if (!DurationCheck(res->res_duration, re->re_duration)) return (Tick)0;
104 switch (re->re_type) {
106 next_time = DoMinute(cur_time, start_time, re, res);
109 next_time = DoDay(cur_time, start_time, re, res);
112 next_time = DoWeek(cur_time, start_time, re, res);
114 case RT_MONTHLY_POSITION:
115 next_time = DoMonthPos(cur_time, start_time, re, res);
118 next_time = DoMonthDay(cur_time, start_time, re, res);
120 case RT_YEARLY_MONTH:
121 next_time = DoYearByMonth(cur_time, start_time, re, res);
124 next_time = DoYearByDay(cur_time, start_time, re, res);
129 * If the duration was not set (thus strictly using the end date)
130 * reset the RepeatEventState duration back to not-set. This is
131 * cleaner than having conditionals through out the code checking
132 * to see if the duration needs to be updated.
134 if (re->re_duration == RE_NOTSET)
135 res->res_duration = RE_NOTSET;
142 * If DoMinute is called, RT_MINUTE must be on top of res stack.
147 const Tick start_time,
148 const RepeatEvent *re,
149 RepeatEventState *res)
157 const Tick start_time,
158 const RepeatEvent *re,
159 RepeatEventState *res)
162 Duration res_duration = res->res_duration;
163 unsigned int dd_ntime = RE_DAILY(re)->dd_ntime,
164 res_time = RES_DSTATE(res).res_time;
167 /* Last event was on the first time for this day. Now must
168 * move to the previous day/interval - latest hour.
170 if (RES_DSTATE(res).res_time == 0) {
171 prev_time = PrevDayTick(cur_time,
172 RE_DAILY(re)->dd_time[dd_ntime - 1]/100,
173 RE_DAILY(re)->dd_time[dd_ntime - 1]%100,
175 RES_DSTATE(res).res_time = dd_ntime - 1;
178 _Xltimeparams localtime_buf;
180 /* There is an earlier valid time on this day, use it */
181 tm = _XLocaltime(&cur_time, localtime_buf);
184 dd_time[--RES_DSTATE(res).res_time] / 100; tm->tm_min =
185 RE_DAILY(re)->dd_time[RES_DSTATE(res).res_time]
188 prev_time = mktime(tm);
192 _Xltimeparams localtime_buf;
194 /* No alternate times for this day/move to the previous
198 start_tm = _XLocaltime(&start_time, localtime_buf);
200 start_tm = _XLocaltime(&cur_time, localtime_buf);
201 prev_time = PrevDayTick(cur_time, start_tm->tm_hour,
202 start_tm->tm_min, re, res);
205 /* We can not move before the start time. */
206 if (prev_time < start_time) {
207 res->res_duration = res_duration;
208 RES_DSTATE(res).res_time = res_time;
218 const Tick start_time,
219 const RepeatEvent *re,
220 RepeatEventState *res)
222 unsigned int res_daytime = RES_WSTATE(res).res_daytime,
223 res_time = RES_WSTATE(res).res_time,
225 re_ndaytime = RE_WEEKLY(re)->wd_ndaytime;
226 Duration res_duration = res->res_duration;
229 DayTime *daytime = RE_WEEKLY(re)->wd_daytime;
231 _Xltimeparams localtime_buf;
233 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
235 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
239 re_ntime = daytime[0].dt_ntime;
241 /* If this is 0 then we are at the first time for this day. */
243 /* If this is 0 then we are at the first day for this week. */
246 /* Beginning of week - move to an earlier week */
247 RES_WSTATE(res).res_daytime = re_ndaytime - 1;
248 RES_WSTATE(res).res_time = re_ntime - 1;
249 prev_time = PrevWeekTick(&cur_tm, &start_tm, re,
250 daytime, NextInterval, res);
252 /* Move to the prev day event (same week), use
255 RES_WSTATE(res).res_time = re_ntime - 1;
256 RES_WSTATE(res).res_daytime--;
257 prev_time = PrevWeekTick(&cur_tm, &start_tm, re,
258 daytime, SameInterval, res);
261 /* Move to an earlier time, same day. */
262 RES_WSTATE(res).res_time--;
263 prev_time = PrevWeekTick(&cur_tm, &start_tm, re, daytime,
267 /* We can not move before the start time. */
268 if (prev_time < start_time) {
269 res->res_duration = res_duration;
270 RES_WSTATE(res).res_time = res_time;
271 RES_WSTATE(res).res_daytime = res_daytime;
281 const Tick start_time,
282 const RepeatEvent *re,
283 RepeatEventState *res)
285 unsigned int *md_days = RE_MONTHLY(re)->md_days,
286 md_nitems = RE_MONTHLY(re)->md_nitems,
287 res_day = RES_MSTATE(res).res_day;
288 Duration res_duration = res->res_duration;
291 int next_interval = FALSE;
292 _Xltimeparams localtime_buf;
294 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
296 /* Check each event day in the month, move to the previous interval
297 * when we run out of event days for the month. Make sure the event
298 * day * exists in that month. e.g. the 31st of June does not exist.
301 if (!RES_MSTATE(res).res_day) {
302 cur_tm.tm_mon -= 1 * re->re_interval;
303 RES_MSTATE(res).res_day = md_nitems - 1;
304 next_interval = TRUE;
306 RES_MSTATE(res).res_day--;
308 cur_tm.tm_isdst = -1;
310 _cur_time = mktime(&cur_tm);
311 cur_tm = *_XLocaltime((const time_t *)&_cur_time, localtime_buf);
312 } while (!DayExists(md_days[RES_MSTATE(res).res_day], cur_tm.tm_mon,
315 cur_tm.tm_mday = DayOfMonth(md_days[RES_MSTATE(res).res_day],
316 cur_tm.tm_mon, cur_tm.tm_year);
317 cur_tm.tm_isdst = -1;
318 _cur_time = mktime(&cur_tm);
320 if (next_interval) res->res_duration++;
322 /* We can not move before the start time. */
323 if (_cur_time < start_time) {
324 res->res_duration = res_duration;
325 RES_MSTATE(res).res_day = res_day;
335 const Tick start_time,
336 const RepeatEvent *re,
337 RepeatEventState *res)
339 WeekDayTime *wdt_list = RE_MONTHLY(re)->md_weektime;
341 Duration res_duration = res->res_duration;
343 unsigned int md_nitems = RE_MONTHLY(re)->md_nitems,
344 res_weektime = RES_MSTATE(res).res_weektime,
345 res_wday = RES_MSTATE(res).res_wday,
346 res_wtime = RES_MSTATE(res).res_wtime,
347 res_wweek = RES_MSTATE(res).res_wweek;
348 _Xltimeparams localtime_buf;
350 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
352 /* XXX: This assumes rules of this form only: MP<n> 1+ WE #4 */
356 RES_MSTATE(res).res_weektime = md_nitems - 1;
357 RES_MSTATE(res).res_wday =
358 wdt_list[md_nitems - 1].wdt_nday - 1;
359 RES_MSTATE(res).res_wtime =
360 wdt_list[md_nitems - 1].wdt_ntime - 1;
361 RES_MSTATE(res).res_wweek =
362 wdt_list[md_nitems - 1].wdt_nweek - 1;
363 _cur_time = PrevMonthTick(&cur_tm, re, wdt_list,
375 /* We can not move before the start time. */
376 if (_cur_time < start_time) {
377 res->res_duration = res_duration;
378 RES_MSTATE(res).res_weektime = res_weektime;
379 RES_MSTATE(res).res_wday = res_wday;
380 RES_MSTATE(res).res_wtime = res_wtime;
381 RES_MSTATE(res).res_wweek = res_wweek;
391 const Tick start_time,
392 const RepeatEvent *re,
393 RepeatEventState *res)
397 Duration res_duration = res->res_duration;
399 unsigned int *month_list = RE_YEARLY(re)->yd_items,
400 nitems = RE_YEARLY(re)->yd_nitems,
401 res_month = RES_YSTATE(res).res_daymonth;
402 _Xltimeparams localtime_buf;
404 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
406 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
407 cur_tm.tm_mday = start_tm.tm_mday;
408 cur_tm.tm_hour = start_tm.tm_hour;
409 cur_tm.tm_min = start_tm.tm_min;
410 cur_tm.tm_sec = start_tm.tm_sec;
414 /* If this equals 0 then we are at the first event slot of the year,
415 * we must move backward one interval/year.
418 cur_tm.tm_year -= re->re_interval;
419 cur_tm.tm_mon = month_list[nitems - 1] - 1; /* 0 = January */
420 RES_YSTATE(res).res_daymonth = nitems - 1;
423 /* Take the next month in the month_list, same year */
424 cur_tm.tm_mon = month_list[--RES_YSTATE(res).res_daymonth] - 1;
427 cur_tm.tm_isdst = -1;
428 _cur_time = mktime(&cur_tm);
430 /* We can not move before the start time. */
431 if (_cur_time < start_time) {
432 res->res_duration = res_duration;
433 RES_YSTATE(res).res_daymonth = res_month;
443 const Tick start_time,
444 const RepeatEvent *re,
445 RepeatEventState *res)
449 Duration res_duration = res->res_duration;
451 unsigned int *day_list = RE_YEARLY(re)->yd_items,
452 nitems = RE_YEARLY(re)->yd_nitems,
453 res_month = RES_YSTATE(res).res_daymonth;
454 _Xltimeparams localtime_buf;
456 cur_tm = *_XLocaltime((const time_t *)&cur_time, localtime_buf);
458 start_tm = *_XLocaltime((const time_t *)&start_time, localtime_buf);
462 cur_tm.tm_mday = start_tm.tm_mday;
463 cur_tm.tm_hour = start_tm.tm_hour;
464 cur_tm.tm_min = start_tm.tm_min;
465 cur_tm.tm_sec = start_tm.tm_sec;
467 cur_tm.tm_isdst = -1;
469 /* If this equals 0 then we are at the first event slot of the year,
470 * we must move backward one interval/year.
473 cur_tm.tm_year -= re->re_interval;
474 cur_tm.tm_mday = day_list[nitems - 1];
475 RES_YSTATE(res).res_daymonth = nitems - 1;
478 /* Take the next day in the day_list, same year */
479 cur_tm.tm_mday = day_list[--RES_YSTATE(res).res_daymonth];
482 _cur_time = mktime(&cur_tm);
484 /* We can not move before the start time. */
485 if (_cur_time < start_time) {
486 res->res_duration = res_duration;
487 RES_YSTATE(res).res_daymonth = res_month;
499 const RepeatEvent *re,
500 RepeatEventState *res)
503 _Xltimeparams localtime_buf;
507 tm = _XLocaltime(&tick, localtime_buf);
509 tm->tm_mday -= re->re_interval;
518 const struct tm *current_tm,
519 const struct tm *start_tm,
520 const RepeatEvent *re,
521 const DayTime *wd_daytime,
522 const MoveIndicator move,
523 RepeatEventState *res)
525 struct tm *cur_tm = (struct tm *)current_tm;
526 unsigned int res_daytime = RES_WSTATE(res).res_daytime;
527 unsigned int res_time = RES_WSTATE(res).res_time;
529 /* Move backward to the previous interval (at least another week) */
530 if (move == (const MoveIndicator)NextInterval) {
531 /* Normalize the date to the beginning of the week. */
532 cur_tm->tm_mday -= cur_tm->tm_wday;
533 cur_tm->tm_sec = cur_tm->tm_min = cur_tm->tm_hour = 0;
534 cur_tm->tm_isdst = -1;
536 /* Subtract an interval */
537 cur_tm->tm_mday -= re->re_interval * 7;
539 /* Put it on the correct day. */
540 cur_tm->tm_mday += wd_daytime[res_daytime].dt_day;
542 /* Put it on the correct time. */
543 if (wd_daytime[res_daytime].dt_time) {
545 wd_daytime[res_daytime].dt_time[res_time] / 100;
547 wd_daytime[res_daytime].dt_time[res_time] % 100;
549 /* Use the time from the first appt */
550 cur_tm->tm_hour = start_tm->tm_hour;
551 cur_tm->tm_min = start_tm->tm_min;
556 return (mktime(cur_tm));
561 /* Move the appropriate number of days forward */
562 cur_tm->tm_mday -= GetWDayDiff(
563 RE_WEEKLY(re)->wd_daytime[res_daytime].dt_day,
566 /* Use the indicated time if available */
567 if (wd_daytime[res_daytime].dt_time) {
568 cur_tm->tm_hour = wd_daytime[res_daytime].dt_time[res_time]
570 cur_tm->tm_min = wd_daytime[res_daytime].dt_time[res_time]
573 /* Use the time from the first appt */
574 cur_tm->tm_hour = start_tm->tm_hour;
575 cur_tm->tm_min = start_tm->tm_min;
578 cur_tm->tm_isdst = -1;
579 return (mktime(cur_tm));
584 const struct tm *current_tm,
585 const RepeatEvent *re,
586 const WeekDayTime *wdt_list,
587 const MoveIndicator move,
588 RepeatEventState *res)
590 struct tm *cur_tm = (struct tm *)current_tm;
591 unsigned int res_weektime = RES_MSTATE(res).res_weektime,
592 res_wweek = RES_MSTATE(res).res_wweek,
593 res_wday = RES_MSTATE(res).res_wday;
596 /* Move backward to the previous interval (at least another month) */
597 if (move == (const MoveIndicator)NextInterval) {
601 /* Add an interval */
602 cur_tm->tm_mon -= re->re_interval;
603 cur_tm->tm_isdst = -1;
605 } while (!(next_time = WeekNumberToDay(mktime(cur_tm),
606 wdt_list[res_weektime].wdt_week[res_wweek],
607 wdt_list[res_weektime].wdt_day[res_wday])));