xref: /openbsd/games/robots/score.c (revision 17df1aa7)
1 /*	$OpenBSD: score.c,v 1.10 2009/10/27 23:59:26 deraadt 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	"robots.h"
34 #include	"pathnames.h"
35 
36 char	*Scorefile = _PATH_SCORE;
37 
38 #ifndef MAX_PER_UID
39 #define MAX_PER_UID	5
40 #endif
41 
42 int	Max_per_uid = MAX_PER_UID;
43 
44 static SCORE	Top[MAXSCORES];
45 
46 /*
47  * score:
48  *	Post the player's score, if reasonable, and then print out the
49  *	top list.
50  */
51 void
52 score(int score_wfd)
53 {
54 	int	inf = score_wfd;
55 	SCORE	*scp;
56 	uid_t	uid;
57 	bool	done_show = FALSE;
58 	static int	numscores, max_uid;
59 
60 	Newscore = FALSE;
61 	if (inf < 0)
62 		return;
63 
64 	if (read(inf, &max_uid, sizeof max_uid) == sizeof max_uid)
65 		read(inf, Top, sizeof Top);
66 	else {
67 		for (scp = Top; scp < &Top[MAXSCORES]; scp++)
68 			scp->s_score = -1;
69 		max_uid = Max_per_uid;
70 	}
71 
72 	uid = getuid();
73 	if (Top[MAXSCORES-1].s_score <= Score) {
74 		numscores = 0;
75 		for (scp = Top; scp < &Top[MAXSCORES]; scp++)
76 			if (scp->s_score < 0 ||
77 			    (scp->s_uid == uid && ++numscores == max_uid)) {
78 				if (scp->s_score > Score)
79 					break;
80 				scp->s_score = Score;
81 				scp->s_uid = uid;
82 				set_name(scp);
83 				Newscore = TRUE;
84 				break;
85 			}
86 		if (scp == &Top[MAXSCORES]) {
87 			Top[MAXSCORES-1].s_score = Score;
88 			Top[MAXSCORES-1].s_uid = uid;
89 			set_name(&Top[MAXSCORES-1]);
90 			Newscore = TRUE;
91 		}
92 		if (Newscore)
93 			qsort(Top, MAXSCORES, sizeof Top[0], cmp_sc);
94 	}
95 
96 	if (!Newscore) {
97 		Full_clear = FALSE;
98 		fsync(inf);
99 		lseek(inf, 0, SEEK_SET);
100 		return;
101 	}
102 	else
103 		Full_clear = TRUE;
104 
105 	for (scp = Top; scp < &Top[MAXSCORES]; scp++) {
106 		if (scp->s_score < 0)
107 			break;
108 		move((scp - Top) + 1, 15);
109 		if (!done_show && scp->s_uid == uid && scp->s_score == Score)
110 			standout();
111 		printw(" %d\t%d\t%-*s ", (scp - Top) + 1, scp->s_score,
112 			(int)(sizeof scp->s_name), scp->s_name);
113 		if (!done_show && scp->s_uid == uid && scp->s_score == Score) {
114 			standend();
115 			done_show = TRUE;
116 		}
117 	}
118 	Num_scores = scp - Top;
119 	refresh();
120 
121 	if (Newscore) {
122 		lseek(inf, 0L, SEEK_SET);
123 		write(inf, &max_uid, sizeof max_uid);
124 		write(inf, Top, sizeof Top);
125 	}
126 	fsync(inf);
127 	lseek(inf, 0, SEEK_SET);
128 }
129 
130 void
131 set_name(SCORE *scp)
132 {
133 	PASSWD	*pp;
134 
135 	if ((pp = getpwuid(scp->s_uid)) == NULL)
136 		pp->pw_name = "???";
137 	strlcpy(scp->s_name, pp->pw_name, MAXLOGNAME);
138 }
139 
140 /*
141  * cmp_sc:
142  *	Compare two scores.
143  */
144 int
145 cmp_sc(const void *s1, const void *s2)
146 {
147 	return ((SCORE *)s2)->s_score - ((SCORE *)s1)->s_score;
148 }
149 
150 /*
151  * show_score:
152  *	Show the score list for the '-s' option.
153  */
154 void
155 show_score(void)
156 {
157 	SCORE	*scp;
158 	int	inf;
159 	static int	max_score;
160 
161 	if ((inf = open(Scorefile, O_RDONLY)) < 0) {
162 		perror(Scorefile);
163 		return;
164 	}
165 
166 	for (scp = Top; scp < &Top[MAXSCORES]; scp++)
167 		scp->s_score = -1;
168 
169 	read(inf, &max_score, sizeof max_score);
170 	read(inf, Top, sizeof Top);
171 	close(inf);
172 	inf = 1;
173 	for (scp = Top; scp < &Top[MAXSCORES]; scp++)
174 		if (scp->s_score >= 0)
175 			printf("%d\t%d\t%.*s\n", inf++, scp->s_score,
176 				(int)(sizeof scp->s_name), scp->s_name);
177 }
178