1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/programs/dtcm/server/repeat.c
2018-07-13 17:29:29 +01:00

1735 lines
39 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $XConsortium: repeat.c /main/7 1996/11/21 19:46:39 drk $ */
/*
* (c) Copyright 1993, 1994 Hewlett-Packard Company
* (c) Copyright 1993, 1994 International Business Machines Corp.
* (c) Copyright 1993, 1994 Novell, Inc.
* (c) Copyright 1993, 1994 Sun Microsystems, Inc.
*/
#include <EUSCompat.h>
#include <stdio.h>
#define XOS_USE_NO_LOCKING
#define X_INCLUDE_TIME_H
#if defined(__linux__)
#undef SVR4
#endif
#include <X11/Xos_r.h>
#include "csa.h"
#include "rtable4.h"
#include "cm.h"
#include "repeat.h"
#include "attr.h"
#include "iso8601.h"
#define EOT 2147483647
extern int debug;
static time_t bot, eot;
typedef enum {
minsec = 60,
fivemins = 300,
hrsec = 3600,
daysec = 86400,
wksec = 604800,
yrsec = 31536000,
leapyrsec = 31622400
} Unit;
static unsigned int weekdaymasks[] = {
0x1, /* sunday */
0x2, /* monday */
0x4, /* tuesday */
0x8, /* wednesday */
0x10, /* thursday */
0x20, /* friday */
0x40 /* saturday */
};
static int monthsecs[12] = {
31*daysec, 28*daysec, 31*daysec,
30*daysec, 31*daysec, 30*daysec,
31*daysec, 31*daysec, 30*daysec,
31*daysec, 30*daysec, 31*daysec
};
int monthdays[12] = {
31, 28, 31,
30, 31, 30,
31, 31, 30,
31, 30, 31
};
static int lastapptofweek(u_int mask);
static int ntimes_this_week(u_int weekmask, int firstday);
static boolean_t nthweekdayofmonth(time_t t, int *nth);
static time_t next_nmonth(time_t t, int n);
static int adjust_dst(time_t start, time_t next);
static time_t prev_nmonth(time_t t, int n);
static time_t nextnyear(time_t t, int n);
static int timeok(time_t t);
static time_t prevnyear(time_t t, int n);
static time_t prevmonth_exactday(time_t t);
static time_t nextmonth_exactday(time_t t);
static time_t previousmonth(time_t t);
static int monthseconds(time_t t);
static int get_ndelta(time_t startdate, Period_4 period, int ntimes);
static time_t lastnthweekday(time_t t, int nth, int ntimes);
static time_t nextnthweekday(time_t t, int nth);
static time_t prevnthweekday(time_t t, int nth);
static time_t nextnday_exacttime(time_t t, int n);
static time_t prevnday_exacttime(time_t t, int n);
static time_t nextnwk_exacttime(time_t t, int n);
static time_t prevnwk_exacttime(time_t t, int n);
static time_t nextnmth_exactday(time_t t, int n);
static time_t prevnmth_exactday(time_t t, int n);
static time_t nextmonTofri(time_t t);
static time_t prevmonTofri(time_t t);
static time_t nextmonwedfri(time_t t);
static time_t prevmonwedfri(time_t t);
static time_t nexttuethur(time_t t);
static time_t prevtuethur(time_t t);
static time_t nextdaysofweek(time_t t, int weekmask);
static time_t prevdaysofweek(time_t t, int weekmask);
/* [ytso 1/26/93]
* cm now supports to up end of 1999. This is due to the limitation
* of cm_getdate() which can only handle up to end of 1999.
* When cm_getdate() is improved to handle up to the system limit,
* definitions of eot and EOT need to be changed as well as some
* of the routines in this file and the caller of these routines.
*/
extern void
init_time(void)
{
struct tm tm, gm;
time_t t;
_Xltimeparams localtime_buf;
_Xgtimeparams gmtime_buf;
t = time(0);
tm = *_XLocaltime(&t, localtime_buf);
gm = *_XGmtime(&t, gmtime_buf);
bot = mktime(&gm) - mktime(&tm);
tm.tm_sec =59;
tm.tm_min =59;
tm.tm_hour =23;
tm.tm_mday =31;
tm.tm_mon =11;
tm.tm_year =137; /* Dec. 31, 2037 */
tm.tm_isdst = -1;
eot =mktime(&tm);
}
extern void
_DtCms_adjust_appt_startdate(Appt_4 *appt)
{
struct tm *tm;
_Xltimeparams localtime_buf;
if (appt->period.period < monThruFri_4 ||
appt->period.period > tueThur_4)
return;
tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
switch (appt->period.period) {
case monThruFri_4:
if (tm->tm_wday < 1 || tm->tm_wday > 5)
appt->appt_id.tick = _DtCms_next_tick_v4(
appt->appt_id.tick,
appt->period);
break;
case monWedFri_4:
if ((tm->tm_wday % 2) == 0)
appt->appt_id.tick = _DtCms_next_tick_v4(
appt->appt_id.tick,
appt->period);
break;
case tueThur_4:
if (tm->tm_wday != 2 && tm->tm_wday != 4)
appt->appt_id.tick = _DtCms_next_tick_v4(
appt->appt_id.tick,
appt->period);
break;
}
}
/*
* Calculate the actual number of instances of the repeating event.
*/
extern int
_DtCms_get_ninstance_v4(Appt_4 *appt)
{
struct tm *tm;
int i, pdelta, ndelta, ninstance, timesperweek;
double dninstance;
_Xltimeparams localtime_buf;
if (appt->ntimes == _DtCM_OLD_REPEAT_FOREVER)
return(appt->ntimes);
switch (appt->period.period) {
case everyNthDay_4:
case everyNthWeek_4:
case everyNthMonth_4:
ninstance = (appt->ntimes+(appt->period.nth-1))/appt->period.nth;
break;
case monThruFri_4:
tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
pdelta = 6 - tm->tm_wday;
ndelta = get_ndelta(appt->appt_id.tick, appt->period,
appt->ntimes);
dninstance = (double)(appt->ntimes - 1) * 5 + pdelta - ndelta;
ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
_DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
break;
case monWedFri_4:
tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
pdelta = (7 - tm->tm_wday) / 2;
ndelta = get_ndelta(appt->appt_id.tick, appt->period,
appt->ntimes);
dninstance = (double)(appt->ntimes - 1) * 3 + pdelta - ndelta;
ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER)
? _DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
break;
case tueThur_4:
tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
pdelta = (tm->tm_wday == 2) ? 2 : 1;
ndelta = get_ndelta(appt->appt_id.tick, appt->period,
appt->ntimes);
dninstance = (double)(appt->ntimes - 1) * 2 + pdelta - ndelta;
ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
_DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
break;
case daysOfWeek_4:
tm = _XLocaltime(&(appt->appt_id.tick), localtime_buf);
timesperweek = ntimes_this_week((u_int)appt->period.nth, 0);
pdelta = ntimes_this_week((u_int)appt->period.nth, tm->tm_wday);
ndelta = get_ndelta(appt->appt_id.tick, appt->period,
appt->ntimes);
dninstance = (double)(appt->ntimes-1) * timesperweek +
pdelta - ndelta;
ninstance = (dninstance > _DtCM_OLD_REPEAT_FOREVER) ?
_DtCM_OLD_REPEAT_FOREVER : (int)dninstance;
break;
default:
ninstance = appt->ntimes;
}
return ninstance;
}
/*
* calculate the ntimes value which, depending on the
* repeating event type, may not be the same
* as the actual number of instances
*/
extern int
_DtCms_get_new_ntimes_v4(Period_4 period, time_t tick, int ninstance)
{
struct tm *tm;
int ntimes;
int delta = 0, firstweek, timesperweek;
_Xltimeparams localtime_buf;
switch (period.period) {
case everyNthDay_4:
case everyNthWeek_4:
case everyNthMonth_4:
ntimes = ninstance * period.nth;
break;
case monThruFri_4:
tm = _XLocaltime(&tick, localtime_buf);
if (ninstance % 5)
delta = ((ninstance % 5) > (6 - tm->tm_wday)) ? 2 : 1;
else if (tm->tm_wday != 1)
delta = 1;
ntimes = (ninstance/5) + delta;
break;
case monWedFri_4:
tm = _XLocaltime(&tick, localtime_buf);
if (ninstance % 3)
delta = ((ninstance % 3) > ((7-tm->tm_wday)/2)) ? 2:1;
else if (tm->tm_wday != 1)
delta = 1;
ntimes = (ninstance/3) + delta;
break;
case tueThur_4:
tm = _XLocaltime(&tick, localtime_buf);
if (ninstance % 2 || tm->tm_wday != 2)
delta = 1;
ntimes = (ninstance/2) + delta;
break;
case daysOfWeek_4:
tm = _XLocaltime(&tick, localtime_buf);
timesperweek = ntimes_this_week((u_int)period.nth, 0);
firstweek=ntimes_this_week((u_int)period.nth,tm->tm_wday);
if (ninstance % timesperweek)
delta = ((ninstance % timesperweek) > firstweek) ? 2:1;
else if (firstweek != timesperweek)
delta = 1;
ntimes = (ninstance/timesperweek) + delta;
break;
default:
ntimes = ninstance;
break;
}
return ntimes;
}
extern time_t
_DtCms_first_tick_v4(time_t t, Period_4 period, int ordinal)
{
int i;
time_t ftick;
ftick = t;
for (i = 1; i < ordinal; i++)
ftick = _DtCms_prev_tick_v4(ftick, period);
return(ftick);
}
/*
* Given a time, calculate the closest instance whose
* tick is later than the time.
* If the calculated tick does not pass timeok(), ftick is
* returned and ordinal set to 1.
*/
extern time_t
_DtCms_closest_tick_v4(time_t target, time_t ftick, Period_4 period, int *ordinal)
{
time_t ctick;
int delta = 0;
int remainder = 0;
int ndays;
struct tm *tm;
struct tm tm1, tm2;
_Xltimeparams localtime_buf;
if (target <= ftick) {
*ordinal = 1;
return(ftick);
}
if (period.period < monthly_4 || period.period == everyNthDay_4 ||
period.period == everyNthWeek_4) {
tm1 = *_XLocaltime(&ftick, localtime_buf);
tm2 = *_XLocaltime(&target, localtime_buf);
}
switch(period.period) {
case daily_4:
delta = (target - ftick) / daysec;
remainder = target - ftick - daysec * delta;
if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
remainder -= hrsec;
*ordinal = delta + (remainder>0?1:0) + 1;
ctick = nextnday_exacttime(ftick, *ordinal - 1);
break;
case weekly_4:
delta = (target - ftick) / wksec;
remainder = target - ftick - wksec * delta;
if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
remainder -= hrsec;
*ordinal = delta + (remainder>0?1:0) + 1;
ctick = nextnwk_exacttime(ftick, *ordinal - 1);
break;
case biweekly_4:
delta = (target - ftick) / (wksec * 2);
remainder = target - ftick - wksec * 2 * delta;
if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
remainder -= hrsec;
*ordinal = delta + (remainder>0?1:0) + 1;
ctick = nextnwk_exacttime(ftick, 2 * (*ordinal - 1));
break;
case monthly_4:
tm = _XLocaltime(&ftick, localtime_buf);
/*
* Calculate the closest tick only if the date
* is < 29; otherwise just return the first tick.
* Use 32 to take care of dst time difference.
* Without dst, we can use 31.
*/
if (tm->tm_mday < 29) {
delta = (target - ftick) / (daysec * 32);
remainder = target - ftick - (daysec * 32) * delta;
*ordinal = delta + (remainder>0?1:0) + 1;
ctick = nextnmth_exactday(ftick, *ordinal - 1);
} else {
ctick = ftick;
*ordinal = 1;
}
break;
case yearly_4:
tm = _XLocaltime(&ftick, localtime_buf);
if (tm->tm_mday == 29 && tm->tm_mon == 1) {
delta = (target - ftick) / (yrsec * 4 + daysec);
remainder = target - ftick - (yrsec * 4) * delta;
*ordinal = delta + (remainder>0?1:0) + 1;
ctick = nextnyear(ftick, (*ordinal - 1) * 4);
} else {
delta = (target - ftick) / yrsec;
/* adjustment for leap year */
remainder = tm->tm_year % 4;
if (remainder == 0 || (remainder + delta) > 3)
delta--;
remainder = target - ftick - yrsec * delta;
*ordinal = delta + (remainder>0?1:0) + 1;
ctick = nextnyear(ftick, *ordinal - 1);
}
break;
case nthWeekday_4:
/* 36 is 5 weeks ==> maximum interval between 2 instances */
delta = (target - ftick) / (daysec * 36);
remainder = target - ftick - (daysec * 36) * delta;
*ordinal = delta + (remainder>0?1:0) + 1;
ctick = lastnthweekday(ftick, period.nth, *ordinal - 1);
break;
case everyNthDay_4:
delta = (target - ftick) / (daysec * period.nth);
remainder = target - ftick - (daysec * period.nth) * delta;
if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
remainder -= hrsec;
*ordinal = delta + (remainder>0?1:0) + 1;
ctick = nextnday_exacttime(ftick,
period.nth * (*ordinal - 1));
break;
case everyNthWeek_4:
delta = (target - ftick) / (wksec * period.nth);
remainder = target - ftick - (wksec * period.nth) * delta;
if (tm1.tm_isdst == 1 && tm1.tm_isdst != tm2.tm_isdst)
remainder -= hrsec;
*ordinal = delta + (remainder>0?1:0) + 1;
ctick = nextnwk_exacttime(ftick,
period.nth * (*ordinal - 1));
break;
case everyNthMonth_4:
tm = _XLocaltime(&ftick, localtime_buf);
if (tm->tm_mday < 29) {
delta = (target - ftick) / (daysec * 32 * period.nth);
remainder = target-ftick-(daysec*32*period.nth)*delta;
*ordinal = delta + (remainder>0?1:0) + 1;
ctick = nextnmth_exactday(ftick,
period.nth * (*ordinal - 1));
} else {
ctick = ftick;
*ordinal = 1;
}
break;
case monThruFri_4:
case monWedFri_4:
case tueThur_4:
case daysOfWeek_4:
delta = (target - ftick) / wksec;
tm = _XLocaltime(&ftick, localtime_buf);
switch (period.period) {
case monThruFri_4:
*ordinal = delta * 5 + 6 - tm->tm_wday;
break;
case monWedFri_4:
*ordinal = delta * 3 + (7 - tm->tm_wday) / 2;
break;
case tueThur_4:
*ordinal = delta * 2 + ((tm->tm_wday == 2) ? 2 : 1);
break;
case daysOfWeek_4:
*ordinal = delta * ntimes_this_week((u_int)period.nth,0)
+ ntimes_this_week((u_int)period.nth,
tm->tm_wday);
}
/* delta*daysperweek+(lastapptofweek-firstday in first week) */
if (period.period == daysOfWeek_4) {
ndays = delta * 7 +
lastapptofweek((u_int)period.nth) - tm->tm_wday;
ctick = ftick + ndays * daysec;
} else if (period.period == tueThur_4) {
ndays = delta * 7 + 4 - tm->tm_wday;
ctick = ftick + ndays * daysec;
} else {
ndays = delta * 7 + 5 - tm->tm_wday;
ctick = ftick + ndays * daysec;
}
if (ctick > target) { /* need to go back 1 week */
ndays -= 7;
if (ndays < 0) {
*ordinal = 1;
ctick = ftick;
} else {
if (period.period == monThruFri_4)
*ordinal -= 5;
else if (period.period == monWedFri_4)
*ordinal -= 3;
else if (period.period == tueThur_4)
*ordinal -= 2;
ctick -= (7 * daysec);
}
}
ctick = adjust_dst(ftick, ctick);
break;
default:
*ordinal = 1;
ctick = ftick;
}
if (timeok(ctick))
return(ctick);
else {
*ordinal = 1;
return(ftick);
}
}
/*
* Calculate the tick of the last instance of a repeating event.
* If the calculated tick does not pass timeok(), EOT is returned.
*/
extern time_t
_DtCms_last_tick_v4(time_t ftick, Period_4 period, int ntimes)
{
struct tm *tm;
double dltick;
time_t ltick = 0;
int i;
_Xltimeparams localtime_buf;
if (ntimes >= _DtCM_OLD_REPEAT_FOREVER)
return(EOT);
if (period.enddate != 0)
return(period.enddate);
switch(period.period) {
case weekly_4:
ltick = nextnwk_exacttime(ftick, ntimes - 1);
break;
case biweekly_4:
/* 2 * (ntimes-1) won't overflow an integer since
* we make sure ntimes is < EOT
*/
ltick = nextnwk_exacttime(ftick, 2 * (ntimes - 1));
break;
case daily_4:
ltick = nextnday_exacttime(ftick, ntimes - 1);
break;
case monthly_4:
tm = _XLocaltime(&ftick, localtime_buf);
/*
* calculate the last tick only if the date
* is < 29; otherwise return EOT to force calculation
*/
if (tm->tm_mday < 29)
ltick = nextnmth_exactday(ftick, ntimes - 1);
else
ltick = EOT;
break;
case yearly_4:
/* 2038 is the last year that can be represented.
* this check is to prevent (ntimes-1)*4 from integer overflow
*/
if (ntimes > 2038)
ltick = EOT;
else {
tm = _XLocaltime(&ftick, localtime_buf);
if (tm->tm_mday == 29 && tm->tm_mon == 1)
ltick = nextnyear(ftick, (ntimes - 1) * 4);
else
ltick = nextnyear(ftick, ntimes - 1);
}
break;
case nthWeekday_4:
ltick = lastnthweekday(ftick, period.nth, ntimes - 1);
break;
case everyNthDay_4:
ltick = nextnday_exacttime(ftick, period.nth *
(((ntimes+(period.nth-1))/period.nth) - 1));
break;
case everyNthWeek_4:
ltick = nextnwk_exacttime(ftick, period.nth *
(((ntimes+(period.nth-1))/period.nth) - 1));
break;
case everyNthMonth_4:
tm = _XLocaltime(&ftick, localtime_buf);
if (tm->tm_mday < 29)
ltick = nextnmth_exactday(ftick, period.nth *
(((ntimes+(period.nth-1))/period.nth) -1));
else
ltick = EOT;
break;
case monThruFri_4:
case monWedFri_4:
case tueThur_4:
case daysOfWeek_4:
tm = _XLocaltime(&ftick, localtime_buf);
/* (ntimes-1)*daysperweek+(lastapptofweek-fstapptofFstweek) */
if (period.period == daysOfWeek_4)
dltick = ftick +
((double)(ntimes - 1) * 7 +
lastapptofweek((u_int)period.nth) - tm->tm_wday)
* daysec;
else if (period.period == tueThur_4)
dltick = ftick +
((double)(ntimes - 1) * 7 + (4 - tm->tm_wday)) *
daysec;
else
dltick = ftick +
((double)(ntimes - 1) * 7 + (5 - tm->tm_wday)) *
daysec;
if (dltick >= EOT || dltick < 0)
ltick = EOT;
else
ltick = adjust_dst(ftick, (time_t)dltick);
break;
default:
break;
}
if(timeok(ltick))
return(ltick);
else
return(EOT);
}
/*
* Calculate the tick of next instance.
* If the calculated tick does not pass timeok(), EOT is returned.
*/
extern time_t
_DtCms_next_tick_v4(time_t tick, Period_4 period)
{
time_t next = 0;
struct tm *tm;
_Xltimeparams localtime_buf;
switch(period.period) {
case weekly_4:
next = nextnwk_exacttime(tick, 1);
break;
case biweekly_4:
next = nextnwk_exacttime(tick, 2);
break;
case daily_4:
next = nextnday_exacttime(tick, 1);
break;
case monthly_4:
next = nextmonth_exactday(tick);
break;
case yearly_4:
tm = _XLocaltime(&tick, localtime_buf);
if (tm->tm_mday == 29 && tm->tm_mon == 1)
next = nextnyear(tick, 4);
else
next = nextnyear(tick, 1);
break;
case nthWeekday_4:
next = nextnthweekday(tick, period.nth);
break;
case everyNthDay_4:
next = nextnday_exacttime(tick, period.nth);
break;
case everyNthWeek_4:
next = nextnwk_exacttime(tick, period.nth);
break;
case everyNthMonth_4:
next = nextnmth_exactday(tick, period.nth);
break;
case monThruFri_4:
next = nextmonTofri(tick);
break;
case monWedFri_4:
next = nextmonwedfri(tick);
break;
case tueThur_4:
next = nexttuethur(tick);
break;
case daysOfWeek_4:
next = nextdaysofweek(tick, period.nth);
break;
default:
break;
}
if(next != tick && timeok(next)) return(next);
else return(EOT);
}
/*
* Calculate the tick of previous instance.
* If the calculated tick does not pass timeok(), bot-1 is returned.
*/
extern time_t
_DtCms_prev_tick_v4(time_t tick, Period_4 period)
{
time_t prev = 0;
struct tm *tm;
_Xltimeparams localtime_buf;
switch(period.period) {
case weekly_4:
prev = prevnwk_exacttime(tick, 1);
break;
case biweekly_4:
prev = prevnwk_exacttime(tick, 2);
break;
case daily_4:
prev = prevnday_exacttime(tick, 1);
break;
case monthly_4:
prev = prevmonth_exactday(tick);
break;
case yearly_4:
tm = _XLocaltime(&tick, localtime_buf);
if (tm->tm_mday == 29 && tm->tm_mon == 1)
prev = prevnyear(tick, 4);
else
prev = prevnyear(tick, 1);
break;
case nthWeekday_4:
prev = prevnthweekday(tick, period.nth);
break;
case everyNthDay_4:
prev = prevnday_exacttime(tick, period.nth);
break;
case everyNthWeek_4:
prev = prevnwk_exacttime(tick, period.nth);
break;
case everyNthMonth_4:
prev = prevnmth_exactday(tick, period.nth);
break;
case monThruFri_4:
prev = prevmonTofri(tick);
break;
case monWedFri_4:
prev = prevmonwedfri(tick);
break;
case tueThur_4:
prev = prevtuethur(tick);
break;
case daysOfWeek_4:
prev = prevdaysofweek(tick, period.nth);
break;
default:
break;
}
if(prev != tick && timeok(prev)) return(prev);
else return(bot-1);
}
/*
* dont_care_cancel:
* TRUE - it is a match regard_DtCmsIsLess the event is cancelled,
* FALSE - it is not a match if the event is cancelled.
*/
extern int
_DtCms_in_repeater(Id_4 *key, Appt_4 *p_appt, boolean_t dont_care_cancel)
{
Period_4 period;
int ordinal;
int ntimes;
time_t tick;
ntimes = _DtCms_get_ninstance_v4(p_appt);
period = p_appt->period;
tick = _DtCms_closest_tick_v4(key->tick, p_appt->appt_id.tick, period, &ordinal);
ordinal--;
while (++ordinal <= ntimes)
{
if (tick > key->tick) /* out-of-bound */
break;
if (tick == key->tick)
{
if (dont_care_cancel)
return (ordinal);
if (!_DtCms_marked_4_cancellation (p_appt, ordinal))
return (ordinal);
}
tick = _DtCms_next_tick_v4 (tick, period);
}
return (0);
}
extern int
_DtCms_marked_4_cancellation(Appt_4 *a, int i)
{
Except_4 *p;
if (a==NULL)
return(0);
p = a->exception; /* in descending order for faster access */
while (p!=NULL) {
if (i > p->ordinal)
break;
if (i == p->ordinal)
return(1);
p = p->next;
}
return(0);
}
extern time_t
next_ndays(time_t t, int n)
{
time_t next;
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_sec = 0;
tm.tm_min = 0;
tm.tm_hour = 0;
#ifdef SVR4
next = mktime(&tm);
#else
next = timelocal(&tm);
#endif /* SVR4 */
next = next + n * daysec;
next = adjust_dst(t, next);
return(next);
}
extern time_t
next_nmins(time_t t, int m)
{
time_t next;
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_sec = 0;
tm.tm_min = 0;
next = mktime(&tm);
next = next + m * minsec;
next = adjust_dst(t, next);
return(next);
}
extern time_t
_DtCmsBeginOfDay(time_t t)
{
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_sec = 0;
tm.tm_min = 0;
tm.tm_hour = 0;
return(mktime(&tm));
}
extern time_t
_DtCmsTimeOfDay(time_t t)
{
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_sec = 0;
tm.tm_min = 0;
tm.tm_hour = 0;
return(t - mktime(&tm));
}
/*
* Given a weekmask, find the last appointment in the week
*/
static int
lastapptofweek(u_int mask)
{
int n;
if (mask == 0)
return -1;
for (n = -1; mask != 0; n++, mask = mask >> 1);
return n;
}
/*
* Given a weekmask and the first day of the week, calculate
* the number of times outstanding in the week.
*/
static int
ntimes_this_week(u_int weekmask, int firstday)
{
int i, ntimes, weekdaymask = 1 << firstday;
if (weekmask == 0)
return 0;
for (i=firstday, ntimes=0; i < 7; i++, weekdaymask <<= 1) {
if (weekdaymask & weekmask)
ntimes++;
}
return ntimes;
}
static boolean_t
nthweekdayofmonth(time_t t, int *nth)
{
struct tm tm, tm2, tmfirstday;
time_t firstday;
_Xltimeparams localtime_buf;
tmfirstday = tm = *_XLocaltime(&t, localtime_buf);
*nth = (12 + tm.tm_mday - tm.tm_wday)/7;
tmfirstday.tm_hour = 0;
tmfirstday.tm_min = 0;
tmfirstday.tm_sec = 0;
tmfirstday.tm_mday = 1;
firstday = mktime(&tmfirstday);
tmfirstday = *_XLocaltime(&firstday, localtime_buf);
if (tm.tm_wday < tmfirstday.tm_wday)
(*nth)--;
if (*nth < 4)
return B_FALSE;
else {
t += (7 * daysec);
tm2 = *_XLocaltime(&t, localtime_buf);
return((tm.tm_mon == tm2.tm_mon) ? B_FALSE : B_TRUE);
}
}
/*
* If the result falls beyond the system limit, -1 is returned by mktime().
*/
static time_t
next_nmonth(time_t t, int n)
{
struct tm tm;
int n12;
_Xltimeparams localtime_buf;
n12 = n/12;
n = n%12;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_hour=0;
tm.tm_min=0;
tm.tm_sec=0;
tm.tm_mday=1;
if (n12 > 0)
tm.tm_year += n12;
if ((tm.tm_mon = tm.tm_mon + n) > 11) {
tm.tm_mon -= 12;
tm.tm_year++;
}
tm.tm_isdst = -1;
return(mktime(&tm));
}
static int
adjust_dst(time_t start, time_t next)
{
struct tm oldt;
struct tm newt;
_Xltimeparams localtime_buf;
oldt = *_XLocaltime(&start, localtime_buf);
newt = *_XLocaltime(&next, localtime_buf);
if (oldt.tm_isdst == newt.tm_isdst) {
return (next);
} else if (oldt.tm_isdst == 1) {
return (next + (int)hrsec);
} else {
return (next - (int)hrsec);
}
}
static time_t
prev_nmonth(time_t t, int n)
{
struct tm tm;
int n12;
_Xltimeparams localtime_buf;
n12 = n/12;
n = n%12;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_hour=0;
tm.tm_min=0;
tm.tm_sec=0;
tm.tm_mday=1;
if (n12 > 0)
tm.tm_year -= n12;
if ((tm.tm_mon = tm.tm_mon - n) < 0) {
tm.tm_mon += 12;
tm.tm_year--;
}
#ifdef SVR4
tm.tm_isdst = -1;
return(mktime(&tm));
#else
return(timelocal(&tm));
#endif /* SVR4 */
}
extern int
leapyr(int y)
{
return
(y % 4 == 0 && y % 100 !=0 || y % 400 == 0);
}
extern int
monthlength(Tick t)
{
int mon;
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
mon = tm.tm_mon;
return(((mon==1) && leapyr(tm.tm_year+1900))? 29 : monthdays[mon]);
}
extern int /* find dow(0-6) that 1st dom falls on */
fdom(Tick t)
{
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_mday = 1;
tm.tm_isdst = -1;
t = mktime(&tm);
tm = *_XLocaltime(&t, localtime_buf);
return(tm.tm_wday);
}
extern int
ldom(Tick t /* find dow(0-6) that last dom falls on */ )
{
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_mday = monthlength(t);
tm.tm_isdst = -1;
t = mktime(&tm);
tm = *_XLocaltime(&t, localtime_buf);
return(tm.tm_wday);
}
extern boolean_t
_DtCmsInExceptionList(cms_entry *eptr, time_t tick)
{
CSA_date_time_entry *dt = NULL;
time_t time;
if (eptr->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value)
dt = eptr->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->\
item.date_time_list_value;
for (; dt != NULL; dt = dt->next) {
if (_csa_iso8601_to_tick(dt->date_time, &time))
continue;
if (time == tick)
return (B_TRUE);
}
return (B_FALSE);
}
static time_t
nextnyear(time_t t, int n)
{
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_year += n;
#ifdef SVR4
return(mktime(&tm));
#else
return(timelocal(&tm));
#endif /* SVR4 */
}
static int
timeok(time_t t)
{
int r =((t >= bot) &&(t <= eot));
return(r);
}
static time_t
prevnyear(time_t t, int n)
{
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_year -= n;
#ifdef SVR4
return(mktime(&tm));
#else
return(timelocal(&tm));
#endif /* SVR4 */
}
static time_t
prevmonth_exactday(time_t t)
{
time_t prev; int day;
struct tm tm;
int sdelta;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
sdelta = tm.tm_hour * hrsec + tm.tm_min * minsec + tm.tm_sec;
day = tm.tm_mday;
if((tm.tm_mday < 31 && tm.tm_mon != 0) || /* at least 30 days everywhere, except Feb.*/
(tm.tm_mday==31 && tm.tm_mon==6) || /* two 31s -- Jul./Aug. */
(tm.tm_mday==31 && tm.tm_mon==11) || /* two 31s -- Dec./Jan. */
(tm.tm_mon == 0 &&(tm.tm_mday < 29 ||(tm.tm_mday==29 && leapyr(tm.tm_year+1900))))) {
prev = t-monthseconds(previousmonth(t));
prev = adjust_dst(t, prev);
}
else { /* brute force */
prev = previousmonth(previousmonth(t)); /* hop over the month */
tm = *_XLocaltime(&prev, localtime_buf);
tm.tm_mday = day;
#ifdef SVR4
tm.tm_isdst = -1;
prev =(mktime(&tm)) + sdelta;
#else
prev =(timelocal(&tm)) + sdelta;
#endif /* SVR4 */
}
return(prev);
}
static time_t
nextmonth_exactday(time_t t)
{
time_t next; int day;
struct tm tm;
int sdelta;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
sdelta = tm.tm_hour * hrsec + tm.tm_min * minsec + tm.tm_sec;
day = tm.tm_mday;
if((tm.tm_mday < 31 && tm.tm_mon != 0) || /* at least 30 days everywhere, except Feb.*/
(tm.tm_mday==31 && tm.tm_mon==6) || /* two 31s -- Jul./Aug. */
(tm.tm_mday==31 && tm.tm_mon==11) || /* two 31s -- Dec./Jan. */
(tm.tm_mon == 0 &&(tm.tm_mday < 29 ||(tm.tm_mday==29 && leapyr(tm.tm_year+1900))))) {
next = t+monthseconds(t);
next = adjust_dst(t, next);
}
else { /* brute force */
next = next_nmonth(t, 2); /* hop over the month */
tm = *_XLocaltime(&next, localtime_buf);
tm.tm_mday = day;
#ifdef SVR4
tm.tm_isdst = -1;
next = mktime(&tm) + sdelta;
#else
next =(timelocal(&tm)) + sdelta;
#endif /* SVR4 */
}
return(next);
}
static time_t
previousmonth(time_t t)
{
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
tm.tm_hour=0;
tm.tm_min=0;
tm.tm_sec=0;
if(tm.tm_mon==0) {
tm.tm_mon=11;
tm.tm_mday=1;
tm.tm_year--;
}
else {
tm.tm_mday=1;
tm.tm_mon--;
}
#ifdef SVR4
tm.tm_isdst = -1;
return(mktime(&tm));
#else
return(timelocal(&tm));
#endif /* SVR4 */
}
static int
monthseconds(time_t t)
{
int mon;
struct tm tm;
_Xltimeparams localtime_buf;
tm = *_XLocaltime(&t, localtime_buf);
mon = tm.tm_mon;
return(((mon==1) && leapyr(tm.tm_year+1900)) ?
29*daysec : monthsecs[mon]);
}
/*
* find the number of instances to be subtracted
*/
static int
get_ndelta(time_t startdate, Period_4 period, int ntimes)
{
struct tm *tm;
int ndelta = 0;
time_t lastdate;
double dlastdate;
_Xltimeparams localtime_buf;
if (period.enddate == 0)
return(ndelta);
/* find last day of the series */
dlastdate = startdate + (double)wksec * (ntimes - 1); /* last week */
if (dlastdate > EOT)
return(ndelta);
else
lastdate = (time_t)dlastdate;
tm = _XLocaltime(&lastdate, localtime_buf);
if (period.period == monThruFri_4 || period.period == monWedFri_4)
lastdate = lastdate + daysec * (5 - tm->tm_wday);
else if (period.period == tueThur_4)
lastdate = lastdate + daysec * (4 - tm->tm_wday);
else if (period.period == daysOfWeek_4)
lastdate = lastdate + daysec *
(lastapptofweek((u_int)period.nth) - tm->tm_wday);
if (period.enddate > lastdate)
return(ndelta);
tm = _XLocaltime(&period.enddate, localtime_buf);
switch (period.period) {
case monThruFri_4:
ndelta = 5 - tm->tm_wday;
break;
case monWedFri_4:
if (tm->tm_wday < 3)
ndelta = 2;
else if (tm->tm_wday < 5)
ndelta = 1;
break;
case tueThur_4:
if (tm->tm_wday < 2)
ndelta = 2;
else if (tm->tm_wday < 4)
ndelta = 1;
break;
case daysOfWeek_4:
ndelta = ntimes_this_week((u_int)period.nth, tm->tm_wday) - 1;
break;
}
return(ndelta);
}
static time_t
lastnthweekday(time_t t, int nth, int ntimes)
{
struct tm tm1, tm2;
time_t tick, ntick;
int delta;
int sdelta;
_Xltimeparams localtime_buf;
/*
* if nth is not specified, assume it's the
* 4th week for the ambiguous case.
*/
if (nth == 0) {
nthweekdayofmonth(t, &nth);
if (nth > 4)
nth = -1;
}
tm1 = *_XLocaltime(&t, localtime_buf);
sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
if (nth > 0) {
if ((tick = next_nmonth(t, ntimes)) == EOT || tick < 0)
return(EOT);
tm2 = *_XLocaltime(&tick, localtime_buf);
delta = tm1.tm_wday - tm2.tm_wday;
if (delta < 0)
delta += 7;
ntick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
} else {
if ((tick = next_nmonth(t, ntimes + 1)) == EOT || tick < 0)
return(EOT);
tm2 = *_XLocaltime(&tick, localtime_buf);
delta = tm2.tm_wday - tm1.tm_wday;
if (tm1.tm_wday >= tm2.tm_wday)
delta += 7;
ntick = tick - (delta * daysec) + sdelta;
}
ntick = adjust_dst(tick, ntick);
return (ntick);
}
static time_t
nextnthweekday(time_t t, int nth)
{
struct tm tm1, tm2;
time_t tick, ntick;
int delta;
int sdelta;
_Xltimeparams localtime_buf;
/*
* if nth is not specified, assume it's the
* 4th week for the ambiguous case.
*/
if (nth == 0) {
nthweekdayofmonth(t, &nth);
if (nth > 4)
nth = -1;
}
tm1 = *_XLocaltime(&t, localtime_buf);
sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
if (nth > 0) {
tick = next_nmonth(t, 1);
tm2 = *_XLocaltime(&tick, localtime_buf);
delta = tm1.tm_wday - tm2.tm_wday;
if (delta < 0)
delta += 7;
ntick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
} else {
tick = next_nmonth(t, 2);
tm2 = *_XLocaltime(&tick, localtime_buf);
delta = tm2.tm_wday - tm1.tm_wday;
if (tm1.tm_wday >= tm2.tm_wday)
delta += 7;
ntick = tick - (delta * daysec) + sdelta;
}
ntick = adjust_dst(tick, ntick);
return (ntick);
}
static time_t
prevnthweekday(time_t t, int nth)
{
struct tm tm1, tm2;
time_t tick, ptick;
int delta;
int sdelta;
_Xltimeparams localtime_buf;
/*
* if nth is not specified, assume it's the
* 4th week for the ambiguous case.
*/
if (nth == 0) {
nthweekdayofmonth(t, &nth);
if (nth > 4)
nth = -1;
}
tm1 = *_XLocaltime(&t, localtime_buf);
sdelta = tm1.tm_hour * hrsec + tm1.tm_min * minsec + tm1.tm_sec;
if (nth > 0) {
tick = prev_nmonth(t, 1);
tm2 = *_XLocaltime(&tick, localtime_buf);
delta = tm1.tm_wday - tm2.tm_wday;
if (delta < 0)
delta += 7;
ptick = tick + (((nth - 1) * 7 + delta) * daysec) + sdelta;
} else {
tick = prev_nmonth(next_nmonth(t, 1), 1);
tm2 = *_XLocaltime(&tick, localtime_buf);
delta = tm2.tm_wday - tm1.tm_wday;
if (tm1.tm_wday >= tm2.tm_wday)
delta += 7;
ptick = tick - (delta * daysec) + sdelta;
}
ptick = adjust_dst(tick, ptick);
return (ptick);
}
/* use double in this routine to avoid integer overflow
* in case n is very large.
*/
static time_t
nextnday_exacttime(time_t t, int n)
{
double next;
next = t + (double)n * daysec;
if (next >= EOT || next < 0)
return(EOT);
else {
next = adjust_dst(t, (time_t)next);
return((time_t)next);
}
}
/*
* This is defined in the private library and is used also by the front
* end -- should it be here?
*/
static time_t
prevnday_exacttime(time_t t, int n)
{
time_t prev;
prev = t - (n * daysec);
prev = adjust_dst(t, prev);
return(prev);
}
/* use double in this routine to avoid integer overflow
* in case n is very large.
*/
static time_t
nextnwk_exacttime(time_t t, int n)
{
double next;
next = t + (double)n * 7 * daysec;
if (next >= EOT || next < 0)
return(EOT);
else {
next = adjust_dst(t, (time_t)next);
return((time_t)next);
}
}
static time_t
prevnwk_exacttime(time_t t, int n)
{
time_t prev;
prev = t - n * 7 * daysec;
prev = adjust_dst(t, prev);
return(prev);
}
static time_t
nextnmth_exactday(time_t t, int n)
{
struct tm tm1, tm2;
boolean_t done = B_FALSE;
time_t next;
_Xltimeparams localtime_buf;
tm1 = *_XLocaltime(&t, localtime_buf);
while (!done) {
if ((next = next_nmonth(t, n)) == EOT || next < 0)
return(EOT);
tm2 = *_XLocaltime(&next, localtime_buf);
/* 1. at least 30 days except feb
* 2. 2/29 on leap year
* 3. 31st on the appropriate month
*/
if ((tm1.tm_mday < 31 && tm2.tm_mon != 1) ||
(tm2.tm_mon == 1 && (tm1.tm_mday < 29 ||
(tm1.tm_mday == 29 && leapyr(tm2.tm_year + 1900)))) ||
(tm1.tm_mday == 31 && ((tm2.tm_mon > 6 && tm2.tm_mon % 2) ||
((tm2.tm_mon <= 6 && (tm2.tm_mon % 2 == 0)))))) {
tm2.tm_sec = tm1.tm_sec;
tm2.tm_min = tm1.tm_min;
tm2.tm_hour = tm1.tm_hour;
tm2.tm_mday = tm1.tm_mday;
done = B_TRUE;
} else
t = next;
}
#ifdef SVR4
tm2.tm_isdst = -1;
next = mktime(&tm2);
#else
next = (timelocal(&tm2));
#endif
return(next);
}
static time_t
prevnmth_exactday(time_t t, int n)
{
struct tm tm1, tm2;
boolean_t done = B_FALSE;
time_t prev;
_Xltimeparams localtime_buf;
tm1 = *_XLocaltime(&t, localtime_buf);
while (!done) {
prev = prev_nmonth(t, n);
tm2 = *_XLocaltime(&prev, localtime_buf);
if ((tm1.tm_mday < 30 && tm2.tm_mon != 1) ||
(tm2.tm_mon == 1 && (tm1.tm_mday < 29 ||
(tm1.tm_mday == 29 && leapyr(tm2.tm_year + 1900)))) ||
(tm1.tm_mday == 31 && ((tm2.tm_mon > 6 && tm2.tm_mon % 2) ||
((tm2.tm_mon <= 6 && (tm2.tm_mon % 2 == 0)))))) {
tm2.tm_sec = tm1.tm_sec;
tm2.tm_min = tm1.tm_min;
tm2.tm_hour = tm1.tm_hour;
tm2.tm_mday = tm1.tm_mday;
done = B_TRUE;
} else
t = prev;
}
#ifdef SVR4
tm2.tm_isdst = -1;
prev = mktime(&tm2);
#else
prev = (timelocal(&tm2));
#endif
return(prev);
}
static time_t
nextmonTofri(time_t t)
{
struct tm *tm;
time_t next;
_Xltimeparams localtime_buf;
tm = _XLocaltime(&t, localtime_buf);
if (tm->tm_wday < 5)
next = t + (int)daysec;
else
next = t + (int)daysec * (8 - tm->tm_wday);
next = adjust_dst(t, next);
return(next);
}
static time_t
prevmonTofri(time_t t)
{
struct tm *tm;
time_t prev;
_Xltimeparams localtime_buf;
tm = _XLocaltime(&t, localtime_buf);
if (tm->tm_wday > 1)
prev = t - (int)daysec;
else
prev = t - (int)daysec * (2 + tm->tm_wday);
prev = adjust_dst(t, prev);
return(prev);
}
static time_t
nextmonwedfri(time_t t)
{
struct tm *tm;
time_t next;
_Xltimeparams localtime_buf;
tm = _XLocaltime(&t, localtime_buf);
if (tm->tm_wday == 5)
next = t + (int)daysec * 3;
else if (tm->tm_wday % 2 || tm->tm_wday == 6)
next = t + (int)daysec * 2;
else
next = t + (int)daysec;
next = adjust_dst(t, next);
return(next);
}
static time_t
prevmonwedfri(time_t t)
{
struct tm *tm;
time_t prev;
_Xltimeparams localtime_buf;
tm = _XLocaltime(&t, localtime_buf);
if (tm->tm_wday == 1)
prev = t - (int)daysec * 3;
else if (tm->tm_wday % 2 || tm->tm_wday == 0)
prev = t - (int)daysec * 2;
else
prev = t - (int)daysec;
prev = adjust_dst(t, prev);
return(prev);
}
static time_t
nexttuethur(time_t t)
{
struct tm *tm;
time_t next;
_Xltimeparams localtime_buf;
tm = _XLocaltime(&t, localtime_buf);
if (tm->tm_wday < 4) {
if (tm->tm_wday % 2)
next = t + (int)daysec;
else
next = t + (int)daysec * 2;
} else
next = t + (int)daysec * (9 - tm->tm_wday);
next = adjust_dst(t, next);
return(next);
}
static time_t
prevtuethur(time_t t)
{
struct tm *tm;
time_t prev;
_Xltimeparams localtime_buf;
tm = _XLocaltime(&t, localtime_buf);
if (tm->tm_wday > 2) {
if (tm->tm_wday % 2)
prev = t - (int)daysec;
else
prev = t - (int)daysec * 2;
} else
prev = t - (int)daysec * (3 + tm->tm_wday);
prev = adjust_dst(t, prev);
return(prev);
}
/*
* the 7-bit mask should be put in the last 7 bits of the int
*/
static time_t
nextdaysofweek(time_t t, int weekmask)
{
unsigned int doublemask;
struct tm *tm;
int i, ndays, daymask;
time_t next;
_Xltimeparams localtime_buf;
doublemask = weekmask | (weekmask << 7);
tm = _XLocaltime(&t, localtime_buf);
daymask = weekdaymasks[tm->tm_wday] << 1;
for (i = 0, ndays = 1; i < 7; i++) {
if (daymask & doublemask)
break;
else {
ndays++;
doublemask >>= 1;
}
}
next = t + (int)daysec * ndays;
next = adjust_dst(t, next);
return(next);
}
static time_t
prevdaysofweek(time_t t, int weekmask)
{
unsigned int doublemask, daymask;
struct tm *tm;
int i, ndays;
time_t prev;
_Xltimeparams localtime_buf;
doublemask = weekmask | (weekmask << 7);
tm = _XLocaltime(&t, localtime_buf);
daymask = weekdaymasks[tm->tm_wday] << 6;
for (i = 0, ndays = 1; i < 7; i++) {
if (daymask & doublemask)
break;
else {
ndays++;
doublemask <<= 1;
}
}
prev = t - (int)daysec * ndays;
prev = adjust_dst(t, prev);
return(prev);
}