1 /// \file
2 /// \brief Support to find files
3 ///
4 ///
5 /// filesearch:
6 ///
7 /// ATTENTION : make sure there is enouth space in filename to put a full path (255 or 512)
8 /// if needmd5check == 0 there is no md5 check
9 /// if completepath then filename will be change with the full path and name
10 /// maxsearchdepth == 0 only search given directory, no subdirs
11 /// return FS_NOTFOUND
12 /// FS_MD5SUMBAD;
13 /// FS_FOUND
14
15 #include <stdio.h>
16 #ifdef __GNUC__
17 #include <dirent.h>
18 #endif
19 #ifdef _WIN32
20 //#define WIN32_LEAN_AND_MEAN
21 #define RPC_NO_WINDOWS_H
22 #include <windows.h>
23 #endif
24 #include <sys/stat.h>
25 #include <string.h>
26
27 #include "filesrch.h"
28 #include "d_netfil.h"
29 #include "m_misc.h"
30 #include "z_zone.h"
31 #include "m_menu.h" // Addons_option_Onchange
32
33 #if defined (_WIN32) && defined (_MSC_VER)
34
35 #include <errno.h>
36 #include <io.h>
37 #include <tchar.h>
38
39 #define SUFFIX "*"
40 #define SLASH "\\"
41 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
42
43 #ifndef INVALID_FILE_ATTRIBUTES
44 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
45 #endif
46
47 struct dirent
48 {
49 long d_ino; /* Always zero. */
50 unsigned short d_reclen; /* Always zero. */
51 unsigned short d_namlen; /* Length of name in d_name. */
52 char d_name[FILENAME_MAX]; /* File name. */
53 };
54
55 /*
56 * This is an internal data structure. Good programmers will not use it
57 * except as an argument to one of the functions below.
58 * dd_stat field is now int (was short in older versions).
59 */
60 typedef struct
61 {
62 /* disk transfer area for this dir */
63 struct _finddata_t dd_dta;
64
65 /* dirent struct to return from dir (NOTE: this makes this thread
66 * safe as long as only one thread uses a particular DIR struct at
67 * a time) */
68 struct dirent dd_dir;
69
70 /* _findnext handle */
71 #if _MSC_VER > 1200
72 intptr_t dd_handle;
73 #else
74 long dd_handle;
75 #endif
76
77 /*
78 * Status of search:
79 * 0 = not started yet (next entry to read is first entry)
80 * -1 = off the end
81 * positive = 0 based index of next entry
82 */
83 int dd_stat;
84
85 /* given path for dir with search pattern (struct is extended) */
86 CHAR dd_name[1];
87 } DIR;
88
89 /*
90 * opendir
91 *
92 * Returns a pointer to a DIR structure appropriately filled in to begin
93 * searching a directory.
94 */
95
96 DIR *
opendir(const CHAR * szPath)97 opendir (const CHAR *szPath)
98 {
99 DIR *nd;
100 DWORD rc;
101 CHAR szFullPath[MAX_PATH];
102
103 errno = 0;
104
105 if (!szPath)
106 {
107 errno = EFAULT;
108 return (DIR *) 0;
109 }
110
111 if (szPath[0] == '\0')
112 {
113 errno = ENOTDIR;
114 return (DIR *) 0;
115 }
116
117 /* Attempt to determine if the given path really is a directory. */
118 rc = GetFileAttributesA(szPath);
119 if (rc == INVALID_FILE_ATTRIBUTES)
120 {
121 /* call GetLastError for more error info */
122 errno = ENOENT;
123 return (DIR *) 0;
124 }
125 if (!(rc & FILE_ATTRIBUTE_DIRECTORY))
126 {
127 /* Error, entry exists but not a directory. */
128 errno = ENOTDIR;
129 return (DIR *) 0;
130 }
131
132 /* Make an absolute pathname. */
133 _fullpath (szFullPath, szPath, MAX_PATH);
134
135 /* Allocate enough space to store DIR structure and the complete
136 * directory path given. */
137 nd = (DIR *) malloc (sizeof (DIR) + (strlen(szFullPath) + strlen (SLASH) +
138 strlen(SUFFIX) + 1) * sizeof (CHAR));
139
140 if (!nd)
141 {
142 /* Error, out of memory. */
143 errno = ENOMEM;
144 return (DIR *) 0;
145 }
146
147 /* Create the search expression. */
148 strcpy (nd->dd_name, szFullPath);
149
150 /* Add on a slash if the path does not end with one. */
151 if (nd->dd_name[0] != '\0' &&
152 nd->dd_name[strlen (nd->dd_name) - 1] != '/' &&
153 nd->dd_name[strlen (nd->dd_name) - 1] != '\\')
154 {
155 strcat (nd->dd_name, SLASH);
156 }
157
158 /* Add on the search pattern */
159 strcat (nd->dd_name, SUFFIX);
160
161 /* Initialize handle to -1 so that a premature closedir doesn't try
162 * to call _findclose on it. */
163 nd->dd_handle = -1;
164
165 /* Initialize the status. */
166 nd->dd_stat = 0;
167
168 /* Initialize the dirent structure. ino and reclen are invalid under
169 * Win32, and name simply points at the appropriate part of the
170 * findfirst_t structure. */
171 nd->dd_dir.d_ino = 0;
172 nd->dd_dir.d_reclen = 0;
173 nd->dd_dir.d_namlen = 0;
174 ZeroMemory(nd->dd_dir.d_name, FILENAME_MAX);
175
176 return nd;
177 }
178
179 /*
180 * readdir
181 *
182 * Return a pointer to a dirent structure filled with the information on the
183 * next entry in the directory.
184 */
185 struct dirent *
readdir(DIR * dirp)186 readdir (DIR * dirp)
187 {
188 errno = 0;
189
190 /* Check for valid DIR struct. */
191 if (!dirp)
192 {
193 errno = EFAULT;
194 return (struct dirent *) 0;
195 }
196
197 if (dirp->dd_stat < 0)
198 {
199 /* We have already returned all files in the directory
200 * (or the structure has an invalid dd_stat). */
201 return (struct dirent *) 0;
202 }
203 else if (dirp->dd_stat == 0)
204 {
205 /* We haven't started the search yet. */
206 /* Start the search */
207 dirp->dd_handle = _findfirst (dirp->dd_name, &(dirp->dd_dta));
208
209 if (dirp->dd_handle == -1)
210 {
211 /* Whoops! Seems there are no files in that
212 * directory. */
213 dirp->dd_stat = -1;
214 }
215 else
216 {
217 dirp->dd_stat = 1;
218 }
219 }
220 else
221 {
222 /* Get the next search entry. */
223 if (_findnext (dirp->dd_handle, &(dirp->dd_dta)))
224 {
225 /* We are off the end or otherwise error.
226 _findnext sets errno to ENOENT if no more file
227 Undo this. */
228 DWORD winerr = GetLastError();
229 if (winerr == ERROR_NO_MORE_FILES)
230 errno = 0;
231 _findclose (dirp->dd_handle);
232 dirp->dd_handle = -1;
233 dirp->dd_stat = -1;
234 }
235 else
236 {
237 /* Update the status to indicate the correct
238 * number. */
239 dirp->dd_stat++;
240 }
241 }
242
243 if (dirp->dd_stat > 0)
244 {
245 /* Successfully got an entry. Everything about the file is
246 * already appropriately filled in except the length of the
247 * file name. */
248 dirp->dd_dir.d_namlen = (unsigned short)strlen (dirp->dd_dta.name);
249 strcpy (dirp->dd_dir.d_name, dirp->dd_dta.name);
250 return &dirp->dd_dir;
251 }
252
253 return (struct dirent *) 0;
254 }
255
256 /*
257 * rewinddir
258 *
259 * Makes the next readdir start from the beginning.
260 */
261 int
rewinddir(DIR * dirp)262 rewinddir (DIR * dirp)
263 {
264 errno = 0;
265
266 /* Check for valid DIR struct. */
267 if (!dirp)
268 {
269 errno = EFAULT;
270 return -1;
271 }
272
273 dirp->dd_stat = 0;
274
275 return 0;
276 }
277
278 /*
279 * closedir
280 *
281 * Frees up resources allocated by opendir.
282 */
283 int
closedir(DIR * dirp)284 closedir (DIR * dirp)
285 {
286 int rc;
287
288 errno = 0;
289 rc = 0;
290
291 if (!dirp)
292 {
293 errno = EFAULT;
294 return -1;
295 }
296
297 if (dirp->dd_handle != -1)
298 {
299 rc = _findclose (dirp->dd_handle);
300 }
301
302 /* Delete the dir structure. */
303 free (dirp);
304
305 return rc;
306 }
307 #endif
308
309 static CV_PossibleValue_t addons_cons_t[] = {{0, "Default"},
310 #if 1
311 {1, "HOME"}, {2, "SRB2"},
312 #endif
313 {3, "CUSTOM"}, {0, NULL}};
314
315 consvar_t cv_addons_option = CVAR_INIT ("addons_option", "Default", CV_SAVE|CV_CALL, addons_cons_t, Addons_option_Onchange);
316 consvar_t cv_addons_folder = CVAR_INIT ("addons_folder", "", CV_SAVE, NULL, NULL);
317
318 static CV_PossibleValue_t addons_md5_cons_t[] = {{0, "Name"}, {1, "Contents"}, {0, NULL}};
319 consvar_t cv_addons_md5 = CVAR_INIT ("addons_md5", "Name", CV_SAVE, addons_md5_cons_t, NULL);
320
321 consvar_t cv_addons_showall = CVAR_INIT ("addons_showall", "No", CV_SAVE, CV_YesNo, NULL);
322
323 consvar_t cv_addons_search_case = CVAR_INIT ("addons_search_case", "No", CV_SAVE, CV_YesNo, NULL);
324
325 static CV_PossibleValue_t addons_search_type_cons_t[] = {{0, "Start"}, {1, "Anywhere"}, {0, NULL}};
326 consvar_t cv_addons_search_type = CVAR_INIT ("addons_search_type", "Anywhere", CV_SAVE, addons_search_type_cons_t, NULL);
327
328 char menupath[1024];
329 size_t menupathindex[menudepth];
330 size_t menudepthleft = menudepth;
331
332 char menusearch[MAXSTRINGLENGTH+1];
333
334 char **dirmenu, **coredirmenu; // core only local for this file
335 size_t sizedirmenu, sizecoredirmenu; // ditto
336 size_t dir_on[menudepth];
337 UINT8 refreshdirmenu = 0;
338 char *refreshdirname = NULL;
339
340 size_t packetsizetally = 0;
341 size_t mainwadstally = 0;
342
filesearch(char * filename,const char * startpath,const UINT8 * wantedmd5sum,boolean completepath,int maxsearchdepth)343 filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth)
344 {
345 filestatus_t retval = FS_NOTFOUND;
346 DIR **dirhandle;
347 struct dirent *dent;
348 struct stat fsstat;
349 int found = 0;
350 char *searchname = strdup(filename);
351 int depthleft = maxsearchdepth;
352 char searchpath[1024];
353 size_t *searchpathindex;
354
355 dirhandle = (DIR**) malloc(maxsearchdepth * sizeof (DIR*));
356 searchpathindex = (size_t *) malloc(maxsearchdepth * sizeof (size_t));
357
358 strcpy(searchpath,startpath);
359 searchpathindex[--depthleft] = strlen(searchpath) + 1;
360
361 dirhandle[depthleft] = opendir(searchpath);
362
363 if (dirhandle[depthleft] == NULL)
364 {
365 free(searchname);
366 free(dirhandle);
367 free(searchpathindex);
368 return FS_NOTFOUND;
369 }
370
371 if (searchpath[searchpathindex[depthleft]-2] != PATHSEP[0])
372 {
373 searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
374 searchpath[searchpathindex[depthleft]] = 0;
375 }
376 else
377 searchpathindex[depthleft]--;
378
379 while ((!found) && (depthleft < maxsearchdepth))
380 {
381 searchpath[searchpathindex[depthleft]]=0;
382 dent = readdir(dirhandle[depthleft]);
383
384 if (!dent)
385 {
386 closedir(dirhandle[depthleft++]);
387 continue;
388 }
389
390 if (dent->d_name[0]=='.' &&
391 (dent->d_name[1]=='\0' ||
392 (dent->d_name[1]=='.' &&
393 dent->d_name[2]=='\0')))
394 {
395 // we don't want to scan uptree
396 continue;
397 }
398
399 // okay, now we actually want searchpath to incorporate d_name
400 strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name);
401
402 if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
403 ; // was the file (re)moved? can't stat it
404 else if (S_ISDIR(fsstat.st_mode) && depthleft)
405 {
406 searchpathindex[--depthleft] = strlen(searchpath) + 1;
407 dirhandle[depthleft] = opendir(searchpath);
408 if (!dirhandle[depthleft])
409 {
410 // can't open it... maybe no read-permissions
411 // go back to previous dir
412 depthleft++;
413 }
414
415 searchpath[searchpathindex[depthleft]-1]=PATHSEP[0];
416 searchpath[searchpathindex[depthleft]]=0;
417 }
418 else if (!strcasecmp(searchname, dent->d_name))
419 {
420 switch (checkfilemd5(searchpath, wantedmd5sum))
421 {
422 case FS_FOUND:
423 if (completepath)
424 strcpy(filename,searchpath);
425 else
426 strcpy(filename,dent->d_name);
427 retval = FS_FOUND;
428 found = 1;
429 break;
430 case FS_MD5SUMBAD:
431 retval = FS_MD5SUMBAD;
432 break;
433 default: // prevent some compiler warnings
434 break;
435 }
436 }
437 }
438
439 for (; depthleft < maxsearchdepth; closedir(dirhandle[depthleft++]));
440
441 free(searchname);
442 free(searchpathindex);
443 free(dirhandle);
444
445 return retval;
446 }
447
448 char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) plus 3 (null terminator, stop, and length including previous two)
449 "\5.txt", "\5.cfg", // exec
450 "\5.wad",
451 #ifdef USE_KART
452 "\6.kart",
453 #endif
454 "\5.pk3", "\5.soc", "\5.lua"}; // addfile
455
456 char filenamebuf[MAX_WADFILES][MAX_WADPATH];
457
458
filemenucmp(char * haystack,char * needle)459 static boolean filemenucmp(char *haystack, char *needle)
460 {
461 static char localhaystack[128];
462 strlcpy(localhaystack, haystack, 128);
463 if (!cv_addons_search_case.value)
464 strupr(localhaystack);
465 if (cv_addons_search_type.value)
466 return (strstr(localhaystack, needle) != 0);
467 return (!strncmp(localhaystack, needle, menusearch[0]));
468 }
469
closefilemenu(boolean validsize)470 void closefilemenu(boolean validsize)
471 {
472 // search
473 if (dirmenu)
474 {
475 if (dirmenu != coredirmenu)
476 {
477 if (dirmenu[0] && ((UINT8)(dirmenu[0][DIR_TYPE]) == EXT_NORESULTS))
478 {
479 Z_Free(dirmenu[0]);
480 dirmenu[0] = NULL;
481 }
482 Z_Free(dirmenu);
483 }
484 dirmenu = NULL;
485 sizedirmenu = 0;
486 }
487
488 if (coredirmenu)
489 {
490 // core
491 if (validsize)
492 {
493 for (; sizecoredirmenu > 0; sizecoredirmenu--)
494 {
495 Z_Free(coredirmenu[sizecoredirmenu-1]);
496 coredirmenu[sizecoredirmenu-1] = NULL;
497 }
498 }
499 else
500 sizecoredirmenu = 0;
501
502 Z_Free(coredirmenu);
503 coredirmenu = NULL;
504 }
505
506 if (refreshdirname)
507 Z_Free(refreshdirname);
508 refreshdirname = NULL;
509 }
510
searchfilemenu(char * tempname)511 void searchfilemenu(char *tempname)
512 {
513 size_t i, first;
514 char localmenusearch[MAXSTRINGLENGTH] = "";
515
516 if (dirmenu)
517 {
518 if (dirmenu != coredirmenu)
519 {
520 if (dirmenu[0] && ((UINT8)(dirmenu[0][DIR_TYPE]) == EXT_NORESULTS))
521 {
522 Z_Free(dirmenu[0]);
523 dirmenu[0] = NULL;
524 }
525 //Z_Free(dirmenu); -- Z_Realloc later tho...
526 }
527 else
528 dirmenu = NULL;
529 }
530
531 first = (((UINT8)(coredirmenu[0][DIR_TYPE]) == EXT_UP) ? 1 : 0); // skip UP...
532
533 if (!menusearch[0])
534 {
535 if (dirmenu)
536 Z_Free(dirmenu);
537 dirmenu = coredirmenu;
538 sizedirmenu = sizecoredirmenu;
539
540 if (tempname)
541 {
542 for (i = first; i < sizedirmenu; i++)
543 {
544 if (!strcmp(dirmenu[i]+DIR_STRING, tempname))
545 {
546 dir_on[menudepthleft] = i;
547 break;
548 }
549 }
550
551 if (i == sizedirmenu)
552 dir_on[menudepthleft] = first;
553
554 Z_Free(tempname);
555 }
556
557 return;
558 }
559
560 strcpy(localmenusearch, menusearch+1);
561 if (!cv_addons_search_case.value)
562 strupr(localmenusearch);
563
564 sizedirmenu = 0;
565 for (i = first; i < sizecoredirmenu; i++)
566 {
567 if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch))
568 sizedirmenu++;
569 }
570
571 if (!sizedirmenu) // no results...
572 {
573 if ((!(dirmenu = Z_Realloc(dirmenu, sizeof(char *), PU_STATIC, NULL)))
574 || !(dirmenu[0] = Z_StrDup(va("%c\13No results...", EXT_NORESULTS))))
575 I_Error("searchfilemenu(): could not create \"No results...\".");
576 sizedirmenu = 1;
577 dir_on[menudepthleft] = 0;
578 if (tempname)
579 Z_Free(tempname);
580 return;
581 }
582
583 if (!(dirmenu = Z_Realloc(dirmenu, sizedirmenu*sizeof(char *), PU_STATIC, NULL)))
584 I_Error("searchfilemenu(): could not reallocate dirmenu.");
585
586 sizedirmenu = 0;
587 for (i = first; i < sizecoredirmenu; i++)
588 {
589 if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch))
590 {
591 if (tempname && !strcmp(coredirmenu[i]+DIR_STRING, tempname))
592 {
593 dir_on[menudepthleft] = sizedirmenu;
594 Z_Free(tempname);
595 tempname = NULL;
596 }
597 dirmenu[sizedirmenu++] = coredirmenu[i]; // pointer reuse
598 }
599 }
600
601 if (tempname)
602 {
603 dir_on[menudepthleft] = 0; //first; -- can't be first, causes problems
604 Z_Free(tempname);
605 }
606 }
607
preparefilemenu(boolean samedepth)608 boolean preparefilemenu(boolean samedepth)
609 {
610 DIR *dirhandle;
611 struct dirent *dent;
612 struct stat fsstat;
613 size_t pos = 0, folderpos = 0, numfolders = 0;
614 char *tempname = NULL;
615
616 if (samedepth)
617 {
618 if (dirmenu && dirmenu[dir_on[menudepthleft]])
619 tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL
620 }
621 else
622 menusearch[0] = menusearch[1] = 0; // clear search
623
624 if (!(dirhandle = opendir(menupath))) // get directory
625 {
626 closefilemenu(true);
627 return false;
628 }
629
630 for (; sizecoredirmenu > 0; sizecoredirmenu--) // clear out existing items
631 {
632 Z_Free(coredirmenu[sizecoredirmenu-1]);
633 coredirmenu[sizecoredirmenu-1] = NULL;
634 }
635
636 while (true)
637 {
638 menupath[menupathindex[menudepthleft]] = 0;
639 dent = readdir(dirhandle);
640
641 if (!dent)
642 break;
643 else if (dent->d_name[0]=='.' &&
644 (dent->d_name[1]=='\0' ||
645 (dent->d_name[1]=='.' &&
646 dent->d_name[2]=='\0')))
647 continue; // we don't want to scan uptree
648
649 strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);
650
651 if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
652 ; // was the file (re)moved? can't stat it
653 else // is a file or directory
654 {
655 if (!S_ISDIR(fsstat.st_mode)) // file
656 {
657 if (!cv_addons_showall.value)
658 {
659 size_t len = strlen(dent->d_name)+1;
660 UINT8 ext;
661 for (ext = 0; ext < NUM_EXT_TABLE; ext++)
662 if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison
663 if (ext == NUM_EXT_TABLE) continue; // not an addfile-able (or exec-able) file
664 }
665 }
666 else // directory
667 numfolders++;
668
669 sizecoredirmenu++;
670 }
671 }
672
673 if (!sizecoredirmenu)
674 {
675 closedir(dirhandle);
676 closefilemenu(false);
677 if (tempname)
678 Z_Free(tempname);
679 return false;
680 }
681
682 if (menudepthleft != menudepth-1) // Make room for UP...
683 {
684 sizecoredirmenu++;
685 numfolders++;
686 folderpos++;
687 }
688
689 if (dirmenu && dirmenu == coredirmenu)
690 dirmenu = NULL;
691
692 if (!(coredirmenu = Z_Realloc(coredirmenu, sizecoredirmenu*sizeof(char *), PU_STATIC, NULL)))
693 {
694 closedir(dirhandle); // just in case
695 I_Error("preparefilemenu(): could not reallocate coredirmenu.");
696 }
697
698 rewinddir(dirhandle);
699
700 while ((pos+folderpos) < sizecoredirmenu)
701 {
702 menupath[menupathindex[menudepthleft]] = 0;
703 dent = readdir(dirhandle);
704
705 if (!dent)
706 break;
707 else if (dent->d_name[0]=='.' &&
708 (dent->d_name[1]=='\0' ||
709 (dent->d_name[1]=='.' &&
710 dent->d_name[2]=='\0')))
711 continue; // we don't want to scan uptree
712
713 strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);
714
715 if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat
716 ; // was the file (re)moved? can't stat it
717 else // is a file or directory
718 {
719 char *temp;
720 size_t len = strlen(dent->d_name)+1;
721 UINT8 ext = EXT_FOLDER;
722 UINT8 folder;
723
724 if (!S_ISDIR(fsstat.st_mode)) // file
725 {
726 if (!((numfolders+pos) < sizecoredirmenu)) continue; // crash prevention
727 for (; ext < NUM_EXT_TABLE; ext++)
728 if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison
729 if (ext == NUM_EXT_TABLE && !cv_addons_showall.value) continue; // not an addfile-able (or exec-able) file
730 ext += EXT_START; // moving to be appropriate position
731
732 if (ext >= EXT_LOADSTART)
733 {
734 size_t i;
735 for (i = 0; i < numwadfiles; i++)
736 {
737 if (!filenamebuf[i][0])
738 {
739 strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH);
740 filenamebuf[i][MAX_WADPATH - 1] = '\0';
741 nameonly(filenamebuf[i]);
742 }
743
744 if (strcmp(dent->d_name, filenamebuf[i]))
745 continue;
746 if (cv_addons_md5.value && !checkfilemd5(menupath, wadfiles[i]->md5sum))
747 continue;
748
749 ext |= EXT_LOADED;
750 }
751 }
752 else if (ext == EXT_TXT)
753 {
754 if (!strncmp(dent->d_name, "log-", 4) || !strcmp(dent->d_name, "errorlog.txt"))
755 ext |= EXT_LOADED;
756 }
757
758 if (!strcmp(dent->d_name, configfile))
759 ext |= EXT_LOADED;
760
761 folder = 0;
762 }
763 else // directory
764 len += (folder = 1);
765
766 if (len > 255)
767 len = 255;
768
769 if (!(temp = Z_Malloc((len+DIR_STRING+folder) * sizeof (char), PU_STATIC, NULL)))
770 I_Error("preparefilemenu(): could not create file entry.");
771 temp[DIR_TYPE] = ext;
772 temp[DIR_LEN] = (UINT8)(len);
773 strlcpy(temp+DIR_STRING, dent->d_name, len);
774 if (folder)
775 {
776 strcpy(temp+len, PATHSEP);
777 coredirmenu[folderpos++] = temp;
778 }
779 else
780 coredirmenu[numfolders + pos++] = temp;
781 }
782 }
783
784 closedir(dirhandle);
785
786 if ((menudepthleft != menudepth-1) // now for UP... entry
787 && !(coredirmenu[0] = Z_StrDup(va("%c\5UP...", EXT_UP))))
788 I_Error("preparefilemenu(): could not create \"UP...\".");
789
790 menupath[menupathindex[menudepthleft]] = 0;
791 sizecoredirmenu = (numfolders+pos); // just in case things shrink between opening and rewind
792
793 if (!sizecoredirmenu)
794 {
795 dir_on[menudepthleft] = 0;
796 closefilemenu(false);
797 return false;
798 }
799
800 searchfilemenu(tempname);
801
802 return true;
803 }
804