/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */ /* rcg10142001 Implemented. */ // !!! FIXME: rcg10142001 This should really be using CTStrings... #include #include #include #include #include #include #include #include #include #include ENGINE_API CFileSystem *_pFileSystem = NULL; class CUnixFileSystem : public CFileSystem { public: CUnixFileSystem(const char *argv0, const char *gamename); virtual ~CUnixFileSystem(void); virtual void GetExecutablePath(char *buf, ULONG bufSize); virtual void GetUserDirectory(char *buf, ULONG bufSize); virtual CDynamicArray *FindFiles(const char *dir, const char *wildcard); protected: char *exePath; char *userDir; }; const char *CFileSystem::GetDirSeparator(void) { return("/"); } BOOL CFileSystem::IsDummyFile(const char *fname) { return( (strcmp(fname, ".") == 0) || (strcmp(fname, "..") == 0) ); } BOOL CFileSystem::Exists(const char *fname) { struct stat s; if (stat(fname, &s) == -1) return(FALSE); return(TRUE); } BOOL CFileSystem::IsDirectory(const char *fname) { struct stat s; if (stat(fname, &s) == -1) return(FALSE); return(S_ISDIR(s.st_mode) ? TRUE : FALSE); } CFileSystem *CFileSystem::GetInstance(const char *argv0, const char *gamename) { return(new CUnixFileSystem(argv0, gamename)); } static char *copyEnvironmentVariable(const char *varname) { const char *envr = getenv(varname); char *retval = NULL; if (envr != NULL) { retval = new char[strlen(envr) + 1]; strcpy(retval, envr); } return(retval); } static char *getUserDirByUID(void) { uid_t uid = getuid(); struct passwd *pw; char *retval = NULL; pw = getpwuid(uid); if ((pw != NULL) && (pw->pw_dir != NULL)) { retval = new char[strlen(pw->pw_dir) + 1]; strcpy(retval, pw->pw_dir); } return(retval); } // !!! FIXME: This could stand to use CTFileNames ... // !!! FIXME: When we move to SDL2, just use SDL_GetBasePath()? static char *calcExePath(const char *_argv0) { char *ptr; char *retval = NULL; char *argv0 = new char[strlen(_argv0) + 1]; strcpy(argv0, _argv0); /* _argv0 may be read-only... */ ptr = strrchr(argv0, '/'); if (ptr != NULL) // explicit path specified? We're done. { retval = new char[strlen(argv0) + 1]; strcpy(retval, argv0); } // If there isn't a path on argv0, then look through the $PATH for it... else { char *envr; char *start; char *exe; envr = copyEnvironmentVariable("PATH"); if (!envr) { delete[] argv0; return(NULL); } start = envr; do { while (*start == ':') start++; // skip empty entries. ptr = strchr(start, ':'); if (ptr) *ptr = '\0'; exe = new char[strlen(start) + strlen(argv0) + 2]; strcpy(exe, start); if (exe[strlen(exe) - 1] != '/') // make sure there's a dir sep... strcat(exe, "/"); strcat(exe, argv0); // add on the binary name... if (access(exe, X_OK) != 0) // Not our binary? delete[] exe; else // matching executable file found on path...this is it. { retval = new char[strlen(exe) + 1]; strcpy(retval, exe); delete[] exe; break; } start = ptr + 1; } while (ptr != NULL); delete[] envr; } delete[] argv0; if (retval != NULL) { char full[MAXPATHLEN]; realpath(retval, full); delete[] retval; retval = new char[strlen(full) + 1]; strcpy(retval, full); } return(retval); } // !!! FIXME: cut and paste from Engine.cpp ! --ryan. // reverses string static void StrRev( char *str) { char ctmp; char *pch0 = str; char *pch1 = str+strlen(str)-1; while( pch1>pch0) { ctmp = *pch0; *pch0 = *pch1; *pch1 = ctmp; pch0++; pch1--; } } // FIXME: This is such a lame hack. --ryan. static void calcModExt(char *full, const char *exePath, const char *gamename) { strcat(full, gamename); // bah...duplication from Engine.cpp ... char strDirPath[MAX_PATH] = ""; char strTmpPath[MAX_PATH] = ""; strncpy(strTmpPath, exePath, sizeof(strTmpPath)-1); strDirPath[sizeof(strTmpPath)-1] = 0; // remove name from application path StrRev(strTmpPath); // find last backslash char *pstr = strchr( strTmpPath, '/'); if( pstr==NULL) { // not found - path is just "\" strcpy( strTmpPath, "/"); pstr = strTmpPath; } // remove 'debug' from app path if needed if( strnicmp( pstr, "/gubed", 6)==0) pstr += 6; if( *pstr == '/') pstr++; char *pstrFin = strchr( pstr, '/'); if( pstrFin==NULL) { strcpy( pstr, "/"); pstrFin = pstr; } // copy that to the path StrRev(pstrFin); strncpy( strDirPath, pstrFin, sizeof(strDirPath)-1); strDirPath[sizeof(strDirPath)-1] = 0; strcat(strDirPath, "/ModExt.txt"); if (access(strDirPath, F_OK) == 0) { FILE *in = fopen(strDirPath, "rb"); int rc = fread(strTmpPath, 1, 30, in); if (rc > 0) { strTmpPath[rc] = '\0'; strcat(full, strTmpPath); } } strcat(full, "/"); } CUnixFileSystem::CUnixFileSystem(const char *argv0, const char *gamename) : exePath(NULL), userDir(NULL) { exePath = calcExePath(argv0); if (exePath == NULL) { exePath = new char[strlen(argv0) + 3]; strcpy(exePath, "./"); // (*shrug*) strcat(exePath, argv0); } userDir = copyEnvironmentVariable("HOME"); if (userDir == NULL) userDir = getUserDirByUID(); char full[MAXPATHLEN]; realpath(userDir, full); delete[] userDir; if (full[strlen(full) - 1] != '/') strcat(full, "/"); // make sure it ends with a dir separator! #if PLATFORM_MACOSX strcat(full, "Library/"); mkdir(full, S_IRWXU); // don't care if this fails. We'll catch it later. strcat(full, "Application Support/"); mkdir(full, S_IRWXU); // don't care if this fails. We'll catch it later. strcat(full, "Serious Sam/"); #else strcat(full, ".serious/"); #endif if (!Exists(full)) { if (mkdir(full, S_IRWXU) == -1) { FatalError("User dir creation failed! (%s)\n", strerror(errno)); } } calcModExt(full, exePath, gamename); if (!Exists(full)) { if (mkdir(full, S_IRWXU) == -1) { FatalError("User dir creation failed! (%s)\n", strerror(errno)); } } userDir = new char[strlen(full) + 1]; strcpy(userDir, full); } CUnixFileSystem::~CUnixFileSystem(void) { delete[] exePath; delete[] userDir; } void CUnixFileSystem::GetExecutablePath(char *buf, ULONG bufSize) { buf[bufSize - 1] = '\0'; // just in case. strncpy(buf, exePath, bufSize); } void CUnixFileSystem::GetUserDirectory(char *buf, ULONG bufSize) { buf[bufSize - 1] = '\0'; // just in case. strncpy(buf, userDir, bufSize); } CDynamicArray *CUnixFileSystem::FindFiles(const char *dir, const char *wildcard) { CDynamicArray *retval = new CDynamicArray; DIR *d = opendir(dir); if (d != NULL) { struct dirent *dent; while ((dent = readdir(d)) != NULL) { CTString str(dent->d_name); if (str.Matches(wildcard)) *retval->New() = str; } closedir(d); } return(retval); } // end of UnixFileSystem.cpp ...