From 661ee6eff2348aea1052094c27ed719eb983f879 Mon Sep 17 00:00:00 2001 From: ac-stef Date: Mon, 12 Jun 2017 18:17:15 +0200 Subject: [PATCH] distinguish between files and directories listfiles now optionally sorts the list and removes doubles --- source/src/command.cpp | 5 +- source/src/main.cpp | 9 +-- source/src/rendermodel.cpp | 5 +- source/src/serverfiles.h | 6 +- source/src/stream.cpp | 151 ++++++++++++++++++++++++++++++++----- source/src/tools.h | 5 +- source/src/worldio.cpp | 3 +- source/src/zip.cpp | 13 ++++ 8 files changed, 161 insertions(+), 36 deletions(-) diff --git a/source/src/command.cpp b/source/src/command.cpp index 7d1b3e2d..1d203d07 100644 --- a/source/src/command.cpp +++ b/source/src/command.cpp @@ -881,8 +881,7 @@ void commandcomplete(char *s, bool reversedirection) vector files; loopv(cdata->dirlist) { - listfiles(cdata->dirlist[i], cdata->ext, files); - files.sort(stringsort); + listfiles(cdata->dirlist[i], cdata->ext, files, stringsort); loopv(files) cdata->list.add(files[i]); files.setsize(0); } @@ -1017,7 +1016,7 @@ void execdir(const char *dir) if(dir[0]) { vector files; - listfiles(dir, "cfg", files); + listfiles(dir, "cfg", files, stringsort); loopv(files) { defformatstring(d)("%s/%s.cfg",dir,files[i]); diff --git a/source/src/main.cpp b/source/src/main.cpp index 7477f304..24e2c747 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -861,12 +861,7 @@ void autostartscripts(const char *prefix) if(!files) { // first run: fetch file names and sort them files = new vector; - listfiles(AUTOSTARTPATH, "cfg", *files); - files->sort(stringsort); - for(int i = files->length() - 1; i > 0; i--) - { - if(!strcmp((*files)[i], (*files)[i - 1])) delstring(files->remove(i)); // delete doubles - } + listfiles(AUTOSTARTPATH, "cfg", *files, stringsort); } loopv(*files) { @@ -1032,6 +1027,8 @@ int main(int argc, char **argv) #define initlog(s) clientlogf("init: " s) + if(*stream_capabilities()) clientlogf("info: %s", stream_capabilities()); + initing = INIT_RESET; for(int i = 1; i files; - listfilesrecursive("packages/models/mapmodels", files); - char *r = NULL; - loopvrev(files) if((r = strrchr(files[i], '/'))) *r = '\0'; // cut off filename and last '/' - loopvrev(files) if(!strchr(files[i], '/')) delstring(files.remove(i)); // require minimum path depth of two + listdirsrecursive("packages/models/mapmodels", files); files.sort(stringsort); loopvrev(files) if(files.inrange(i + 1) && !strcmp(files[i], files[i + 1])) delstring(files.remove(i + 1)); // remove doubles silentmodelloaderror = true; diff --git a/source/src/serverfiles.h b/source/src/serverfiles.h index aaebb0fb..294c25e1 100644 --- a/source/src/serverfiles.h +++ b/source/src/serverfiles.h @@ -466,9 +466,9 @@ int readmapsthread(void *logfileprefix) vector maps_off, maps_serv, maps_incom; // get all map file names - listfiles(servermappath_off, "cgz", maps_off); - listfiles(servermappath_serv, "cgz", maps_serv); - listfiles(servermappath_incom, "cgz", maps_incom); + listfiles(servermappath_off, "cgz", maps_off, stringsort); + listfiles(servermappath_serv, "cgz", maps_serv, stringsort); + listfiles(servermappath_incom, "cgz", maps_incom, stringsort); if(readmaplog) readmaplog->printf("\n#### %s #### scanning all map directories... found %d official maps, %d servermaps and %d maps in 'incoming'\n", timestring(false), maps_off.length(), maps_serv.length(), maps_incom.length()); // enforce priority: official > servermaps > incoming diff --git a/source/src/stream.cpp b/source/src/stream.cpp index 0a52c7af..6955fea5 100644 --- a/source/src/stream.cpp +++ b/source/src/stream.cpp @@ -261,17 +261,25 @@ const char *findfile(const char *filename, const char *mode) return filename; } -bool listdir(const char *dir, const char *ext, vector &files) +const char *stream_capabilities() +{ + #if !defined(WIN32) && !defined(_DIRENT_HAVE_D_TYPE) + return "no support for d_type, listing directories may be slow"; + #else + return ""; + #endif +} + +bool listsubdir(const char *dir, vector &subdirs) { - int extsize = ext ? (int)strlen(ext)+1 : 0; #if defined(WIN32) - defformatstring(pathname)("%s\\*.%s", dir, ext ? ext : "*"); + defformatstring(pathname)("%s\\*", dir); WIN32_FIND_DATA FindFileData; HANDLE Find = FindFirstFile(path(pathname), &FindFileData); if(Find != INVALID_HANDLE_VALUE) { do { - files.add(newstring(FindFileData.cFileName, (int)strlen(FindFileData.cFileName) - extsize)); + if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) subdirs.add(newstring(FindFileData.cFileName)); } while(FindNextFile(Find, &FindFileData)); FindClose(Find); return true; @@ -285,12 +293,90 @@ bool listdir(const char *dir, const char *ext, vector &files) struct dirent *de, b; while(!readdir_r(d, &b, &de) && de != NULL) { - if(!ext) files.add(newstring(de->d_name)); - else + #ifdef _DIRENT_HAVE_D_TYPE + if(de->d_type == DT_DIR) subdirs.add(newstring(de->d_name)); + #else + struct stat s; + int dl = (int)strlen(pathname); + concatformatstring(pathname, "/%s", de->d_name); + if(!lstat(pathname, &s) && S_ISDIR(s.st_mode)) subdirs.add(newstring(de->d_name)); + pathname[dl] = '\0'; + #endif + } + closedir(d); + return true; + } + #endif + else return false; +} + +void listsubdirs(const char *dir, vector &subdirs, int (__cdecl *sf)(const char **, const char **)) +{ + listsubdir(dir, subdirs); + string s; + if(homedir[0]) + { + formatstring(s)("%s%s", homedir, dir); + listsubdir(s, subdirs); + } + loopv(packagedirs) + { + formatstring(s)("%s%s", packagedirs[i], dir); + listsubdir(s, subdirs); + } +#ifndef STANDALONE + listzipdirs(dir, subdirs); +#endif + subdirs.sort(sf); + for(int i = subdirs.length() - 1; i > 0; i--) + { // remove doubles + if(!strcmp(subdirs[i], subdirs[i - 1])) delstring(subdirs.remove(i)); + } +} + +bool listdir(const char *dir, const char *ext, vector &files) +{ + int extsize = ext ? (int)strlen(ext)+1 : 0; + #if defined(WIN32) + defformatstring(pathname)("%s\\*.%s", dir, ext ? ext : "*"); + WIN32_FIND_DATA FindFileData; + HANDLE Find = FindFirstFile(path(pathname), &FindFileData); + if(Find != INVALID_HANDLE_VALUE) + { + do { + if(!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + files.add(newstring(FindFileData.cFileName, (int)strlen(FindFileData.cFileName) - extsize)); + } while(FindNextFile(Find, &FindFileData)); + FindClose(Find); + return true; + } + #else + string pathname; + copystring(pathname, dir); + DIR *d = opendir(path(pathname)); + if(d) + { + struct dirent *de, b; + while(!readdir_r(d, &b, &de) && de != NULL) + { + #ifdef _DIRENT_HAVE_D_TYPE + if(de->d_type == DT_REG) + #else + struct stat s; + int dl = (int)strlen(pathname); + concatformatstring(pathname, "/%s", de->d_name); + bool isreg = !lstat(pathname, &s) && !S_ISDIR(s.st_mode); + pathname[dl] = '\0'; + if(isreg) + #endif { - int namelength = (int)strlen(de->d_name) - extsize; - if(namelength > 0 && de->d_name[namelength] == '.' && strncmp(de->d_name+namelength+1, ext, extsize-1)==0) - files.add(newstring(de->d_name, namelength)); + if(!ext) files.add(newstring(de->d_name)); + else + { + int namelength = (int)strlen(de->d_name) - extsize; + if(namelength > 0 && de->d_name[namelength] == '.' && strncmp(de->d_name+namelength+1, ext, extsize-1)==0) + files.add(newstring(de->d_name, namelength)); + } } } closedir(d); @@ -300,7 +386,7 @@ bool listdir(const char *dir, const char *ext, vector &files) else return false; } -void listfiles(const char *dir, const char *ext, vector &files) +void listfiles(const char *dir, const char *ext, vector &files, int (__cdecl *sf)(const char **, const char **)) { listdir(dir, ext, files); string s; @@ -317,25 +403,56 @@ void listfiles(const char *dir, const char *ext, vector &files) #ifndef STANDALONE listzipfiles(dir, ext, files); #endif + if(sf) + { // sort and remove doubles + files.sort(sf); + for(int i = files.length() - 1; i > 0; i--) + { + if(!strcmp(files[i], files[i - 1])) delstring(files.remove(i)); + } + } } #ifndef STANDALONE void listfilesrecursive(const char *dir, vector &files, int level) { if(level > 8) return; // 8 levels is insane enough... - vector thisdir; + vector dirs, thisdir; + listsubdirs(dir, dirs, stringsort); + loopv(dirs) + { + if(dirs[i][0] != '.') // ignore "." and ".." (and also other directories starting with '.', like it is unix-convention - and doesn't hurt on windows) + { + defformatstring(name)("%s/%s", dir, dirs[i]); + listfilesrecursive(name, files, level + 1); + } + delstring(dirs[i]); + } listfiles(dir, NULL, thisdir); loopv(thisdir) { - if(thisdir[i][0] != '.') // ignore "." and ".." (and also other directories starting with '.', like it is unix-convention - and doesn't hurt on windows) - { - defformatstring(name)("%s/%s", dir, thisdir[i]); - files.add(newstring(name)); - listfilesrecursive(name, files, level + 1); - } + defformatstring(name)("%s/%s", dir, thisdir[i]); + files.add(newstring(name)); delstring(thisdir[i]); } } + +void listdirsrecursive(const char *dir, vector &subdirs, int level) +{ + if(level > 8) return; // 8 levels is insane enough... + vector dirs; + listsubdirs(dir, dirs, stringsort); + loopv(dirs) + { + if(dirs[i][0] != '.') // ignore "." and ".." (and also other directories starting with '.', like it is unix-convention - and doesn't hurt on windows) + { + defformatstring(name)("%s/%s", dir, dirs[i]); + subdirs.add(newstring(name)); + listdirsrecursive(name, subdirs, level + 1); + } + delstring(dirs[i]); + } +} #endif bool delfile(const char *path) diff --git a/source/src/tools.h b/source/src/tools.h index 32a00bc2..ca92f93d 100644 --- a/source/src/tools.h +++ b/source/src/tools.h @@ -953,10 +953,13 @@ extern stream *opengzfile(const char *filename, const char *mode, stream *file = extern char *loadfile(const char *fn, int *size, const char *mode = NULL); extern int streamcopy(stream *dest, stream *source, int maxlen = INT_MAX); extern void filerotate(const char *basename, const char *ext, int keepold, const char *oldformat = NULL); +extern const char *stream_capabilities(); extern bool listdir(const char *dir, const char *ext, vector &files); -extern void listfiles(const char *dir, const char *ext, vector &files); +extern void listfiles(const char *dir, const char *ext, vector &files, int (__cdecl *sf)(const char **, const char **) = NULL); extern void listfilesrecursive(const char *dir, vector &files, int level = 0); +extern void listdirsrecursive(const char *dir, vector &subdirs, int level = 0); extern void listzipfiles(const char *dir, const char *ext, vector &files); +extern void listzipdirs(const char *dir, vector &subdirs); extern bool delfile(const char *path); extern void backup(char *name, char *backupname); extern bool validzipmodname(char *name); diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index df5014a7..33dd4776 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -1493,8 +1493,7 @@ int loadallxmaps() // at game start, load all xmaps from mapediting/xmaps { vector xmapnames; string filename; - listfiles(xmapspath, "xmap", xmapnames); - xmapnames.sort(stringsort); + listfiles(xmapspath, "xmap", xmapnames, stringsort); loopv(xmapnames) { loadxmap(xmapnames[i]); diff --git a/source/src/zip.cpp b/source/src/zip.cpp index 41a4ce1a..21ab8561 100644 --- a/source/src/zip.cpp +++ b/source/src/zip.cpp @@ -798,3 +798,16 @@ void listzipfiles(const char *dir, const char *ext, vector &files) // (d }); } +void listzipdirs(const char *dir, vector &subdirs) // (does not list memfiles) +{ + int dirsize = (int)strlen(dir); + enumerate(zipfiles, zipfile *, zf, + { + if(strncmp(zf->fullname, dir, dirsize)) continue; + const char *name = zf->fullname + dirsize; + if(name[0] == PATHDIV) name++; + const char *endname = strchr(name, PATHDIV); + if(!endname) continue; + subdirs.add(newstring(name, endname - name)); + }); +}