xref: /openbsd/games/robots/score.c (revision aa41ab08)
1 /*	$OpenBSD: score.c,v 1.17 2023/10/10 09:48:06 tb Exp $	*/
2 /*	$NetBSD: score.c,v 1.3 1995/04/22 10:09:12 cgd Exp $	*/
3 
4 /*
5  * Copyright (c) 1980, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <fcntl.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include "robots.h"
39 
40 char	Scorefile[PATH_MAX];
41 
42 #ifndef MAX_PER_UID
43 #define MAX_PER_UID	5
44 #endif
45 
46 int	Max_per_uid = MAX_PER_UID;
47 
48 static SCORE	Top[MAXSCORES];
49 
50 /*
51  * score:
52  *	Post the player's score, if reasonable, and then print out the
53  *	top list.
54  */
55 void
score(int score_wfd)56 score(int score_wfd)
57 {
58 	int	inf = score_wfd;
59 	SCORE	*scp;
60 	uid_t	uid;
61 	bool	done_show = FALSE;
62 	static int	numscores, max_uid;
63 
64 	Newscore = FALSE;
65 	if (inf < 0)
66 		return;
67 
68 	if (read(inf, &max_uid, sizeof max_uid) == sizeof max_uid)
69 		read(inf, Top, sizeof Top);
70 	else {
71 		for (scp = Top; scp < &Top[MAXSCORES]; scp++)
72 			scp->s_score = -1;
73 		max_uid = Max_per_uid;
74 	}
75 
76 	uid = getuid();
77 	if (Top[MAXSCORES-1].s_score <= Score) {
78 		numscores = 0;
79 		for (scp = Top; scp < &Top[MAXSCORES]; scp++)
80 			if (scp->s_score < 0 ||
81 			    (scp->s_uid == uid && ++numscores == max_uid)) {
82 				if (scp->s_score > Score)
83 					break;
84 				scp->s_score = Score;
85 				scp->s_uid = uid;
86 				set_name(scp);
87 				Newscore = TRUE;
88 				break;
89 			}
90 		if (scp == &Top[MAXSCORES]) {
91 			Top[MAXSCORES-1].s_score = Score;
92 			Top[MAXSCORES-1].s_uid = uid;
93 			set_name(&Top[MAXSCORES-1]);
94 			Newscore = TRUE;
95 		}
96 		if (Newscore)
97 			qsort(Top, MAXSCORES, sizeof Top[0], cmp_sc);
98 	}
99 
100 	if (!Newscore) {
101 		Full_clear = FALSE;
102 		fsync(inf);
103 		lseek(inf, 0, SEEK_SET);
104 		return;
105 	}
106 	else
107 		Full_clear = TRUE;
108 
109 	for (scp = Top; scp < &Top[MAXSCORES]; scp++) {
110 		if (scp->s_score < 0)
111 			break;
112 		move((scp - Top) + 1, 6);
113 		if (!done_show && scp->s_uid == uid && scp->s_score == Score)
114 			standout();
115 		printw(" %td\t%d\t%-*s ", (scp - Top) + 1, scp->s_score,
116 			(int)(sizeof scp->s_name), scp->s_name);
117 		if (!done_show && scp->s_uid == uid && scp->s_score == Score) {
118 			standend();
119 			done_show = TRUE;
120 		}
121 	}
122 	Num_scores = scp - Top;
123 	refresh();
124 
125 	if (Newscore) {
126 		lseek(inf, 0L, SEEK_SET);
127 		write(inf, &max_uid, sizeof max_uid);
128 		write(inf, Top, sizeof Top);
129 	}
130 	fsync(inf);
131 	lseek(inf, 0, SEEK_SET);
132 }
133 
134 void
set_name(SCORE * scp)135 set_name(SCORE *scp)
136 {
137 	const char	*name;
138 
139 	name = getenv("LOGNAME");
140 	if (name == NULL || *name == '\0')
141 		name = getenv("USER");
142 	if (name == NULL || *name == '\0')
143 		name = getlogin();
144 	if (name == NULL || *name == '\0')
145 		name = "  ???";
146 
147 	strlcpy(scp->s_name, name, LOGIN_NAME_MAX);
148 }
149 
150 /*
151  * cmp_sc:
152  *	Compare two scores.
153  */
154 int
cmp_sc(const void * s1,const void * s2)155 cmp_sc(const void *s1, const void *s2)
156 {
157 	return ((SCORE *)s2)->s_score - ((SCORE *)s1)->s_score;
158 }
159 
160 /*
161  * show_score:
162  *	Show the score list for the '-s' option.
163  */
164 void
show_score(void)165 show_score(void)
166 {
167 	SCORE	*scp;
168 	int	inf;
169 	static int	max_score;
170 
171 	if ((inf = open(Scorefile, O_RDONLY)) == -1) {
172 		perror(Scorefile);
173 		return;
174 	}
175 
176 	for (scp = Top; scp < &Top[MAXSCORES]; scp++)
177 		scp->s_score = -1;
178 
179 	read(inf, &max_score, sizeof max_score);
180 	read(inf, Top, sizeof Top);
181 	close(inf);
182 	inf = 1;
183 	for (scp = Top; scp < &Top[MAXSCORES]; scp++)
184 		if (scp->s_score >= 0)
185 			printf("%d\t%d\t%.*s\n", inf++, scp->s_score,
186 				(int)(sizeof scp->s_name), scp->s_name);
187 }
188