-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtournament_files.c
411 lines (355 loc) · 11.8 KB
/
tournament_files.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
/* Windows includes */
#ifdef _WIN32
#include <io.h>
#endif
/* Non-windows includes */
#include <dirent.h>
#include <getopt.h>
#include <libgen.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
/* Local Includes */
#include "entry.h"
#include "data_dir.h"
/** Takes an tournaments name and returns an int representing whether it
* found the tournament in the system.
*
* \param '*t_name' the name of the tournament to be searched for.
* \return integer representing whether the a tournament of the given name was
* not found (-1), was found (>= 0) or if an error was experienced (<= -2).
* If the tournament of the given name was found, its id is returned as the
* return value.
*/
int t_file_contains_tournament(const char *data_dir_file_path, char *t_name) {
char *full_t_file_path = data_dir_file_path_t_file(data_dir_file_path);
FILE* t_file = fopen(full_t_file_path, "rb+");
if (t_file == NULL) {
fprintf(stderr, \
"Error: t_file_contains_tournament(): " \
"opening file \"%s\": ", \
full_t_file_path);
perror("");
return -2;
}
int ret = -1;
unsigned short num_t;
char temp_name[MAX_NAME_LEN + 1];
if (1 != fread(&num_t, sizeof(short), 1, t_file)) return -3;
/* Binary search on file to find given name's id */
long L = 0;
long R = num_t - 1;
long m;
long oldm = 0;
while (L <= R) {
m = floor(((double) (L + R)) / 2.0);
/* Seek to mth spot of array */
fseek(t_file, \
(m - oldm) * (MAX_NAME_LEN + 1 + sizeof(short)), SEEK_CUR);
/* Read corresponding t_id of the array[m] */
unsigned long start_of_m = ftell(t_file);
short t_id = -1;
if (1 != fread(&t_id, sizeof(short), 1, t_file)) return -4;
/* Read t name of the array[m] */
int j = 0;
if (1 != fread(&temp_name[j], sizeof(char), 1, t_file)) return -5;
/* Provided it hasn't hit a null terminator or end of file */
while (temp_name[j] != '\0' && j < MAX_NAME_LEN && !(feof(t_file))) {
j++;
if (1 != fread(&temp_name[j], sizeof(char), 1, t_file)) return -6;
}
/* Seek to start of array[m] so fseek to next spot isn't offset */
fseek(t_file, start_of_m, SEEK_SET);
int comp = strncmp(&temp_name[0], t_name, MAX_NAME_LEN);
if (0 > comp) {
oldm = m;
L = m + 1;
} else if (0 < comp) {
oldm = m;
R = m - 1;
} else {
ret = t_id;
R = L - 1; /* Terminate loop */
}
}
fclose(t_file);
free(full_t_file_path);
/* The tournament name was not found, return -1 */
return ret;
}
/** Helper function that writes the t_id and tournament name in the provided
* entry to an open file.
*
* \param '*E' a pointer to a struct entry containing the info to be written.
* \param '*f' an open file pointer where the content will be written.
* \return 0 upon success, a negative integer upon failure.
*/
int write_new_t_name(struct entry *E, FILE *f) {
if (1 != fwrite(&E->tournament_id, sizeof(short), 1, f)) return -1;
if (E->len_t_name != \
fwrite(&E->t_name, sizeof(char), E->len_t_name, f)) {
return -2;
}
char zero = '\0';
for (int i = 0; i < MAX_NAME_LEN + 1 - E->len_t_name; i++) {
if (1 != fwrite(&zero, sizeof(char), 1, f)) return -3;
}
return 0;
}
/** Takes a struct entry containing a filled in 't_name' and set
* 'tournament_id', and adds it to the system.
*
* \param '*E' a struct entry with a set 't_name' and 'tournament_id'.
* \return integer representing whether the function failed or succeeded.
* It will return < 0 if the function failed, and 0 if it succeeded.
*/
int t_file_add_new_tournament(const char *data_dir_file_path, struct entry *E) {
char *full_t_file_path = data_dir_file_path_t_file(data_dir_file_path);
FILE *t_file = fopen(full_t_file_path, "rb");
if (t_file == NULL) {
fprintf(stderr, \
"Error: t_file_add_new_tournament(): " \
"opening file \"%s\": ", \
full_t_file_path);
perror("");
return -1;
}
char new_file_name[] = { "tempG2MEXXXXXX\0" };
int r = mkstemp(new_file_name);
close(r);
unlink(new_file_name);
// TODO: may need to modify the lines of code above for windows
#ifdef _WIN32
/* If compiling on macOS or Linux */
#else
#endif
FILE *new_file = fopen(new_file_name, "wb+");
if (new_file == NULL) {
fprintf(stderr, \
"Error: t_file_add_new_tournament(): " \
"opening file \"%s\": ", \
new_file_name);
perror("");
return -2;
}
char zero = '\0';
unsigned short num_t;
char wrote_new_name = 0;
/* Read number of tournaments and write [said number + 1] to temp file */
if (1 != fread(&num_t, sizeof(short), 1, t_file)) return -11;
/* Correct the t_id (0 indexed id) */
E->tournament_id = num_t;
num_t += 1;
if (1 != fwrite(&num_t, sizeof(short), 1, new_file)) return -12;
/* Read and write all the names of the tournaments to the temp file */
for (int i = 0; i < num_t - 1; i++) {
unsigned short id = -1;
char name[MAX_NAME_LEN + 1];
if (1 != fread(&id, sizeof(short), 1, t_file)) return -13;
if (MAX_NAME_LEN + 1 != \
fread(&name[0], sizeof(char), MAX_NAME_LEN + 1, t_file)) {
return -15;
}
/* If the name to be inserted is lexiographically before the name about
* to be written, write the new name first */
if (wrote_new_name != 1) {
if (0 > strncmp(E->t_name, &name[0], E->len_t_name)) {
if (0 != write_new_t_name(E, new_file)) return -16;
wrote_new_name = 1;
}
}
if (1 != fwrite(&id, sizeof(short), 1, new_file)) return -14;
if (MAX_NAME_LEN + 1 != \
fwrite(&name[0], sizeof(char), MAX_NAME_LEN + 1, new_file)) {
return -14;
}
}
if (wrote_new_name != 1) {
if (0 != write_new_t_name(E, new_file)) return -16;
}
fclose(new_file);
fclose(t_file);
/* Delete original file */
remove(full_t_file_path);
/* Copy temp file to original file path */
rename(new_file_name, full_t_file_path);
free(full_t_file_path);
char *full_t_id_file_path = data_dir_file_path_t_id_file(data_dir_file_path);
FILE *t_id_file = fopen(full_t_id_file_path, "rb+");
if (t_id_file == NULL) {
fprintf(stderr, \
"Error: t_file_add_new_tournament(): " \
"opening file \"%s\": ", \
full_t_id_file_path);
perror("");
return -1;
}
/* Update counter at start of file */
if (1 != fwrite(&num_t, sizeof(short), 1, t_id_file)) return -12;
if (0 != fseek(t_id_file, 0, SEEK_END)) return -13;
if (E->len_t_name != \
fwrite(&E->t_name, sizeof(char), E->len_t_name, t_id_file)) return -14;
for (int i = 0; i < MAX_NAME_LEN + 1 - E->len_t_name; i++) {
if (1 != fwrite(&zero, sizeof(char), 1, t_id_file)) return -14;
}
fclose(t_id_file);
free(full_t_id_file_path);
return 0;
}
/** Takes an entry containing the tournament id to be searched for. Updates the
* struct entry's 't_name' field to the tournament name associated with the
* given 'tournament_id'.
*
* \param '*E' the struct entry containing the tournament id to be
* searched for, and which will have its 't_name' field updated to
* the name, if this function is successful.
* \return 0 upon success, and a negative value if there was an error.
*/
int t_file_get_tournament_name_from_id(const char *data_dir_file_path, \
struct entry *E) {
char *full_t_id_file_path = \
data_dir_file_path_t_id_file(data_dir_file_path);
FILE* t_id_file = fopen(full_t_id_file_path, "rb+");
if (t_id_file == NULL) {
fprintf(stderr, \
"Error: t_file_get_tournament_name_from_id(): " \
"opening file \"%s\": ", \
full_t_id_file_path);
perror("");
return -1;
}
unsigned short num_t;
if (1 != fread(&num_t, sizeof(short), 1, t_id_file)) return -2;
/* If the id is outside of the range of the array */
if (E->tournament_id >= num_t) return -3;
/* Seek to the location of the name in the file by using its id */
fseek(t_id_file, \
sizeof(short) + E->tournament_id * (MAX_NAME_LEN + 1), SEEK_SET);
int j = 0;
/* Read first byte and add to name */
if (1 != fread(&E->t_name[j], sizeof(char), 1, t_id_file )) return -4;
/* Provided it hasn't hit a null terminator or end of file */
while (E->t_name[j] != '\0' && j < MAX_NAME_LEN && !(feof(t_id_file ))) {
j++;
if (1 != fread(&E->t_name[j], sizeof(char), 1, t_id_file)) return -5;
}
E->len_t_name = j - 1;
fclose(t_id_file);
free(full_t_id_file_path);
return 0;
}
/** Takes an struct entry containing the tournament name to be
* searched for. Returns the id of a tournament, given the name of a
* tournament. Returns -1 if the tournament of that name could not be found.
* Returns < -1 if there was an error.
*
* \param '*E' the struct entry containing the tournament name to be
* searched for and which will have its tournament_id field updated to
* the id if this function is successful.
* \return non-negative number upon success (the tournament's id), -1 if the
* name could not be found, and < -1 if there was an error.
*/
int t_file_get_tournament_id_from_name(const char *data_dir_file_path, \
struct entry *E) {
char *full_t_file_path = data_dir_file_path_t_file(data_dir_file_path);
FILE* t_file = fopen(full_t_file_path, "rb+");
if (t_file == NULL) {
fprintf(stderr, \
"Error: t_file_get_tournament_id_from_name(): " \
"opening file \"%s\": ", \
full_t_file_path);
perror("");
return -1;
}
int ret = -1;
unsigned short num_t;
char temp_name[MAX_NAME_LEN + 1];
if (1 != fread(&num_t, sizeof(short), 1, t_file)) return -7;
/* Binary search on file to find given name's id */
long L = 0;
long R = num_t - 1;
long m;
long oldm = 0;
while (L <= R) {
m = floor(((double) (L + R)) / 2.0);
/* Seek to mth spot of array */
fseek(t_file, \
(m - oldm) * (MAX_NAME_LEN + 1 + sizeof(short)), SEEK_CUR);
/* Read corresponding t_id of the array[m] */
unsigned long start_of_m = ftell(t_file);
short t_id = -1;
if (1 != fread(&t_id, sizeof(short), 1, t_file)) return -8;
/* Read t name of the array[m] */
int j = 0;
if (1 != fread(&temp_name[j], sizeof(char), 1, t_file)) return -11;
/* Provided it hasn't hit a null terminator or end of file */
while (temp_name[j] != '\0' && j < MAX_NAME_LEN && !(feof(t_file))) {
j++;
if (1 != fread(&temp_name[j], sizeof(char), 1, t_file)) return -11;
}
/* Seek to start of array[m] so fseek to next spot isn't offset */
fseek(t_file, start_of_m, SEEK_SET);
int comp = strncmp(&temp_name[0], E->t_name, MAX_NAME_LEN);
if (0 > comp) {
oldm = m;
L = m + 1;
} else if (0 < comp) {
oldm = m;
R = m - 1;
} else {
ret = t_id;
E->tournament_id = t_id;
R = L - 1; /* Terminate loop */
}
}
/* The tournament name was not found, return -1 */
return ret;
}
/** On success, returns the id of the most recent season. Returns < -1 if there
* was an error. -1 is a reserved return value since season ids are 0 indexed,
* and an empty system's most recent season should be -1.
*
* \return number >= -1 upon success (the most recent season id),
* and < -2 if there was an error.
*/
short s_file_get_latest_season_id(const char *data_dir_file_path) {
char *full_season_file_path = \
data_dir_file_path_season_file(data_dir_file_path);
FILE* s_file = fopen(full_season_file_path, "rb+");
if (s_file == NULL) {
fprintf(stderr, \
"Error: s_file_get_latest_season_id(): " \
"opening file \"%s\": ", \
full_season_file_path);
perror("");
return -2;
}
int ret = -3;
if (1 != fread(&ret, sizeof(short), 1, s_file)) return -4;
fclose(s_file);
return ret;
}
/** Writes the latest season id 'new_s_id' to the global season file.
*
* \return 0 upon success, a negative number if there was an error.
*/
int s_file_set_latest_season_id(const char *data_dir_file_path, int new_s_id) {
char *full_season_file_path = \
data_dir_file_path_season_file(data_dir_file_path);
FILE* s_file = fopen(full_season_file_path, "rb+");
if (s_file == NULL) {
fprintf(stderr, \
"Error: s_file_set_latest_season_id(): " \
"opening file \"%s\": ", \
full_season_file_path);
perror("");
return -1;
}
if (1 != fwrite(&new_s_id, sizeof(short), 1, s_file)) { return -2; }
fclose(s_file);
return 0;
}