#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include "acctdef.h"
#include <time.h>
#include <ctype.h>
static int thisyear = 1970;
static int holidays[NHOLIDAYS];
static int day_tab[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
static struct hours {
int h_sec;
int h_min;
int h_hour;
long h_type;
} h[4];
struct tm daysend = {
.tm_sec = 0,
.tm_min = 60,
.tm_hour = 23
};
long tmsecs(struct tm *, struct tm *);
int
pnpsplit(long start, ulong_t etime, long result[2])
{
struct tm cur, end, hours;
time_t tcur, tend;
long tmp;
int sameday;
struct hours *hp;
if(thisyear && (checkhol() == 0)) {
return(0);
}
tcur = start;
tend = start + etime;
memcpy(&end, localtime(&tend), sizeof(end));
result[PRIME] = 0;
result[NONPRIME] = 0;
while ( tcur < tend ) {
memcpy(&cur, localtime(&tcur), sizeof(cur));
sameday = cur.tm_yday == end.tm_yday;
if (ssh(&cur)) {
if (sameday) {
result[NONPRIME] += tend-tcur;
break;
} else {
tmp = tmsecs(&cur, &daysend);
result[NONPRIME] += tmp;
tcur += tmp;
}
} else {
for (hp = h; tmless(hp, &cur); hp++);
for (; hp->h_sec >= 0; hp++) {
if (sameday && tmless(&end, hp)) {
result[hp->h_type] += tend-tcur;
tcur = tend;
break;
} else {
hours.tm_sec = hp->h_sec;
hours.tm_min = hp->h_min;
hours.tm_hour = hp->h_hour;
tmp = tmsecs(&cur, &hours);
result[hp->h_type] += tmp;
tcur += tmp;
cur.tm_sec = hp->h_sec;
cur.tm_min = hp->h_min;
cur.tm_hour = hp->h_hour;
}
}
}
}
return(1);
}
int
checkhol(void)
{
struct tm *tp;
time_t t;
if(inithol() == 0) {
fprintf(stderr, "pnpsplit: holidays table setup failed\n");
thisyear = 0;
holidays[0] = -1;
return(0);
}
time(&t);
tp = localtime(&t);
tp->tm_year += 1900;
if ((tp->tm_year == thisyear && tp->tm_yday > 359)
|| tp->tm_year > thisyear)
fprintf(stderr,
"***UPDATE %s WITH NEW HOLIDAYS***\n", HOLFILE);
thisyear = 0;
return(1);
}
int
ssh(struct tm *ltp)
{
int i;
if (ltp->tm_wday == 0 || ltp->tm_wday == 6)
return(1);
for (i = 0; holidays[i] >= 0; i++)
if (ltp->tm_yday == holidays[i])
return(1);
return(0);
}
int
inithol(void)
{
FILE *holptr;
char holbuf[128];
int line = 0,
holindx = 0,
errflag = 0;
int pstart, npstart;
int doy;
int month, day;
char *c;
if((holptr=fopen(HOLFILE, "r")) == NULL) {
perror(HOLFILE);
fclose(holptr);
return(0);
}
while(fgets(holbuf, sizeof(holbuf), holptr) != NULL) {
if (holbuf[0] == '*')
continue;
for (c = holbuf; isspace(*c); c++)
;
if (*c == '\0')
continue;
else if(++line == 1) {
if(sscanf(holbuf, "%4d %4d %4d",
&thisyear, &pstart, &npstart) != 3) {
fprintf(stderr,
"%s: bad {yr ptime nptime} conversion\n",
HOLFILE);
errflag++;
break;
}
if(thisyear < 1970 || thisyear > 2037) {
fprintf(stderr, "pnpsplit: invalid year: %d\n",
thisyear);
errflag++;
break;
}
if((! okay(pstart)) || (! okay(npstart))) {
fprintf(stderr,
"pnpsplit: invalid p/np hours\n");
errflag++;
break;
}
h[0].h_sec = 0;
h[0].h_min = pstart%100;
h[0].h_hour = (pstart/100==24) ? 0 : pstart/100;
h[0].h_type = NONPRIME;
if ((npstart/100) == 24) {
h[1].h_sec = 0;
h[1].h_min = 60;
h[1].h_hour = 23;
} else {
h[1].h_sec = 0;
h[1].h_min = npstart % 100;
h[1].h_hour = npstart / 100;
}
h[1].h_type = PRIME;
h[2].h_sec = 0;
h[2].h_min = 60;
h[2].h_hour = 23;
h[2].h_type = NONPRIME;
h[3].h_sec = -1;
continue;
}
else if(holindx >= NHOLIDAYS) {
fprintf(stderr, "pnpsplit: too many holidays, ");
fprintf(stderr, "recompile with larger NHOLIDAYS\n");
errflag++;
break;
}
sscanf(holbuf, "%d/%d %*s %*s %*[^\n]\n", &month, &day);
if (month < 0 || month > 12) {
fprintf(stderr, "pnpsplit: invalid month %d\n", month);
errflag++;
break;
}
if (day < 0 || day > 31) {
fprintf(stderr, "pnpsplit: invalid day %d\n", day);
errflag++;
break;
}
doy = day_of_year(thisyear, month, day);
holidays[holindx++] = (doy - 1);
}
fclose(holptr);
if(!errflag && holindx < NHOLIDAYS) {
holidays[holindx] = -1;
return(1);
}
else
return(0);
}
long
tmsecs(struct tm *t1, struct tm *t2)
{
return((t2->tm_sec - t1->tm_sec) +
60*(t2->tm_min - t1->tm_min) +
3600L*(t2->tm_hour - t1->tm_hour));
}
int
tmless(struct tm *t1, struct tm *t2)
{
if (t1->tm_hour != t2->tm_hour)
return(t1->tm_hour < t2->tm_hour);
if (t1->tm_min != t2->tm_min)
return(t1->tm_min < t2->tm_min);
return(t1->tm_sec < t2->tm_sec);
}
int
day_of_year(int year, int month, int day)
{
int i, leap;
leap = year%4 == 0 && year%100 || year%400 == 0;
for (i = 1; i < month; i++)
day += day_tab[leap][i];
return(day);
}