Fix error message when SDL_ttf is not present.
[attac-man.git] / score.c
blob8727f86968c5f50c410df0add97b444e71e7b1db
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <sys/queue.h>
6 #include <sys/types.h>
7 #include <assert.h>
8 #include <errno.h>
10 #include "oglconsole.h"
11 #include "score.h"
13 /* Data stored to disk */
14 struct high_score {
15 char playername[32];
16 uint64_t score;
17 }__attribute__((packed));
18 #define SCORE_FILE (DATADIR "/high-scores")
20 #define NR_HIGH_SCORES 10
21 #define HIGH_SCORES_SIZE (sizeof(struct high_score) * NR_HIGH_SCORES)
22 #define SCORE_VALID(sc) (sc.playername[0] != '\0')
24 /* .bss initialized on program startup */
25 static struct high_score *high_scores;
27 #define TEMPLATE DATADIR "/scores.XXXXXX"
29 void
30 rewrite_score_file(void)
32 int fd, ret, i;
33 char *template;
34 int score_len = sizeof(struct high_score);
35 struct high_score *cur;
36 mode_t oldmask;
38 template = strdup(TEMPLATE);
39 assert(template);
41 /* Write out the new scores to a tmp file */
42 oldmask = umask(0);
43 fd = mkstemp(template);
44 if (fd < 0) {
45 con_printf("Unable to write out new scores file.\n");
46 con_printf("mkstemp failed with %d\n", errno);
47 goto out;
49 ret = fchmod(fd, 0660);
50 if (ret < 0)
51 con_printf("fchmod failed with %d\n", errno);
53 for (i = 0; i < NR_HIGH_SCORES; i++) {
54 if (!SCORE_VALID(high_scores[i]))
55 break;
56 ret = write(fd, &high_scores[i], score_len);
57 if (ret != score_len) {
58 if (ret < 0 && errno == EINTR) {
59 i--;
60 continue;
62 cur = &high_scores[i];
63 close(fd);
64 unlink(template);
65 goto out;
68 close(fd);
70 /* Move the tmp file into place */
71 ret = rename(template, SCORE_FILE);
72 if (ret != 0)
73 con_printf("failed to move new scores file into place [%d]\n",
74 errno);
75 out:
76 free(template);
77 umask(oldmask);
78 return;
82 * The high scores list is pretty small, so it's just an array. Insertion
83 * is done by allocating a new array, and copying the old contents into it,
84 * inserting the score in its proper place. The last element falls off the
85 * list.
87 void
88 insert_score(char *name, uint64_t score, int slot)
90 struct high_score *new_high_scores = malloc(HIGH_SCORES_SIZE);
91 int i, j;
93 assert(new_high_scores);
95 for (i = 0, j = 0; i < NR_HIGH_SCORES; i++) {
96 if (i == slot) {
97 new_high_scores[i].score = score;
98 strcpy(new_high_scores[i].playername, name);
99 continue;
100 } else
101 new_high_scores[i] = high_scores[j];
102 j++;
105 free(high_scores);
106 high_scores = new_high_scores;
109 void
110 add_high_score(char *name, uint64_t score)
112 int i;
114 for (i = 0; i < NR_HIGH_SCORES; i++) {
115 if (score > high_scores[i].score) {
116 insert_score(name, score, i);
117 break;
123 high_score(uint64_t score)
125 if (score > high_scores[NR_HIGH_SCORES-1].score)
126 return 1;
127 return 0;
130 void
131 flock_init(struct flock *fl, short type)
133 memset(fl, 0, sizeof(*fl));
134 fl->l_type = type;
135 fl->l_whence = SEEK_SET;
136 fl->l_start = 0;
137 fl->l_len = 0;
140 score_lock_t
141 lock_scores(void)
143 int fd, ret;
144 struct flock fl;
146 flock_init(&fl, F_WRLCK);
148 fd = open(SCORE_FILE, O_RDWR);
149 if (fd < 0) {
150 con_printf("failed to open scores file!\n");
151 return -1;
154 retry:
155 ret = fcntl(fd, F_SETLKW, &fl);
156 if (ret < 0) {
157 if (errno == EINTR)
158 goto retry;
159 con_printf("failed to lock scores file!\n");
160 close(fd);
161 return -1;
164 return fd;
167 void
168 unlock_scores(score_lock_t lock)
170 int fd = (int)lock;
171 int ret;
172 struct flock fl;
174 flock_init(&fl, F_UNLCK);
176 retry:
177 ret = fcntl(fd, F_SETLKW, &fl);
178 if (ret < 0) {
179 if (errno == EINTR)
180 goto retry;
181 con_printf("Failed to release lock on scores file!\n");
184 close(fd);
187 void
188 debug_print_high_scores(void)
190 int i;
192 for (i = 0; i < NR_HIGH_SCORES; i++) {
193 if (!SCORE_VALID(high_scores[i]))
194 break;
195 con_printf("%s -> %llu\n", high_scores[i].playername,
196 high_scores[i].score);
200 void
201 high_scores_init(void)
203 int fd, ret;
204 struct high_score score;
205 int hs_size = sizeof(struct high_score);
207 fd = open(SCORE_FILE, O_CREAT);
208 if (fd < 0) {
209 perror("open");
210 printf("Unable to open scores file.\n");
211 return;
214 /* File is sorted from highest to lowest */
215 high_scores = malloc(HIGH_SCORES_SIZE);
216 memset(high_scores, 0, HIGH_SCORES_SIZE);
217 assert(high_scores);
218 while ((ret = read(fd, &score, hs_size)) == hs_size)
219 add_high_score(score.playername, score.score);
220 close(fd);