/* ************************************************************************* ArmageTron -- Just another Tron Lightcycle Game in 3D. Copyright (C) 2000 Manuel Moos (manuel@moosnet.de) Copyright (C) 2004 Armagetron Advanced Team (http://sourceforge.net/projects/armagetronad/) ************************************************************************** This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *************************************************************************** */ #include "tLocale.h" #include "tDirectories.h" #include "tString.h" #include "config.h" #include "tConfiguration.h" #ifdef WIN32 #include #endif #include #include #include #ifdef WIN32 #define _stat stat #endif #ifdef DATA_DIR static tString st_DataDir(DATA_DIR); // directory for game data #else static tString st_DataDir("."); // directory for game data #endif #ifdef USER_DATA_DIR static tString st_UserDataDir(DATA_DIR); // directory for game data #else static tString st_UserDataDir("."); // directory for game data #endif #ifdef CONFIG_DIR static tString st_ConfigDir(CONFIG_DIR); // directory for static configuration files #else static tString st_ConfigDir(""); // directory for static configuration files #endif #ifdef USER_CONFIG_DIR static tString st_UserConfigDir(CONFIG_DIR); // directory for static configuration files #else static tString st_UserConfigDir(""); // directory for static configuration files #endif #ifdef VAR_DIR static tString st_VarDir(VAR_DIR); // directory for dynamic logs and highscores #else static tString st_VarDir(""); // directory for dynamic logs and highscores #endif class tPathConfig: public tPath { public: private: void Paths ( tArray< tString >& paths ) const { paths.SetLen( 0 ); int pos = 0; paths[ pos++ ] = st_DataDir + "/config"; if ( st_ConfigDir.Len() > 1 ) { paths[ pos++ ] = st_ConfigDir; } if ( st_UserDataDir.Len() > 1 ) { paths[ pos++ ] = st_UserDataDir + "/config"; } if ( st_UserConfigDir.Len() > 1 ) { paths[ pos++ ] = st_UserConfigDir; } } }; static const tPathConfig st_Config; class tPathData: public tPath { public: private: void Paths ( tArray< tString >& paths ) const { paths.SetLen( 0 ); int pos = 0; paths[ pos++ ] = st_DataDir; if ( st_UserDataDir.Len() > 1 ) { paths[ pos++ ] = st_UserDataDir; } } }; static const tPathData st_Data; class tPathVar: public tPath { public: private: void Paths ( tArray< tString >& paths ) const { paths.SetLen( 0 ); int pos = 0; paths[ pos++ ] = st_DataDir + "/var"; if ( st_UserDataDir.Len() > 1 ) { paths[ pos++ ] = st_UserDataDir + "/var"; } if ( st_VarDir.Len() > 1 ) { paths[ pos++ ] = st_VarDir; } } }; static const tPathVar st_Var; bool tPath::Open ( std::ifstream& f, const char* filename ) const { tArray< tString > paths; Paths( paths ); for ( int prio = paths.Len() - 1; prio>=0; --prio ) { // std::ifstream test; tString fullname; fullname << paths( prio ) << "/" << filename; #ifdef DEBUG std::cout << "Trying to open " << fullname << "..."; #endif // test.open( fullname ); f.clear(); f.open( fullname ); // if ( test ) if ( f && f.good() ) { #ifdef DEBUG std::cout << " success!\n"; #endif // f.open( fullname ); // return f; return true; } #ifdef DEBUG std::cout << " failed.\n"; #endif } return false; } bool tPath::Open ( std::ofstream& f, const char* filename, std::ios::openmode mode ) const { tArray< tString > paths; Paths( paths ); tString fullname; fullname << paths( paths.Len() -1 ) << "/" << filename; f.open( fullname, mode ); return ( f && f.good() ); } tString tPath::GetReadPath ( const char* filename ) const { tArray< tString > paths; Paths( paths ); for ( int prio = paths.Len() - 1; prio>=0; --prio ) { tString fullname; fullname << paths( prio ) << "/" << filename; std::ifstream f; f.open( fullname ); if ( f && f.good() ) { return fullname; } } return tString(); } tString tPath::GetWritePath ( const char* filename ) const { tArray< tString > paths; Paths( paths ); tString fullname; fullname << paths( paths.Len() -1 ) << "/" << filename; return fullname; } const tPath& tDirectories::Data() { return st_Data; } const tPath& tDirectories::Config() { return st_Config; } const tPath& tDirectories::Var() { return st_Var; } // set location of data directory void tDirectories::SetData( const tString& dir ) { st_DataDir = dir; } // set location of user data directory void tDirectories::SetUserData( const tString& dir ) { st_UserDataDir = dir; } // set location of config directory void tDirectories::SetConfig( const tString& dir ) { st_ConfigDir = dir; } // set location of user config directory void tDirectories::SetUserConfig( const tString& dir ) { st_UserConfigDir = dir; } // set location of var directory void tDirectories::SetVar( const tString& dir ) { st_VarDir = dir; } /* * robust glob pattern matcher * ozan s. yigit/dec 1994 * public domain * http://www.cs.yorku.ca/~oz/glob.bun * * glob patterns: * * matches zero or more characters * ? matches any single character * * char matches itself except where char is '*' or '?' or '[' * \char matches char, including any pattern character * * examples: * a*c ac abc abbc ... * a?c acc abc aXc ... * * Revision 1.5 2004/08/24 12:24:23 k * added case sensitive/insensitive option * * Revision 1.4 2004/08/17 12:24:23 k * removed [a-z] checking to match Windows wildcard parsing */ // check if a file name matches a wildcard (* and ? are valid wild cards) bool tDirectories::FileMatchesWildcard(const char *str, const char *pattern, bool ignoreCase /* = true */) { int c; while (*pattern) { if (!*str && *pattern != '*') return false; switch (c = *pattern++) { case '*': while (*pattern == '*') pattern++; if (!*pattern) return true; if (*pattern != '?' && *pattern != '\\') { if (ignoreCase) { while (*str && tolower(*pattern) != tolower(*str) ) str++; } else { while (*str && *pattern != *str ) str++; } } while (*str) { if (FileMatchesWildcard(str, pattern, ignoreCase)) return true; str++; } return false; case '?': if (*str) break; return false; case '\\': if (*pattern) c = *pattern++; default: if (ignoreCase) { if (tolower(c) != tolower(*str)) return false; } else { if (c != *str) return false; } break; } str++; } return !*str; } // get a list of files for a directory // flag: 0=files+dirs, 1=files, 2=dirs void tDirectories::GetFiles( const tString& dir, const tString& fileSpec, tArray< tString >& files, int flag /* = eGetFilesAllFiles */ ) { tArray specList; long pos = 0; struct stat statbuf; tString temp; bool bDir = false; files.SetLen( 0 ); // Check for multiple file specs GetSpecList( fileSpec, specList ); DIR *dirp; struct dirent *entry; dirp = opendir( dir ); if ( dirp != NULL ) { while ( ( entry = readdir( dirp ) ) != NULL ) { // Ignore "." and ".." entries if ( entry->d_name[0] != '.' ) { // Build path. Make sure dir ends with a '/'. temp = dir; if ( ( dir.Len() > 1 ) && ( dir[ dir.Len() - 2 ] != '/' ) ) { temp += "/"; } temp += entry->d_name; // Is the entry a directory? bDir = false; if ( stat( temp, &statbuf ) == 0 ) { if( statbuf.st_mode & S_IFDIR ) { bDir = true; // Don't add directories when flag = 1 if ( flag == eGetFilesFilesOnly ) continue; } else { // Don't add files when flag = 2 if ( flag == eGetFilesDirsOnly ) continue; } } // If the entry matches a file spec add it to the list for ( int i = 0; i < specList.Len(); i++ ) { if ( FileMatchesWildcard( entry->d_name, specList( i ), true ) ) { files[ pos ] = entry->d_name; if ( bDir ) files[ pos ] += "/"; pos++; break; } } } } closedir( dirp ); } // Sort the list of files SortFiles( files ); } // Convert a file name to a menu name (strip extension, replace '_' with ' ') tString& tDirectories::FileNameToMenuName(const char* fileName, tString& menuName) { char szBuf[256]; int i = 0; // copy string to buffer for manipulation memset( szBuf, 0, sizeof( szBuf ) ); strncpy( szBuf, fileName, sizeof( szBuf ) - 1 ); // skip translation strings if ( szBuf[0] != '$' ) { // strip extension for ( i = strlen(szBuf); i >= 0; i-- ) { if ( szBuf[i] == '.' ) { szBuf[i] = '\0'; } } // replace underscores with spaces for ( i = 0; (unsigned)i < strlen(szBuf); i++ ) { if ( szBuf[i] == '_' ) { szBuf[i] = ' '; } } } menuName = szBuf; return menuName; } // split the file spec into a list void tDirectories::GetSpecList( const tString& fileSpec, tArray< tString >& specList ) { char szBuf[256]; char szSep[] = ";"; char *token = NULL; long pos = 0; specList.SetLen( 0 ); // Check for multiple file specs memset( szBuf, 0, sizeof( szBuf ) ); strncpy( szBuf, (const char *) fileSpec, sizeof( szBuf ) - 1 ); token = strtok( szBuf, szSep ); while( token != NULL ) { specList[ pos++ ] = token; token = strtok( NULL, szSep ); } } // Helper function to see if tString s1 is less than s2 ignoring case static bool tStringLessThan(const tString &s1, const tString &s2) { for (int i = 0; i < s1.Len() - 1; i++) { if ( tolower( s2( i ) ) >= tolower( s1( i ) ) ) { return false; } } return true; } // Sort the list of files void tDirectories::SortFiles( tArray< tString >& files ) { tString temp; long pos = 0; // bubble sort for now for ( pos = 0; pos < files.Len() - 1; pos ++ ) { for ( long pos2 = pos + 1; pos2 < files.Len(); pos2++ ) { //if ( strcmp( (const char *) files( pos2 ), (const char *) files( pos ) ) < 0 ) if ( tStringLessThan( files( pos2 ), files( pos ) ) ) { temp = files( pos ); files( pos ) = files( pos2 ); files( pos2 ) = temp; } } } } static void quitWithMessage( const char* message ) { #ifdef WIN32 #ifndef DEDICATED #define USEBOX #endif #endif #ifdef USEBOX int result = MessageBox (NULL, message , "Message", MB_OK); #else std::cout << message; #endif tLocale::Clear(); } //#define QUIT(x) { std::ostringstream s; s << x; quitWithMessage(s.str().c_str()); name_.Clear(); } exit(0) #define QUIT(x) { std::ostringstream s; s << x; quitWithMessage(s.str().c_str()); name_.Clear(); } return false bool ReadDir( int& i, int argc, char **argv, const char* argument, tString& target ) { if ( !strcmp(argv[i],argument ) ) { if ( i < argc - 1 ) { i++; target = argv[i]; return true; } else { tString name_; QUIT( "\n\n" << argument << " needs another argument.\n\n" ); } } return false; } bool tCommandLineData::Analyse(int argc,char **argv) { tASSERT( programVersion_ ); { char *run = argv[0]; while (*run) { if (*run == '\\' || *run == '/') name_ = run+1; run++; } if ( name_.Len() <= 3 ) { name_ = "Armagetron"; } } //std::cout << "config loaded\n"; #ifndef WIN32 #define HELPAVAIL #endif #ifdef DEDICATED #define HELPAVAIL #endif for(int i=1;i : read game data (textures, sounds and texts)\n" << " from this directory\n"; s << "--userdatadir : read customized game data from this directory\n"; s << "--configdir : read game configuration (.cfg-files)\n" << " from this directory\n"; s << "--userconfigdir : read user game configuration from this directory\n"; s << "--vardir : save game logs and highscores in this directory\n\n"; #ifndef DEDICATED s << "-f, +f, --fullscreen : start in fullscreen mode\n"; s << "-w, +w, --window, --windowed : start in windowed mode\n\n"; #ifdef WIN32 s << "+directx, -directx : enable/disable usage of DirectX for screen\n" << " initialisation under MS Windows\n\n"; s << "\n\nYes, I know this looks ugly. Sorry about that.\n"; #endif #else #ifndef WIN32 s << "-d, +d, --daemon : allow the dedicated server to run as a daemon\n" << " (will not poll for input on stdin)\n"; #endif #endif s << "\n\n"; name_.Clear(); quitWithMessage( s.str().c_str() ); } return false; // exit(0); } #ifdef HELPAVAIL else if (!strcmp(argv[i],"--doc") ) { doc_ = true; } #endif else if (!strcmp(argv[i],"+d") || !strcmp(argv[i],"-d") || !strcmp(argv[i],"--daemon") ) { daemon_ = true; } else if (!strcmp(argv[i],"-v") || !strcmp(argv[i],"--version")) { QUIT( "This is " << name_ << " version " << *programVersion_ << ".\n" ); } else if (!strcmp(argv[i],"-fullscreen") || !strcmp(argv[i],"-f") || !strcmp(argv[i],"+f")){ fullscreen_=true; } else if (!strcmp(argv[i],"-window") || !strcmp(argv[i],"-windowed") || !strcmp(argv[i],"+w") || !strcmp(argv[i],"-w")){ windowed_=true; } #ifdef WIN32 else if (!strcmp(argv[i],"+directx")){ use_directx_=true; } else if (!strcmp(argv[i],"-directx")){ dont_use_directx_=true; } #endif #ifdef POWERPAK_DEB else if (!strcmp(argv[i],"nodeb")){ pp_out=0; } #endif else { bool dir = false; dir = ReadDir( i, argc, argv, "--datadir", st_DataDir ) || ReadDir( i, argc, argv, "--userdatadir", st_UserDataDir ) || ReadDir( i, argc, argv, "--configdir", st_ConfigDir ) || ReadDir( i, argc, argv, "--userconfigdir", st_UserConfigDir ) || ReadDir( i, argc, argv, "--vardir", st_VarDir ); if ( !dir ) { QUIT( "\n\nUnknown command line option " << argv[i] << ". Type " << name_ << " -h to get a list of possible options.\n\n" ); } } } return true; } bool tCommandLineData::Execute() { tString name; if ( doc_ ) { std::cout << "Available console commands/config file settings:\n\n"; tConfItemBase::DocAll( std::cout ); QUIT("\n"); } return true; }