xref: /illumos-gate/usr/src/cmd/acct/lib/pnpsplit.c (revision 71d45228ba245d505c3beae1d756e775616f6d5a)
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
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
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
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
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
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
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
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