00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "aa_config.h"
00030
00031 #include <errno.h>
00032 #include <sys/types.h>
00033 #ifndef WIN32
00034 #include <sys/stat.h>
00035 #endif
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038
00039 #include "tLocale.h"
00040 #include "tDirectories.h"
00041 #include "tString.h"
00042 #include "tConfiguration.h"
00043 #include "tCommandLine.h"
00044 #include "tMemManager.h"
00045
00046 #if HAVE_UNISTD_H
00047 #include <unistd.h>
00048 #endif
00049
00050
00051 #ifndef MACOSX_XCODE
00052 #ifdef TOP_SOURCE_DIR
00053 static const char * s_topSourceDir = TOP_SOURCE_DIR;
00054 #else
00055 static const char * s_topSourceDir = ".";
00056 #endif
00057 #endif // !MACOSX_XCODE
00058
00059
00060 #ifndef PROGNAME
00061 #ifdef DEDICATED
00062 #define PROGNAME "armagetronad-dedicated"
00063 #else
00064 #define PROGNAME "armagetronad"
00065 #endif
00066 #endif
00067
00068 #ifndef PROGNAMEBASE
00069 #define PROGNAMEBASE "armagetronad"
00070 #endif
00071
00072 #ifndef PROGDIR_SUFFIX
00073 #define PROGDIR_SUFFIX ""
00074 #endif
00075
00076 #ifdef WIN32
00077
00078 #ifdef __MINGW32__
00079 #define _WIN32_IE 0x400
00080 #endif
00081
00082 #include <direct.h>
00083 #include <windows.h>
00084 #include <shlobj.h>
00085 #define mkdir(x, y) _mkdir(x)
00086 #ifndef strdup
00087 #define strdup _strdup
00088 #endif
00089 #ifndef _stat
00090 #define _stat stat
00091 #endif
00092 #else
00093 #include <pwd.h>
00094 #endif
00095
00096 #ifdef TOP_SOURCE_DIR
00097
00098 #include "tUniversalVariables.h"
00099 #endif
00100
00101 #ifndef PREFIX
00102 #define PREFIX "/usr/local"
00103 #endif
00104
00105 #ifndef BINDIR
00106 #define BINDIR "/usr/local/bin"
00107 #endif
00108
00109
00110 static tString st_prefixCompiled(PREFIX);
00111 static tString st_bindirCompiled(BINDIR);
00112
00113
00114
00115 #ifndef SYSBINDIR
00116 #define SYSBINDIR "/does/not/exist"
00117 #endif
00118
00119 #ifndef DATASUFFIX
00120 #define DATASUFFIX ""
00121 #endif
00122
00123 #ifndef CONFIGSUFFIX
00124 #define CONFIGSUFFIX ""
00125 #endif
00126
00127 #define PROGDIR PROGNAME PROGDIR_SUFFIX
00128
00129 #ifdef WIN32
00130
00131 #ifdef __MINGW32__
00132 #define _WIN32_IE 0x400
00133 #endif
00134
00135 #undef DATADIR
00136 #include <direct.h>
00137 #include <windows.h>
00138 #include <shlobj.h>
00139 #define mkdir(x, y) _mkdir(x)
00140 #ifndef strdup
00141 #define strdup _strdup
00142 #endif
00143 #ifndef _stat
00144 #define _stat stat
00145 #endif
00146 #else
00147 #include <pwd.h>
00148 #endif
00149
00150 #ifdef DEBUG
00151
00152
00153
00154 #endif
00155
00156 #include <dirent.h>
00157 #include <sys/types.h>
00158 #include <sys/stat.h>
00159
00160 #ifdef ENABLE_BINRELOC
00161 #include "thirdparty/binreloc/prefix.h"
00162 #endif
00163
00164 tString expand_home(const tString & pathname);
00165
00166 #define expand_home_c(c) expand_home(tString(c))
00167
00168 #ifdef DATA_DIR
00169 static tString st_DataDir(expand_home_c(DATA_DIR));
00170 #else
00171 static tString st_DataDir(".");
00172 #endif
00173
00174 #ifdef MUSIC_DIR
00175 static tString st_MusicDir(expand_home_c(DATA_DIR));
00176 #else
00177 static tString st_MusicDir(".");
00178 #endif
00179
00180 #ifdef USER_DATA_DIR
00181 static tString st_UserDataDir(expand_home_c(USER_DATA_DIR));
00182 #else
00183 static tString st_UserDataDir(expand_home_c("~/." PROGDIR));
00184 #endif
00185
00186 #ifdef CONFIG_DIR
00187 static tString st_ConfigDir(expand_home_c(CONFIG_DIR));
00188 #else
00189 static tString st_ConfigDir("");
00190 #endif
00191
00192 #ifdef SCRIPT_DIR
00193 static tString st_ScriptDir(expand_home_c(SCRIPT_DIR));
00194 #else
00195 static tString st_ScriptDir("");
00196 #endif
00197
00198 #ifdef USER_CONFIG_DIR
00199 static tString st_UserConfigDir(expand_home_c(USER_CONFIG_DIR));
00200 #else
00201 static tString st_UserConfigDir("");
00202 #endif
00203
00204 #ifdef VAR_DIR
00205 static tString st_VarDir(expand_home_c(VAR_DIR));
00206 #else
00207 static tString st_VarDir("");
00208 #endif
00209
00210 #ifdef DEDICATED
00211 #ifdef WWWROOTDIR
00212 static tString st_WwwDir(expand_home_c(WWWROOTDIR));
00213 #else
00214 static tString st_WwwDir("");
00215 #endif
00216 #endif
00217
00218 #ifdef RESOURCE_DIR
00219 static tString st_ResourceDir(expand_home_c(RESOURCE_DIR));
00220 #else
00221 static tString st_ResourceDir("");
00222 #endif
00223
00224 #ifdef AUTORESOURCE_DIR
00225 static tString st_AutoResourceDir(expand_home_c(AUTORESOURCE_DIR));
00226 #else
00227 static tString st_AutoResourceDir("");
00228 #endif
00229
00230 #ifdef INCLUDEDRESOURCE_DIR
00231 static tString st_IncludedResourceDir(expand_home_c(INCLUDEDRESOURCE_DIR));
00232 #else
00233 static tString st_IncludedResourceDir("");
00234 #endif
00235
00236 #ifdef SCREENSHOT_DIR
00237 static tString st_ScreenshotDir(expand_home_c(SCREENSHOT_DIR));
00238 #else
00239 static tString st_ScreenshotDir("");
00240 #endif
00241
00242
00243 static bool st_IsPathDelimiter( char c )
00244 {
00245 return ( c == '/' || c == '\\' );
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255 static bool mkdir_recurse(char *pathname, size_t safe_path) {
00256
00257
00258
00259 size_t i;
00260 bool fs = false;
00261 bool e = false;
00262
00263 size_t len = strlen(pathname);
00264
00265 for (i = len - 1; i < len && !e; fs ? ++i : --i) {
00266 if ( st_IsPathDelimiter( pathname[i] ) ) {
00267 if (pathname[i + 1] == '.' && i + 2 > safe_path)
00268 return false;
00269 char delimiter = pathname[i];
00270 pathname[i] = '\0';
00271
00272 #ifdef DEBUG_PATH
00273 static bool first = true;
00274 if (fs || first )
00275 {
00276 first = false;
00277 con << "Making directory " << pathname << "\n";
00278 }
00279 #endif
00280
00281 if (!mkdir(pathname, 0777) || errno == EEXIST)
00282 fs = true;
00283 else if (fs)
00284 e = true;
00285 pathname[i] = delimiter;
00286 }
00287 if (i == 0 && !fs)
00288 e = true;
00289 }
00290 return !e;
00291 }
00292
00293 static bool st_checkPathAbsolute = true;
00294 static bool st_checkPathRelative = true;
00295 static bool st_checkPathHidden = true;
00296
00297
00298
00299
00300
00301
00314
00315
00316 bool tPath::IsValidPath( char const * filename )
00317 {
00318
00319 if ( !filename || filename[0] == 0 )
00320 {
00321 con << tOutput( "$directory_path_null" );
00322 return false;
00323 }
00324
00325
00326
00327 if ( st_checkPathAbsolute && ( st_IsPathDelimiter( filename[0] ) || strstr(filename,":") ) )
00328 {
00329 con << tOutput( "$directory_path_absolute", filename );
00330 return false;
00331 }
00332
00333
00334
00335 if ( st_checkPathRelative )
00336 {
00337
00338 char const * run = filename;
00339 while ( run && *run )
00340 {
00341
00342 run = strstr(run,"..");
00343
00344
00345 if ( run )
00346 {
00347 if ( ( run == filename || st_IsPathDelimiter( run[-1] ) ) &&
00348 ( run[2] == 0 || st_IsPathDelimiter( run[2] ) ) )
00349 {
00350 con << tOutput( "$directory_path_relative", filename );
00351 return false;
00352 }
00353
00354
00355 run ++;
00356 }
00357 }
00358 }
00359
00360
00361 if ( st_checkPathHidden )
00362 {
00363
00364 char const * run = filename;
00365 while ( run && *run )
00366 {
00367
00368 if ( run[0] == '.' )
00369 {
00370
00371 if ( run[1] != '.' || ( !st_IsPathDelimiter( run[2] ) && run[2] != 0 ) )
00372 {
00373 con << tOutput( "$directory_path_hidden", filename );
00374 return false;
00375 }
00376 }
00377
00378
00379 while ( *run && !st_IsPathDelimiter( *run ) )
00380 ++run;
00381
00382
00383 if ( *run )
00384 ++run;
00385 }
00386 }
00387
00388 return true;
00389 }
00390
00391
00392
00393
00394 char *eh_getdir(const char *da, size_t *len) {
00395 const char *s, *r, *d;
00396 char *type = 0, *user = 0, *ret = 0;
00397 size_t l;
00398
00399
00400 if (da[0] == '~') {
00401 type = strdup("HOME");
00402 {
00403
00404 char const * slash = strchr(da, '/');
00405 char const * backslash = strchr(da, '\\');
00406 if ( slash && backslash )
00407 d = slash < backslash ? slash : backslash;
00408 else
00409 d = slash ? slash : backslash;
00410 }
00411 l = ((d ? d : strchr(da, '\0')) - da - 1) * sizeof(char);
00412 user = (char *)memcpy(malloc(l + sizeof(char)), da + 1, l); user[l] = '\0';
00413 *len = l + 1;
00414 } else if (!strncmp(da, "${", 2)) {
00415 s = strchr(da, '}');
00416 if (!s) {
00417
00418 return 0;
00419 }
00420 if ((r = strchr(da, ':'))) {
00421 l = (s - r - 1) * sizeof(char);
00422 user = (char *)memcpy(malloc(l + sizeof(char)), r + 1, l); user[l] = '\0';
00423 } else {
00424 r = s;
00425 user = (char *)malloc(sizeof(char));
00426 user[0] = '\0';
00427 }
00428 l = (r - da - 2) * sizeof(char);
00429 type = (char *)memcpy(malloc(l + sizeof(char)), da + 2, l); type[l] = '\0';
00430 *len = s - da + 1;
00431 }
00432
00433
00434 #ifdef WIN32
00435 if (!strcmp(type, "HOME")) {
00436 free(type);
00437 type = strdup("HOMEPATH");
00438 }
00439 #endif
00440 if ((ret = getenv(type)))
00441 ret = strdup(ret);
00442 else {
00443 # ifdef WIN32
00444 {
00445 char path[MAX_PATH];
00446 int ssf = 0;
00447
00448
00449 if (!strcmp(type, "HOME")) ssf = 0x28;
00450 if (!strcmp(type, "APPDATA")) ssf = 0x1a;
00451 if (!strcmp(type, "COMMONAPPDATA")) ssf = 0x23;
00452 if (!strcmp(type, "DESKTOP")) ssf = 0x10;
00453 if (!strcmp(type, "LOCALAPPDATA")) ssf = 0x1c;
00454 if (!strcmp(type, "MYPICTURES")) ssf = 0x27;
00455 if (!strcmp(type, "PERSONAL")) ssf = 0x05;
00456 if (!strcmp(type, "PROFILE")) ssf = 0x28;
00457 if (!strcmp(type, "SYSTEM")) ssf = 0x25;
00458 if (!strcmp(type, "WINDOWS")) ssf = 0x24;
00459
00460
00461 if (ssf && SHGetSpecialFolderPath(NULL, path, ssf, 1))
00462 ret = strdup(path);
00463 }
00464 # else
00465
00466 if (!strcmp(type, "HOME")) {
00467 struct passwd *pw;
00468
00469 if (user[0] == '\0')
00470 pw = getpwuid(getuid());
00471 else
00472 pw = getpwnam(user);
00473 if (pw)
00474 ret = strdup(pw->pw_dir);
00475
00476 }
00477 # endif
00478
00479 }
00480
00481 #ifdef DEBUG_PATH
00482 std::cout << "Changing " << type << " to " << ret << "\n";
00483 #endif
00484
00485
00486 free(type);
00487 free(user);
00488 if (!ret && da[0] != '~') {
00489
00490 free(ret);
00491 ret = (char *)malloc(sizeof(char));
00492 ret[0] = '\0';
00493 }
00494
00495 return ret;
00496 }
00497
00498 tString expand_home(tString const & pathname) {
00499 const char *pn = (const char *)pathname;
00500 char *s;
00501 size_t len;
00502 tString r;
00503
00504 if ((pn[0] == '~' || !strncmp(pn, "${", 2)) && (s = eh_getdir(pn, &len))) {
00505 tString sStr(s);
00506 r = sStr << (pn + len);
00507 free(s);
00508 }
00509 else
00510 r = pathname;
00511
00512 #ifdef DEBUG
00513 printf("changed %s to %s\n", (const char *)pathname, (const char *)r);
00514 #endif
00515 return r;
00516 }
00517
00518 class tPathConfig: public tPath
00519 {
00520 public:
00521 private:
00522 void Paths ( tArray< tString >& paths ) const
00523 {
00524 paths.SetLen( 0 );
00525 int pos = 0;
00526
00527 paths[ pos++ ] = st_DataDir + "/config";
00528
00529 if ( st_ConfigDir.Len() > 1 )
00530 {
00531 paths[ pos++ ] = st_ConfigDir;
00532 }
00533
00534 if ( st_UserDataDir.Len() > 1 )
00535 {
00536 paths[ pos++ ] = st_UserDataDir + "/config";
00537 }
00538
00539 if ( st_UserConfigDir.Len() > 1 )
00540 {
00541 paths[ pos++ ] = st_UserConfigDir;
00542 }
00543 }
00544 };
00545
00546 static const tPathConfig st_Config;
00547
00548 class tPathData: public tPath
00549 {
00550 public:
00551 private:
00552 void Paths ( tArray< tString >& paths ) const
00553 {
00554 paths.SetLen( 0 );
00555 int pos = 0;
00556
00557 paths[ pos++ ] = st_DataDir;
00558
00559 if ( st_UserDataDir.Len() > 1 )
00560 {
00561 paths[ pos++ ] = st_UserDataDir;
00562 }
00563 }
00564 };
00565
00566 static const tPathData st_Data;
00567
00568
00569 class tPathMusic: public tPath
00570 {
00571 public:
00572 private:
00573 void Paths ( tArray< tString >& paths ) const
00574 {
00575 paths.SetLen( 0 );
00576 int pos = 0;
00577
00578 paths[ pos++ ] = st_MusicDir;
00579 }
00580 };
00581
00582 static const tPathMusic st_Music;
00583
00584 #ifdef DEDICATED
00585 void tPathWebroot::Paths ( tArray< tString >& paths ) const
00586 {
00587 paths.SetLen( 0 );
00588 int pos = 0;
00589
00590 paths[ pos++ ] = st_WwwDir;
00591 }
00592
00593 tString tPathWebroot::GetDirPath() {
00594
00595 return st_WwwDir;
00596 }
00597
00598 static const tPathWebroot st_Webroot;
00599
00600 const tPathWebroot& tDirectories::Webroot()
00601 {
00602 return st_Webroot;
00603 }
00604
00605 #endif
00606
00607 class tPathVar: public tPath
00608 {
00609 public:
00610 private:
00611 void Paths ( tArray< tString >& paths ) const
00612 {
00613 paths.SetLen( 0 );
00614 int pos = 0;
00615
00616 paths[ pos++ ] = st_DataDir + "/var";
00617
00618 if ( st_UserDataDir.Len() > 1 )
00619 {
00620 paths[ pos++ ] = st_UserDataDir + "/var";
00621 }
00622
00623 if ( st_VarDir.Len() > 1 )
00624 {
00625 paths[ pos++ ] = st_VarDir;
00626 }
00627 }
00628 };
00629
00630 static const tPathVar st_Var;
00631
00632
00633 class tPathScreenshot: public tPath
00634 {
00635 public:
00636 private:
00637 void Paths ( tArray< tString >& paths ) const
00638 {
00639 paths.SetLen( 0 );
00640 int pos = 0;
00641
00642 paths[ pos++ ] = st_DataDir + "/screenshot";
00643
00644 if ( st_UserDataDir.Len() > 1 )
00645 paths[ pos++ ] = st_UserDataDir + "/screenshot";
00646
00647 if ( st_ScreenshotDir.Len() > 1 )
00648 paths[ pos++ ] = st_ScreenshotDir;
00649 }
00650 };
00651
00652 static const tPathScreenshot st_Screenshot;
00653
00654
00655 tString tPathResource::GetWritePath(const char *filename) const {
00656 if ( !tPath::IsValidPath( filename ) )
00657 return tString();
00658
00659 tArray< tString > paths;
00660 Paths( paths );
00661
00662 tString fullname;
00663 fullname << paths(0) << "/" << filename;
00664
00665 {
00666 bool s;
00667
00668 char *fpmr = strdup( static_cast< char const * >( fullname ) );
00669 s = mkdir_recurse(fpmr, paths(0).Len());
00670 free(fpmr);
00671
00672 if (!s)
00673 {
00674 tERR_WARN( tOutput( "$directory_path_nonwritable", fullname ) );
00675 return tString();
00676 }
00677 }
00678
00679 return fullname;
00680 }
00681
00682 tString tPathResource::GetDirPath()
00683 {
00684 if ( st_IncludedResourceDir.Len() > 2 )
00685 return st_IncludedResourceDir;
00686 else
00687 return st_DataDir + "/resource/included";
00688 }
00689
00690 void tPathResource::Paths(tArray< tString >& paths) const {
00691 paths.SetLen( 0 );
00692 int pos = 0;
00693
00694 if ( st_AutoResourceDir.Len() > 1 )
00695 paths[ pos++ ] = st_AutoResourceDir;
00696 else if ( st_ResourceDir.Len() > 1 )
00697 paths[ pos++ ] = st_ResourceDir + "/automatic";
00698 else if ( st_UserDataDir.Len() > 1 )
00699 paths[ pos++ ] = st_UserDataDir + "/resource/automatic";
00700 else
00701 paths[ pos++ ] = st_DataDir + "/resource/automatic";
00702
00703 paths[ pos++ ] = st_DataDir + "/resource/included";
00704 if ( st_IncludedResourceDir.Len() > 1 )
00705 paths[ pos++ ] = st_IncludedResourceDir;
00706
00707 paths[ pos++ ] = st_DataDir + "/resource";
00708 if ( st_UserDataDir.Len() > 1 )
00709 paths[ pos++ ] = st_UserDataDir + "/resource";
00710 if ( st_ResourceDir.Len() > 1 )
00711 paths[ pos++ ] = st_ResourceDir;
00712 }
00713
00714
00715 static const tPathResource st_Resource;
00716
00717 tString tPathScripts::GetDirPath()
00718 {
00719 return st_DataDir + "/scripts";
00720 }
00721
00722 void tPathScripts::Paths(tArray< tString >& paths) const {
00723 paths.SetLen(0);
00724 paths[0] = GetDirPath();
00725 }
00726
00727 static const tPathScripts st_Scripts;
00728
00729 bool tPath::Open ( std::ifstream& f,
00730 const char* filename ) const
00731 {
00732 if ( !tPath::IsValidPath( filename ) )
00733 return false;
00734
00735 tArray< tString > paths;
00736 Paths( paths );
00737
00738 for ( int prio = paths.Len() - 1; prio>=0; --prio )
00739 {
00740
00741
00742 tString fullname;
00743 fullname << paths( prio ) << "/" << filename;
00744
00745 #ifdef PRINTSEARCH
00746 #endif
00747
00748
00749 f.clear();
00750 f.open( fullname );
00751
00752
00753 if ( f && f.good() )
00754 {
00755 #ifdef PRINTSEARCH
00756 std::cout << "Trying to open " << fullname << " succeeded.";
00757 #endif
00758
00759
00760
00761 return true;
00762 }
00763
00764 #ifdef PRINTSEARCH
00765 std::cout << "Trying to open " << fullname << " succeeded.";
00766 #endif
00767 }
00768
00769 return false;
00770 }
00771
00772 static bool st_protectFiles = true;
00773 tSettingItem<bool> st_protectFilesConf("PROTECT_SENSITIVE_FILES", st_protectFiles);
00774
00775 bool tPath::Open ( std::ofstream& f,
00776 const char* filename,
00777 std::ios::openmode mode,
00778 bool sensitive) const
00779 {
00780 if ( !tPath::IsValidPath( filename ) )
00781 return false;
00782
00783
00784
00785
00786 tString fullname = GetWritePath(filename);
00787
00788 #ifndef WIN32
00789 mode_t oldmask=0;
00790 if(sensitive && st_protectFiles)
00791 {
00792 oldmask = umask(0600);
00793 }
00794 #endif
00795 f.open( fullname, mode );
00796 #ifndef WIN32
00797 if(sensitive && st_protectFiles)
00798 {
00799 chmod( &fullname(0), 0600 );
00800 umask(oldmask);
00801 }
00802 #endif
00803
00804 return ( f && f.good() );
00805 }
00806
00807 bool tPath::Open(std::fstream& f, const char* filename) const
00808 {
00809
00810
00811 tString fullname = GetWritePath(filename);
00812 f.open(fullname, std::ios::in | std::ios::out);
00813
00814 return ( f.good() );
00815 }
00816
00817 tString tPath::GetReadPath ( const char* filename ) const
00818 {
00819 if ( !tPath::IsValidPath( filename ) )
00820 return tString();
00821
00822 tArray< tString > paths;
00823 Paths( paths );
00824
00825 for ( int prio = paths.Len() - 1; prio>=0; --prio )
00826 {
00827 tString fullname;
00828 fullname << paths( prio ) << "/" << filename;
00829 std::ifstream f;
00830
00831
00832 #ifdef PRINTSEARCH
00833 printf("Searching %s...", (const char *)fullname);
00834 #endif
00835 f.open( fullname );
00836
00837 if ( f && f.good() )
00838 {
00839
00840 #ifdef PRINTSEARCH
00841 printf("OK\n");
00842 #endif
00843 return fullname;
00844 }
00845
00846 #ifdef PRINTSEARCH
00847 printf("nope\n");
00848 #endif
00849 }
00850
00851 return tString();
00852 }
00853
00854 tString tPath::GetWritePath ( const char* filename ) const
00855 {
00856 if ( !tPath::IsValidPath( filename ) )
00857 return tString();
00858
00859 tArray< tString > paths;
00860 Paths( paths );
00861
00862 tString fullname;
00863 fullname << paths( paths.Len() -1 ) << "/" << filename;
00864
00865 {
00866 bool s;
00867
00868 char *fpmr = strdup( static_cast< char const * > ( fullname ) );
00869 s = mkdir_recurse(fpmr, paths( paths.Len() -1 ).Len());
00870 free(fpmr);
00871
00872 if (!s)
00873 {
00874 tERR_WARN( "Could not create path to " << fullname << ". Check your user's rights." );
00875 return tString();
00876 }
00877 }
00878
00879 return fullname;
00880 }
00881
00882 const tPath& tDirectories::Data()
00883 {
00884 return st_Data;
00885 }
00886
00887 const tPath& tDirectories::Music()
00888 {
00889 return st_Music;
00890 }
00891
00892 const tPath& tDirectories::Config()
00893 {
00894 return st_Config;
00895 }
00896
00897 const tPath& tDirectories::Scripts()
00898 {
00899 return st_Scripts;
00900 }
00901
00902 const tPath& tDirectories::Var()
00903 {
00904 return st_Var;
00905 }
00906
00907 const tPath& tDirectories::Screenshot()
00908 {
00909 return st_Screenshot;
00910 }
00911
00912 const tPathResource& tDirectories::Resource()
00913 {
00914 return st_Resource;
00915 }
00916
00917
00918 void tDirectories::SetData( const tString& dir )
00919 {
00920 st_DataDir = dir;
00921 }
00922
00923
00924 void tDirectories::SetUserData( const tString& dir )
00925 {
00926 st_UserDataDir = dir;
00927 }
00928
00929
00930 void tDirectories::SetConfig( const tString& dir )
00931 {
00932 st_ConfigDir = dir;
00933 }
00934
00935
00936 void tDirectories::SetUserConfig( const tString& dir )
00937 {
00938 st_UserConfigDir = dir;
00939 }
00940
00941
00942 void tDirectories::SetVar( const tString& dir )
00943 {
00944 st_VarDir = dir;
00945 }
00946
00947
00948 void tDirectories::SetScreenshot( const tString& dir ) {
00949 st_ScreenshotDir = dir;
00950 }
00951
00952 void tDirectories::SetResource( const tString& dir ) {
00953 st_ResourceDir = dir;
00954 }
00955
00956 void tDirectories::SetAutoResource( const tString& dir ) {
00957 st_AutoResourceDir = dir;
00958 }
00959
00960 void tDirectories::SetIncludedResource( const tString& dir ) {
00961 st_IncludedResourceDir = dir;
00962 }
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988 bool tDirectories::FileMatchesWildcard(const char *str, const char *pattern,
00989 bool ignoreCase )
00990 {
00991 int c;
00992
00993 while (*pattern)
00994 {
00995 if (!*str && *pattern != '*')
00996 return false;
00997
00998 switch (c = *pattern++)
00999 {
01000
01001 case '*':
01002 while (*pattern == '*')
01003 pattern++;
01004
01005 if (!*pattern)
01006 return true;
01007
01008 if (*pattern != '?' && *pattern != '\\')
01009 {
01010 if (ignoreCase)
01011 {
01012 while (*str && tolower(*pattern) != tolower(*str) )
01013 str++;
01014 }
01015 else
01016 {
01017 while (*str && *pattern != *str )
01018 str++;
01019 }
01020 }
01021
01022 while (*str)
01023 {
01024 if (FileMatchesWildcard(str, pattern, ignoreCase))
01025 return true;
01026 str++;
01027 }
01028 return false;
01029
01030 case '?':
01031 if (*str)
01032 break;
01033 return false;
01034
01035 case '\\':
01036 if (*pattern)
01037 c = *pattern++;
01038
01039 default:
01040 if (ignoreCase)
01041 {
01042 if (tolower(c) != tolower(*str))
01043 return false;
01044 }
01045 else
01046 {
01047 if (c != *str)
01048 return false;
01049 }
01050 break;
01051
01052 }
01053 str++;
01054 }
01055
01056 return !*str;
01057 }
01058
01059
01060
01061 void tDirectories::GetFiles( const tString& dir, const tString& fileSpec,
01062 tArray< tString >& files, int flag )
01063 {
01064 tArray<tString> specList;
01065 long pos = 0;
01066 struct stat statbuf;
01067 tString temp;
01068 bool bDir = false;
01069
01070 files.SetLen( 0 );
01071
01072
01073 GetSpecList( fileSpec, specList );
01074
01075 DIR *dirp;
01076 struct dirent *entry;
01077
01078 dirp = opendir( dir );
01079
01080 if ( dirp != NULL )
01081 {
01082 while ( ( entry = readdir( dirp ) ) != NULL )
01083 {
01084
01085 if ( entry->d_name[0] != '.' )
01086 {
01087
01088 temp = dir;
01089 if ( ( dir.Len() > 1 ) && ( dir[ dir.Len() - 2 ] != '/' && dir[ dir.Len() - 2 ] != '\\' ) )
01090 {
01091 temp += "/";
01092 }
01093 temp += entry->d_name;
01094
01095
01096 bDir = false;
01097 if ( stat( temp, &statbuf ) == 0 )
01098 {
01099 if( statbuf.st_mode & S_IFDIR )
01100 {
01101 bDir = true;
01102
01103 if ( flag == eGetFilesFilesOnly )
01104 continue;
01105 }
01106 else
01107 {
01108
01109 if ( flag == eGetFilesDirsOnly )
01110 continue;
01111 }
01112 }
01113
01114
01115 for ( int i = 0; i < specList.Len(); i++ )
01116 {
01117 if ( FileMatchesWildcard( entry->d_name, specList( i ), true ) )
01118 {
01119 files[ pos ] = entry->d_name;
01120 if ( bDir )
01121 files[ pos ] += "/";
01122 pos++;
01123 break;
01124 }
01125 }
01126 }
01127 }
01128
01129 closedir( dirp );
01130 }
01131
01132
01133 SortFiles( files );
01134 }
01135
01136
01137 tString& tDirectories::FileNameToMenuName(const char* fileName, tString& menuName)
01138 {
01139 char szBuf[256];
01140 int i = 0;
01141
01142
01143 memset( szBuf, 0, sizeof( szBuf ) );
01144 strncpy( szBuf, fileName, sizeof( szBuf ) - 1 );
01145
01146
01147 if ( szBuf[0] != '$' )
01148 {
01149
01150 for ( i = strlen(szBuf); i >= 0; i-- )
01151 {
01152 if ( szBuf[i] == '.' )
01153 {
01154 szBuf[i] = '\0';
01155 }
01156 }
01157
01158
01159 for ( i = 0; (unsigned)i < strlen(szBuf); i++ )
01160 {
01161 if ( szBuf[i] == '_' )
01162 {
01163 szBuf[i] = ' ';
01164 }
01165 }
01166 }
01167
01168 menuName = szBuf;
01169
01170 return menuName;
01171 }
01172
01173
01174 void tDirectories::GetSpecList( const tString& fileSpec, tArray< tString >& specList )
01175 {
01176 char szBuf[256];
01177 char szSep[] = ";";
01178 char *token = NULL;
01179 long pos = 0;
01180
01181 specList.SetLen( 0 );
01182
01183
01184 memset( szBuf, 0, sizeof( szBuf ) );
01185 strncpy( szBuf, (const char *) fileSpec, sizeof( szBuf ) - 1 );
01186 token = strtok( szBuf, szSep );
01187 while( token != NULL )
01188 {
01189 specList[ pos++ ] = token;
01190 token = strtok( NULL, szSep );
01191 }
01192 }
01193
01194
01195 static bool tStringLessThan(const tString &s1, const tString &s2)
01196 {
01197 for (int i = 0; i < s1.Len() - 1; i++)
01198 {
01199 if ( tolower( s2( i ) ) >= tolower( s1( i ) ) )
01200 {
01201 return false;
01202 }
01203 }
01204 return true;
01205 }
01206
01207
01208 void tDirectories::SortFiles( tArray< tString >& files )
01209 {
01210 tString temp;
01211 long pos = 0;
01212
01213
01214 for ( pos = 0; pos < files.Len() - 1; pos ++ )
01215 {
01216 for ( long pos2 = pos + 1; pos2 < files.Len(); pos2++ )
01217 {
01218
01219 if ( tStringLessThan( files( pos2 ), files( pos ) ) )
01220 {
01221 temp = files( pos );
01222 files( pos ) = files( pos2 );
01223 files( pos2 ) = temp;
01224 }
01225 }
01226 }
01227 }
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249 #define QUIT(x) { std::ostringstream s; s << x; quitWithMessage(s.str().c_str()); name_.Clear(); } return false
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275 void ReplacePath( tString & path, char const * replacement )
01276 {
01277
01278 if ( path.Len() < 3 )
01279 {
01280 path = replacement;
01281 }
01282 }
01283
01284
01285 bool TestPath( char const * path, char const * file )
01286 {
01287 std::string testData( path );
01288 testData += "/";
01289 testData += file;
01290 std::ifstream f(testData.c_str());
01291
01292
01293 #ifdef DEBUG_PATH
01294 con << "Testing existence of file " << testData << ( f.good() ? " : good.\n" : " : bad!\n" );
01295 #endif
01296
01297 return ( f.good() );
01298 }
01299
01300
01301 bool TestConfigurationPath( char const * path )
01302 {
01303 if ( TestPath( path, "settings.cfg" ) )
01304 {
01305 #ifdef DEBUG_PATH
01306 con << "Configuration path " << path << " is good.\n";
01307 #endif
01308
01309 ReplacePath( st_ConfigDir, path );
01310
01311 return true;
01312 }
01313
01314 #ifdef DEBUG_PATH
01315 con << "Configuration path " << path << " is bad!\n";
01316 #endif
01317
01318 return false;
01319 }
01320
01321
01322 bool TestDataPath( char const * path )
01323 {
01324 if ( TestPath( path, "language/english_base.txt") )
01325 {
01326 #ifdef DEBUG_PATH
01327 con << "Data path " << path << " is good.\n";
01328 #endif
01329
01330 ReplacePath( st_DataDir, path );
01331
01332 return true;
01333 }
01334
01335 #ifdef DEBUG_PATH
01336 con << "Data path " << path << " is bad!\n";
01337 #endif
01338
01339 return false;
01340 }
01341
01342
01343 static tString GetParent( char const * child, int levels )
01344 {
01345 tString ret( child );
01346
01347
01348 int toStrip = levels;
01349 int stripCurrent = ret.Size()-1;
01350 while (stripCurrent >= 0 && toStrip > 0)
01351 {
01352 char & c = ret[ stripCurrent ];
01353
01354 if (c == '/' || c == '\\' || c == ':')
01355 --toStrip;
01356 c=0;
01357 --stripCurrent;
01358 }
01359
01360 #ifdef DEBUG_PATH
01361 std::cout << "Parent: " << ret << "\n";
01362 #endif
01363
01364 return tString(static_cast<char const *>(ret));
01365 }
01366
01368 class tPathToExecutable
01369 {
01370 public:
01372 void Set( char const * defaultPath )
01373 {
01374 #ifndef WIN32
01375 #ifdef ENABLE_BINRELOC
01376
01377 char const * bestGuess = SELFPATH;
01378 #else // binreloc
01379 char const * bestGuess = BINDIR "/" PROGNAME;
01380 #endif// binreloc
01381 #else // win32
01382 char const * bestGuess = "./" PROGNAME;
01383 #endif// win32
01384
01385 #ifndef ENABLE_BINRELOC
01386
01387 if ( strstr( defaultPath, "/" ) || strstr( defaultPath, "\\" ) )
01388 bestGuess = defaultPath;
01389
01390 #endif
01391
01392 path_ = bestGuess;
01393
01394 #ifdef DEBUG_PATH
01395 con << "path to executable: " << path_ << "\n";
01396 #endif
01397 }
01398
01399
01400 char const * Get() const
01401 {
01402 tASSERT( path_.Len() > 2 );
01403 return path_;
01404 }
01405 private:
01406 tString path_;
01407 };
01408
01409 static tPathToExecutable st_pathToExecutable;
01410
01411 static tString GenerateParentOfExecutable( int levels = 2 )
01412 {
01413 return GetParent( st_pathToExecutable.Get(), levels );
01414 }
01415
01416
01417 struct tRunningInBuildDirectory
01418 {
01419 };
01420
01421
01422
01423 static tString GeneratePrefix()
01424 {
01425
01426 tString const & prefixCompiled = st_prefixCompiled;
01427
01428 tString const & bindirCompiled = st_bindirCompiled;
01429
01430 tString bindirNow(GenerateParentOfExecutable(1));
01431
01432
01433 int bindirSuffixLength=bindirCompiled.Len() - prefixCompiled.Len();
01434
01435
01436 int bindirNowPrefixEnd=bindirNow.Len() - 1 - bindirSuffixLength;
01437 if ( bindirNowPrefixEnd < 0 )
01438 bindirNowPrefixEnd = 0;
01439
01440
01441 tString suffixNow = bindirNow.SubStr( bindirNowPrefixEnd + 1 );
01442 tString suffixCompiled = bindirCompiled.SubStr( prefixCompiled.Len() );
01443
01444 #ifdef DEBUG_PATH
01445 con << "suffices: " << suffixNow << ", " << suffixCompiled << "\n";
01446 #endif
01447
01448 if ( suffixNow != suffixCompiled )
01449 {
01450
01451 int bindirEndStart = bindirNow.Len() - 5;
01452 if ( bindirEndStart < 0 )
01453 bindirEndStart = 0;
01454
01455 tString bindirEnd = bindirNow.SubStr( bindirEndStart );
01456
01457 #ifdef DEBUG_PATH
01458 con << "bindirEnd: " << bindirEnd << "\n";
01459 #endif
01460
01461 if ( TestPath( bindirNow, "Makefile" ) )
01462 throw tRunningInBuildDirectory();
01463
01464 tERR_ERROR("Relocation error. The binary was supposed to be installed into " << bindirCompiled << " and found itself in " << bindirNow << " and could not find out what this means for the prefix " << prefixCompiled << "." );
01465 }
01466
01467
01468 tString prefixNow = bindirNow.SubStr( 0, bindirNowPrefixEnd );
01469
01470 #ifdef DEBUG_PATH
01471 con << "prefix: " << prefixNow << "\n";
01472 #endif
01473
01474 return prefixNow;
01475 }
01476
01477
01478 static char const * GetPrefix()
01479 {
01480 static tString ret( GeneratePrefix() );
01481 return ret;
01482 }
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495 #ifndef WIN32
01496 static tString st_RelocatePath( tString const & original )
01497 {
01498
01499 tString const & prefixCompiled = st_prefixCompiled;
01500
01501 static tString prefixNow(GetPrefix());
01502
01503
01504 if ( original.StartsWith( prefixCompiled ) )
01505 {
01506
01507 return prefixNow + original.SubStr( prefixCompiled.Len()-1 );
01508 }
01509 else
01510 {
01511
01512 return original;
01513 }
01514 }
01515 #endif
01516
01517
01518 static void FindDataPath()
01519 {
01520 #ifndef MACOSX_XCODE
01521 #ifdef WIN32
01522
01523 if ( TestDataPath(GetParent(st_pathToExecutable.Get(), 1) ) ) return;
01524 #else
01525
01526 if ( TestDataPath( st_RelocatePath( tString(AA_DATADIR ) ) ) ) return;
01527
01528 #endif
01529
01530 #ifdef DEBUG_PATH
01531 con << "Data sarch failed, trying debug fallback.\n";
01532 #endif
01533
01534 #ifdef DEBUG_PATH
01535 tERR_MESSAGE("Could not determine path to data files. Using defaults or command line arguments.\n");
01536 #endif
01537 #endif // !MACOSX_XCODE
01538 }
01539
01540
01541 static void FindConfigurationPath()
01542 {
01543 #ifndef MACOSX_XCODE
01544 #ifndef WIN32
01545 if ( TestConfigurationPath( st_RelocatePath( tString( AA_SYSCONFDIR ) ) ) ) return;
01546 #endif
01547
01548
01549 if ( TestConfigurationPath(st_DataDir + "/config") ) return;
01550
01551 tERR_WARN("Could not determine path to configuration files. Using defaults or command line arguments.\n");
01552 #endif // !MACOSX_XCODE
01553 }
01554
01555
01556
01557 static bool ReadDir( tCommandLineParser & parser, tString & target, const char* argument )
01558 {
01559 if ( parser.GetOption( target, argument ) )
01560 {
01561 target = expand_home_c( target );
01562
01563 return true;
01564 }
01565
01566 return false;
01567 }
01568
01569 class tDirectoriesCommandLineAnalyzer: public tCommandLineAnalyzer
01570 {
01571 private:
01572 virtual void DoInitialize( tCommandLineParser & parser )
01573 {
01574
01575 #ifndef MACOSX_XCODE
01576 try
01577 {
01578 st_pathToExecutable.Set( parser.Executable() );
01579 FindDataPath();
01580 FindConfigurationPath();
01581 }
01582 catch( tRunningInBuildDirectory )
01583 {
01584
01585 if ( TestPath( ".", "language/languages.txt") && TestDataPath(s_topSourceDir) && TestConfigurationPath(st_DataDir + "/config") )
01586 {
01587
01588 st_UserDataDir = ".";
01589
01590
01591 st_IncludedResourceDir = "./resource/included";
01592 return;
01593 }
01594 }
01595 #endif // !MACOSX_XCODE
01596
01597
01598 }
01599
01600 virtual bool DoAnalyze( tCommandLineParser & parser )
01601 {
01602 if( ReadDir( parser, st_DataDir, "--datadir" ) ) return true;
01603 if( ReadDir( parser, st_UserDataDir, "--userdatadir" ) ) return true;
01604 if( ReadDir( parser, st_ConfigDir, "--configdir" ) ) return true;
01605 if( ReadDir( parser, st_UserConfigDir, "--userconfigdir" ) ) return true;
01606 if( ReadDir( parser, st_VarDir, "--vardir" ) ) return true;
01607 if( ReadDir( parser, st_ResourceDir, "--resourcedir" ) ) return true;
01608 if( ReadDir( parser, st_AutoResourceDir, "--autoresourcedir" ) ) return true;
01609
01610 if ( parser.GetSwitch( "--path-no-absolutecheck" ) )
01611 {
01612 st_checkPathAbsolute = false;
01613 return true;
01614 }
01615
01616 if ( parser.GetSwitch( "--path-no-relativecheck" ) )
01617 {
01618 st_checkPathRelative = false;
01619 return true;
01620 }
01621
01622 if ( parser.GetSwitch( "--path-no-hiddencheck" ) )
01623 {
01624 st_checkPathHidden = false;
01625 return true;
01626 }
01627
01628 if ( parser.GetSwitch( "--prefix" ) )
01629 {
01630 std::cout << GetPrefix() << '\n';
01631 throw 1;
01632 return true;
01633 }
01634
01635 return false;
01636 }
01637
01638 virtual void DoHelp( std::ostream & s )
01639 {
01640 s << "--datadir <Directory> : read game data (textures, sounds and texts)\n"
01641 << " from this directory\n";
01642 s << "--userdatadir <Directory> : read customized game data from this directory\n";
01643 s << "--configdir <Directory> : read game configuration (.cfg-files)\n"
01644 << " from this directory\n";
01645 s << "--userconfigdir <Directory> : read user game configuration from this directory\n";
01646 s << "--vardir <Directory> : save game logs and highscores in this directory\n\n";
01647 s << "--resourcedir <Directory> : look for resources in this directory\n\n";
01648 s << "--autoresourcedir <Directory>: download missing resources into this directory\n\n";
01649 s << "--path-no-absolutecheck : disables security check against absolute paths\n";
01650 s << "--path-no-hiddencheck : disables security check against hidden paths\n";
01651 s << "--path-no-relativecheck : disables security check against relative paths.\n"
01652 << " Not recommended, this check is really important.\n\n";
01653 s << "--prefix : prints the prefix the game was installed to\n";
01654 }
01655 };
01656
01657 static tDirectoriesCommandLineAnalyzer analyzer;
01658
01659 tString tPath::GetPaths(void) const {
01660 tString ret;
01661 tArray<tString> paths;
01662 Paths(paths);
01663 for (int i = 0; i < paths.Len(); ++i) {
01664 if(i > 0 && paths[i - 1] == paths[i]) continue;
01665 ret << " - " << paths[i] << "\n";
01666 }
01667 return ret;
01668 }
01669
01670 extern char *st_userConfigs[];
01671 void st_PrintPathInfo(tOutput &buf) {
01672 tString const hcol("0xff8888");
01673 buf << hcol << "$path_info_user_cfg" << "0xRESETT\n " << tDirectories::Var().GetReadPath("user.cfg") << "\n"
01674 << hcol << "$path_info_config" << "0xRESETT\n" << tDirectories::Config().GetPaths()
01675 << hcol << "$path_info_resource" << "0xRESETT\n" << tDirectories::Resource().GetPaths()
01676 << hcol << "$path_info_data" << "0xRESETT\n" << tDirectories::Data().GetPaths()
01677 << hcol << "$path_info_screenshot" << "0xRESETT\n" << tDirectories::Screenshot().GetPaths()
01678 << hcol << "$path_info_var" << "0xRESETT\n" << tDirectories::Var().GetPaths();
01679 }