Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
18 kB · 683 lines
C++
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* * Main authors: * Guido Tack <guido.tack@monash.edu> */
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef _MSC_VER#define _CRT_SECURE_NO_WARNINGS#endif
#include <minizinc/config.hh>#include <minizinc/exception.hh>#include <minizinc/file_utils.hh>#include <minizinc/thirdparty/b64/decode.h>#include <minizinc/thirdparty/b64/encode.h>#include <minizinc/thirdparty/miniz.h>
#include <cstring>#include <sstream>#include <string>
#ifdef HAS_PIDPATH#include <libproc.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#elif defined(HAS_GETMODULEFILENAME) || defined(HAS_GETFILEATTRIBUTES)#include <windows.h>#else#include <unistd.h>#endif#include <sys/stat.h>#include <sys/types.h>
#ifdef _MSC_VER#include "Shlwapi.h"#pragma comment(lib, "Shlwapi.lib")#include "Shlobj.h"
#include <direct.h>#else#include <dirent.h>#include <ftw.h>#include <libgen.h>#endif
namespace MiniZinc {namespace FileUtils {
#ifdef HAS_PIDPATHstd::string progpath(void) { pid_t pid = getpid(); char path[PROC_PIDPATHINFO_MAXSIZE]; int ret = proc_pidpath(pid, path, sizeof(path)); if (ret <= 0) { return ""; } else { std::string p(path); size_t slash = p.find_last_of("/"); if (slash != std::string::npos) { p = p.substr(0, slash); } return p; }}#elif defined(HAS_GETMODULEFILENAME)std::string progpath(void) { char path[MAX_PATH]; int ret = GetModuleFileName(NULL, path, MAX_PATH); if (ret <= 0) { return ""; } else { std::string p(path); size_t slash = p.find_last_of("/\\"); if (slash != std::string::npos) { p = p.substr(0, slash); } return p; }}#elsestd::string progpath(void) { const int bufsz = 2000; char path[bufsz + 1]; ssize_t sz = readlink("/proc/self/exe", path, bufsz); if (sz < 0) { return ""; } else { path[sz] = '\0'; std::string p(path); size_t slash = p.find_last_of("/"); if (slash != std::string::npos) { p = p.substr(0, slash); } return p; }}#endif
bool file_exists(const std::string& filename) {#if defined(HAS_GETFILEATTRIBUTES) DWORD dwAttrib = GetFileAttributes(filename.c_str());
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));#else struct stat info; return stat(filename.c_str(), &info) == 0 && (info.st_mode & S_IFREG);#endif}
bool directory_exists(const std::string& dirname) {#if defined(HAS_GETFILEATTRIBUTES) DWORD dwAttrib = GetFileAttributes(dirname.c_str());
return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));#else struct stat info; return stat(dirname.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);#endif}
std::string file_path(const std::string& filename, const std::string& basePath) {#ifdef _MSC_VER LPSTR lpBuffer, lpFilePart; DWORD nBufferLength = GetFullPathName(filename.c_str(), 0, 0, &lpFilePart); if (!(lpBuffer = (LPTSTR)LocalAlloc(LMEM_FIXED, sizeof(TCHAR) * nBufferLength))) return 0; std::string ret; DWORD error = GetFullPathName(filename.c_str(), nBufferLength, lpBuffer, &lpFilePart); DWORD fileAttr = GetFileAttributes(lpBuffer); DWORD lastError = GetLastError();
if (error == 0 || (fileAttr == INVALID_FILE_ATTRIBUTES && lastError != NO_ERROR)) { if (basePath.empty()) ret = filename; else ret = file_path(basePath + "/" + filename); } else { ret = std::string(lpBuffer); } LocalFree(lpBuffer); return ret;#else char* rp = realpath(filename.c_str(), NULL); if (rp == NULL) { if (basePath.empty()) return filename; else return file_path(basePath + "/" + filename); } std::string rp_s(rp); free(rp); return rp_s;#endif}
std::string dir_name(const std::string& filename) {#ifdef _MSC_VER size_t pos = filename.find_last_of("\\/"); return (pos == std::string::npos) ? "" : filename.substr(0, pos);#else char* fn = strdup(filename.c_str()); char* dn = dirname(fn); std::string ret(dn); free(fn); return ret;#endif}
std::string base_name(const std::string& filename) {#ifdef _MSC_VER size_t pos = filename.find_last_of("\\/"); return (pos == std::string::npos) ? filename : filename.substr(pos + 1);#else char* fn = strdup(filename.c_str()); char* dn = basename(fn); std::string ret(dn); free(fn); return ret;#endif}
bool is_absolute(const std::string& path) {#ifdef _MSC_VER return !PathIsRelative(path.c_str());#else return path.empty() ? false : (path[0] == '/');#endif}
std::string find_executable(const std::string& filename) { if (is_absolute(filename)) { if (file_exists(filename)) { return filename; }#ifdef _MSC_VER if (FileUtils::file_exists(filename + ".exe")) { return filename + ".exe"; } else if (FileUtils::file_exists(filename + ".bat")) { return filename + ".bat"; }#endif return ""; } char* path_c = getenv("PATH");#ifdef _MSC_VER char pathsep = ';';#else char pathsep = ':';#endif std::string path; if (path_c) { path = path_c; if (path.size()) { path += pathsep; } } path += progpath(); std::string pathItem; std::stringstream pathStream(path); while (std::getline(pathStream, pathItem, pathsep)) { std::string fileWithPath = pathItem + "/" + filename; if (file_exists(fileWithPath)) return fileWithPath;#ifdef _MSC_VER if (FileUtils::file_exists(fileWithPath + ".exe")) { return fileWithPath + ".exe"; } else if (FileUtils::file_exists(fileWithPath + ".bat")) { return fileWithPath + ".bat"; }#endif } return "";}
std::vector<std::string> directory_list(const std::string& dir, const std::string& ext) { std::vector<std::string> entries;#ifdef _MSC_VER WIN32_FIND_DATA findData; HANDLE hFind = ::FindFirstFile((dir + "/*." + ext).c_str(), &findData); if (hFind != INVALID_HANDLE_VALUE) { do { if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { entries.push_back(findData.cFileName); } } while (::FindNextFile(hFind, &findData)); ::FindClose(hFind); }#else DIR* dirp = opendir(dir.c_str()); if (dirp) { struct dirent* dp; while ((dp = readdir(dirp)) != NULL) { std::string fileName(dp->d_name); struct stat info; if (stat((dir + "/" + fileName).c_str(), &info) == 0 && (info.st_mode & S_IFREG)) { if (ext == "*") { entries.push_back(fileName); } else { if (fileName.size() > ext.size() + 2 && fileName.substr(fileName.size() - ext.size() - 1) == "." + ext) { entries.push_back(fileName); } } } } closedir(dirp); }#endif return entries;}
std::string working_directory(void) { char wd[FILENAME_MAX];#ifdef _MSC_VER if (!_getcwd(wd, sizeof(wd))) return "";#else if (!getcwd(wd, sizeof(wd))) return "";#endif return wd;}
std::string share_directory(void) { if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) { return std::string(MZNSTDLIBDIR); } std::string mypath = FileUtils::progpath(); int depth = 0; for (unsigned int i = 0; i < mypath.size(); i++) if (mypath[i] == '/' || mypath[i] == '\\') depth++; for (int i = 0; i <= depth; i++) { if (FileUtils::file_exists(mypath + "/share/minizinc/std/builtins.mzn")) return mypath + "/share/minizinc"; mypath += "/.."; } return "";}
std::string user_config_dir(void) {#ifdef _MSC_VER HRESULT hr; PWSTR pszPath = NULL;
hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &pszPath); if (SUCCEEDED(hr)) { int charsRequired = WideCharToMultiByte(CP_ACP, 0, pszPath, -1, 0, 0, 0, 0); std::string configPath; if (charsRequired > 0) { char* tmp = new char[charsRequired]; if (WideCharToMultiByte(CP_ACP, 0, pszPath, -1, tmp, charsRequired, 0, 0) != 0) { tmp[charsRequired - 1] = 0; configPath = tmp; } delete[] tmp; } CoTaskMemFree(pszPath); if (configPath.empty()) { return ""; } else { return configPath + "/MiniZinc"; } } return "";#else if (const char* hd = getenv("HOME")) { return std::string(hd) + "/.minizinc"; } return "";#endif}
std::string global_config_file(void) { std::string sd = share_directory(); if (sd.empty()) return ""; return sd + "/Preferences.json";}
std::string user_config_file(void) { return user_config_dir() + "/Preferences.json"; }
TmpFile::TmpFile(const std::string& ext) {#ifdef _WIN32 TCHAR szTempFileName[MAX_PATH]; TCHAR lpTempPathBuffer[MAX_PATH];
GetTempPath(MAX_PATH, lpTempPathBuffer); GetTempFileName(lpTempPathBuffer, "tmp_mzn_", 0, szTempFileName);
_name = szTempFileName; MoveFile(_name.c_str(), (_name + ext).c_str()); _name += ext;#else _tmpfile_desc = -1; _name = "/tmp/mznfileXXXXXX" + ext; char* tmpfile = strndup(_name.c_str(), _name.size()); _tmpfile_desc = mkstemps(tmpfile, ext.size()); if (_tmpfile_desc == -1) { ::free(tmpfile); throw InternalError("Error occurred when creating temporary file"); } _name = std::string(tmpfile); ::free(tmpfile);#endif}
TmpFile::~TmpFile(void) { remove(_name.c_str());#ifndef _WIN32 if (_tmpfile_desc != -1) close(_tmpfile_desc);#endif}
TmpDir::TmpDir(void) {#ifdef _WIN32 TCHAR szTempFileName[MAX_PATH]; TCHAR lpTempPathBuffer[MAX_PATH];
GetTempPath(MAX_PATH, lpTempPathBuffer); GetTempFileName(lpTempPathBuffer, "tmp_mzn_", 0, szTempFileName);
_name = szTempFileName; DeleteFile(_name.c_str()); CreateDirectory(_name.c_str(), NULL);#else _name = "/tmp/mzndirXXXXXX"; char* tmpfile = strndup(_name.c_str(), _name.size());
if (mkdtemp(tmpfile) == NULL) { ::free(tmpfile); throw InternalError("Error occurred when creating temporary directory"); } _name = std::string(tmpfile); ::free(tmpfile);#endif}
#ifdef _WIN32namespace {void remove_dir(const std::string& d) { HANDLE dh; WIN32_FIND_DATA info;
std::string pattern = d + "\\*.*"; dh = ::FindFirstFile(pattern.c_str(), &info); if (dh != INVALID_HANDLE_VALUE) { do { if (info.cFileName[0] != '.') { std::string fp = d + "\\" + info.cFileName; if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { remove_dir(fp); } else { ::SetFileAttributes(fp.c_str(), FILE_ATTRIBUTE_NORMAL); ::DeleteFile(fp.c_str()); } } } while (::FindNextFile(dh, &info) == TRUE); } ::FindClose(dh); ::SetFileAttributes(d.c_str(), FILE_ATTRIBUTE_NORMAL); ::RemoveDirectory(d.c_str());}} // namespace#elsenamespace {int remove_file(const char* fpath, const struct stat*, int, struct FTW*) { return unlink(fpath); }} // namespace#endif
TmpDir::~TmpDir(void) {#ifdef _WIN32 remove_dir(_name);#else nftw(_name.c_str(), remove_file, 64, FTW_DEPTH | FTW_PHYS); rmdir(_name.c_str());#endif}
std::vector<std::string> parseCmdLine(const std::string& s) { // Break the string up at whitespace, except inside quotes, but ignore escaped quotes std::vector<std::string> c; size_t cur = 0; size_t l = s.length(); std::ostringstream oss; bool inside_quote = false; bool had_escape = false; for (; cur < l; cur++) { if (inside_quote) { if (s[cur] == '"') { if (had_escape) { oss << "\""; had_escape = false; } else { inside_quote = false; } } else if (s[cur] == '\\') { had_escape = true; } else { if (had_escape) { oss << "\\"; had_escape = false; } oss << s[cur]; } } else { if (s[cur] == ' ') { if (had_escape) { oss << " "; had_escape = false; } else { c.push_back(oss.str()); oss.str(std::string()); } } else if (s[cur] == '\\') { if (had_escape) { oss << "\\"; had_escape = false; } else { had_escape = true; } } else if (s[cur] == '"') { if (had_escape) { oss << "\""; had_escape = false; } else { inside_quote = true; } } else { if (had_escape) { switch (s[cur]) { case 'a': oss << "\a"; break; case 'b': oss << "\b"; break; case 'f': oss << "\f"; break; case 'n': oss << "\n"; break; case 'r': oss << "\r"; break; case 't': oss << "\t"; break; case 'v': oss << "\v"; break; default: oss << "\\" << s[cur]; break; } had_escape = false; } else { oss << s[cur]; } } } } c.push_back(oss.str()); return c;}
std::string combineCmdLine(const std::vector<std::string>& cmd) { std::ostringstream ret; for (unsigned int i = 0; i < cmd.size(); i++) { auto& c = cmd[i]; ret << "\""; for (size_t i = 0; i < c.size(); i++) { switch (c[i]) { case '\a': ret << "\\a"; break; case '\b': ret << "\\b"; break; case '\f': ret << "\\f"; break; case '\n': ret << "\\n"; break; case '\r': ret << "\\r"; break; case '\t': ret << "\\t"; break; case '\v': ret << "\\v"; break; case '"': ret << "\\\""; break; case '\\': ret << "\\\\"; break; default: ret << c[i]; break; } } ret << "\""; if (i < cmd.size() - 1) { ret << " "; } } return ret.str();}
void inflateString(std::string& s) { unsigned char* cc = reinterpret_cast<unsigned char*>(&s[0]); // autodetect compressed string if (s.size() >= 2 && ((cc[0] == 0x1F && cc[1] == 0x8B) // gzip || (cc[0] == 0x78 && (cc[1] == 0x01 // zlib || cc[1] == 0x9C || cc[1] == 0xDA)))) { const int BUF_SIZE = 1024; unsigned char s_outbuf[BUF_SIZE]; z_stream stream; std::memset(&stream, 0, sizeof(stream));
unsigned char* dataStart; int windowBits; size_t dataLen; if (cc[0] == 0x1F && cc[1] == 0x8B) { dataStart = cc + 10; windowBits = -Z_DEFAULT_WINDOW_BITS; if (cc[3] & 0x4) { dataStart += 2; if (dataStart >= cc + s.size()) throw(-1); } if (cc[3] & 0x8) { while (*dataStart != '\0') { dataStart++; if (dataStart >= cc + s.size()) throw(-1); } dataStart++; if (dataStart >= cc + s.size()) throw(-1); } if (cc[3] & 0x10) { while (*dataStart != '\0') { dataStart++; if (dataStart >= cc + s.size()) throw(-1); } dataStart++; if (dataStart >= cc + s.size()) throw(-1); } if (cc[3] & 0x2) { dataStart += 2; if (dataStart >= cc + s.size()) throw(-1); } dataLen = s.size() - (dataStart - cc); } else { dataStart = cc; windowBits = Z_DEFAULT_WINDOW_BITS; dataLen = s.size(); }
stream.next_in = dataStart; stream.avail_in = static_cast<unsigned int>(dataLen); stream.next_out = &s_outbuf[0]; stream.avail_out = BUF_SIZE; int status = inflateInit2(&stream, windowBits); if (status != Z_OK) throw(status); std::ostringstream oss; while (true) { status = inflate(&stream, Z_NO_FLUSH); if (status == Z_STREAM_END || !stream.avail_out) { // output buffer full or compression finished oss << std::string(reinterpret_cast<char*>(s_outbuf), BUF_SIZE - stream.avail_out); stream.next_out = &s_outbuf[0]; stream.avail_out = BUF_SIZE; } if (status == Z_STREAM_END) break; if (status != Z_OK) throw(status); } status = inflateEnd(&stream); if (status != Z_OK) throw(status); s = oss.str(); }}
std::string deflateString(const std::string& s) { mz_ulong compressedLength = compressBound(static_cast<mz_ulong>(s.size())); unsigned char* cmpr = static_cast<unsigned char*>(::malloc(compressedLength * sizeof(unsigned char))); int status = compress(cmpr, &compressedLength, reinterpret_cast<const unsigned char*>(&s[0]), static_cast<mz_ulong>(s.size())); if (status != Z_OK) { ::free(cmpr); throw(status); } std::string ret(reinterpret_cast<const char*>(cmpr), compressedLength); ::free(cmpr); return ret;}
std::string encodeBase64(const std::string& s) { base64::encoder E; std::ostringstream oss; oss << "@"; // add leading "@" to distinguish from valid MiniZinc code std::istringstream iss(s); E.encode(iss, oss); return oss.str();}
std::string decodeBase64(const std::string& s) { if (s.size() == 0 || s[0] != '@') throw InternalError("string is not base64 encoded"); base64::decoder D; std::ostringstream oss; std::istringstream iss(s); (void)iss.get(); // remove leading "@" D.decode(iss, oss); return oss.str();}
} // namespace FileUtils} // namespace MiniZinc