Rev 4997 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1652 | terminx | 1 | //------------------------------------------------------------------------- |
2 | /* |
||
3 | Copyright (C) 2010 EDuke32 developers and contributors |
||
4 | |||
5 | This file is part of EDuke32. |
||
6 | |||
7 | EDuke32 is free software; you can redistribute it and/or |
||
8 | modify it under the terms of the GNU General Public License version 2 |
||
9 | as published by the Free Software Foundation. |
||
10 | |||
11 | This program is distributed in the hope that it will be useful, |
||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
14 | |||
15 | See the GNU General Public License for more details. |
||
16 | |||
17 | You should have received a copy of the GNU General Public License |
||
18 | along with this program; if not, write to the Free Software |
||
4541 | hendricks2 | 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
1652 | terminx | 20 | */ |
21 | //------------------------------------------------------------------------- |
||
22 | |||
241 | terminx | 23 | #include "compat.h" |
24 | #include "baselayer.h" |
||
25 | |||
26 | #include "scriptfile.h" |
||
27 | #include "cache1d.h" |
||
28 | #include "crc32.h" |
||
29 | |||
30 | #include "duke3d.h" |
||
2726 | hendricks2 | 31 | #include "common_game.h" |
241 | terminx | 32 | #include "grpscan.h" |
33 | |||
3708 | terminx | 34 | // custom GRP support for the startup window, file format reflects the structure below |
35 | #define GAMELISTFILE "games.list" |
||
3803 | terminx | 36 | // name crc size flags dependency scriptname defname |
3708 | terminx | 37 | struct grpfile internalgrpfiles[NUMGRPFILES] = |
559 | terminx | 38 | { |
3803 | terminx | 39 | { "Duke Nukem 3D", DUKE13_CRC, 26524524, GAMEFLAG_DUKE, 0, NULL, NULL, NULL }, |
40 | { "Duke Nukem 3D (South Korean Censored)", DUKEKR_CRC, 26385383, GAMEFLAG_DUKE, 0, NULL, NULL, NULL }, |
||
41 | { "Duke Nukem 3D: Atomic Edition", DUKE15_CRC, 44356548, GAMEFLAG_DUKE, 0, NULL, NULL, NULL }, |
||
42 | { "Duke Nukem 3D: Plutonium Pak", DUKEPP_CRC, 44348015, GAMEFLAG_DUKE, 0, NULL, NULL, NULL }, |
||
43 | { "Duke Nukem 3D Shareware 0.99", DUKE099_CRC, 9690241, GAMEFLAG_DUKE|GAMEFLAG_DUKEBETA, 0, NULL, NULL, NULL }, |
||
44 | { "Duke Nukem 3D Shareware 1.0", DUKE10_CRC, 10429258, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE, 0, NULL, NULL, NULL }, |
||
45 | { "Duke Nukem 3D Shareware 1.1", DUKE11_CRC, 10442980, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE, 0, NULL, NULL, NULL }, |
||
46 | { "Duke Nukem 3D Shareware 1.3D", DUKESW_CRC, 11035779, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE, 0, NULL, NULL, NULL }, |
||
47 | { "Duke Nukem 3D Mac Demo", DUKEMD_CRC, 10444391, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE, 0, NULL, NULL, NULL }, |
||
48 | { "Duke it out in D.C.", DUKEDC_CRC, 8410183 , GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, NULL, NULL }, |
||
49 | { "Duke Caribbean: Life's a Beach", DUKECB_CRC, 22213819, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, NULL, NULL }, |
||
4887 | hendricks2 | 50 | { "Duke: Nuclear Winter", DUKENW_CRC, 16169365, GAMEFLAG_DUKE|GAMEFLAG_ADDON|GAMEFLAG_NWINTER, DUKE15_CRC, "NWINTER.CON", NULL, NULL }, |
4789 | hendricks2 | 51 | { "NAM", NAM_CRC, 43448927, GAMEFLAG_NAM, 0, NULL, NULL, NULL }, |
52 | { "NAPALM", NAPALM_CRC, 44365728, GAMEFLAG_NAM|GAMEFLAG_NAPALM, 0, NULL, NULL, NULL }, |
||
53 | { "WWII GI", WW2GI_CRC, 77939508, GAMEFLAG_WW2GI|GAMEFLAG_NAM, 0, NULL, NULL, NULL }, |
||
559 | terminx | 54 | }; |
241 | terminx | 55 | struct grpfile *foundgrps = NULL; |
3708 | terminx | 56 | struct grpfile *listgrps = NULL; |
241 | terminx | 57 | |
3708 | terminx | 58 | static void LoadList(const char * filename) |
59 | { |
||
60 | struct grpfile *fg; |
||
61 | |||
62 | char *grpend = NULL; |
||
63 | |||
64 | scriptfile *script = scriptfile_fromfile(filename); |
||
65 | |||
66 | if (!script) |
||
67 | return; |
||
68 | |||
69 | scriptfile_addsymbolvalue("GAMEFLAG_DUKE", GAMEFLAG_DUKE); |
||
70 | scriptfile_addsymbolvalue("GAMEFLAG_ADDON", GAMEFLAG_DUKE|GAMEFLAG_ADDON); |
||
5050 | hendricks2 | 71 | scriptfile_addsymbolvalue("GAMEFLAG_NAM", GAMEFLAG_NAM); |
72 | scriptfile_addsymbolvalue("GAMEFLAG_NAPALM", GAMEFLAG_NAM|GAMEFLAG_NAPALM); |
||
73 | scriptfile_addsymbolvalue("GAMEFLAG_WW2GI", GAMEFLAG_NAM|GAMEFLAG_WW2GI); |
||
3708 | terminx | 74 | scriptfile_addsymbolvalue("DUKE15_CRC", DUKE15_CRC); |
5050 | hendricks2 | 75 | scriptfile_addsymbolvalue("DUKEPP_CRC", DUKEPP_CRC); |
3708 | terminx | 76 | scriptfile_addsymbolvalue("DUKE13_CRC", DUKE13_CRC); |
77 | scriptfile_addsymbolvalue("DUKEDC_CRC", DUKEDC_CRC); |
||
78 | scriptfile_addsymbolvalue("DUKECB_CRC", DUKECB_CRC); |
||
79 | scriptfile_addsymbolvalue("DUKENW_CRC", DUKENW_CRC); |
||
5050 | hendricks2 | 80 | scriptfile_addsymbolvalue("NAM_CRC", NAM_CRC); |
81 | scriptfile_addsymbolvalue("NAPALM_CRC", NAPALM_CRC); |
||
82 | scriptfile_addsymbolvalue("WW2GI_CRC", WW2GI_CRC); |
||
3708 | terminx | 83 | |
3711 | helixhorne | 84 | while (!scriptfile_eof(script)) |
3708 | terminx | 85 | { |
3711 | helixhorne | 86 | enum |
87 | { |
||
88 | T_GRPINFO, |
||
89 | T_GAMENAME, |
||
90 | T_CRC, |
||
91 | T_SIZE, |
||
92 | T_DEPCRC, |
||
93 | T_SCRIPTNAME, |
||
94 | T_DEFNAME, |
||
95 | T_FLAGS, |
||
96 | }; |
||
3708 | terminx | 97 | |
3711 | helixhorne | 98 | static const tokenlist profiletokens[] = |
99 | { |
||
100 | { "grpinfo", T_GRPINFO }, |
||
101 | }; |
||
3708 | terminx | 102 | |
4385 | terminx | 103 | int32_t token = getatoken(script,profiletokens,ARRAY_SIZE(profiletokens)); |
3708 | terminx | 104 | switch (token) |
105 | { |
||
106 | case T_GRPINFO: |
||
3711 | helixhorne | 107 | { |
108 | int32_t gsize = 0, gcrcval = 0, gflags = GAMEFLAG_DUKE, gdepcrc = DUKE15_CRC; |
||
109 | char *gname = NULL, *gscript = NULL, *gdef = NULL; |
||
110 | |||
111 | static const tokenlist grpinfotokens[] = |
||
3708 | terminx | 112 | { |
3711 | helixhorne | 113 | { "name", T_GAMENAME }, |
114 | { "scriptname", T_SCRIPTNAME }, |
||
115 | { "defname", T_DEFNAME }, |
||
116 | { "crc", T_CRC }, |
||
117 | { "dependency", T_DEPCRC }, |
||
118 | { "size", T_SIZE }, |
||
119 | { "flags", T_FLAGS }, |
||
3708 | terminx | 120 | |
3711 | helixhorne | 121 | }; |
3708 | terminx | 122 | |
3711 | helixhorne | 123 | if (scriptfile_getbraces(script,&grpend)) break; |
3708 | terminx | 124 | |
3711 | helixhorne | 125 | while (script->textptr < grpend) |
126 | { |
||
4385 | terminx | 127 | int32_t token = getatoken(script,grpinfotokens,ARRAY_SIZE(grpinfotokens)); |
3708 | terminx | 128 | |
3711 | helixhorne | 129 | switch (token) |
3708 | terminx | 130 | { |
3711 | helixhorne | 131 | case T_GAMENAME: |
132 | scriptfile_getstring(script,&gname); break; |
||
133 | case T_SCRIPTNAME: |
||
134 | scriptfile_getstring(script,&gscript); break; |
||
135 | case T_DEFNAME: |
||
136 | scriptfile_getstring(script,&gdef); break; |
||
3708 | terminx | 137 | |
3711 | helixhorne | 138 | case T_FLAGS: |
5050 | hendricks2 | 139 | scriptfile_getsymbol(script,&gflags); gflags &= GAMEFLAGMASK; break; |
3711 | helixhorne | 140 | case T_DEPCRC: |
141 | scriptfile_getsymbol(script,&gdepcrc); break; |
||
142 | case T_CRC: |
||
143 | scriptfile_getsymbol(script,&gcrcval); break; |
||
144 | case T_SIZE: |
||
145 | scriptfile_getnumber(script,&gsize); break; |
||
146 | default: |
||
147 | break; |
||
148 | } |
||
3708 | terminx | 149 | |
4491 | helixhorne | 150 | fg = (struct grpfile *)Xcalloc(1, sizeof(struct grpfile)); |
3711 | helixhorne | 151 | fg->next = listgrps; |
152 | listgrps = fg; |
||
3708 | terminx | 153 | |
3711 | helixhorne | 154 | if (gname) |
4491 | helixhorne | 155 | fg->name = Xstrdup(gname); |
3708 | terminx | 156 | |
3711 | helixhorne | 157 | fg->size = gsize; |
158 | fg->crcval = gcrcval; |
||
159 | fg->dependency = gdepcrc; |
||
160 | fg->game = gflags; |
||
3708 | terminx | 161 | |
3711 | helixhorne | 162 | if (gscript) |
163 | fg->scriptname = dup_filename(gscript); |
||
3708 | terminx | 164 | |
3711 | helixhorne | 165 | if (gdef) |
166 | fg->defname = dup_filename(gdef); |
||
3708 | terminx | 167 | } |
3711 | helixhorne | 168 | break; |
169 | } |
||
3708 | terminx | 170 | |
171 | default: |
||
172 | break; |
||
173 | } |
||
174 | } |
||
175 | |||
176 | scriptfile_close(script); |
||
177 | scriptfile_clearsymbols(); |
||
178 | } |
||
179 | |||
180 | static void LoadGameList(void) |
||
181 | { |
||
182 | struct grpfile *fg; |
||
183 | CACHE1D_FIND_REC *srch, *sidx; |
||
184 | |||
185 | int32_t i; |
||
186 | |||
187 | for (i = 0; i<NUMGRPFILES; i++) |
||
188 | { |
||
4491 | helixhorne | 189 | fg = (struct grpfile *)Xcalloc(1, sizeof(struct grpfile)); |
3708 | terminx | 190 | |
4491 | helixhorne | 191 | fg->name = Xstrdup(internalgrpfiles[i].name); |
3708 | terminx | 192 | fg->crcval = internalgrpfiles[i].crcval; |
193 | fg->size = internalgrpfiles[i].size; |
||
194 | fg->game = internalgrpfiles[i].game; |
||
195 | fg->dependency = internalgrpfiles[i].dependency; |
||
196 | |||
197 | if (internalgrpfiles[i].scriptname) |
||
198 | fg->scriptname = dup_filename(internalgrpfiles[i].scriptname); |
||
199 | |||
200 | if (internalgrpfiles[i].defname) |
||
201 | fg->defname = dup_filename(internalgrpfiles[i].defname); |
||
202 | |||
203 | fg->next = listgrps; |
||
204 | listgrps = fg; |
||
205 | } |
||
206 | |||
207 | srch = klistpath("/", "*.grpinfo", CACHE1D_FIND_FILE); |
||
208 | |||
209 | for (sidx = srch; sidx; sidx = sidx->next) |
||
210 | LoadList(srch->name); |
||
211 | |||
212 | klistfree(srch); |
||
213 | } |
||
214 | |||
215 | static void FreeGameList(void) |
||
216 | { |
||
217 | struct grpfile *fg; |
||
218 | |||
219 | while (listgrps) |
||
220 | { |
||
221 | fg = listgrps->next; |
||
222 | Bfree(listgrps->name); |
||
223 | |||
224 | if (listgrps->scriptname) |
||
225 | Bfree(listgrps->scriptname); |
||
226 | |||
227 | if (listgrps->defname) |
||
228 | Bfree(listgrps->defname); |
||
229 | |||
230 | Bfree(listgrps); |
||
231 | listgrps = fg; |
||
232 | } |
||
233 | } |
||
234 | |||
235 | |||
241 | terminx | 236 | #define GRPCACHEFILE "grpfiles.cache" |
335 | terminx | 237 | static struct grpcache |
238 | { |
||
241 | terminx | 239 | struct grpcache *next; |
1205 | terminx | 240 | int32_t size; |
241 | int32_t mtime; |
||
242 | int32_t crcval; |
||
1457 | terminx | 243 | char name[BMAX_PATH]; |
335 | terminx | 244 | } |
245 | *grpcache = NULL, *usedgrpcache = NULL; |
||
241 | terminx | 246 | |
1205 | terminx | 247 | static int32_t LoadGroupsCache(void) |
241 | terminx | 248 | { |
249 | struct grpcache *fg; |
||
250 | |||
1205 | terminx | 251 | int32_t fsize, fmtime, fcrcval; |
241 | terminx | 252 | char *fname; |
253 | |||
254 | scriptfile *script; |
||
255 | |||
256 | script = scriptfile_fromfile(GRPCACHEFILE); |
||
257 | if (!script) return -1; |
||
258 | |||
335 | terminx | 259 | while (!scriptfile_eof(script)) |
260 | { |
||
2726 | hendricks2 | 261 | if (scriptfile_getstring(script, &fname)) break; // filename |
262 | if (scriptfile_getnumber(script, &fsize)) break; // filesize |
||
263 | if (scriptfile_getnumber(script, &fmtime)) break; // modification time |
||
264 | if (scriptfile_getnumber(script, &fcrcval)) break; // crc checksum |
||
241 | terminx | 265 | |
4491 | helixhorne | 266 | fg = (struct grpcache *)Xcalloc(1, sizeof(struct grpcache)); |
241 | terminx | 267 | fg->next = grpcache; |
268 | grpcache = fg; |
||
269 | |||
1221 | terminx | 270 | Bstrncpy(fg->name, fname, BMAX_PATH); |
241 | terminx | 271 | fg->size = fsize; |
272 | fg->mtime = fmtime; |
||
273 | fg->crcval = fcrcval; |
||
274 | } |
||
275 | |||
276 | scriptfile_close(script); |
||
277 | return 0; |
||
278 | } |
||
279 | |||
280 | static void FreeGroupsCache(void) |
||
281 | { |
||
282 | struct grpcache *fg; |
||
283 | |||
335 | terminx | 284 | while (grpcache) |
285 | { |
||
241 | terminx | 286 | fg = grpcache->next; |
1527 | terminx | 287 | Bfree(grpcache); |
241 | terminx | 288 | grpcache = fg; |
289 | } |
||
290 | } |
||
291 | |||
3654 | terminx | 292 | void RemoveGroup(int32_t crcval) |
293 | { |
||
3661 | terminx | 294 | struct grpfile *grp; |
3654 | terminx | 295 | |
296 | for (grp = foundgrps; grp; grp=grp->next) |
||
297 | { |
||
298 | if (grp->crcval == crcval) |
||
299 | { |
||
300 | if (grp == foundgrps) |
||
301 | foundgrps = grp->next; |
||
3661 | terminx | 302 | else |
303 | { |
||
304 | struct grpfile *fg; |
||
3654 | terminx | 305 | |
3661 | terminx | 306 | for (fg = foundgrps; fg; fg=fg->next) |
307 | { |
||
308 | if (fg->next == grp) |
||
309 | { |
||
310 | fg->next = grp->next; |
||
311 | break; |
||
312 | } |
||
313 | } |
||
314 | } |
||
315 | |||
3654 | terminx | 316 | Bfree((char *)grp->name); |
317 | Bfree(grp); |
||
318 | |||
3661 | terminx | 319 | RemoveGroup(crcval); |
320 | |||
3654 | terminx | 321 | break; |
322 | } |
||
323 | } |
||
324 | } |
||
325 | |||
326 | struct grpfile * FindGroup(int32_t crcval) |
||
327 | { |
||
328 | struct grpfile *grp; |
||
329 | |||
330 | for (grp = foundgrps; grp; grp=grp->next) |
||
331 | { |
||
332 | if (grp->crcval == crcval) |
||
333 | return grp; |
||
334 | } |
||
335 | |||
336 | return NULL; |
||
337 | } |
||
338 | |||
1205 | terminx | 339 | int32_t ScanGroups(void) |
241 | terminx | 340 | { |
341 | CACHE1D_FIND_REC *srch, *sidx; |
||
342 | struct grpcache *fg, *fgg; |
||
343 | struct grpfile *grp; |
||
344 | char *fn; |
||
345 | struct Bstat st; |
||
1430 | terminx | 346 | #define BUFFER_SIZE (1024 * 1024 * 8) |
4491 | helixhorne | 347 | uint8_t *buf = (uint8_t *)Xmalloc(BUFFER_SIZE); |
241 | terminx | 348 | |
1643 | terminx | 349 | initprintf("Searching for game data...\n"); |
241 | terminx | 350 | |
3708 | terminx | 351 | LoadGameList(); |
241 | terminx | 352 | LoadGroupsCache(); |
353 | |||
354 | srch = klistpath("/", "*.grp", CACHE1D_FIND_FILE); |
||
355 | |||
335 | terminx | 356 | for (sidx = srch; sidx; sidx = sidx->next) |
357 | { |
||
358 | for (fg = grpcache; fg; fg = fg->next) |
||
359 | { |
||
241 | terminx | 360 | if (!Bstrcmp(fg->name, sidx->name)) break; |
361 | } |
||
362 | |||
335 | terminx | 363 | if (fg) |
364 | { |
||
2726 | hendricks2 | 365 | if (findfrompath(sidx->name, &fn)) continue; // failed to resolve the filename |
335 | terminx | 366 | if (Bstat(fn, &st)) |
367 | { |
||
1527 | terminx | 368 | Bfree(fn); |
335 | terminx | 369 | continue; |
2726 | hendricks2 | 370 | } // failed to stat the file |
1527 | terminx | 371 | Bfree(fn); |
4997 | terminx | 372 | if (fg->size == (int32_t)st.st_size && fg->mtime == (int32_t)st.st_mtime) |
335 | terminx | 373 | { |
4491 | helixhorne | 374 | grp = (struct grpfile *)Xcalloc(1, sizeof(struct grpfile)); |
375 | grp->name = Xstrdup(sidx->name); |
||
241 | terminx | 376 | grp->crcval = fg->crcval; |
377 | grp->size = fg->size; |
||
378 | grp->next = foundgrps; |
||
379 | foundgrps = grp; |
||
380 | |||
4491 | helixhorne | 381 | fgg = (struct grpcache *)Xcalloc(1, sizeof(struct grpcache)); |
241 | terminx | 382 | strcpy(fgg->name, fg->name); |
383 | fgg->size = fg->size; |
||
384 | fgg->mtime = fg->mtime; |
||
385 | fgg->crcval = fg->crcval; |
||
386 | fgg->next = usedgrpcache; |
||
387 | usedgrpcache = fgg; |
||
388 | continue; |
||
389 | } |
||
390 | } |
||
391 | |||
392 | { |
||
1205 | terminx | 393 | int32_t b, fh; |
4625 | terminx | 394 | int32_t crcval = 0; |
241 | terminx | 395 | |
396 | fh = openfrompath(sidx->name, BO_RDONLY|BO_BINARY, BS_IREAD); |
||
397 | if (fh < 0) continue; |
||
3171 | helixhorne | 398 | if (Bfstat(fh, &st)) continue; |
241 | terminx | 399 | |
400 | initprintf(" Checksumming %s...", sidx->name); |
||
335 | terminx | 401 | do |
402 | { |
||
1430 | terminx | 403 | b = read(fh, buf, BUFFER_SIZE); |
4642 | terminx | 404 | if (b > 0) crcval = Bcrc32((uint8_t *)buf, b, crcval); |
335 | terminx | 405 | } |
1430 | terminx | 406 | while (b == BUFFER_SIZE); |
241 | terminx | 407 | close(fh); |
408 | initprintf(" Done\n"); |
||
409 | |||
4491 | helixhorne | 410 | grp = (struct grpfile *)Xcalloc(1, sizeof(struct grpfile)); |
411 | grp->name = Xstrdup(sidx->name); |
||
241 | terminx | 412 | grp->crcval = crcval; |
413 | grp->size = st.st_size; |
||
414 | grp->next = foundgrps; |
||
415 | foundgrps = grp; |
||
416 | |||
4491 | helixhorne | 417 | fgg = (struct grpcache *)Xcalloc(1, sizeof(struct grpcache)); |
1221 | terminx | 418 | Bstrncpy(fgg->name, sidx->name, BMAX_PATH); |
241 | terminx | 419 | fgg->size = st.st_size; |
420 | fgg->mtime = st.st_mtime; |
||
421 | fgg->crcval = crcval; |
||
422 | fgg->next = usedgrpcache; |
||
423 | usedgrpcache = fgg; |
||
424 | } |
||
425 | } |
||
426 | |||
427 | klistfree(srch); |
||
428 | FreeGroupsCache(); |
||
429 | |||
3654 | terminx | 430 | for (grp = foundgrps; grp; /*grp=grp->next*/) |
431 | { |
||
3708 | terminx | 432 | struct grpfile *igrp; |
433 | for (igrp = listgrps; igrp; igrp=igrp->next) |
||
434 | if (grp->crcval == igrp->crcval) break; |
||
3654 | terminx | 435 | |
3708 | terminx | 436 | if (igrp == NULL) |
437 | { |
||
438 | grp = grp->next; |
||
439 | continue; |
||
440 | } |
||
3654 | terminx | 441 | |
3708 | terminx | 442 | if (igrp->dependency) |
3654 | terminx | 443 | { |
3723 | terminx | 444 | struct grpfile *depgrp; |
445 | |||
3654 | terminx | 446 | //initprintf("found grp with dep\n"); |
3723 | terminx | 447 | for (depgrp = foundgrps; depgrp; depgrp=depgrp->next) |
448 | if (depgrp->crcval == igrp->dependency) break; |
||
3654 | terminx | 449 | |
3723 | terminx | 450 | if (depgrp == NULL || depgrp->crcval != igrp->dependency) // couldn't find dependency |
3654 | terminx | 451 | { |
452 | //initprintf("removing %s\n", grp->name); |
||
3708 | terminx | 453 | RemoveGroup(igrp->crcval); |
3654 | terminx | 454 | grp = foundgrps; |
455 | continue; |
||
456 | } |
||
457 | } |
||
458 | |||
3803 | terminx | 459 | if (igrp->game && !grp->game) |
460 | grp->game = igrp->game; |
||
461 | |||
3654 | terminx | 462 | grp=grp->next; |
463 | } |
||
464 | |||
335 | terminx | 465 | if (usedgrpcache) |
466 | { |
||
1205 | terminx | 467 | int32_t i = 0; |
241 | terminx | 468 | FILE *fp; |
469 | fp = fopen(GRPCACHEFILE, "wt"); |
||
335 | terminx | 470 | if (fp) |
471 | { |
||
472 | for (fg = usedgrpcache; fg; fg=fgg) |
||
473 | { |
||
241 | terminx | 474 | fgg = fg->next; |
475 | fprintf(fp, "\"%s\" %d %d %d\n", fg->name, fg->size, fg->mtime, fg->crcval); |
||
1527 | terminx | 476 | Bfree(fg); |
1000 | terminx | 477 | i++; |
241 | terminx | 478 | } |
479 | fclose(fp); |
||
480 | } |
||
1178 | terminx | 481 | // initprintf("Found %d recognized GRP %s.\n",i,i>1?"files":"file"); |
2978 | helixhorne | 482 | |
483 | Bfree(buf); |
||
1000 | terminx | 484 | return 0; |
241 | terminx | 485 | } |
1642 | terminx | 486 | |
487 | initprintf("Found no recognized game data!\n"); |
||
488 | |||
2978 | helixhorne | 489 | Bfree(buf); |
241 | terminx | 490 | return 0; |
491 | } |
||
492 | |||
3654 | terminx | 493 | |
241 | terminx | 494 | void FreeGroups(void) |
495 | { |
||
496 | struct grpfile *fg; |
||
497 | |||
335 | terminx | 498 | while (foundgrps) |
499 | { |
||
241 | terminx | 500 | fg = foundgrps->next; |
1677 | terminx | 501 | Bfree((char *)foundgrps->name); |
1527 | terminx | 502 | Bfree(foundgrps); |
241 | terminx | 503 | foundgrps = fg; |
504 | } |
||
3708 | terminx | 505 | |
506 | FreeGameList(); |
||
241 | terminx | 507 | } |
508 |