1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29
30 /*
31 * pnpsplit splits interval into prime & nonprime portions
32 * ONLY ROUTINE THAT KNOWS ABOUT HOLIDAYS AND DEFN OF PRIME/NONPRIME
33 */
34
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include "acctdef.h"
39 #include <time.h>
40 #include <ctype.h>
41
42 /*
43 * validate that hours and minutes of prime/non-prime read in
44 * from holidays file fall within proper boundaries.
45 * Time is expected in the form and range of 0000-2400.
46 */
47
48 static int thisyear = 1970; /* this is changed by holidays file */
49 static int holidays[NHOLIDAYS]; /* holidays file day-of-year table */
50
51
52 static int day_tab[2][13] = {
53 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
54 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
55 };
56
57 /*
58 * prime(0) and nonprime(1) times during a day
59 * for BTL, prime time is 9AM to 5PM
60 */
61 static struct hours {
62 int h_sec; /* normally always zero */
63 int h_min; /* initialized from holidays file (time%100) */
64 int h_hour; /* initialized from holidays file (time/100) */
65 long h_type; /* prime/nonprime of previous period */
66 } h[4];
67 int daysend[] = {0, 60, 23}; /* the sec, min, hr of the day's end */
68
69 struct tm *localtime();
70 long tmsecs();
71
72 /*
73 * split interval of length etime, starting at start into prime/nonprime
74 * values, return as result
75 * input values in seconds
76 */
77 int
pnpsplit(start,etime,result)78 pnpsplit(start, etime, result)
79 long start, result[2];
80 ulong_t etime;
81 {
82 struct tm cur, end;
83 time_t tcur, tend;
84 long tmp;
85 int sameday;
86 register struct hours *hp;
87 char *memcpy();
88
89 /* once holidays file is read, this is zero */
90 if(thisyear && (checkhol() == 0)) {
91 return(0);
92 }
93 tcur = start;
94 tend = start + etime;
95 memcpy(&end, localtime(&tend), sizeof(end));
96 result[PRIME] = 0;
97 result[NONPRIME] = 0;
98
99 while ( tcur < tend ) { /* one iteration per day or part thereof */
100 memcpy(&cur, localtime(&tcur), sizeof(cur));
101 sameday = cur.tm_yday == end.tm_yday;
102 if (ssh(&cur)) { /* ssh:only NONPRIME */
103 if (sameday) {
104 result[NONPRIME] += tend-tcur;
105
106 break;
107 } else {
108 tmp = tmsecs(&cur, daysend);
109 result[NONPRIME] += tmp;
110 tcur += tmp;
111 }
112 } else { /* working day, PRIME or NONPRIME */
113 for (hp = h; tmless(hp, &cur); hp++);
114 for (; hp->h_sec >= 0; hp++) {
115 if (sameday && tmless(&end, hp)) {
116 /* WHCC mod, change from = to += 3/6/86 Paul */
117 result[hp->h_type] += tend-tcur;
118 tcur = tend;
119 break; /* all done */
120 } else { /* time to next PRIME /NONPRIME change */
121 tmp = tmsecs(&cur, hp);
122 result[hp->h_type] += tmp;
123 tcur += tmp;
124 cur.tm_sec = hp->h_sec;
125 cur.tm_min = hp->h_min;
126 cur.tm_hour = hp->h_hour;
127 }
128 }
129 }
130 }
131 return(1);
132 }
133
134 /*
135 * Starting day after Christmas, complain if holidays not yet updated.
136 * This code is only executed once per program invocation.
137 */
138 int
checkhol()139 checkhol()
140 {
141 register struct tm *tp;
142 time_t t;
143
144 if(inithol() == 0) {
145 fprintf(stderr, "pnpsplit: holidays table setup failed\n");
146 thisyear = 0;
147 holidays[0] = -1;
148 return(0);
149 }
150 time(&t);
151 tp = localtime(&t);
152 tp->tm_year += 1900;
153 if ((tp->tm_year == thisyear && tp->tm_yday > 359)
154 || tp->tm_year > thisyear)
155 fprintf(stderr,
156 "***UPDATE %s WITH NEW HOLIDAYS***\n", HOLFILE);
157 thisyear = 0; /* checkhol() will not be called again */
158 return(1);
159 }
160
161 /*
162 * ssh returns 1 if Sat, Sun, or Holiday
163 */
164 int
ssh(ltp)165 ssh(ltp)
166 register struct tm *ltp;
167 {
168 int i;
169
170 if (ltp->tm_wday == 0 || ltp->tm_wday == 6)
171 return(1);
172 for (i = 0; holidays[i] >= 0; i++)
173 if (ltp->tm_yday == holidays[i])
174 return(1);
175 return(0);
176 }
177
178 /*
179 * inithol - read from an ascii file and initialize the "thisyear"
180 * variable, the times that prime and non-prime start, and the
181 * holidays array.
182 */
183 int
inithol()184 inithol()
185 {
186 FILE *fopen(), *holptr;
187 char *fgets(), holbuf[128];
188 register int line = 0,
189 holindx = 0,
190 errflag = 0;
191 int pstart, npstart;
192 int doy; /* day of the year */
193 int month, day;
194 char *c;
195
196 if((holptr=fopen(HOLFILE, "r")) == NULL) {
197 perror(HOLFILE);
198 fclose(holptr);
199 return(0);
200 }
201 while(fgets(holbuf, sizeof(holbuf), holptr) != NULL) {
202 /* skip over blank lines and comments */
203 if (holbuf[0] == '*')
204 continue;
205
206 for (c = holbuf; isspace(*c); c++)
207 /* is a space */;
208
209 if (*c == '\0')
210 continue;
211
212 else if(++line == 1) { /* format: year p-start np-start */
213 if(sscanf(holbuf, "%4d %4d %4d",
214 &thisyear, &pstart, &npstart) != 3) {
215 fprintf(stderr,
216 "%s: bad {yr ptime nptime} conversion\n",
217 HOLFILE);
218 errflag++;
219 break;
220 }
221
222 /* validate year */
223 if(thisyear < 1970 || thisyear > 2037) {
224 fprintf(stderr, "pnpsplit: invalid year: %d\n",
225 thisyear);
226 errflag++;
227 break;
228 }
229
230 /* validate prime/nonprime hours */
231 if((! okay(pstart)) || (! okay(npstart))) {
232 fprintf(stderr,
233 "pnpsplit: invalid p/np hours\n");
234 errflag++;
235 break;
236 }
237
238 /* Set up start of prime time; 2400 == 0000 */
239 h[0].h_sec = 0;
240 h[0].h_min = pstart%100;
241 h[0].h_hour = (pstart/100==24) ? 0 : pstart/100;
242 h[0].h_type = NONPRIME;
243
244 /* Set up start of non-prime time; 2400 == 2360 */
245 if ((npstart/100) == 24) {
246 h[1].h_sec = 0;
247 h[1].h_min = 60;
248 h[1].h_hour = 23;
249 } else {
250 h[1].h_sec = 0;
251 h[1].h_min = npstart % 100;
252 h[1].h_hour = npstart / 100;
253 }
254
255 h[1].h_type = PRIME;
256
257 /* This is the end of the day */
258 h[2].h_sec = 0;
259 h[2].h_min = 60;
260 h[2].h_hour = 23;
261 h[2].h_type = NONPRIME;
262
263 /* The end of the array */
264 h[3].h_sec = -1;
265
266 continue;
267 }
268 else if(holindx >= NHOLIDAYS) {
269 fprintf(stderr, "pnpsplit: too many holidays, ");
270 fprintf(stderr, "recompile with larger NHOLIDAYS\n");
271 errflag++;
272 break;
273 }
274
275 /* Fill up holidays array from holidays file */
276 sscanf(holbuf, "%d/%d %*s %*s %*[^\n]\n", &month, &day);
277 if (month < 0 || month > 12) {
278 fprintf(stderr, "pnpsplit: invalid month %d\n", month);
279 errflag++;
280 break;
281 }
282 if (day < 0 || day > 31) {
283 fprintf(stderr, "pnpsplit: invalid day %d\n", day);
284 errflag++;
285 break;
286 }
287 doy = day_of_year(thisyear, month, day);
288 holidays[holindx++] = (doy - 1);
289 }
290 fclose(holptr);
291 if(!errflag && holindx < NHOLIDAYS) {
292 holidays[holindx] = -1;
293 return(1);
294 }
295 else
296 return(0);
297 }
298
299 /*
300 * tmsecs returns number of seconds from t1 to t2,
301 * times expressed in localtime format.
302 * assumed that t1 <= t2, and are in same day.
303 */
304
305 long
tmsecs(t1,t2)306 tmsecs(t1, t2)
307 register struct tm *t1, *t2;
308 {
309 return((t2->tm_sec - t1->tm_sec) +
310 60*(t2->tm_min - t1->tm_min) +
311 3600L*(t2->tm_hour - t1->tm_hour));
312 }
313
314 /*
315 * return 1 if t1 earlier than t2 (times in localtime format)
316 * assumed that t1 and t2 are in same day
317 */
318
319 int
tmless(t1,t2)320 tmless(t1, t2)
321 register struct tm *t1, *t2;
322 {
323 if (t1->tm_hour != t2->tm_hour)
324 return(t1->tm_hour < t2->tm_hour);
325 if (t1->tm_min != t2->tm_min)
326 return(t1->tm_min < t2->tm_min);
327 return(t1->tm_sec < t2->tm_sec);
328 }
329
330 /* set day of year from month and day */
331
332 int
day_of_year(year,month,day)333 day_of_year(year, month, day)
334 {
335 int i, leap;
336
337 leap = year%4 == 0 && year%100 || year%400 == 0;
338 for (i = 1; i < month; i++)
339 day += day_tab[leap][i];
340 return(day);
341 }
342