xref: /openbsd-src/games/atc/log.c (revision b65f9321d8c4b34a2b6b9b358d86bb110f8e6755)
1*b65f9321Sderaadt /*	$OpenBSD: log.c,v 1.26 2024/08/20 15:48:32 deraadt Exp $	*/
2df930be7Sderaadt /*	$NetBSD: log.c,v 1.3 1995/03/21 15:04:21 cgd Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*-
5df930be7Sderaadt  * Copyright (c) 1990, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt  * Ed James.
10df930be7Sderaadt  *
11df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt  * modification, are permitted provided that the following conditions
13df930be7Sderaadt  * are met:
14df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
197a09557bSmillert  * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
21df930be7Sderaadt  *    without specific prior written permission.
22df930be7Sderaadt  *
23df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt  * SUCH DAMAGE.
34df930be7Sderaadt  */
35df930be7Sderaadt 
36df930be7Sderaadt /*
37df930be7Sderaadt  * Copyright (c) 1987 by Ed James, UC Berkeley.  All rights reserved.
38df930be7Sderaadt  *
39df930be7Sderaadt  * Copy permission is hereby granted provided that this notice is
40df930be7Sderaadt  * retained on all partial or complete copies.
41df930be7Sderaadt  *
42df930be7Sderaadt  * For more info on this and all of my stuff, mail edjames@berkeley.edu.
43df930be7Sderaadt  */
44df930be7Sderaadt 
452317ec67Smestre #include <sys/stat.h>
462317ec67Smestre #include <sys/types.h>
472317ec67Smestre 
482317ec67Smestre #include <err.h>
492317ec67Smestre #include <errno.h>
502317ec67Smestre #include <fcntl.h>
512317ec67Smestre #include <stdlib.h>
522317ec67Smestre #include <string.h>
53ee7acb09Stb #include <time.h>
542317ec67Smestre #include <unistd.h>
552317ec67Smestre 
562317ec67Smestre #include "extern.h"
57df930be7Sderaadt #include "pathnames.h"
58df930be7Sderaadt 
59f83b5105Skstailey static FILE *score_fp;
60f83b5105Skstailey 
6131aab2a5Spjanzen int
623eb8c9edSjsg compar(const void *va, const void *vb)
63df930be7Sderaadt {
6431aab2a5Spjanzen 	const SCORE *a, *b;
6531aab2a5Spjanzen 
665803e5dcSpjanzen 	a = (const SCORE *)va;
675803e5dcSpjanzen 	b = (const SCORE *)vb;
68df930be7Sderaadt 	if (b->planes == a->planes)
69df930be7Sderaadt 		return (b->time - a->time);
70df930be7Sderaadt 	else
71df930be7Sderaadt 		return (b->planes - a->planes);
72df930be7Sderaadt }
73df930be7Sderaadt 
74df930be7Sderaadt #define SECAMIN		60
75df930be7Sderaadt #define MINAHOUR	60
76df930be7Sderaadt #define HOURADAY	24
77df930be7Sderaadt #define SECAHOUR	(SECAMIN * MINAHOUR)
78df930be7Sderaadt #define SECADAY		(SECAHOUR * HOURADAY)
79df930be7Sderaadt #define DAY(t)		((t) / SECADAY)
80df930be7Sderaadt #define HOUR(t)		(((t) % SECADAY) / SECAHOUR)
81f0bac872Spjanzen #define MINUTES(t)		(((t) % SECAHOUR) / SECAMIN)
82df930be7Sderaadt #define SEC(t)		((t) % SECAMIN)
83df930be7Sderaadt 
8431aab2a5Spjanzen const char	*
853eb8c9edSjsg timestr(int t)
86df930be7Sderaadt {
87df930be7Sderaadt 	static char	s[80];
88df930be7Sderaadt 
89df930be7Sderaadt 	if (DAY(t) > 0)
9042ceebb3Sderaadt 		(void)snprintf(s, sizeof s, "%dd+%02dhrs", DAY(t), HOUR(t));
91df930be7Sderaadt 	else if (HOUR(t) > 0)
9242ceebb3Sderaadt 		(void)snprintf(s, sizeof s, "%d:%02d:%02d",
9342ceebb3Sderaadt 		    HOUR(t), MINUTES(t), SEC(t));
94f0bac872Spjanzen 	else if (MINUTES(t) > 0)
9542ceebb3Sderaadt 		(void)snprintf(s, sizeof s, "%d:%02d", MINUTES(t), SEC(t));
96df930be7Sderaadt 	else if (SEC(t) > 0)
9742ceebb3Sderaadt 		(void)snprintf(s, sizeof s, ":%02d", SEC(t));
98df930be7Sderaadt 	else
99df930be7Sderaadt 		*s = '\0';
100df930be7Sderaadt 
101df930be7Sderaadt 	return (s);
102df930be7Sderaadt }
103df930be7Sderaadt 
10431aab2a5Spjanzen int
1053eb8c9edSjsg open_score_file(void)
106df930be7Sderaadt {
107f83b5105Skstailey 	mode_t old_mode;
108bf2d3977Stb 	char *home;
109bf2d3977Stb 	char scorefile[PATH_MAX];
110bf2d3977Stb 	int ret;
111f83b5105Skstailey 	int score_fd;
112df930be7Sderaadt 
113bf2d3977Stb 	home = getenv("HOME");
114bf2d3977Stb 	if (home == NULL || *home == '\0')
115bf2d3977Stb 		err(1, "getenv");
116bf2d3977Stb 	ret = snprintf(scorefile, sizeof(scorefile), "%s/%s", home,
117bf2d3977Stb 	    ".atc.scores");
118bf2d3977Stb 	if (ret < 0 || ret >= PATH_MAX)
119bf2d3977Stb 		errc(1, ENAMETOOLONG, "%s/%s", home, ".atc.scores");
120bf2d3977Stb 
121f83b5105Skstailey 	old_mode = umask(0);
122bf2d3977Stb 	score_fd = open(scorefile, O_CREAT|O_RDWR, 0644);
123df69c215Sderaadt 	if (score_fd == -1)
124bf2d3977Stb 		err(1, "open");
125df930be7Sderaadt 	/*
126df930be7Sderaadt 	 * This is done to take advantage of stdio, while still
127df930be7Sderaadt 	 * allowing a O_CREAT during the open(2) of the log file.
128df930be7Sderaadt 	 */
129f83b5105Skstailey 	score_fp = fdopen(score_fd, "r+");
130bf2d3977Stb 	if (score_fp == NULL)
131bf2d3977Stb 		err(1, "fdopen");
132f83b5105Skstailey 	umask(old_mode);
13331aab2a5Spjanzen 	return (0);
134f83b5105Skstailey }
135f83b5105Skstailey 
13631aab2a5Spjanzen int
1373eb8c9edSjsg log_score(int list_em)
138f83b5105Skstailey {
139f83b5105Skstailey 	int		i, num_scores = 0, good, changed = 0, found = 0;
140bf2d3977Stb 	const char	*name;
141f83b5105Skstailey 	char		*cp;
1427163d9d0Spjanzen 	char		scanstr[50];
143f0bac872Spjanzen 	SCORE		score[NUM_SCORES], thisscore;
144f83b5105Skstailey 
14531aab2a5Spjanzen 	if (score_fp == NULL)
14631aab2a5Spjanzen 		return (-1);
147df69c215Sderaadt 	if (flock(fileno(score_fp), LOCK_EX) == -1)
148bf2d3977Stb 		err(1, "flock");
1491717b5a3Schl 	snprintf(scanstr, 50, "%%%zus %%%zus %%d %%d %%d", sizeof(score[0].name)-1,
150cd48ae86Sderaadt 	    sizeof(score[0].game)-1);
151df930be7Sderaadt 	for (;;) {
1527163d9d0Spjanzen 		good = fscanf(score_fp, scanstr,
153df930be7Sderaadt 			score[num_scores].name,
154df930be7Sderaadt 			score[num_scores].game,
155df930be7Sderaadt 			&score[num_scores].planes,
156df930be7Sderaadt 			&score[num_scores].time,
157df930be7Sderaadt 			&score[num_scores].real_time);
158f0bac872Spjanzen 		if (good != 5 || ++num_scores >= NUM_SCORES)
159df930be7Sderaadt 			break;
160df930be7Sderaadt 	}
161df930be7Sderaadt 	if (!test_mode && !list_em) {
162bf2d3977Stb 		name = getenv("LOGNAME");
163bf2d3977Stb 		if (name == NULL || *name == '\0')
164bf2d3977Stb 			name = getenv("USER");
165bf2d3977Stb 		if (name == NULL || *name == '\0')
166bf2d3977Stb 			name = getlogin();
167bf2d3977Stb 		if (name == NULL || *name == '\0')
168bf2d3977Stb 			name = "  ???";
169bf2d3977Stb 		strlcpy(thisscore.name, name, sizeof(thisscore.name));
170df930be7Sderaadt 
171180acc8fSmillert 		cp = strrchr(file, '/');
172df930be7Sderaadt 		if (cp == NULL) {
173f0bac872Spjanzen 			warnx("log: where's the '/' in %s?", file);
174df930be7Sderaadt 			return (-1);
175df930be7Sderaadt 		}
176df930be7Sderaadt 		cp++;
177f0bac872Spjanzen 		strlcpy(thisscore.game, cp, sizeof(thisscore.game));
178df930be7Sderaadt 
179df930be7Sderaadt 		thisscore.time = clck;
180df930be7Sderaadt 		thisscore.planes = safe_planes;
181df930be7Sderaadt 		thisscore.real_time = time(0) - start_time;
182df930be7Sderaadt 
183df930be7Sderaadt 		for (i = 0; i < num_scores; i++) {
184df930be7Sderaadt 			if (strcmp(thisscore.name, score[i].name) == 0 &&
185df930be7Sderaadt 			    strcmp(thisscore.game, score[i].game) == 0) {
186df930be7Sderaadt 				if (thisscore.time > score[i].time) {
187df930be7Sderaadt 					score[i].time = thisscore.time;
188df930be7Sderaadt 					score[i].planes = thisscore.planes;
189df930be7Sderaadt 					score[i].real_time =
190df930be7Sderaadt 						thisscore.real_time;
191df930be7Sderaadt 					changed++;
192df930be7Sderaadt 				}
193df930be7Sderaadt 				found++;
194df930be7Sderaadt 				break;
195df930be7Sderaadt 			}
196df930be7Sderaadt 		}
197df930be7Sderaadt 		if (!found) {
198df930be7Sderaadt 			for (i = 0; i < num_scores; i++) {
199df930be7Sderaadt 				if (thisscore.time > score[i].time) {
200df930be7Sderaadt 					if (num_scores < NUM_SCORES)
201df930be7Sderaadt 						num_scores++;
20231aab2a5Spjanzen 					memcpy(&score[num_scores - 1],
20331aab2a5Spjanzen 						&score[i],
204df930be7Sderaadt 						sizeof (score[i]));
20531aab2a5Spjanzen 					memcpy(&score[i], &thisscore,
206df930be7Sderaadt 						sizeof (score[i]));
207df930be7Sderaadt 					changed++;
208df930be7Sderaadt 					break;
209df930be7Sderaadt 				}
210df930be7Sderaadt 			}
211df930be7Sderaadt 		}
212df930be7Sderaadt 		if (!found && !changed && num_scores < NUM_SCORES) {
21331aab2a5Spjanzen 			memcpy(&score[num_scores], &thisscore,
214df930be7Sderaadt 				sizeof (score[num_scores]));
215df930be7Sderaadt 			num_scores++;
216df930be7Sderaadt 			changed++;
217df930be7Sderaadt 		}
218df930be7Sderaadt 
219cceea54aSderaadt 		if (seeded) {
220cceea54aSderaadt 			puts("The high score list does not include '-r' seeded games.");
221cceea54aSderaadt 		} else if (changed) {
222df930be7Sderaadt 			if (found)
223df930be7Sderaadt 				puts("You beat your previous score!");
224df930be7Sderaadt 			else
225df930be7Sderaadt 				puts("You made the top players list!");
226df930be7Sderaadt 			qsort(score, num_scores, sizeof (*score), compar);
22745555366Smestre 			if (fseek(score_fp, 0L, SEEK_SET) == -1)
22845555366Smestre 				err(1, "fseek");
229df930be7Sderaadt 			for (i = 0; i < num_scores; i++)
230f0bac872Spjanzen 				fprintf(score_fp, "%s %s %d %d %d\n",
231f0bac872Spjanzen 					score[i].name,
232df930be7Sderaadt 					score[i].game, score[i].planes,
233df930be7Sderaadt 					score[i].time, score[i].real_time);
234df930be7Sderaadt 		} else {
235df930be7Sderaadt 			if (found)
236df930be7Sderaadt 				puts("You didn't beat your previous score.");
237df930be7Sderaadt 			else
238df930be7Sderaadt 				puts("You didn't make the top players list.");
239df930be7Sderaadt 		}
240df930be7Sderaadt 		putchar('\n');
241df930be7Sderaadt 	}
242f83b5105Skstailey 	flock(fileno(score_fp), LOCK_UN);
243f83b5105Skstailey 	fflush(score_fp);
244f83b5105Skstailey 	fsync(fileno(score_fp));
24545555366Smestre 	if (fseek(score_fp, 0L, SEEK_SET) == -1)
24645555366Smestre 		err(1, "fseek");
247f0bac872Spjanzen 	printf("%2s:  %-31s  %-18s  %4s  %9s  %4s\n", "#", "name",
248f0bac872Spjanzen 		"game", "time", "real time", "safe");
249df930be7Sderaadt 	puts("-------------------------------------------------------------------------------");
250df930be7Sderaadt 	for (i = 0; i < num_scores; i++) {
251f0bac872Spjanzen 		printf("%2d:  %-31s  %-18s  %4d  %9s  %4d\n", i + 1,
252f0bac872Spjanzen 			score[i].name, score[i].game,
253df930be7Sderaadt 			score[i].time, timestr(score[i].real_time),
254df930be7Sderaadt 			score[i].planes);
255df930be7Sderaadt 	}
256df930be7Sderaadt 	putchar('\n');
257df930be7Sderaadt 	return (0);
258df930be7Sderaadt }
25931aab2a5Spjanzen 
26031aab2a5Spjanzen void
2613eb8c9edSjsg log_score_quit(int dummy)
26231aab2a5Spjanzen {
263*b65f9321Sderaadt 	(void)log_score(0);	/* XXX signal race */
264*b65f9321Sderaadt 	exit(0);		/* XXX signal race */
26531aab2a5Spjanzen }
266