336 lines
8.2 KiB
C
336 lines
8.2 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: recount.c /main/6 1996/11/21 19:45:46 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.
|
|
*/
|
|
|
|
#define XOS_USE_NO_LOCKING
|
|
#define X_INCLUDE_TIME_H
|
|
#if defined(__linux__)
|
|
#undef SVR4
|
|
#endif
|
|
#include <X11/Xos_r.h>
|
|
|
|
#include <EUSCompat.h>
|
|
#include "csa.h"
|
|
#include "rerule.h"
|
|
#include "repeat.h"
|
|
#include "reutil.h"
|
|
#include "iso8601.h"
|
|
|
|
static int InitialEventsToExclude(time_t, RepeatEvent *);
|
|
static int EventsPerMonth(RepeatEvent *);
|
|
static int DoBruteForce(const time_t, RepeatEvent *);
|
|
|
|
/*
|
|
* Give a start time, a parsed rule and a list of exception dates, determine
|
|
* the number of events that will be generated.
|
|
*/
|
|
int
|
|
CountEvents(
|
|
Tick start_time,
|
|
RepeatEvent *re,
|
|
CSA_date_time_entry *dte)
|
|
{
|
|
time_t exclude_time,
|
|
close_time;
|
|
int excluded_days = 0;
|
|
unsigned int nevents1 = (unsigned int)-1,
|
|
nevents2 = (unsigned int)-1;
|
|
|
|
if (!re || !start_time) return RE_ERROR;
|
|
|
|
if (!re->re_end_date && re->re_duration == RE_INFINITY)
|
|
return RE_INFINITY;
|
|
|
|
/*
|
|
* Count the number of times an excluded time hits an event time
|
|
* generated by the rule.
|
|
*/
|
|
for (; dte; dte = dte->next) {
|
|
RepeatEventState *res;
|
|
|
|
if (_csa_iso8601_to_tick(dte->date_time, &exclude_time) == -1)
|
|
continue;
|
|
|
|
if (!(close_time = ClosestTick(exclude_time, start_time, re,
|
|
&res))) {
|
|
time_t last_time;
|
|
|
|
last_time = LastTick(start_time, re);
|
|
if (last_time == exclude_time)
|
|
excluded_days++;
|
|
} else {
|
|
if (close_time == exclude_time)
|
|
excluded_days++;
|
|
}
|
|
|
|
_DtCm_free_re_state(res);
|
|
}
|
|
|
|
/*
|
|
* If there is an end date, then we must calculate the total number
|
|
* of events via the brute force method.
|
|
*/
|
|
if (re->re_end_date) {
|
|
nevents1 = DoBruteForce(start_time, re) - excluded_days;
|
|
}
|
|
|
|
if (re->re_duration == RE_NOTSET)
|
|
return nevents1;
|
|
|
|
switch (re->re_type) {
|
|
case RT_MINUTE:
|
|
break;
|
|
case RT_DAILY:
|
|
nevents2 = re->re_duration;
|
|
break;
|
|
case RT_WEEKLY:
|
|
if (!RE_WEEKLY(re)->wd_ndaytime)
|
|
nevents2 = re->re_duration;
|
|
else
|
|
nevents2 = re->re_duration *
|
|
RE_WEEKLY(re)->wd_ndaytime;
|
|
|
|
nevents2 -= InitialEventsToExclude(start_time, re);
|
|
break;
|
|
case RT_MONTHLY_POSITION: {
|
|
int events_per_month = EventsPerMonth(re);
|
|
|
|
if (!events_per_month) {
|
|
nevents2 = DoBruteForce(start_time, re);
|
|
} else {
|
|
nevents2 = re->re_duration * events_per_month -
|
|
InitialEventsToExclude(start_time, re);
|
|
}
|
|
break;
|
|
}
|
|
case RT_MONTHLY_DAY: {
|
|
int ndays = RE_MONTHLY(re)->md_nitems;
|
|
struct tm *start_tm;
|
|
_Xltimeparams localtime_buf;
|
|
|
|
start_tm = _XLocaltime((const time_t *)&start_time, localtime_buf);
|
|
/*
|
|
* Need to do this by brute force if they want days that may
|
|
* not exist in a given month.
|
|
*/
|
|
if (((!ndays) && start_tm->tm_mday > 28) ||
|
|
(ndays && RE_MONTHLY(re)->md_days[ndays - 1] > 28)) {
|
|
nevents2 = DoBruteForce(start_time, re);
|
|
} else {
|
|
if (!ndays)
|
|
nevents2 = re->re_duration;
|
|
else
|
|
nevents2 = re->re_duration * ndays;
|
|
|
|
nevents2 -= InitialEventsToExclude(start_time, re);
|
|
}
|
|
break;
|
|
}
|
|
case RT_YEARLY_MONTH:
|
|
if (!RE_YEARLY(re)->yd_nitems)
|
|
nevents2 = re->re_duration;
|
|
else
|
|
nevents2 = re->re_duration *
|
|
RE_YEARLY(re)->yd_nitems;
|
|
nevents2 -= InitialEventsToExclude(start_time, re);
|
|
break;
|
|
case RT_YEARLY_DAY:
|
|
if (!RE_YEARLY(re)->yd_nitems)
|
|
nevents2 = re->re_duration;
|
|
else
|
|
nevents2 = re->re_duration *
|
|
RE_YEARLY(re)->yd_nitems;
|
|
nevents2 -= InitialEventsToExclude(start_time, re);
|
|
break;
|
|
}
|
|
|
|
nevents2 -= excluded_days;
|
|
|
|
/*
|
|
* If both a duration and and enddate are set the policy is to use
|
|
* the lesser of the two.
|
|
*/
|
|
if (nevents1 < nevents2)
|
|
return nevents1;
|
|
|
|
return nevents2;
|
|
}
|
|
|
|
/*
|
|
* If the rule is a weekly or monthly style with specific weekdays listed,
|
|
* such as W1 MO WE FR and the start_time indicates the rule starts on say a
|
|
* WE, then the first MO would not count as an event day so it must be
|
|
* excluded from the total count.
|
|
*/
|
|
static int
|
|
InitialEventsToExclude(
|
|
time_t start_time,
|
|
RepeatEvent *re)
|
|
{
|
|
struct tm *start_tm;
|
|
_Xltimeparams localtime_buf;
|
|
|
|
start_tm = _XLocaltime((const time_t *)&start_time, localtime_buf);
|
|
|
|
if (re->re_type == RT_WEEKLY) {
|
|
DayTime *daytime = (DayTime *)RE_WEEKLY(re)->wd_daytime;
|
|
int nevent_days = RE_WEEKLY(re)->wd_ndaytime,
|
|
i;
|
|
|
|
if (!nevent_days) return 0;
|
|
|
|
for (i = 0; i < nevent_days; i++) {
|
|
if (daytime[i].dt_day >= start_tm->tm_wday)
|
|
return i;
|
|
}
|
|
return (nevent_days);
|
|
} else if (re->re_type == RT_MONTHLY_POSITION) {
|
|
WeekDayTime *wdt = (WeekDayTime *)RE_MONTHLY(re)->md_weektime;
|
|
int i,
|
|
ndays = 0;
|
|
|
|
for (i = 0; i < RE_MONTHLY(re)->md_nitems; i++) {
|
|
int j, k;
|
|
time_t date;
|
|
|
|
for (j = 0;
|
|
j < RE_MONTHLY(re)->md_weektime[i].wdt_nweek;
|
|
j++) {
|
|
|
|
for (k = 0;
|
|
k < RE_MONTHLY(re)->md_weektime[i].wdt_nday;
|
|
k++) {
|
|
|
|
date = WeekNumberToDay(start_time,
|
|
RE_MONTHLY(re)->md_weektime[i].
|
|
wdt_week[j],
|
|
RE_MONTHLY(re)->md_weektime[i].
|
|
wdt_day[k]);
|
|
if (!date || date < start_time)
|
|
ndays++;
|
|
}
|
|
}
|
|
}
|
|
return (ndays);
|
|
} else if (re->re_type == RT_MONTHLY_DAY) {
|
|
int i;
|
|
|
|
if (!RE_MONTHLY(re)->md_nitems) return 0;
|
|
|
|
for (i = 0; i < RE_MONTHLY(re)->md_nitems; i++) {
|
|
if (RE_MONTHLY(re)->md_days[i] >= start_tm->tm_mday)
|
|
return i;
|
|
}
|
|
return (RE_MONTHLY(re)->md_nitems);
|
|
} else if (re->re_type == RT_YEARLY_MONTH) {
|
|
int i;
|
|
|
|
if (!RE_YEARLY(re)->yd_nitems) return 0;
|
|
|
|
for (i = 0; i < RE_YEARLY(re)->yd_nitems; i++) {
|
|
if (RE_YEARLY(re)->yd_items[i] >= (start_tm->tm_mon +1))
|
|
return i;
|
|
}
|
|
return (RE_YEARLY(re)->yd_nitems);
|
|
} else if (re->re_type == RT_YEARLY_DAY) {
|
|
int i;
|
|
|
|
if (!RE_YEARLY(re)->yd_nitems) return 0;
|
|
|
|
for (i = 0; i < RE_YEARLY(re)->yd_nitems; i++) {
|
|
if (RE_YEARLY(re)->yd_items[i] >=
|
|
(start_tm->tm_yday + 1))
|
|
return i;
|
|
}
|
|
return (RE_YEARLY(re)->yd_nitems);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Given a parsed MP rule determine the number of events it would generate
|
|
* in a month. If the rule suggests events should occure on the 5th week
|
|
* which means the number of events generated in a given month is not
|
|
* constant, we return 0.
|
|
*/
|
|
static int
|
|
EventsPerMonth(
|
|
RepeatEvent *re)
|
|
{
|
|
int nevents = 1,
|
|
i;
|
|
|
|
for (i = 0, nevents = 0; i < RE_MONTHLY(re)->md_nitems; i++) {
|
|
int j;
|
|
|
|
/* If 5+ or 5- is used, we must compute count by brute force */
|
|
for (j = 0; j < RE_MONTHLY(re)->md_weektime[i].wdt_nweek; j++) {
|
|
if ((RE_MONTHLY(re)->md_weektime[i].wdt_week[j] ==
|
|
WK_F5) ||
|
|
(RE_MONTHLY(re)->md_weektime[i].wdt_week[j] ==
|
|
WK_L5))
|
|
return 0;
|
|
}
|
|
|
|
nevents += RE_MONTHLY(re)->md_weektime[i].wdt_nday *
|
|
RE_MONTHLY(re)->md_weektime[i].wdt_nweek;
|
|
}
|
|
|
|
return nevents;
|
|
}
|
|
|
|
/*
|
|
* Given a start time and a parsed rule determine the number events generated
|
|
* by walking the event stream until we reach the end.
|
|
*/
|
|
static int
|
|
DoBruteForce(
|
|
const time_t start_time,
|
|
RepeatEvent *re)
|
|
{
|
|
RepeatEventState *res;
|
|
time_t cur_time;
|
|
int nevents = 0;
|
|
|
|
|
|
if (!(cur_time = ClosestTick(start_time, start_time, re, &res)))
|
|
return nevents;
|
|
|
|
nevents = 1;
|
|
|
|
while ((cur_time = NextTick(cur_time, start_time, re, res))) {
|
|
nevents++;
|
|
}
|
|
|
|
_DtCm_free_re_state(res);
|
|
|
|
return nevents;
|
|
}
|