Initial import of the CDE 2.1.30 sources from the Open Group.
This commit is contained in:
310
cde/programs/dtcm/server/recount.c
Normal file
310
cde/programs/dtcm/server/recount.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/* $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
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user