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