#include #include "Functions4U.h" #ifdef PLATFORM_WIN32 // || defined (PLATFORM_WIN64) #define Ptr Ptr_ #define byte byte_ #ifndef win32_CY_ #define win32_CY_ long #endif #define CY win32_CY_ #include #include #include #undef Ptr #undef byte #undef CY #endif #define TFILE #include /* Hi Koldo, I checked the functions in Functions4U. Here are some notes about trashing: * On older systems, the trash folder was $HOME/.Trash * Your implementation of disregards the folder $HOME/.local/share/trash/info. You should create there a .trashinfo file when moving something in trash and delete it when deleting corresponding file permanently. * If you delete something on different partition than $HOME, you should also check if .Trash-XXXX exists in root of that partition (XXXX is id of user who deleted the files in it). .local/share/Trash/files .local/share/Trash/info A file every time a file is removed with KK.trashinfo [Trash Info] Path=/home/pubuntu/KK DeletionDate=2010-05-19T18:00:52 You might also be interested in following: * Official trash specification from freedesktop.org * Project implementing command line access to trash (unfortunately in python) according to the specification mentioned above Hope this might help Smile It definitely learned me a lot of new things Very Happy Best regards, Honza */ namespace Upp { ///////////////////////////////////////////////////////////////////// // LaunchFile #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) bool LaunchFileCreateProcess(const char *file, const char *, const char *directory) { STARTUPINFOW startInfo; PROCESS_INFORMATION procInfo; ZeroMemory(&startInfo, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); ZeroMemory(&procInfo, sizeof(procInfo)); WString wexec; wexec = Format("\"%s\" \"%s\"", GetExtExecutable(GetFileExt(file)), file).ToWString(); WStringBuffer wsbexec(wexec); if (!CreateProcessW(NULL, wsbexec, NULL, NULL, FALSE, 0, NULL, ToSystemCharsetW(directory), &startInfo, &procInfo)) return false; WaitForSingleObject(procInfo.hProcess, 0); CloseHandle(procInfo.hProcess); CloseHandle(procInfo.hThread); return true; } bool LaunchFileShellExecute(const char *file, const char *params, const char *directory) { uint64 ret = uint64(ShellExecuteW(NULL, L"open", ToSystemCharsetW(file), ToSystemCharsetW(params), ToSystemCharsetW(directory), SW_SHOWNORMAL)); return 32 < ret; } bool LaunchFile(const char *file, const char *params, const char *directory) { String _file = Trim(WinPath(file)); String _params, _directory; if (params) _params = WinPath(params); if (directory) _directory = WinPath(directory); if (!LaunchFileShellExecute(_file, _params, _directory)) // First try return LaunchFileCreateProcess(_file, _params, _directory); // Second try return true; } #endif #ifdef PLATFORM_POSIX String GetDesktopManagerNew() { if(GetEnv("GNOME_DESKTOP_SESSION_ID").GetCount() || GetEnv("GNOME_KEYRING_SOCKET").GetCount()) return "gnome"; else if(GetEnv("KDE_FULL_SESSION").GetCount() || GetEnv("KDEDIR").GetCount() || GetEnv("KDE_MULTIHEAD").GetCount()) return "kde"; else { StringParse desktopStr; if (Sys("xprop -root _DT_SAVE_MODE").Find("xfce") >= 0) return "xfce"; else if ((desktopStr = Sys("xprop -root")).Find("ENLIGHTENMENT") >= 0) return "enlightenment"; else return GetEnv("DESKTOP_SESSION"); } } bool LaunchFile(const char *_file, const char *_params, const char *) { String file = UnixPath(_file); String params = UnixPath(_params); int ret; if (GetDesktopManagerNew() == "gnome") ret = system("gnome-open \"" + file + "\" " + params); else if (GetDesktopManagerNew() == "kde") ret = system("kfmclient exec \"" + file + "\" " + params + " &"); else if (GetDesktopManagerNew() == "enlightenment") { String mime = GetExtExecutable(GetFileExt(file)); String program = mime.Left(mime.Find(".")); // Left side of mime executable is the program to run ret = system(program + " \"" + file + "\" " + params + " &"); } else ret = system("xdg-open \"" + String(file) + "\""); return (ret >= 0); } #endif ///////////////////////////////////////////////////////////////////// // General utilities bool FileCat(const char *file, const char *appendFile) { if (!FileExists(file)) return FileCopy(appendFile, file); FileAppend f(file); if(!f.IsOpen()) return false; FileIn fi(appendFile); if(!fi.IsOpen()) return false; CopyStream(f, fi, fi.GetLeft()); fi.Close(); f.Close(); if(f.IsError()) return false; return true; } bool FileStrAppend(const char *file, const char *str) { FileAppend f(file); if(!f.IsOpen()) return false; f << str; f.Close(); if(f.IsError()) return false; return true; } bool AppendFile(const char *file, const char *str) {return FileStrAppend(file, str);} String FormatLong(long a) { return Sprintf("%ld", a); } String Replace(String str, String find, String replace) { String ret; int lenStr = str.GetCount(); int lenFind = find.GetCount(); int i = 0, j; while ((j = str.Find(find, i)) >= i) { ret += str.Mid(i, j-i) + replace; i = j + lenFind; if (i >= lenStr) break; } ret += str.Mid(i); return ret; } String Replace(String str, char find, char replace) { StringBuffer ret(str); for (int i = 0; i < ret.GetCount(); ++i) { if (ret[i] == find) ret[i] = replace; } return ret; } // Rename file or folder bool FileMoveX(const char *oldpath, const char *newpath, EXT_FILE_FLAGS flags) { bool usr, grp, oth; if (flags & DELETE_READ_ONLY) { if (IsReadOnly(oldpath, usr, grp, oth)) SetReadOnly(oldpath, false, false, false); } bool ret = FileMove(oldpath, newpath); if (flags & DELETE_READ_ONLY) SetReadOnly(newpath, usr, grp, oth); return ret; } bool FileDeleteX(const char *path, EXT_FILE_FLAGS flags) { if (flags & USE_TRASH_BIN) return FileToTrashBin(path); else { if (flags & DELETE_READ_ONLY) SetReadOnly(path, false, false, false); return FileDelete(path); } } bool FolderDeleteX(const char *path, EXT_FILE_FLAGS flags) { if (flags & USE_TRASH_BIN) return FileToTrashBin(path); else { if (flags & DELETE_READ_ONLY) SetReadOnly(path, false, false, false); return DirectoryDelete(path); } } bool DirectoryExistsX_Each(const char *name) { #if defined(PLATFORM_WIN32) if(name[0] && name[1] == ':' && name[2] == '\\' && name[3] == 0 && GetDriveType(name) != DRIVE_NO_ROOT_DIR) return true; DWORD res = GetFileAttributes(ToSystemCharset(name)); if (!(res & FILE_ATTRIBUTE_DIRECTORY)) return false; if (res != INVALID_FILE_ATTRIBUTES) return true; if (!(name[0] && name[1] == ':')) return false; if (!(ERROR_PATH_NOT_FOUND == GetLastError())) return false; String localName = String(name, 2); char remoteName[256]; DWORD lenRemoteName = sizeof(remoteName); res = WNetGetConnection(localName, remoteName, &lenRemoteName); if (res != ERROR_CONNECTION_UNAVAIL) return false; NETRESOURCE nr; memset(&nr, 0, sizeof(NETRESOURCE)); nr.dwType = RESOURCETYPE_DISK; nr.lpLocalName = const_cast(localName.Begin()); nr.lpRemoteName = remoteName; nr.lpProvider = NULL; DWORD dwFlags = CONNECT_UPDATE_PROFILE; res = WNetAddConnection2(&nr, NULL, NULL, dwFlags); if (res != NO_ERROR) return false; res = GetFileAttributes(ToSystemCharset(name)); return (res != INVALID_FILE_ATTRIBUTES && (res & FILE_ATTRIBUTE_DIRECTORY)); #else FindFile ff(name); return ff && ff.IsDirectory(); #endif } bool DirectoryExistsX(const char *path, EXT_FILE_FLAGS flags) { String spath = path; if (spath.EndsWith(DIR_SEPS)) spath = spath.Left(spath.GetCount() - 1); if (!(flags & BROWSE_LINKS)) return DirectoryExistsX_Each(spath); if (DirectoryExistsX_Each(spath)) return true; if (!IsSymLink(spath)) return false; String filePath; filePath = GetSymLinkPath(spath); if (filePath.IsEmpty()) return false; return DirectoryExistsX_Each(filePath); } bool IsFile(const char *fileName) { FindFile ff; if(ff.Search(fileName) && ff.IsFile()) return true; return false; } bool IsFolder(const char *fileName) { FindFile ff; if(ff.Search(fileName) && ff.IsFolder()) return true; return false; } bool GetRelativePath(String from, String path, String& ret, bool normalize) { if (normalize) { String creplace = DIR_SEP == '\\' ? "/" : "\\"; from.Replace(creplace, DIR_SEPS); path.Replace(creplace, DIR_SEPS); if (!PLATFORM_PATH_HAS_CASE) { from = ToLower(from); path = ToLower(path); } } ret.Clear(); int pos_from = 0, pos_path = 0; bool first = true; while (!IsNull(pos_from)) { String f_from = Tokenize2(from, DIR_SEPS, pos_from); String f_path = Tokenize2(path, DIR_SEPS, pos_path); if (f_from != f_path) { if (first) return false; ret << f_path; String fileName = path.Mid(pos_path); if (!fileName.IsEmpty()) ret << DIR_SEPS << fileName; while (!IsNull(pos_from)) { ret.Insert(0, String("..") + DIR_SEPS); Tokenize2(from, DIR_SEPS, pos_from); } ret.Insert(0, String("..") + DIR_SEPS); return true; } first = false; } ret = path.Mid(pos_path); return true; } bool SetReadOnly(const char *path, bool readOnly) { return SetReadOnly(path, readOnly, readOnly, readOnly); } bool SetReadOnly(const char *path, bool usr, bool, bool) { #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) DWORD attr = GetFileAttributesW(ToSystemCharsetW(path)); if (attr == INVALID_FILE_ATTRIBUTES) return false; DWORD newattr; if (usr) newattr = attr | FILE_ATTRIBUTE_READONLY; else newattr = attr & ~FILE_ATTRIBUTE_READONLY; if (attr != newattr) return SetFileAttributesW(ToSystemCharsetW(path), newattr); else return true; #else struct stat buffer; //int status; if(0 != stat(ToSystemCharset(path), &buffer)) return false; mode_t m = buffer.st_mode; mode_t newmode = (m & S_IRUSR) | (m & S_IRGRP) | (m & S_IROTH); if (newmode != buffer.st_mode) return 0 == chmod(ToSystemCharset(path), newmode); else return true; #endif } bool IsReadOnly(const char *path, bool &usr, bool &grp, bool &oth) { #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) DWORD attr = GetFileAttributesW(ToSystemCharsetW(path)); if (attr == INVALID_FILE_ATTRIBUTES) return false; usr = grp = oth = attr & FILE_ATTRIBUTE_READONLY; return true; #else struct stat buffer; if(0 != stat(ToSystemCharset(path), &buffer)) return false; usr = buffer.st_mode & S_IRUSR; grp = buffer.st_mode & S_IRGRP; oth = buffer.st_mode & S_IROTH; return true; #endif } #ifdef PLATFORM_POSIX int GetUid() { String proc = LoadFile_Safe("/etc/passwd"); int pos = proc.Find(GetUserName()); if (pos < 0) return -1; pos = proc.Find(':', pos); if (pos < 0) return -1; pos = proc.Find(':', pos+1); if (pos < 0) return -1; int posend = proc.Find(':', pos+1); if (posend < 0) return -1; return ScanInt(proc.Mid(pos+1, posend-pos-1)); } String GetMountDirectory(const String &path) { Vector drives = GetDriveList(); for (int i = 0; i < drives.GetCount(); ++i) { if (path.Find(drives[i]) == 0) return drives[i]; } String localPath = AppendFileName(GetCurrentDirectory(), path); if (!FileExists(localPath) && !DirectoryExists(localPath)) return ""; for (int i = 0; i < drives.GetCount(); ++i) { if (localPath.Find(drives[i]) == 0) return drives[i]; } return ""; } String GetTrashBinDirectory() { String ret = GetEnv("XDG_DATA_HOME"); if (ret.IsEmpty()) ret = AppendFileName(GetHomeDirectory(), ".local/share/Trash"); else ret = AppendFileName(ret, "Trash"); return ret; } bool FileToTrashBin(const char *path) { String newPath = AppendFileName(GetTrashBinDirectory(), GetFileName(path)); return FileMove(path, newPath); } int64 TrashBinGetCount() { int64 ret = 0; FindFile ff; if(ff.Search(AppendFileName(GetTrashBinDirectory(), "*"))) { do { String name = ff.GetName(); if (name != "." && name != "..") ret++; } while(ff.Next()); } return ret; } bool TrashBinClear() { FindFile ff; String trashBinDirectory = GetTrashBinDirectory(); if(ff.Search(AppendFileName(trashBinDirectory, "*"))) { do { String name = ff.GetName(); if (name != "." && name != "..") { String path = AppendFileName(trashBinDirectory, name); if (ff.IsFile()) FileDelete(path); else if (ff.IsDirectory()) DeleteFolderDeep(path); } } while(ff.Next()); } return true; } #endif #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) bool DirectoryMove(const char *dir, const char *newPlace) { if (strcmp(dir, newPlace) == 0) return true; WString wDir(dir), wNewPlace(newPlace); wDir.Cat() << L'\0'; wNewPlace.Cat() << L'\0'; SHFILEOPSTRUCTW fileOp = {}; fileOp.hwnd = NULL; fileOp.wFunc = FO_MOVE; fileOp.pFrom = ~wDir; fileOp.pTo = ~wNewPlace; fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT; int ret = SHFileOperationW(&fileOp); return ret == 0; } bool FileToTrashBin(const char *path) { if (!FileExists(path) && !DirectoryExists(path)) return false; WString wpath(path); wpath.Cat() << L'\0'; SHFILEOPSTRUCTW fileOp = {}; fileOp.hwnd = NULL; fileOp.wFunc = FO_DELETE; fileOp.pFrom = ~wpath; fileOp.pTo = NULL; fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT; int ret = SHFileOperationW(&fileOp); return ret == 0; } int64 TrashBinGetCount() { SHQUERYRBINFO shqbi; shqbi.cbSize = sizeof(SHQUERYRBINFO); if (S_OK != SHQueryRecycleBin(0, &shqbi)) return -1; return shqbi.i64NumItems; } bool TrashBinClear() { if (S_OK != SHEmptyRecycleBin(0, 0, SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI | SHERB_NOSOUND)) return false; return true; } #endif #include #include #include String LoadFile_Safe(const String fileName) { #ifdef PLATFORM_POSIX int fid = open(fileName, O_RDONLY); #else int fid = _wopen(fileName.ToWString(), O_RDONLY|O_BINARY); #endif if (fid < 0) return String(); const int size = 1024; int nsize; StringBuffer s; char buf[size]; while((nsize = read(fid, buf, size)) == size) s.Cat(buf, size); if (nsize > 1) s.Cat(buf, nsize-1); close(fid); return s; } String LoadFile(const char *fileName, off_t from, size_t len) { #ifdef PLATFORM_POSIX int fid = open(fileName, O_RDONLY); #else int fid = _wopen(String(fileName).ToWString(), O_RDONLY|O_BINARY); #endif if (fid < 0) return String(); if (0 > lseek(fid, from, SEEK_SET)) return String(); size_t size = 1024; if (len != 0 && size > len) size = len; size_t nsize; StringBuffer s; Buffer buf(size); size_t loaded; for (loaded = 0; (nsize = read(fid, buf, unsigned(size))) == size && (len == 0 || loaded < len); loaded += nsize) { if (len != 0 && loaded + size > len) size = len - loaded; s.Cat(buf, int(size)); } if (nsize > 1 && (len == 0 || loaded < len)) s.Cat(buf, int(nsize-1)); close(fid); return s; } String GetExtExecutable(const String _ext) { String ext = _ext; String exeFile = ""; if (ext[0] != '.') ext = String(".") + ext; #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) String file = AppendFileName(GetHomeDirectory(), String("dummy") + ext); // Required by FindExecutableW SaveFile(file, " "); if (!FileExists(file)) return ""; HINSTANCE ret; WString fileW(file); WCHAR exe[1024]; ret = FindExecutableW(fileW, NULL, exe); if (reinterpret_cast(ret) > 32) exeFile = WString(exe).ToString(); DeleteFile(file); #endif #ifdef PLATFORM_POSIX StringParse mime; //if (LaunchCommand(String("xdg-mime query filetype ") + file, mime) >= 0) // xdg-mime query filetype does not work properly in Enlightenment mime = LoadFile_Safe("/etc/mime.types"); // Search in /etc/mime.types the mime type for the extension if ((mime.GoAfter_Init(String(" ") + ext.Right(ext.GetCount()-1))) || (mime.GoAfter_Init(String("\t") + ext.Right(ext.GetCount()-1)))) { mime.GoBeginLine(); mime = mime.GetText(); exeFile = TrimRight(Sys(String("xdg-mime query default ") + mime)); } #endif return exeFile; } #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) Vector GetDriveList() { char drvStr[26*4+1]; // A, B, C, ... Vector ret; int lenDrvStrs = ::GetLogicalDriveStrings(sizeof(drvStr), drvStr); // To get the error call GetLastError() if (lenDrvStrs == 0) return ret; ret.Add(drvStr); for (int i = 0; i < lenDrvStrs-1; ++i) { if (drvStr[i] == '\0') ret.Add(drvStr + i + 1); } return ret; } #endif #if defined(PLATFORM_POSIX) Vector GetDriveList() { Vector ret; // Search for mountable file systems String mountableFS = "cofs."; StringParse sfileSystems(LoadFile_Safe("/proc/filesystems")); String str; while (true) { str = sfileSystems.GetText(); if (str == "") break; else if (str != "nodev") mountableFS << str << "."; else str = sfileSystems.GetText(); } // Get mounted drives StringParse smounts(LoadFile_Safe("/proc/mounts")); StringParse smountLine(Trim(smounts.GetText("\r\n"))); do { String devPath = smountLine.GetText(); String mountPath = smountLine.GetText(); String fs = smountLine.GetText(); if ((mountableFS.Find(fs) >= 0) && (mountPath.Find("/dev") < 0) && (mountPath.Find("/rofs") < 0) && (mountPath != "/")) // Is mountable ret.Add(mountPath); smountLine = Trim(smounts.GetText("\r\n")); } while (smountLine != ""); ret.Add("/"); // Last but not least return ret; } #endif #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) String GetShellFolder2(int clsid) { wchar path[MAX_PATH]; if(SHGetFolderPathW(NULL, clsid, NULL, //SHGFP_TYPE_CURRENT 0, path) == S_OK) return FromUnicodeBuffer(path); return Null; } String GetShellFolder2(const char *local, const char *users) { String ret = FromSystemCharset(GetWinRegString(local, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", HKEY_CURRENT_USER)); if (ret == "" && *users != '\0') return FromSystemCharset(GetWinRegString(users, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", HKEY_LOCAL_MACHINE)); return ret; } String GetPersonalFolder() {return GetShellFolder2("Personal", 0);} String GetStartupFolder() {return GetShellFolder2(CSIDL_STARTUP);} String GetTempFolder() { String ret; if ((ret = GetEnv("TEMP")) == "") // One or the other one ret = GetEnv("TMP"); return ret; } String GetOsFolder() { char ret[MAX_PATH]; ::GetWindowsDirectory(ret, MAX_PATH); return String(ret); } String GetSystemFolder() { char ret[MAX_PATH]; ::GetSystemDirectory(ret, MAX_PATH); return String(ret); } #ifdef PLATFORM_WIN32 String GetCommonAppDataFolder() { wchar path[MAX_PATH]; if(SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, path) == S_OK) return FromUnicodeBuffer(path); return Null; } #endif bool SetEnv(const char *id, const char *val) { // EnvMap().Put(WString(id), WString(val)); #ifdef PLATFORM_POSIX return setenv(id, val, 1) == 0; #else return _wputenv(WString(id) + "=" + WString(val)) == 0; #endif } #endif #ifdef PLATFORM_POSIX String GetPathXdg2(String xdgConfigHome, String xdgConfigDirs) { String ret; if (FileExists(ret = AppendFileName(xdgConfigHome, "user-dirs.dirs"))) ; else if (FileExists(ret = AppendFileName(xdgConfigDirs, "user-dirs.defaults"))) ; else if (FileExists(ret = AppendFileName(xdgConfigDirs, "user-dirs.dirs"))) ; return ret; } String GetPathDataXdg2(String fileConfig, const char *folder) { StringParse fileData = LoadFile(fileConfig); if (!fileData.GoAfter(folder)) return ""; if (!fileData.GoAfter("=")) return ""; String ret = ""; StringParse path = fileData.GetText(); if(path.GoAfter("$HOME/")) ret = AppendFileName(GetHomeDirectory(), path.Right()); else if (!FileExists(path)) ret = AppendFileName(GetHomeDirectory(), path); return ret; } String GetShellFolder2(const char *local, const char *users) { String xdgConfigHome = GetEnv("XDG_CONFIG_HOME"); if (xdgConfigHome == "") // By default xdgConfigHome = AppendFileName(GetHomeDirectory(), ".config"); String xdgConfigDirs = GetEnv("XDG_CONFIG_DIRS"); if (xdgConfigDirs == "") // By default xdgConfigDirs = "/etc/xdg"; String xdgFileConfigData = GetPathXdg2(xdgConfigHome, xdgConfigDirs); String ret = GetPathDataXdg2(xdgFileConfigData, local); if (ret == "" && *users != '\0') return GetPathDataXdg2(xdgFileConfigData, users); else return ret; } String GetTempFolder() { return GetHomeDirectory(); } String GetOsFolder() { return String("/bin"); } String GetSystemFolder() { return String(""); } String GetPersonalFolder() {return GetShellFolder2("XDG_DOCUMENTS_DIR", "DOCUMENTS");} #endif struct StringNormalCompare__ { int operator()(char a, char b) const { return a - b; } }; int Compare(const String& a, int i0, const String& b, int len) { return IterCompare(a.Begin() + i0, a.Begin() + i0 + len, b.Begin(), b.Begin() + len, StringNormalCompare__()); } int ReverseFind(const String& s, const String& toFind, int from) { ASSERT(from >= 0 && from <= s.GetLength()); int lc = toFind.GetLength(); for (int i = from; i >= 0; --i) { if (Compare(s, i, toFind, lc) == 0) return i; } return -1; } Time StrToTime(const char *s) { Time ret; if (StrToTime(ret, s)) return ret; else return Null; } Date StrToDate(const char *s) { Time ret; if (StrToDate(ret, s)) return ret; else return Null; } void StringToHMS(String durat, int &hour, int &min, double &seconds) { StringParse duration(durat); String s1, s2, s3; s1 = duration.GetText(":"); s2 = duration.GetText(":"); s3 = duration.GetText(); if (s3 != "") { hour = ScanInt(s1); min = ScanInt(s2); seconds = ScanDouble(s3); } else if (s2 != "") { hour = 0; min = ScanInt(s1); seconds = ScanDouble(s2); } else { hour = 0; min = 0; seconds = ScanDouble(s1); } if (IsNull(hour) || IsNull(min) || IsNull(seconds)) { hour = min = Null; seconds = Null; } else if (hour < 0 || min < 0 || seconds < 0) { hour = Neg(hour); min = Neg(min); seconds = Neg(seconds); } } double StringToSeconds(String duration) { int hour, min; double secs; StringToHMS(duration, hour, min, secs); return 3600.*hour + 60.*min + secs; } String formatSeconds(double seconds, int dec, bool fill) { int iseconds = int(seconds); String ret; if (fill) ret = FormatIntDec(iseconds, 2, '0'); else ret = FormatInt(iseconds); double decs = seconds - iseconds; if (decs > 0 && dec > 0) ret << "." << FormatIntDec(static_cast(decs*pow(10, dec)), dec, '0'); return ret; } /* String HMSToString0(int hour, int min, double seconds, bool units, int dec) { String sunits; if (units) { if (hour >= 1) sunits = t_("hours"); else if (min >= 2) sunits = t_("mins"); else if (min == 1) sunits = t_("min"); else if (seconds > 1) sunits = t_("secs"); else sunits = t_("sec"); } String ret; if (hour > 0) ret << hour << ":"; if (min > 0 || hour > 0) ret << (ret.IsEmpty() ? FormatInt(min) : FormatIntDec(min, 2, '0')) << ":"; ret << formatSeconds(seconds, dec, min > 0 || hour > 0); if (units) ret << " " << sunits; return ret; }*/ String HMSToString(int hour, int min, double seconds, int dec, bool units, bool space, bool tp, bool longUnits, bool forcesec) { String ret; bool isneg = hour < 0 || min < 0 || seconds < 0; if (hour > 0) { ret << hour; if (space) ret << " "; if (tp) ret << ":"; if (units) ret << (longUnits ? ((hour > 1) ? t_("hours") : t_("hour")) : t_("h")); } if (min > 0) { if (tp) { String fmt = hour > 0 ? "%02d" : "%d"; ret << Format(fmt, min); } else ret << (ret.IsEmpty() ? "" : " ") << min; if (space) ret << " "; if (tp && forcesec) ret << ":"; if (units) ret << (longUnits ? ((min > 1) ? t_("mins") : t_("min")) : t_("m")); } else if (tp) { if (hour > 0) { ret << "00"; if (forcesec) ret << ":"; } } if (forcesec || (hour == 0 && (seconds > 1 || (seconds > 0 && dec > 0)))) { ret << (ret.IsEmpty() || tp ? "" : " ") << formatSeconds(seconds, dec, tp); if (space) ret << " "; if (units) ret << (longUnits ? ((seconds > 1) ? t_("secs") : t_("sec")) : t_("s")); } if (isneg) ret = "-" + ret; return ret; } String SecondsToString(double seconds, int dec, bool units, bool space, bool tp, bool longUnits, bool forcesec) { int hour, min; hour = static_cast(seconds/3600.); seconds -= hour*3600; min = static_cast(seconds/60.); seconds -= min*60; return HMSToString(hour, min, seconds, dec, units, space, tp, longUnits, forcesec); } String SeasonName(int iseason) { static const char *season[] = {t_("winter"), t_("spring"), t_("summer"), t_("autumn")}; return iseason >= 0 && iseason < 4 ? season[iseason] : ""; } int GetSeason(Date &date) { return int((date.month - 1)/3.); } String BytesToString(uint64 _bytes, bool units) { String ret; uint64 bytes = _bytes; if (bytes >= 1024) { bytes /= 1024; if (bytes >= 1024) { bytes /= 1024; if (bytes >= 1024) { bytes /= 1024; if (bytes >= 1024) { bytes /= 1024; ret = Format("%.1f %s", _bytes/(1024*1024*1024*1024.), units ? "Tb" : ""); } else ret = Format("%.1f %s", _bytes/(1024*1024*1024.), units ? "Gb" : ""); } else ret = Format("%.1f %s", _bytes/(1024*1024.), units ? "Mb" : ""); } else ret = Format("%.1f %s", _bytes/1024., units ? "Kb" : ""); } else ret << _bytes << (units ? "b" : ""); return ret; } String FormatDoubleAdjust(double d, double range) { if (fabs(d) <= 1e-15) d = 0; if (0.001 <= range && range < 0.01) return FormatDouble(d,5); else if (0.01 <= range && range < 0.1) return FormatDouble(d,4); else if (0.1 <= range && range < 1) return FormatDouble(d,3); else if (1 <= range && range < 10) return FormatDouble(d,2); else if (10 <= range && range < 100) return FormatDouble(d,1); else if (100 <= range && range < 100000) return FormatDouble(d,0); else return FormatDoubleExp(d,2); } String RemoveAccent(wchar c) { WString wsret; if (IsAlNum(c) || IsSpace(c)) { wsret.Cat(c); return wsret.ToString(); } //const WString accented = "ÂÃÀÁÇÈÉÊËẼÌÍÎÏÑÒÓÔÕÙÚÛÝàáâãçèéêëẽìíîïñòóôõøùúûýÿ"; const WString accented = "\303\202\303\203\303\200\303\201\303\207\303\210\303\211\303\212\303\213\341\272\274\303\214\303\215\303\216\303\217\303\221\303\222\303\223\303\224\303\225\303\231\303\232\303\233\303\235\303\240\303\241\303\242\303\243\303\247\303\250\303\251\303\252\303\253\341\272\275\303\254\303\255\303\256\303\257\303\261\303\262\303\263\303\264\303\265\303\270\303\271\303\272\303\273\303\275\303\277"; const char *unaccented = "AAAACEEEEEIIIINOOOOUUUYaaaaceeeeeiiiinooooouuuyy"; for (int i = 0; accented[i]; ++i) { if (accented[i] == c) { wsret.Cat(unaccented[i]); return wsret.ToString(); } } //const WString maccented = "ÅåÆæØøþÞßÐðÄäÖöÜü"; const WString maccented = "\303\205\303\245\303\206\303\246\303\230\303\270\303\276\303\236\303\237\303\220\303\260\303\204\303\244\303\226\303\266\303\234\303\274"; const char *unmaccented[] = {"AA", "aa", "AE", "ae", "OE", "oe", "TH", "th", "SS", "ETH", "eth", "AE", "ae", "OE", "oe", "UE", "ue"}; for (int i = 0; maccented[i]; ++i) { if (maccented[i] == c) return unmaccented[i]; } wsret.Cat(c); return wsret.ToString(); } bool IsPunctuation(wchar c) { //const WString punct = "\"’'()[]{}<>:;,‒–—―….,¡!¿?«»-‐‘’“”/\\&@*\\•^©¤฿¢$€ƒ£₦¥₩₪†‡〃#№ºª\%‰‱ ¶′®§℠℗~™|¦="; const WString punct = "\"\342\200\231'()[]{}<>:;,\342\200\222\342\200\223\342\200\224\342\200\225\342\200\246.,\302\241!\302\277?\302\253\302\273-\342\200\220\342\200\230\342\200\231\342\200\234\342\200\235/\\&@*\\\342\200\242^\302\251\302\244\340\270\277\302\242$\342\202\254\306\222\302\243\342\202\246\302\245\342\202\251\342\202\252\342\200\240\342\200\241\343\200\203#\342\204\226\302\272\302\252%\342\200\260\342\200\261 " "\302\266\342\200\262\302\256\302\247\342\204\240\342\204\227~\342\204\242|\302\246="; for (int i = 0; punct[i]; ++i) { if (punct[i] == c) return true; } return false; } String RemoveAccents(String str) { String ret; WString wstr = str.ToWString(); for (int i = 0; i < wstr.GetCount(); ++i) { String schar = RemoveAccent(wstr[i]); if (i == 0 || ((i > 0) && ((IsSpace(wstr[i-1]) || IsPunctuation(wstr[i-1]))))) { if (schar.GetCount() > 1) { if (IsUpper(schar[0]) && IsLower(wstr[1])) schar = String(schar[0], 1) + ToLower(schar.Mid(1)); } } ret += schar; } return ret; } String RemovePunctuation(String str) { String ret; WString wstr = str.ToWString(); for (int i = 0; i < wstr.GetCount(); ++i) { if (!IsPunctuation(wstr[i])) ret += wstr[i]; } return ret; } String FitFileName(const String fileName, int len) { if (fileName.GetCount() <= len) return fileName; Vector path; const char *s = fileName; char c; int pos0 = 0; for (int pos1 = 0; (c = s[pos1]) != '\0'; ++pos1) { #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) if(c == '\\' || c == '/') { #else if(c == '/') { #endif path.Add(fileName.Mid(pos0, pos1-pos0)); pos0 = ++pos1; } } path.Add(fileName.Mid(pos0)); String begin, end; int iBegin = 0; int iEnd = path.GetCount() - 1; if (path[iEnd].GetCount() >= len) return path[iEnd].Left(len); if (path[iEnd].GetCount() >= len-4) return path[iEnd]; len -= 3; // ... for (; iBegin <= iEnd; iBegin++, iEnd--) { if (path[iEnd].GetCount() + 1 > len) break; end = DIR_SEPS + path[iEnd] + end; len -= path[iEnd].GetCount() + 1; if (path[iBegin].GetCount() + 1 > len) break; begin += path[iBegin] + DIR_SEPS; len -= path[iBegin].GetCount() + 1; } return begin + "..." + end; } String Tokenize2(const String &str, const String &token, int &pos) { if (IsNull(pos) || pos >= str.GetCount()) { pos = Null; return Null; } int npos = str.Find(token, pos); /* for (int i = 0; i < token.GetCount(); ++i) { if ((npos = str.Find(token[i], pos)) >= 0) break; }*/ int oldpos = pos; if (npos < 0) { pos = Null; return str.Mid(oldpos); } else { pos = npos + token.GetCount(); return str.Mid(oldpos, npos - oldpos); } } String Tokenize2(const String &str, const String &token) { int dummy = 0; return Tokenize2(str, token, dummy); } Vector Tokenize(const String &str, const String &token, int pos) { Vector ret; Tokenize(str, token, ret, pos); return ret; } void Tokenize(const String &str, const String &token, Vector &ret, int pos) { int _pos = pos; while (true) { String strRet = Tokenize2(str, token, _pos); if (IsNull(_pos)) { if (!IsNull(strRet)) ret << strRet; break; } ret << strRet; } } String GetLine(const String &str, int &pos) { String ret; int npos = str.Find("\n", pos); if (npos == -1) { ret = str.Mid(pos); pos = -1; } else { ret = str.Mid(pos, npos - pos); pos = npos + 1; } return TrimBoth(ret); } Value GetField(const String &str, int &pos, char separator, char decimalSign, bool onlyStrings) { ASSERT(separator != '\"'); String sret; int npos = str.Find(separator, pos); int spos = str.Find('\"', pos); if (spos < 0 || spos > npos) { if (npos < 0) { int lspos = str.Find('\"', spos + 1); if (lspos < 0) sret = str.Mid(max(pos, spos)); else sret = str.Mid(spos + 1, lspos - spos - 1); pos = -1; } else { sret = Trim(str.Mid(pos, npos - pos)); pos = npos + 1; } } else { int lspos = str.Find('\"', spos + 1); if (lspos < 0) { sret = str.Mid(spos); pos = -1; } else { sret = str.Mid(spos + 1, lspos - spos - 1); npos = str.Find(separator, lspos); pos = npos + 1; } } if (onlyStrings) return sret; if (sret.IsEmpty()) return Null; bool hasDecimal = false, hasLetter = false; for (int i = 0; i < sret.GetCount(); ++i) { if (sret[i] == decimalSign) hasDecimal = true; else if (!IsNumber(sret[i])) hasLetter = true; } if (!hasLetter) { if (hasDecimal) { double dbl = ScanDouble(sret, NULL, decimalSign == ','); if (IsNull(dbl)) return sret; else return dbl; } else { int64 it64 = ScanInt64(sret); if (IsNull(it64)) return sret; int it = int(it64); if (it64 != it) return it64; else return it; } } else { Time t = ScanTime(sret); if (IsNull(t)) return sret; else if (t.hour == 0 && t.minute == 0 && t.second == 0) return Date(t); else return t; } } Vector > ReadCSV(const String strFile, char separator, bool bycols, bool removeRepeated, char decimalSign, bool onlyStrings, int fromRow) { Vector > result; if (strFile.IsEmpty()) return result; int posLine = 0; for (int i = 0; i < fromRow; ++i) GetLine(strFile, posLine); String line; int pos = 0; if (bycols) { line = GetLine(strFile, posLine); while (pos >= 0) { Value name = GetField(line, pos, separator, decimalSign, onlyStrings); if (/*pos >= 0 && */!IsNull(name)) { Vector &data = result.Add(); data.Add(name); } } while (posLine >= 0) { pos = 0; line = GetLine(strFile, posLine); if (!line.IsEmpty()) { bool repeated = removeRepeated; int row = result[0].GetCount() - 1; for (int col = 0; col < result.GetCount(); col++) { if (pos >= 0) { Value data = GetField(line, pos, separator, decimalSign, onlyStrings); result[col].Add(data); if (row > 0 && result[col][row] != data) repeated = false; } else result[col].Add(); } if (row > 0 && repeated) { for (int col = 0; col < result.GetCount(); col++) result[col].Remove(row+1); } } else break; } } else { int row = 0; while (posLine >= 0) { pos = 0; line = GetLine(strFile, posLine); bool repeated = removeRepeated; if (!line.IsEmpty()) { Vector &linedata = result.Add(); int col = 0; while (pos >= 0) { Value val = GetField(line, pos, separator, decimalSign, onlyStrings); if (val.IsNull()) linedata << ""; else linedata << val; if (row > 0 && (result[row - 1].GetCount() <= col || result[row - 1][col] != val)) repeated = false; col++; } } else break; if (row > 0 && repeated) result.Remove(row); else row++; } } return result; } Vector > ReadCSVFile(const String fileName, char separator, bool bycols, bool removeRepeated, char decimalSign, bool onlyStrings, int fromRow) { return ReadCSV(LoadFile(fileName), separator, bycols, removeRepeated, decimalSign, onlyStrings, fromRow); } bool ReadCSVFileByLine(const String fileName, Gate&, String &> WhenRow, char separator, char decimalSign, bool onlyStrings, int fromRow) { Vector result; FindFile ff(fileName); if(!ff || !ff.IsFile()) return false; FileIn in(fileName); in.ClearError(); for (int i = 0; i < fromRow; ++i) in.GetLine(); for (int row = 0; true; row++) { String line = in.GetLine(); if (line.IsVoid()) { WhenRow(row, result, line); return true; } int pos = 0; while (pos >= 0) { Value val = GetField(line, pos, separator, decimalSign, onlyStrings); if (val.IsNull()) result << ""; else result << val; } if (!WhenRow(row, result, line)) return false; result.Clear(); } return false; } String ToStringDecimalSign(Value &val, const String &decimalSign) { String ret = val.ToString(); if (val.Is() && decimalSign != ".") ret.Replace(".", decimalSign); return ret; } String WriteCSV(Vector > &data, char separator, bool bycols, char decimalSign) { String ret; String _decimalSign(decimalSign, 1); if (bycols) { int maxr = 0; for (int c = 0; c < data.GetCount(); ++c) maxr = max(maxr, data[c].GetCount()); for (int r = 0; r < maxr; ++r) { if (r > 0) ret << "\n"; for (int c = 0; c < data.GetCount(); ++c) { if (c > 0) ret << separator; if (r >= data[c].GetCount()) continue; String str = ToStringDecimalSign(data[c][r], _decimalSign); if (str.Find(separator) >= 0) ret << '\"' << str << '\"'; else ret << str; } } } else { for (int r = 0; r < data.GetCount(); ++r) { if (r > 0) ret << "\n"; for (int c = 0; c < data[r].GetCount(); ++c) { if (c > 0) ret << separator; String str = ToStringDecimalSign(data[r][c], _decimalSign); if (str.Find(separator) >= 0) ret << '\"' << str << '\"'; else ret << str; } } } return ret; } bool WriteCSVFile(const String fileName, Vector > &data, char separator, bool bycols, char decimalSign) { String str = WriteCSV(data, separator, bycols, decimalSign); return SaveFile(fileName, str); } #ifdef PLATFORM_POSIX String FileRealName(const char *_fileName) { String fileName = GetFullPath(_fileName); FindFile ff(fileName); if (!ff) return String(""); else return fileName; } #endif #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) bool GetRealName_Next(String &real, String file) { bool ret; String old; int from = real.GetCount()+1; int to = file.Find(DIR_SEP, from); if (to >= 0) { old = file.Mid(from, to-from); ret = true; } else { old = file.Mid(from); ret = false; } real += DIR_SEP; FindFile ff(real + old); real += ff.GetName(); return ret; } String FileRealName(const char *_fileName) { String fileName = GetFullPath(_fileName); int len = fileName.GetCount(); if (len == 3) { FindFile ff(fileName + "*"); if (!ff) return String(""); else return fileName; } FindFile ff(fileName); if (!ff) return String(""); String ret; ret.Reserve(len); if (fileName.Left(2) == "\\\\") return String(""); // Not valid for UNC paths ret = ToUpper(fileName.Left(1)) + ":"; while (GetRealName_Next(ret, fileName)) ; return ret; } #endif #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) #define Ptr Ptr_ #define byte byte_ #define CY win32_CY_ #include #include #include #include #undef Ptr #undef byte #undef CY #endif bool IsSymLink(const char *path) { #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) return GetFileExt(path) == ".lnk"; #else struct stat stf; lstat(path, &stf); return S_ISLNK(stf.st_mode); #endif } String GetNextFolder(const String &folder, const String &lastFolder) { int pos = lastFolder.Find(DIR_SEP, folder.GetCount()+1); if (pos >= 0) return lastFolder.Left(pos); else return lastFolder; } bool IsRootFolder(const char *folderName) { if (!folderName) return false; if (folderName[0] == '\0') return false; #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) if (strlen(folderName) == 3 && folderName[1] == ':' && folderName[2] == DIR_SEP) #else if (strlen(folderName) == 1 && folderName[0] == DIR_SEP) #endif return true; return false; } String GetUpperFolder(const String &folderName) { if (IsRootFolder(folderName)) return folderName; int len = folderName.GetCount(); if (len == 0) return String(); if (folderName[len-1] == DIR_SEP) len--; int pos = folderName.ReverseFind(DIR_SEP, len-1); #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) if (pos == 2) #else if (pos == 0) #endif pos++; return folderName.Left(pos); } /* bool CreateFolderDeep(const char *dir) { if (RealizePath(dir)) return DirectoryCreate(dir); else return false; }*/ bool DeleteDeepWildcardsX(const char *pathwc, bool filefolder, EXT_FILE_FLAGS flags, bool deep) { return DeleteDeepWildcardsX(GetFileFolder(pathwc), GetFileName(pathwc), filefolder, flags, deep); } bool DeleteDeepWildcardsX(const char *path, const char *namewc, bool filefolder, EXT_FILE_FLAGS flags, bool deep) { FindFile ff(AppendFileName(path, "*.*")); while(ff) { String name = ff.GetName(); String full = AppendFileName(path, name); if (PatternMatch(namewc, name)) { if (ff.IsFolder() && !filefolder) { if (!DeleteFolderDeepX(full, flags)) return false; } else if (ff.IsFile() && filefolder) { if (!FileDeleteX(full, flags)) return false; } } else if(deep && ff.IsFolder()) { if (!DeleteDeepWildcardsX(full, namewc, filefolder, flags)) return false; } ff.Next(); } return true; } bool DeleteFolderDeepWildcardsX(const char *path, EXT_FILE_FLAGS flags) { return DeleteDeepWildcardsX(path, false, flags, true); } bool DeleteFolderDeepWildcardsX(const char *path, const char *name, EXT_FILE_FLAGS flags) { return DeleteDeepWildcardsX(path, name, false, flags, true); } bool DeleteFileDeepWildcardsX(const char *path, EXT_FILE_FLAGS flags) { return DeleteDeepWildcardsX(path, true, flags, true); } bool DeleteFileWildcardsX(const char *path, EXT_FILE_FLAGS flags) { return DeleteDeepWildcardsX(path, true, flags, false); } bool DeleteFolderDeepX_Folder(const char *dir, EXT_FILE_FLAGS flags) { FindFile ff(AppendFileName(dir, "*.*")); while(ff) { String name = ff.GetName(); String p = AppendFileName(dir, name); if(ff.IsFile()) FileDeleteX(p, flags); else if(ff.IsFolder()) DeleteFolderDeepX_Folder(p, flags); ff.Next(); } return FolderDeleteX(dir, flags); } bool DeleteFolderDeepX(const char *path, EXT_FILE_FLAGS flags) { if (flags & USE_TRASH_BIN) return FileToTrashBin(path); return DeleteFolderDeepX_Folder(path, flags); } bool RenameDeepWildcardsX(const char *path, const char *namewc, const char *newname, bool forfile, bool forfolder, EXT_FILE_FLAGS flags) { FindFile ff(AppendFileName(path, "*.*")); while(ff) { String name = ff.GetName(); String full = AppendFileName(path, name); if(ff.IsFolder()) { if (!RenameDeepWildcardsX(full, namewc, newname, forfile, forfolder, flags)) return false; } if (PatternMatch(namewc, name)) { if ((ff.IsFolder() && forfolder) || (ff.IsFile() && forfile)) { if (!FileMoveX(full, AppendFileName(path, newname), flags)) return false; } } ff.Next(); } return true; } void DirectoryCopy_Each(const char *dir, const char *newPlace, String relPath, bool replaceOnlyNew, String filesToExclude, String &errorList) { String dirPath = AppendFileName(dir, relPath); String newPath = AppendFileName(newPlace, relPath); LOG(dirPath); LOG(newPath); LOG (AppendFileName(dirPath, "*.*")); FindFile ff(AppendFileName(dirPath, "*.*")); while(ff) { String name = ff.GetName(); String newFullPath = AppendFileName(newPath, name); if(ff.IsFile()) { bool copy = !replaceOnlyNew; if (replaceOnlyNew) { Time newPathTime = FileGetTime(newFullPath); if (IsNull(newPathTime) || (newPathTime < Time(ff.GetLastWriteTime()))) copy = true; } if (copy) { if (!PatternMatchMulti(filesToExclude, name)) { if (!FileCopy(ff.GetPath(), newFullPath)) errorList << "\n" << Format(t_("Impossible to copy '%s' to '%s': %s"), ff.GetPath(), newFullPath, GetLastErrorMessage()); } } } else if (ff.IsFolder()) { if (!DirectoryExists(newFullPath)) { if (!DirectoryCreate(newFullPath)) errorList << "\n" << Format(t_("Impossible to create directory '%s': %s"), newFullPath, GetLastErrorMessage()); } DirectoryCopy_Each(dir, newPlace, AppendFileName(relPath, name), replaceOnlyNew, filesToExclude, errorList); } ff.Next(); } } void DirectoryCopyX(const char *dir, const char *newPlace, bool replaceOnlyNew, String filesToExclude, String &errorList) { if (!DirectoryExists(dir)) errorList << "\n" << Format(t_("Directory '%s' does not exist"), dir); else DirectoryCopy_Each(dir, newPlace, "", replaceOnlyNew, filesToExclude, errorList); } bool FolderIsEmpty(const char *path) { FindFile ff(AppendFileName(path, "*.*")); while(ff) { if(ff.IsFile() || ff.IsFolder()) return false; ff.Next(); } return true; } #if defined(__MINGW32__) #define _SH_DENYNO 0x40 #endif int FileCompare(const char *path1, const char *path2) { int fp1; #ifdef PLATFORM_POSIX fp1 = open(ToSystemCharset(path1), O_RDONLY, S_IWRITE|S_IREAD); #else fp1 = _wsopen(ToSystemCharsetW(path1), O_RDONLY|O_BINARY, _SH_DENYNO, _S_IREAD|_S_IWRITE); #endif if (fp1 == -1) return -2; int fp2; #ifdef PLATFORM_POSIX fp2 = open(ToSystemCharset(path2), O_RDONLY, S_IWRITE|S_IREAD); #else fp2 = _wsopen(ToSystemCharsetW(path2), O_RDONLY|O_BINARY, _SH_DENYNO, _S_IREAD|_S_IWRITE); #endif if (fp2 == -1) { close(fp1); return -2; } Buffer c1(8192), c2(8192); int ret = -1; while (true) { int n1 = read(fp1, c1, 8192); int n2 = read(fp2, c2, 8192); if (n1 == -1 || n2 == -1) { ret = -2; break; } if (n1 != n2) break; if (memcmp(c1, c2, n1) != 0) break; if (n1 == 0) { ret = 1; break; } } #ifdef PLATFORM_POSIX if (-1 == close(fp1)) ret = -2; if (-1 == close(fp2)) ret = -2; #else if (-1 == _close(fp1)) ret = -2; if (-1 == _close(fp2)) ret = -2; #endif return ret; } int64 FindStringInFile(const char *file, const String text, int64 pos0) { #ifdef PLATFORM_POSIX FILE *fp = fopen(file, "rb"); #else FILE *fp = _wfopen(String(file).ToWString(), L"rb"); #endif if (fp != NULL) { int64 pos = 0; if (pos0 > 0) { pos = pos0; if (0 == fseek(fp, long(pos0), SEEK_SET)) return -2; } int i = 0, c; for (; (c = fgetc(fp)) != EOF; pos++) { if (c == text[i]) { ++i; if (i == text.GetCount()) return pos - i; } else { if (i != 0) if (0 == fseek(fp, -(i-1), SEEK_CUR)) return -2; i = 0; } } fclose(fp); } else return -2; return -1; } bool MatchPathName(const char *name, const Vector &cond, const Vector &ext) { for (int i = 0; i < cond.GetCount(); ++i) { if(!PatternMatch(cond[i], name)) return false; } for (int i = 0; i < ext.GetCount(); ++i) { if(PatternMatch(ext[i], name)) return false; } return true; } void SearchFile_Each(String dir, const Vector &condFiles, const Vector &condFolders, const Vector &extFiles, const Vector &extFolders, const String text, Vector &files, Vector &errorList) { FindFile ff; if (ff.Search(AppendFileName(dir, "*"))) { do { if(ff.IsFile()) { String name = AppendFileName(dir, ff.GetName()); if (MatchPathName(ff.GetName(), condFiles, extFiles)) { if (text.IsEmpty()) files.Add(name); else { switch(FindStringInFile(name, text)) { case 1: files.Add(name); break; case -1:errorList.Add(AppendFileName(dir, ff.GetName()) + String(": ") + t_("Impossible to open file")); break; } } } } else if(ff.IsDirectory()) { String folder = ff.GetName(); if (folder != "." && folder != "..") { String name = AppendFileName(dir, folder); if (MatchPathName(name, condFolders, extFolders)) SearchFile_Each(name, condFiles, condFolders, extFiles, extFolders, text, files, errorList); } } } while (ff.Next()); } } Vector SearchFile(String dir, const Vector &condFiles, const Vector &condFolders, const Vector &extFiles, const Vector &extFolders, const String text, Vector &errorList) { Vector files; errorList.Clear(); SearchFile_Each(dir, condFiles, condFolders, extFiles, extFolders, text, files, errorList); return files; } Vector SearchFile(String dir, String condFile, String text, Vector &errorList) { Vector condFiles, condFolders, extFiles, extFolders, files; errorList.Clear(); condFiles.Add(condFile); SearchFile_Each(dir, condFiles, condFolders, extFiles, extFolders, text, files, errorList); return files; } Vector SearchFile(String dir, String condFile, String text) { Vector errorList; Vector condFiles, condFolders, extFiles, extFolders, files; condFiles.Add(condFile); SearchFile_Each(dir, condFiles, condFolders, extFiles, extFolders, text, files, errorList); return files; } bool fileDataSortAscending; char fileDataSortBy; FileDataArray::FileDataArray(bool use, int _fileFlags) { Clear(); fileDataSortAscending = true; fileDataSortBy = 'n'; useId = use; fileFlags = _fileFlags; } bool FileDataArray::Init(String , FileDataArray &orig, FileDiffArray &diff) { basePath = orig.basePath; fileCount = orig.fileCount; folderCount = orig.folderCount; fileSize = orig.fileSize; useId = orig.useId; fileList.SetCount(orig.GetCount()); for (int i = 0; i < orig.GetCount(); ++i) fileList[i] = orig[i]; for (int i = 0; i < diff.GetCount(); ++i) { long id; if (diff[i].action != 'n') { id = Find(diff[i].relPath, diff[i].fileName, diff[i].isFolder); if (id < 0) return false; } switch(diff[i].action) { case 'u': fileList[id].id = diff[i].idMaster; fileList[id].length = diff[i].lengthMaster; fileList[id].t = diff[i].tMaster; break; case 'n': fileList.Add(FileData(diff[i].isFolder, diff[i].fileName, diff[i].relPath, diff[i].lengthMaster, diff[i].tMaster, diff[i].idMaster)); if (diff[i].isFolder) folderCount++; else fileCount++; break; case 'd': fileList.Remove(id); if (diff[i].isFolder) folderCount--; else fileCount--; break; break; case 'p': SetLastError(t_("Problem found")); // To Fix //return false; } } return true; } void FileDataArray::Clear() { fileList.Clear(); errorList.Clear(); fileCount = folderCount = 0; fileSize = 0; basePath = ""; } bool FileDataArray::Search(String dir, String condFile, bool recurse, String text) { Clear(); if (fileFlags & BROWSE_LINKS) { if (IsSymLink(dir)) dir = basePath = GetSymLinkPath(dir); else basePath = dir; } else basePath = dir; Search_Each(dir, condFile, recurse, text); return errorList.IsEmpty(); } void FileDataArray::Search_Each(String dir, String condFile, bool recurse, String text) { FindFile ff; if (ff.Search(AppendFileName(dir, condFile))) { do { if(ff.IsFile()) { String p = AppendFileName(dir, ff.GetName()); //if (ff.IsSymLink()) { // p = p; //} /* fileList.Add(FileData(true, ff.GetName(), GetRelativePath(dir), 0, ff.GetLastWriteTime(), 0)); folderCount++; if (recurse) Search_Each(p, condFile, recurse, text); } else */ if (text.IsEmpty()) { uint64 len = ff.GetLength(); fileList.Add(FileData(false, ff.GetName(), GetRelativePath(dir), len, ff.GetLastWriteTime(), (useId && len > 0) ? GetFileId(p) : 0)); fileCount++; fileSize += len; } else { FILE *fp = fopen(p, "r"); if (fp != NULL) { int i = 0, c; while ((c = fgetc(fp)) != EOF) { if (c == text[i]) { ++i; if (i == text.GetCount()) { uint64 len = ff.GetLength(); fileList.Add(FileData(false, ff.GetName(), GetRelativePath(dir), len, ff.GetLastWriteTime(), useId ? GetFileId(p) : 0)); fileCount++; fileSize += len; break; } } else { if (i != 0) fseek(fp, -(i-1), SEEK_CUR); i = 0; } } fclose(fp); } else errorList.Add(AppendFileName(dir, ff.GetName()) + String(": ") + t_("Impossible to open file")); } } } while (ff.Next()); } ff.Search(AppendFileName(dir, "*")); do { String name = ff.GetName(); if(ff.IsDirectory() && name != "." && name != "..") { String p = AppendFileName(dir, name); fileList.Add(FileData(true, name, GetRelativePath(dir), 0, ff.GetLastWriteTime(), 0)); folderCount++; if (recurse) Search_Each(p, condFile, recurse, text); } } while (ff.Next()); } int64 FileDataArray::GetFileId(String fileName) { int64 id = -1; #ifdef PLATFORM_POSIX FILE *fp = fopen(fileName, "rb"); #else FILE *fp = _wfopen(fileName.ToWString(), L"rb"); #endif if (fp != NULL) { int c; long i = 0; while ((c = fgetc(fp)) != EOF) { id += c*i; i++; } fclose(fp); } return id; } void FileDataArray::SortByName(bool ascending) { fileDataSortBy = 'n'; fileDataSortAscending = ascending; Sort(fileList); } void FileDataArray::SortByDate(bool ascending) { fileDataSortBy = 'd'; fileDataSortAscending = ascending; Sort(fileList); } void FileDataArray::SortBySize(bool ascending) { fileDataSortBy = 's'; fileDataSortAscending = ascending; Sort(fileList); } bool operator<(const FileData& a, const FileData& b) { if ((a.isFolder && b.isFolder) || (!a.isFolder && !b.isFolder)) { switch (fileDataSortBy) { case 'n': { bool ais = IsDigit(a.fileName[0]); bool bis = IsDigit(b.fileName[0]); if (ais && bis) return atoi(a.fileName) < atoi(b.fileName); if (ais) return true; if (bis) return false; } #ifdef PLATFORM_POSIX return (a.fileName < b.fileName)&fileDataSortAscending; #else return (ToLower(a.fileName) < ToLower(b.fileName))&fileDataSortAscending; #endif case 'd': return (a.t < b.t)&fileDataSortAscending; default: return (a.length < b.length)&fileDataSortAscending; } } else return a.isFolder; } bool CheckFileData(FileData &data, String &, String &, String &lowrelFileName, String &lowfileName, bool isFolder) { if (data.isFolder == isFolder) { if (ToLower(data.fileName) == lowfileName) { if (ToLower(data.relFilename) == lowrelFileName) return true; } } return false; } int FileDataArray::Find(String &relFileName, String &fileName, bool isFolder) { String lowrelFileName = ToLower(relFileName); String lowfileName = ToLower(fileName); for (int i = 0; i < fileList.GetCount(); ++i) { if (CheckFileData(fileList[i], relFileName, fileName, lowrelFileName, lowfileName, isFolder)) return i; } return -1; } /* int FileDataArray::Find(FileDataArray &data, int id) { return Find(data[id].relFilename, data[id].fileName, data[id].isFolder); } */ int FileDataArray::Find(FileDataArray &data, int id) { String lowrelFileName = ToLower(data[id].relFilename); String lowfileName = ToLower(data[id].fileName); bool isFolder = data[id].isFolder; int num = fileList.GetCount(); if (num == 0) return -1; if (num == 1) { if (CheckFileData(fileList[0], data[id].relFilename, data[id].fileName, lowrelFileName, lowfileName, isFolder)) return 0; else return -1; } int down, up; down = id < num-1 ? id : num-2; up = down + 1; while (down >= 0 || up < num) { if (down >= 0) { if (CheckFileData(fileList[down], data[id].relFilename, data[id].fileName, lowrelFileName, lowfileName, isFolder)) return down; down--; } if (up < num) { if (CheckFileData(fileList[up], data[id].relFilename, data[id].fileName, lowrelFileName, lowfileName, isFolder)) return up; up++; } } return -1; } String FileDataArray::GetFileText() { String ret; for (int i = 0; i < fileList.GetCount(); ++i) { ret << fileList[i].relFilename << "; "; ret << fileList[i].fileName << "; "; ret << fileList[i].isFolder << "; "; ret << fileList[i].length << "; "; ret << fileList[i].t << "; "; ret << fileList[i].id << "; "; ret << "\n"; } return ret; } bool FileDataArray::SaveFile(const char *fileName) { return Upp::SaveFile(fileName, GetFileText()); } bool FileDataArray::AppendFile(const char *fileName) { return Upp::AppendFile(fileName, GetFileText()); } bool FileDataArray::LoadFile(const char *fileName) { Clear(); StringParse in = Upp::LoadFile(fileName); if (in == "") return false; int numData = in.Count("\n"); fileList.SetCount(numData); for (int row = 0; row < numData; ++row) { fileList[row].relFilename = in.GetText(";"); fileList[row].fileName = in.GetText(";"); fileList[row].isFolder = in.GetText(";") == "true" ? true : false; if (fileList[row].isFolder) folderCount++; else fileCount++; fileList[row].length = in.GetUInt64(";"); struct Upp::Time t; StrToTime(t, in.GetText(";")); fileList[row].t = t; fileList[row].id = in.GetUInt64(";"); } return true; } String FileDataArray::GetRelativePath(const String &fullPath) { if (basePath != fullPath.Left(basePath.GetCount())) return ""; return fullPath.Mid(basePath.GetCount()); } int64 GetDirectoryLength(const char *directoryName) { FileDataArray files; files.Search(directoryName, "*.*", true); return files.GetSize(); } int64 GetLength(const char *fileName) { if (FileExists(fileName)) return GetFileLength(fileName); else return GetDirectoryLength(fileName); } FileDiffArray::FileDiffArray() { Clear(); } void FileDiffArray::Clear() { diffList.Clear(); } // True if equal bool FileDiffArray::Compare(FileDataArray &master, FileDataArray &secondary, const String folderFrom, Vector &excepFolders, Vector &excepFiles, int sensSecs) { if (master.GetCount() == 0) { if (secondary.GetCount() == 0) return true; else return false; } else if (secondary.GetCount() == 0) return false; bool equal = true; diffList.Clear(); Vector secReviewed; secReviewed.SetCount(secondary.GetCount(), false); for (int i = 0; i < master.GetCount(); ++i) { bool cont = true; if (master[i].isFolder) { String fullfolder = AppendFileName(AppendFileName(folderFrom, master[i].relFilename), master[i].fileName); for (int iex = 0; iex < excepFolders.GetCount(); ++iex) if (PatternMatch(excepFolders[iex] + "*", fullfolder)) {// Subfolders included cont = false; break; } } else { String fullfolder = AppendFileName(folderFrom, master[i].relFilename); for (int iex = 0; iex < excepFolders.GetCount(); ++iex) if (PatternMatch(excepFolders[iex] + "*", fullfolder)) { cont = false; break; } for (int iex = 0; iex < excepFiles.GetCount(); ++iex) if (PatternMatch(excepFiles[iex], master[i].fileName)) { cont = false; break; } } if (cont) { int idSec = secondary.Find(master, i); if (idSec >= 0) { bool useId = master.UseId() && secondary.UseId(); secReviewed[idSec] = true; if (master[i].isFolder) ; else if ((useId && (master[i].id == secondary[idSec].id)) || (!useId && (master[i].length == secondary[idSec].length) && (abs(master[i].t - secondary[idSec].t) <= sensSecs))) ; else { equal = false; FileDiffData &f = diffList.Add(); //bool isf = f.isFolder = master[i].isFolder; f.relPath = master[i].relFilename; String name = f.fileName = master[i].fileName; f.idMaster = master[i].id; f.idSecondary = secondary[idSec].id; f.tMaster = master[i].t; f.tSecondary = secondary[idSec].t; f.lengthMaster = master[i].length; f.lengthSecondary = secondary[idSec].length; if (master[i].t > secondary[idSec].t) f.action = 'u'; else f.action = 'p'; } } else { equal = false; FileDiffData &f = diffList.Add(); f.isFolder = master[i].isFolder; f.relPath = master[i].relFilename; f.fileName = master[i].fileName; f.idMaster = master[i].id; f.idSecondary = 0; f.tMaster = master[i].t; f.tSecondary = Null; f.lengthMaster = master[i].length; f.lengthSecondary = 0; f.action = 'n'; } } } for (int i = 0; i < secReviewed.GetCount(); ++i) { if (!secReviewed[i]) { bool cont = true; if (secondary[i].isFolder) { String fullfolder = AppendFileName(AppendFileName(folderFrom, secondary[i].relFilename), secondary[i].fileName); for (int iex = 0; iex < excepFolders.GetCount(); ++iex) if (PatternMatch(excepFolders[iex] + "*", fullfolder)) { cont = false; break; } } else { String fullfolder = AppendFileName(folderFrom, secondary[i].relFilename); for (int iex = 0; iex < excepFolders.GetCount(); ++iex) if (PatternMatch(excepFolders[iex] + "*", fullfolder)) { cont = false; break; } for (int iex = 0; iex < excepFiles.GetCount(); ++iex) if (PatternMatch(excepFiles[iex], secondary[i].fileName)) { cont = false; break; } } if (cont) { equal = false; FileDiffData &f = diffList.Add(); f.isFolder = secondary[i].isFolder; f.relPath = secondary[i].relFilename; f.fileName = secondary[i].fileName; f.idMaster = 0; f.idSecondary = secondary[i].id; f.tMaster = Null; f.tSecondary = secondary[i].t; f.lengthMaster = 0; f.lengthSecondary = secondary[i].length; f.action = 'd'; } } } return equal; } #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) String WinLastError() { LPVOID lpMsgBuf; String ret; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ::GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&lpMsgBuf), 0, NULL); ret = static_cast(lpMsgBuf); LocalFree(lpMsgBuf); return ret; } #endif bool FileDiffArray::Apply(String toFolder, String fromFolder, EXT_FILE_FLAGS flags) { for (int i = 0; i < diffList.GetCount(); ++i) { bool ok = true; String dest = AppendFileName(toFolder, AppendFileName(diffList[i].relPath, diffList[i].fileName)); if (diffList[i].action == 'u' || diffList[i].action == 'd') { if (diffList[i].isFolder) { if (DirectoryExists(dest)) { if (!SetReadOnly(dest, false)) ok = false; } } else { if (FileExists(dest)) { if (!SetReadOnly(dest, false)) ok = false; } } } if (!ok) { String strError = t_("Not possible to modify ") + dest; SetLastError(strError); //return false; } switch (diffList[i].action) { case 'n': case 'u': if (diffList[i].isFolder) { if (!DirectoryExists(dest)) { ok = DirectoryCreate(dest); //////////////////////////////////////////////////////////////////////////////////////// } } else { if (FileExists(dest)) { if (!SetReadOnly(dest, false)) ok = false; } if (ok) { ok = FileCopy(AppendFileName(fromFolder, FormatInt(i)), dest); diffList[i].tSecondary = diffList[i].tMaster; } } if (!ok) { String strError = t_("Not possible to create ") + dest; #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) strError += ". " + WinLastError(); #endif SetLastError(strError); //return false; } break; case 'd': if (diffList[i].isFolder) { if (DirectoryExists(dest)) ok = DeleteFolderDeep(dest); // Necessary to add the "X" } else { if (FileExists(dest)) ok = FileDeleteX(dest, flags); } if (!ok) { String strError = t_("Not possible to delete") + String(" ") + dest; #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) strError += ". " + WinLastError(); #endif SetLastError(strError); //return false; } break; case 'p': SetLastError(t_("There was a problem in the copy")); //return false; break; } } return true; } bool FileDiffArray::SaveFile(const char *fileName) { return Upp::SaveFile(fileName, ToString()); } String FileDiffArray::ToString() { String ret; for (int i = 0; i < diffList.GetCount(); ++i) { ret << diffList[i].action << "; "; ret << diffList[i].isFolder << "; "; ret << diffList[i].relPath << "; "; ret << diffList[i].fileName << "; "; ret << diffList[i].idMaster << "; "; ret << diffList[i].idSecondary << "; "; ret << diffList[i].tMaster << "; "; ret << diffList[i].tSecondary << "; "; ret << diffList[i].lengthMaster << "; "; ret << diffList[i].lengthSecondary << "; "; ret << "\n"; } return ret; } bool FileDiffArray::LoadFile(const char *fileName) { Clear(); StringParse in = Upp::LoadFile(fileName); if (in == "") return false; int numData = in.Count("\n"); diffList.SetCount(numData); for (int row = 0; row < numData; ++row) { diffList[row].action = TrimLeft(in.GetText(";"))[0]; diffList[row].isFolder = in.GetText(";") == "true" ? true : false; diffList[row].relPath = in.GetText(";"); diffList[row].fileName = in.GetText(";"); diffList[row].idMaster = in.GetUInt64(";"); diffList[row].idSecondary = in.GetUInt64(";"); struct Upp::Time t; StrToTime(t, in.GetText(";")); diffList[row].tMaster = t; StrToTime(t, in.GetText(";")); diffList[row].tSecondary = t; diffList[row].lengthMaster = in.GetUInt64(";"); diffList[row].lengthSecondary = in.GetUInt64(";"); } return true; } #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) Value GetVARIANT(VARIANT &result) { Value ret; switch(result.vt) { case VT_EMPTY: case VT_NULL: case VT_BLOB: break; case VT_BOOL: ret = result.boolVal;// ? "true" : "false"; break; case VT_I2: ret = result.iVal; break; case VT_I4: ret = static_cast(result.lVal); break; case VT_R4: ret = AsString(result.fltVal); break; case VT_R8: ret = AsString(result.dblVal); break; case VT_BSTR: ret = WideToString(result.bstrVal); break; case VT_LPSTR: //ret = result.pszVal; ret = "Unknown VT_LPSTR"; break; case VT_DATE: SYSTEMTIME stime; VariantTimeToSystemTime(result.date, &stime); { Time t; t.day = static_cast(stime.wDay); t.month = static_cast(stime.wMonth); t.year = stime.wYear; t.hour = static_cast(stime.wHour); t.minute = static_cast(stime.wMinute); t.second = static_cast(stime.wSecond); ret = t; } break; case VT_CF: ret = "(Clipboard format)"; break; } return ret; } String WideToString(LPCWSTR wcs, int len) { if (len == -1) { len = WideCharToMultiByte(CP_UTF8, 0, wcs, len, nullptr, 0, nullptr, nullptr); if (len == 0) return Null; } Buffer w(len); WideCharToMultiByte(CP_UTF8, 0, wcs, len, w, len, nullptr, nullptr); return ~w; } #endif #if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64) Dl::Dl() { hinstLib = 0; } Dl::~Dl() { if (hinstLib) if (FreeLibrary(hinstLib) == 0) LOG(t_("Dl cannot be released")); } #ifndef LOAD_IGNORE_CODE_AUTHZ_LEVEL #define LOAD_IGNORE_CODE_AUTHZ_LEVEL 0x00000010 #endif bool Dl::Load(const String &fileDll) { if (hinstLib) if (FreeLibrary(hinstLib) == 0) return false; hinstLib = LoadLibraryEx(TEXT(fileDll), nullptr, LOAD_IGNORE_CODE_AUTHZ_LEVEL); if (!hinstLib) return false; return true; } void *Dl::GetFunction(const String &functionName) { if (!hinstLib) return nullptr; return reinterpret_cast(GetProcAddress(hinstLib, functionName)); } #else #include Dl::Dl() { hinstLib = 0; } Dl::~Dl() { if (hinstLib) if (dlclose(hinstLib) == 0) ; // Dl cannot be released } bool Dl::Load(const String &fileDll) { if (hinstLib) if (dlclose(hinstLib) == 0) return false; hinstLib = dlopen(fileDll, RTLD_LAZY); if (!hinstLib) return false; return true; } void *Dl::GetFunction(const String &functionName) { if (!hinstLib) return nullptr; return dlsym(hinstLib, functionName); } #endif Color RandomColor() { return Color().FromRaw(Random()); } Image GetRect(const Image& orig, const Rect &r) { if(r.IsEmpty()) return Image(); ImageBuffer ib(r.GetSize()); for(int y = r.top; y < r.bottom; y++) { const RGBA *s = orig[y] + r.left; const RGBA *e = orig[y] + r.right; RGBA *t = ib[y - r.top]; while(s < e) { *t = *s; t++; s++; } } return ib; } double tmGetTimeX() { #ifdef __linux__ timespec t; if (0 != clock_gettime(CLOCK_REALTIME, &t)) return Null; return t.tv_sec + (double)t.tv_nsec/1000000000.; #elif defined(_WIN32) || defined(WIN32) LARGE_INTEGER clock; LARGE_INTEGER freq; if(!QueryPerformanceCounter(&clock) || !QueryPerformanceFrequency(&freq)) return Null; return double(clock.QuadPart)/freq.QuadPart; #else return double(time(0)); // Low resolution #endif } int SysX(const char *cmd, String& out, String& err, double timeOut, Gate3 progress, bool convertcharset) { out.Clear(); LocalProcess p; p.ConvertCharset(convertcharset); double t0 = tmGetTimeX(); if(!p.Start2(cmd)) return -1; int ret = Null; String os, es; while(p.IsRunning()) { if (p.Read2(os, es)) { out.Cat(os); err.Cat(es); } double elapsed = tmGetTimeX() - t0; if (!IsNull(timeOut) && elapsed > timeOut) { ret = -2; break; } if (progress(elapsed, out, err)) { ret = -3; break; } Sleep(1); } out.Cat(os); err.Cat(es); if (!IsNull(ret)) p.Kill(); return IsNull(ret) ? 0 : ret; } int LevenshteinDistance(const char *s, const char *t) { int lens = int(strlen(s)); int lent = int(strlen(t)); Buffer v0(lent + 1); Buffer v1(lent + 1); for (int i = 0; i <= lent; ++i) v0[i] = i; for (int i = 0; i < lens; ++i) { v1[0] = i + 1; for (int j = 0; j < lent; ++j) { int deletionCost = v0[j + 1] + 1; int insertionCost = v1[j] + 1; int substitutionCost; if (s[i] == t[j]) substitutionCost = v0[j]; else substitutionCost = v0[j] + 1; v1[j + 1] = min(deletionCost, insertionCost, substitutionCost); } Swap(v0, v1); } return v0[lent]; } int DamerauLevenshteinDistance(const char *s, const char *t, int alphabetLength) { int lens = int(strlen(s)); int lent = int(strlen(t)); int lent2 = lent + 2; Buffer H((lens+2)*lent2); int infinity = lens + lent; H[0] = infinity; for(int i = 0; i <= lens; i++) { H[lent2*(i+1)+1] = i; H[lent2*(i+1)+0] = infinity; } for(int j = 0; j <= lent; j++) { H[lent2*1+(j+1)] = j; H[lent2*0+(j+1)] = infinity; } Buffer DA(alphabetLength, 0); for(int i = 1; i <= lens; i++) { int DB = 0; for(int j = 1; j <= lent; j++) { int i1 = DA[int(t[j-1])]; int j1 = DB; int cost = (s[i-1] == t[j-1]) ? 0 : 1; if(cost == 0) DB = j; H[lent2*(i+1)+j+1] = min(H[lent2*i + j] + cost, H[lent2*(i+1) + j] + 1, H[lent2*i + j+1] + 1, H[lent2*i1 + j1] + (i-i1-1) + 1 + (j-j1-1)); } DA[int(s[i-1])] = i; } return H[lent2*(lens+1)+lent+1]; } int SentenceSimilitude(const char *s, const char *t) { int ls = int(strlen(s)); int lt = int(strlen(t)); if (ls > lt) { Swap(s, t); Swap(ls, lt); } int mind = ls; for (int i = 0; i < t - s; ++i) { int d = DamerauLevenshteinDistance(s, String(t).Mid(i, ls)); if (d < mind) mind = d; } return (100*mind)/ls; } // Dummy functions added after TheIDE change Upp::String GetCurrentMainPackage() {return "dummy";} Upp::String GetCurrentBuildMethod() {return "dummy";} void IdePutErrorLine(const Upp::String& ) {} size_t GetNumLines(Stream &stream) { size_t res = 0; int c; if ((c = stream.Get()) < 0) return 0; if (c == '\n') res++; while ((c = stream.Get()) > 0) if (c == '\n') res++; if (c != '\n') res++; return res; } bool SetConsoleColor(CONSOLE_COLOR color) { static Vector colors; if (color == RESET) colors.Clear(); else if(color == PREVIOUS) { int num = colors.size(); if (num == 0) color = RESET; else { colors.Remove(num-1); if (num-2 < 0) color = RESET; else color = static_cast(colors[num-2]); } } else colors << color; #ifdef PLATFORM_WIN32 static HANDLE hstdout = 0; static CONSOLE_SCREEN_BUFFER_INFO csbiInfo = {}; static WORD woldattrs; if (hstdout == 0) { hstdout = GetStdHandle(STD_OUTPUT_HANDLE); if (!GetConsoleScreenBufferInfo(hstdout, &csbiInfo)) { hstdout = 0; return false; } woldattrs = csbiInfo.wAttributes; } if (color == RESET) return SetConsoleTextAttribute(hstdout, woldattrs); else return SetConsoleTextAttribute(hstdout, color); #else if (color < 100) printf("\x1b[%dm", color); else printf("\x1b[1;%dm", color-100); return true; #endif } void ConsoleOutputDisable(bool disable) { #ifdef PLATFORM_WIN32 if (disable) freopen("nul", "w", stdout); else freopen("CONOUT$", "w", stdout); #else static int saved_id = Null; static fpos_t saved_pos; if (disable) { fflush(stdout); fgetpos(stdout, &saved_pos); saved_id = dup(fileno(stdout)); close(fileno(stdout)); } else { if (!IsNull(saved_id)) { fflush(stdout); dup2(saved_id, fileno(stdout)); close(saved_id); clearerr(stdout); fsetpos(stdout, &saved_pos); } } #endif } }