📄 filepath.cpp
字号:
#include "SString.h"#include "Platform.h"#include "filepath.h"#include "PropSet.h"#include <stdlib.h>#include <string.h>#include <ctype.h>#include <stdio.h>#include <fcntl.h>#include <sys/stat.h>#include <time.h>#include <fstream>using namespace std;#ifdef WIN32#include <windows.h>#include <direct.h>#include <io.h>#else#include <unistd.h>#include <dirent.h>#include <errno.h>#endif#ifdef WIN32const char pathSepString[] = "\\";const char pathSepChar = '\\';const char listSepString[] = ";";const char configFileVisibilityString[] = "";const char fileRead[] = "rb";const char fileWrite[] = "wb";#elseconst char pathSepString[] = "/";const char pathSepChar = '/';const char listSepString[] = ":";const char configFileVisibilityString[] = ".";const char fileRead[] = "rb";const char fileWrite[] = "wb";#endifFilePath::FilePath(const char *fileName_):fileName(fileName_){}FilePath::FilePath(FilePath const &directory,FilePath const &name){ Set(directory,name);}void FilePath::Set(const char *fileName_){ fileName = fileName_;}const char *FilePath::AsFileSystem() const{ return AsInternal();}void FilePath::Set(FilePath const &other){ fileName = other.fileName;}void FilePath::Set(FilePath const &directory,FilePath const &name){ if(name.IsAbsolute()){ fileName = name.fileName; }else{ fileName = directory.fileName; fileName.appendwithseparator(name.fileName.c_str(),fileName.endswith(pathSepString) ? '\0' : pathSepChar); }}void FilePath::SetDirectory(FilePath directory) { FilePath curName(*this); Set(directory, curName);}void FilePath::Init(){ fileName = "";}bool FilePath::SameNameAs(const char *other) const{#ifdef WIN32 return EqualCaseInsensitive(fileName.c_str(),other);#else return fileName == other;#endif}bool FilePath::SameNameAs(const FilePath &other) const{ return SameNameAs(other.fileName.c_str());}bool FilePath::IsSet() const{ return fileName.length() > 0;}bool FilePath::IsUntitled() const{ const char *dirEnd = strrchr(AsInternal(),pathSepChar); return !dirEnd || !dirEnd[1];}bool FilePath::IsAbsolute() const{ if (fileName.length() == 0) return false;#ifdef WIN32 if (fileName[0] == pathSepChar || fileName[1] == ':') // UNC path or drive separator return true;#else if(fileName[0] == '/') return true;#endif return false;}bool FilePath::IsRoot() const{#ifdef WIN32 if ((fileName[0] == pathSepChar) && (fileName[1] == pathSepChar) && (fileName.search(pathSepString, 2) < 0)) return true; // UNC path like \\server return (fileName.length() == 3) && (fileName[1] == ':') && (fileName[2] == pathSepChar);#else return fileName == "/";#endif}int FilePath::RootLength(){#ifdef WIN32 return 3;#else return 1;#endif}const char *FilePath::AsInternal() const{ return fileName.c_str();}FilePath FilePath::Name() const{ const char *dirEnd = strrchr(fileName.c_str(), pathSepChar); if (dirEnd) return dirEnd + 1; else return fileName.c_str();}const char *FilePath::getType() const{ return fileType.c_str();}void FilePath::setType(const char *type){ fileType = type;}FilePath FilePath::BaseName() const{ const char *dirEnd = strrchr(fileName.c_str(), pathSepChar); const char *extStart = strrchr(fileName.c_str(), '.'); if (dirEnd) { if (extStart > dirEnd) { return FilePath(SString(dirEnd + 1, 0, extStart - dirEnd - 1).c_str()); } else { return FilePath(dirEnd + 1); } } else if (extStart) { return FilePath(SString(fileName.c_str(), 0, extStart - fileName.c_str()).c_str()); } else { return fileName.c_str(); }}FilePath FilePath::Extension() const{ const char *dirEnd = strrchr(fileName.c_str(), pathSepChar); const char *extStart = strrchr(fileName.c_str(), '.'); if (extStart > dirEnd) return extStart + 1; else return "";}FilePath FilePath::Directory() const{ if (IsRoot()) { return FilePath(fileName.c_str()); } else { const char *dirEnd = strrchr(fileName.c_str(), pathSepChar); if (dirEnd) { int lenDirectory = dirEnd - fileName.c_str(); if (lenDirectory < RootLength()) { lenDirectory = RootLength(); } return FilePath(fileName.substr(0, lenDirectory).c_str()); } else { return FilePath(); } }}static char *split(char *&s,char c){ char *t = s; if(s && (s = strchr(s,c)) != NULL) * s++ = '\0'; return t;}FilePath FilePath::NormalizePath() const{ char *path = new char[fileName.length() + 1]; strcpy(path,AsInternal());#ifdef WIN32 // Convert unix path separators to Windows for (char *cp = path; *cp; cp++) { if (*cp == '/') *cp = pathSepChar; }#endif char *absPath = new char[fileName.length() + 1]; char *cur = absPath; *cur = '\0'; char *tmp = path; if(*tmp == pathSepChar){ *cur++ = pathSepChar; *cur = '\0'; tmp++; } char *part; while((part = split(tmp,pathSepChar)) != NULL){ char *last; if(strcmp(part,".") == 0) ; else if(strcmp(part,"..") == 0 && (last == strrchr(absPath,pathSepChar)) != NULL){ if(last > absPath) cur = last; else cur = last + 1; *cur = '\0'; }else{ if(cur > absPath && *(cur - 1) != pathSepChar) *cur++ = pathSepChar; strcpy(cur,part); cur += strlen(part); } } FilePath ret(absPath); delete []path; delete []absPath; return ret;}/** * Take a filename or relative path and put it at the end of the current path. * If the path is absolute, return the same path. */FilePath FilePath::AbsolutePath() const{#ifdef WIN32 // The runtime libraries for GCC and Visual C++ give different results for _fullpath // so use the OS. char absPath[2000]; absPath[0] = '\0'; LPTSTR fileBit = 0; ::GetFullPathNameA(AsFileSystem(), sizeof(absPath), absPath, &fileBit); return FilePath(absPath);#else if (IsAbsolute()) { return NormalizePath(); } else { return FilePath(GetWorkingDirectory(), *this).NormalizePath(); }#endif}// Only used on Windows to fix the case of file namesFilePath FilePath::GetWorkingDirectory(){ char dir[MAX_PATH + 1]; getcwd(dir, MAX_PATH); dir[MAX_PATH] = '\0'; // In Windows, getcwd returns a trailing backslash // when the CWD is at the root of a disk, so remove it size_t endOfPath = strlen(dir) - 1; if (dir[endOfPath] == pathSepChar) { dir[endOfPath] = '\0'; } return FilePath(dir);}void FilePath::FixCase(){}void FilePath::List(FilePathSet &directories, FilePathSet &files){#ifdef WIN32 FilePath wildCard(*this, "*.*"); bool complete = false; WIN32_FIND_DATA findFileData; HANDLE hFind = ::FindFirstFile(wildCard.AsFileSystem(), &findFileData); if (hFind != INVALID_HANDLE_VALUE) { while (!complete) { if ((strcmp(findFileData.cFileName, ".") != 0) && (strcmp(findFileData.cFileName, "..") != 0)) { if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { directories.Append(FilePath(AsInternal(), findFileData.cFileName)); } else { files.Append(FilePath(AsInternal(), findFileData.cFileName)); } } if (!::FindNextFile(hFind, &findFileData)) { complete = true; } } ::FindClose(hFind); }#else errno = 0; DIR *dp = opendir(AsInternal()); if (dp == NULL) { //~ fprintf(stderr, "%s: cannot open for reading: %s\n", AsInternal(), strerror(errno)); return; } struct dirent *ent; while ((ent = readdir(dp)) != NULL) { if ((strcmp(ent->d_name, ".") != 0) && (strcmp(ent->d_name, "..") != 0)) { FilePath pathFull(AsInternal(), ent->d_name); if (pathFull.IsDirectory()) { directories.Append(pathFull); } else { files.Append(pathFull); } } } if (errno == 0) { closedir(dp); }#endif}FILE *FilePath::Open(const char *mode) const{ if(IsSet()){ return fopen(fileName.c_str(),mode); }else{ return NULL; }}void FilePath::Remove() const{ unlink(AsFileSystem());}#ifndef R_OK// Neither Borland nor Microsoft define the constants used to call access#define R_OK 4#endiftime_t FilePath::ModifiedTime() const{ if (IsUntitled()) return 0; if (access(AsFileSystem(), R_OK) == -1) return 0; struct stat statusFile; if (stat(AsFileSystem(), &statusFile) != -1) return statusFile.st_mtime; else return 0;}int FilePath::GetFileLength() const{ int size = -1; if(IsSet()){ FILE *fp = Open(fileRead); if(fp){ fseek(fp,0,SEEK_END); size = ftell(fp); fseek(fp,0,SEEK_SET); fclose(fp); } } return size;}bool FilePath::Exists() const{ bool ret = false; if (IsSet()) { FILE *fp = Open(fileRead); if (fp) { ret = true; fclose(fp); } } return ret;}bool FilePath::IsDirectory() const{ struct stat statusFile; if (stat(AsFileSystem(), &statusFile) != -1)#ifdef WIN32 return statusFile.st_mode & _S_IFDIR;#else return statusFile.st_mode & S_IFDIR;#endif else return false;}bool FilePath::Matches(const char *pattern) const{ SString pat(pattern); pat.substitute(' ', '\0'); SString nameCopy(Name().fileName); nameCopy.lowercase(); size_t start = 0; while (start < pat.length()) { const char *patElement = pat.c_str() + start; if (patElement[0] == '*') { if (nameCopy.endswith(patElement + 1)) { return true; } } else { if (nameCopy == SString(patElement).lowercase()) { return true; } } start += strlen(patElement) + 1; } return false;}#ifdef WIN32/** * Makes a long path from a given, possibly short path/file. * * The short path/file must exist, and if it is a file it must be fully specified * otherwise the function fails. * * sizeof @a longPath buffer must be a least _MAX_PATH * @returns true on success, and the long path in @a longPath buffer, * false on failure, and copies the @a shortPath arg to the @a longPath buffer. */bool MakeLongPath(const char* shortPath, char* longPath){ // when we have pfnGetLong, we assume it never changes as kernel32 is always loaded static DWORD (STDAPICALLTYPE* pfnGetLong)(const char* lpszShortPath, char* lpszLongPath, DWORD cchBuffer) = NULL; static bool kernelTried = FALSE; bool ok = FALSE; if (!kernelTried) { HMODULE hModule; kernelTried = true; hModule = ::GetModuleHandleA("KERNEL32"); //assert(hModule != NULL); // must not call FreeLibrary on such handle // attempt to get GetLongPathName (implemented in Win98/2000 only!) (FARPROC&)pfnGetLong = ::GetProcAddress(hModule, "GetLongPathNameA"); } // the kernel GetLongPathName proc is faster and (hopefully) more reliable if (pfnGetLong != NULL) { // call kernel proc ok = (pfnGetLong)(shortPath, longPath, _MAX_PATH) != 0; } else { char short_path[_MAX_PATH]; // copy, so we can modify it char* tok; *longPath = '\0'; lstrcpyn(short_path, shortPath, _MAX_PATH); for (;;) { tok = strtok(short_path, "\\"); if (tok == NULL) break; if ((strlen(shortPath) > 3) && (shortPath[0] == '\\') && (shortPath[1] == '\\')) { // UNC, skip first seps strcat(longPath, "\\\\"); strcat(longPath, tok); strcat(longPath, "\\"); tok = strtok(NULL, "\\"); if (tok == NULL) break; } strcat(longPath, tok); bool isDir = false; for (;;) { WIN32_FIND_DATA fd; HANDLE hfind; char* tokend; tok = strtok(NULL, "\\"); if (tok == NULL) break; strcat(longPath, "\\"); tokend = longPath + strlen(longPath); // temporary add short component strcpy(tokend, tok); hfind = ::FindFirstFile(longPath, &fd); if (hfind == INVALID_HANDLE_VALUE) break; isDir = (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; // finally add long component we got strcpy(tokend, fd.cFileName); ::FindClose(hfind); } ok = tok == NULL; if (ok && isDir) strcat(longPath, "\\"); break; } } if (!ok) { lstrcpyn(longPath, shortPath, _MAX_PATH); } return ok;}#endifvoid FilePath::FixName(){#ifdef WIN32 // Only used on Windows to use long file names and fix the case of file names char longPath[_MAX_PATH]; // first try MakeLongPath which corrects the path and the case of filename too if (MakeLongPath(AsFileSystem(), longPath)) { Set(longPath); } else { // On Windows file comparison is done case insensitively so the user can // enter scite.cxx and still open this file, SciTE.cxx. To ensure that the file // is saved with correct capitalisation FindFirstFile is used to find out the // real name of the file. WIN32_FIND_DATA FindFileData; HANDLE hFind = ::FindFirstFile(AsFileSystem(), &FindFileData); FilePath dir = Directory(); if (hFind != INVALID_HANDLE_VALUE) { // FindFirstFile found the file Set(dir, FindFileData.cFileName); ::FindClose(hFind); } }#endif}FilePathSet &FilePathSet::operator=(const FilePathSet &){ // Private so won't be called. return *this;}FilePathSet::FilePathSet(int size_){ size = size_; body = new FilePath[size]; lengthBody = 0;}FilePathSet::FilePathSet(const FilePathSet &other){ size = other.size; lengthBody = other.lengthBody; body = new FilePath[size]; for (size_t i = 0; i < lengthBody; i++) { body[i] = other.body[i]; }}FilePathSet::~FilePathSet(){ delete []body; body = NULL; size = 0; lengthBody = 0;}FilePath FilePathSet::At(size_t pos) const{ return body[pos];}void FilePathSet::Append(FilePath fp){ if (lengthBody >= size) { size *= 2; FilePath *bodyNew = new FilePath[size]; for (size_t i = 0; i < lengthBody; i++) { bodyNew[i] = body[i]; } delete []body; body = bodyNew; } body[lengthBody++] = fp;}size_t FilePathSet::Length() const{ return lengthBody;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -