xref: /openbsd/games/atc/log.c (revision 78b63d65)
1 /*	$OpenBSD: log.c,v 1.9 2001/08/06 22:59:13 pjanzen Exp $	*/
2 /*	$NetBSD: log.c,v 1.3 1995/03/21 15:04:21 cgd Exp $	*/
3 
4 /*-
5  * Copyright (c) 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Ed James.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  */
39 
40 /*
41  * Copyright (c) 1987 by Ed James, UC Berkeley.  All rights reserved.
42  *
43  * Copy permission is hereby granted provided that this notice is
44  * retained on all partial or complete copies.
45  *
46  * For more info on this and all of my stuff, mail edjames@berkeley.edu.
47  */
48 
49 #ifndef lint
50 #if 0
51 static char sccsid[] = "@(#)log.c	8.1 (Berkeley) 5/31/93";
52 #else
53 static char rcsid[] = "$OpenBSD: log.c,v 1.9 2001/08/06 22:59:13 pjanzen Exp $";
54 #endif
55 #endif /* not lint */
56 
57 #include "include.h"
58 #include "pathnames.h"
59 
60 static FILE *score_fp;
61 
62 int
63 compar(va, vb)
64 	const void *va, *vb;
65 {
66 	const SCORE *a, *b;
67 
68 	a = (const SCORE *)va;
69 	b = (const SCORE *)vb;
70 	if (b->planes == a->planes)
71 		return (b->time - a->time);
72 	else
73 		return (b->planes - a->planes);
74 }
75 
76 #define SECAMIN		60
77 #define MINAHOUR	60
78 #define HOURADAY	24
79 #define SECAHOUR	(SECAMIN * MINAHOUR)
80 #define SECADAY		(SECAHOUR * HOURADAY)
81 #define DAY(t)		((t) / SECADAY)
82 #define HOUR(t)		(((t) % SECADAY) / SECAHOUR)
83 #define MINUTES(t)		(((t) % SECAHOUR) / SECAMIN)
84 #define SEC(t)		((t) % SECAMIN)
85 
86 const char	*
87 timestr(t)
88 	int t;
89 {
90 	static char	s[80];
91 
92 	if (DAY(t) > 0)
93 		(void)sprintf(s, "%dd+%02dhrs", DAY(t), HOUR(t));
94 	else if (HOUR(t) > 0)
95 		(void)sprintf(s, "%d:%02d:%02d", HOUR(t), MINUTES(t), SEC(t));
96 	else if (MINUTES(t) > 0)
97 		(void)sprintf(s, "%d:%02d", MINUTES(t), SEC(t));
98 	else if (SEC(t) > 0)
99 		(void)sprintf(s, ":%02d", SEC(t));
100 	else
101 		*s = '\0';
102 
103 	return (s);
104 }
105 
106 int
107 open_score_file()
108 {
109 	mode_t old_mode;
110 	int score_fd;
111 
112 	old_mode = umask(0);
113 	score_fd = open(_PATH_SCORE, O_CREAT|O_RDWR, 0664);
114 	if (score_fd < 0) {
115 		perror(_PATH_SCORE);
116 		return (-1);
117 	}
118 	/*
119 	 * This is done to take advantage of stdio, while still
120 	 * allowing a O_CREAT during the open(2) of the log file.
121 	 */
122 	score_fp = fdopen(score_fd, "r+");
123 	if (score_fp == NULL) {
124 		perror(_PATH_SCORE);
125 		return (-1);
126 	}
127 	umask(old_mode);
128 	return (0);
129 }
130 
131 int
132 log_score(list_em)
133 	int list_em;
134 {
135 	int		i, num_scores = 0, good, changed = 0, found = 0;
136 	struct passwd	*pw;
137 	char		*cp;
138 	char		scanstr[50];
139 	SCORE		score[NUM_SCORES], thisscore;
140 
141 	if (score_fp == NULL)
142 		return (-1);
143 #ifdef BSD
144 	if (flock(fileno(score_fp), LOCK_EX) < 0)
145 #endif
146 #ifdef SYSV
147 	while (lockf(fileno(score_fp), F_LOCK, 1) < 0)
148 #endif
149 	{
150 		perror("flock");
151 		return (-1);
152 	}
153 	snprintf(scanstr, 50, "%%%ds %%256s %%d %%d %%d", MAXLOGNAME);
154 	for (;;) {
155 		good = fscanf(score_fp, scanstr,
156 			score[num_scores].name,
157 			score[num_scores].game,
158 			&score[num_scores].planes,
159 			&score[num_scores].time,
160 			&score[num_scores].real_time);
161 		if (good != 5 || ++num_scores >= NUM_SCORES)
162 			break;
163 	}
164 	if (!test_mode && !list_em) {
165 		if ((pw = (struct passwd *) getpwuid(getuid())) == NULL) {
166 			fprintf(stderr,
167 				"getpwuid failed for uid %d.  Who are you?\n",
168 				getuid());
169 			return (-1);
170 		}
171 		strlcpy(thisscore.name, pw->pw_name, sizeof(thisscore.name));
172 
173 		cp = strrchr(file, '/');
174 		if (cp == NULL) {
175 			warnx("log: where's the '/' in %s?", file);
176 			return (-1);
177 		}
178 		cp++;
179 		strlcpy(thisscore.game, cp, sizeof(thisscore.game));
180 
181 		thisscore.time = clck;
182 		thisscore.planes = safe_planes;
183 		thisscore.real_time = time(0) - start_time;
184 
185 		for (i = 0; i < num_scores; i++) {
186 			if (strcmp(thisscore.name, score[i].name) == 0 &&
187 			    strcmp(thisscore.game, score[i].game) == 0) {
188 				if (thisscore.time > score[i].time) {
189 					score[i].time = thisscore.time;
190 					score[i].planes = thisscore.planes;
191 					score[i].real_time =
192 						thisscore.real_time;
193 					changed++;
194 				}
195 				found++;
196 				break;
197 			}
198 		}
199 		if (!found) {
200 			for (i = 0; i < num_scores; i++) {
201 				if (thisscore.time > score[i].time) {
202 					if (num_scores < NUM_SCORES)
203 						num_scores++;
204 					memcpy(&score[num_scores - 1],
205 						&score[i],
206 						sizeof (score[i]));
207 					memcpy(&score[i], &thisscore,
208 						sizeof (score[i]));
209 					changed++;
210 					break;
211 				}
212 			}
213 		}
214 		if (!found && !changed && num_scores < NUM_SCORES) {
215 			memcpy(&score[num_scores], &thisscore,
216 				sizeof (score[num_scores]));
217 			num_scores++;
218 			changed++;
219 		}
220 
221 		if (changed) {
222 			if (found)
223 				puts("You beat your previous score!");
224 			else
225 				puts("You made the top players list!");
226 			qsort(score, num_scores, sizeof (*score), compar);
227 			rewind(score_fp);
228 			for (i = 0; i < num_scores; i++)
229 				fprintf(score_fp, "%s %s %d %d %d\n",
230 					score[i].name,
231 					score[i].game, score[i].planes,
232 					score[i].time, score[i].real_time);
233 		} else {
234 			if (found)
235 				puts("You didn't beat your previous score.");
236 			else
237 				puts("You didn't make the top players list.");
238 		}
239 		putchar('\n');
240 	}
241 #ifdef BSD
242 	flock(fileno(score_fp), LOCK_UN);
243 #endif
244 #ifdef SYSV
245 	/* lock will evaporate upon close */
246 #endif
247 #if 0
248 	fclose(score_fp);
249 #else
250 	fflush(score_fp);
251 	fsync(fileno(score_fp));
252 	rewind(score_fp);
253 #endif
254 	printf("%2s:  %-31s  %-18s  %4s  %9s  %4s\n", "#", "name",
255 		"game", "time", "real time", "safe");
256 	puts("-------------------------------------------------------------------------------");
257 	for (i = 0; i < num_scores; i++) {
258 		printf("%2d:  %-31s  %-18s  %4d  %9s  %4d\n", i + 1,
259 			score[i].name, score[i].game,
260 			score[i].time, timestr(score[i].real_time),
261 			score[i].planes);
262 	}
263 	putchar('\n');
264 	return (0);
265 }
266 
267 void
268 log_score_quit(dummy)
269 	int dummy;
270 {
271 	(void)log_score(0);
272 	exit(0);
273 }
274