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