1 /*                                                              */
2 /* score.c --  for xemeraldia                                   */
3 /*                                                              */
4 /* This file is copied from "xtetris" Version 2.5, and modified */
5 
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9 
10 #include "games.h"
11 #include <string.h>
12 #include <errno.h>
13 #include <sys/file.h>
14 #include <sys/types.h>
15 #include <time.h>
16 #include <unistd.h>
17 
18 #ifdef HAVE_FCNTL_H
19 #include <fcntl.h>
20 #endif
21 
22 FILE *f_scores = NULL;
23 int errno_scores;
24 
25 /* #define DEBUG */
26 
27 #define HIGH_TABLE_SIZE 30      /* size of high score table */
28 
29 static struct score_table
30 {
31 	char name[28];
32 	int score;
33 	int level;
34 	time_t date;
35 } high_scores[HIGH_TABLE_SIZE];
36 
37 
update_highscore_table()38 void  update_highscore_table ()
39 {
40   int           i, j;
41 
42   if (! app_data.usescorefile) return;
43   read_high_scores ();
44 
45   /* Check for previous best score */
46   for (i = 0; i < HIGH_TABLE_SIZE; i++)
47     {
48       if (strcmp (name, high_scores[i].name) == 0) break;
49     }
50   if (i < HIGH_TABLE_SIZE)
51     {
52       /* We have a previous best score. */
53       if (high_scores[i].score >= sc)
54 	return;                       /* Same/worse score - no update */
55       for (j = i; j > 0; j--)         /* Remove previous best */
56 	high_scores[j] = high_scores[j - 1];
57     }
58 
59   /* Next line finds score greater than current one */
60   for (i = 0; i < HIGH_TABLE_SIZE && sc >= high_scores[i].score; i++);
61   i--;
62   if (i >= 0)
63     {
64       for (j = 0; j < i; j++)
65 	high_scores[j] = high_scores[j + 1];
66       strcpy(high_scores[i].name, name);
67       high_scores[i].score = sc;
68       high_scores[i].level = blocks / 20 + 1;
69       time(&(high_scores[i].date));
70       write_high_scores ();
71     }
72 }
73 
open_high_scores_file()74 void open_high_scores_file()
75 {
76 	f_scores = fopen (app_data.scorefile, "r+");
77 	if(!f_scores)
78 		f_scores = fopen (app_data.scorefile, "w+");
79 	if(!f_scores)
80 		errno_scores = errno;
81 #ifdef HAVE_SETREGID
82 	setregid(getgid(),getgid());
83 #endif
84 }
85 
read_high_scores()86 void  read_high_scores()
87 {
88 	int    i;
89 #if HAVE_LOCKF
90 	struct flock fl;
91 #endif
92 
93   if (! app_data.usescorefile)  return;
94 
95 #ifdef F_SETLKW
96 	fl.l_type = F_RDLCK;
97 	fl.l_whence = SEEK_SET;
98 	fl.l_start = 0;
99 	fl.l_len = 0;
100 	if(fcntl(fileno(f_scores), F_SETLKW, &fl))
101 	{
102 		perror(_("read_high_scores:can't lock for reading"));
103 		return;
104 	}
105 #elif HAVE_FLOCK
106 	if(flock(fileno(f_scores), LOCK_SH) == -1)
107 	{
108 		perror(_("read_high_scores:can't lock for reading"));
109 		return;
110 	}
111 #endif
112 	clearerr(f_scores);
113 	rewind(f_scores);
114   for (i = 0; i < HIGH_TABLE_SIZE; i++)
115     {
116       struct score_table *score = &(high_scores[i]);
117       if(feof(f_scores) || ferror(f_scores) || 4 != fscanf(f_scores, "%12[^,],%7d,%6d,%ld\n",
118 		      score->name,
119 		      &score->score,
120 		      &score->level,
121 		      &score->date))
122 	{
123 	  strcpy( score->name, _("No name") );
124 	  score->date = -1;
125 	  score->level = score->score = 0;
126 	}
127     }
128 #ifdef F_SETLKW
129 	fl.l_type = F_UNLCK;
130 	if(fcntl(fileno(f_scores), F_SETLKW, &fl))
131 		perror(_("read_high_scores:can't unlock"));
132 #elif HAVE_FLOCK
133   if (flock (fileno (f_scores), LOCK_UN) == -1)
134     perror (_("read_high_scores:can't unlock"));
135 #endif
136 }
137 
138 
write_high_scores()139 void  write_high_scores()
140 {
141 	int     i;
142 #if HAVE_LOCKF
143 	struct flock fl;
144 #endif
145 
146 #ifdef F_SETLKW
147 	fl.l_type = F_WRLCK;
148 	fl.l_whence = SEEK_SET;
149 	fl.l_start = 0;
150 	fl.l_len = 0;
151 	if(fcntl(fileno(f_scores), F_SETLKW, &fl))
152 	{
153 		perror(_("write_high_scores:can't lock for writing"));
154 		return;
155 	}
156 #elif HAVE_FLOCK
157 	if (flock(fileno(f_scores), LOCK_EX) == -1)
158 	{
159 		perror(_("write_high_scores:can't lock for writing"));
160 		return;
161 	}
162 #endif
163 	rewind(f_scores);
164 	if(ftruncate(fileno(f_scores), 0) != 0)
165 	{
166 		perror(_("write_high_scores:can't truncate scores file"));
167 		return;
168 	}
169 	for (i = 0; i < HIGH_TABLE_SIZE; i++)
170 	fprintf (f_scores, "%-12s,%7d,%6d,%ld\n",
171 	     high_scores[i].name,
172 	     high_scores[i].score,
173 	     high_scores[i].level,
174 	     high_scores[i].date);
175 	fflush(f_scores);
176 #if HAVE_LOCKF
177 	fl.l_type = F_UNLCK;
178 	if(fcntl(fileno(f_scores), F_SETLKW, &fl))
179 		perror(_("write_high_scores:can't unlock"));
180 #elif HAVE_FLOCK
181   if (flock (fileno (f_scores), LOCK_UN) == -1)
182     perror (_("write_high_scores:can't unlock"));
183 #endif
184 }
185 
186 
PrintHighScores()187 void  PrintHighScores ()
188 {
189 	GtkWidget *table, *align, *scroll;
190 	GtkListStore *model;
191 	GtkTreeIter iter;
192 	GtkCellRenderer *renderer;
193 	GtkTreeViewColumn *column;
194 	GtkTreeSelection *sel;
195 	int     i;
196 
197 	if (! app_data.usescorefile) return;
198 	read_high_scores();
199 	score_frame = gtk_dialog_new_with_buttons(_("xemeraldia's high scores"),
200 		GTK_WINDOW(topLevel),
201 		GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
202 		GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT,
203 		NULL);
204 	gtk_dialog_set_default_response(GTK_DIALOG(score_frame), GTK_RESPONSE_ACCEPT);
205 
206 	model = gtk_list_store_new(4,
207 		G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING);
208 
209 	for (i = HIGH_TABLE_SIZE-1; i >= 0; i--)
210 	{
211 		if (high_scores[i].score != 0)
212 		{
213 			char d[100], *dd;
214 			strftime(d, sizeof(d), "%c", localtime(&(high_scores[i].date)));
215 			dd = g_locale_to_utf8(d, -1, NULL, NULL, NULL);
216 			gtk_list_store_append(model, &iter);
217 			gtk_list_store_set(model, &iter,
218 				0, high_scores[i].name,
219 				1, high_scores[i].score,
220 				2, high_scores[i].level,
221 				3, dd,
222 				-1);
223 			g_free(dd);
224 		}
225 	}
226 
227 	table = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
228 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(table), TRUE);
229 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(table));
230 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_NONE);
231 
232 	renderer = gtk_cell_renderer_text_new ();
233 	column = gtk_tree_view_column_new_with_attributes (_("Name"),
234 		renderer,
235 		"text", 0,
236 		NULL);
237 	gtk_tree_view_append_column (GTK_TREE_VIEW (table), column);
238 
239 	renderer = gtk_cell_renderer_text_new ();
240 	column = gtk_tree_view_column_new_with_attributes (_("Score"),
241 		renderer,
242 		"text", 1,
243 		NULL);
244 	gtk_tree_view_append_column (GTK_TREE_VIEW (table), column);
245 
246 	renderer = gtk_cell_renderer_text_new ();
247 	column = gtk_tree_view_column_new_with_attributes (_("Level"),
248 		renderer,
249 		"text", 2,
250 		NULL);
251 	gtk_tree_view_append_column (GTK_TREE_VIEW (table), column);
252 
253 	renderer = gtk_cell_renderer_text_new ();
254 	column = gtk_tree_view_column_new_with_attributes (_("Date"),
255 		renderer,
256 		"text", 3,
257 		NULL);
258 	gtk_tree_view_append_column (GTK_TREE_VIEW (table), column);
259 
260 	align = gtk_alignment_new(.5, .5, .8, .7);
261 	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(score_frame)->vbox), align, TRUE, TRUE, 0);
262 
263 	scroll = gtk_scrolled_window_new(NULL, NULL);
264 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
265 
266 	gtk_container_add(GTK_CONTAINER(scroll), table);
267 
268 	gtk_container_add(GTK_CONTAINER(align), scroll);
269 
270 //	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(score_frame)->vbox), gtk_label_new("Hola"), TRUE, TRUE, 0);
271 
272 	gtk_widget_set_size_request(score_frame,500,200);
273 
274 	gtk_widget_show_all(score_frame);
275 	gtk_dialog_run(GTK_DIALOG(score_frame));
276 	gtk_widget_destroy(score_frame);
277 }
278