File indexing completed on 2024-05-12 05:45:31
0001 /* 0002 Copyright Hannah von Reth <vonreth@kde.org> 0003 0004 Redistribution and use in source and binary forms, with or without 0005 modification, are permitted provided that the following conditions 0006 are met: 0007 1. Redistributions of source code must retain the above copyright 0008 notice, this list of conditions and the following disclaimer. 0009 2. Redistributions in binary form must reproduce the above copyright 0010 notice, this list of conditions and the following disclaimer in the 0011 documentation and/or other materials provided with the distribution. 0012 0013 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 0014 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 0015 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 0016 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 0017 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 0018 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 0019 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 0020 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 0021 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 0022 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 0023 SUCH DAMAGE. 0024 */ 0025 0026 #include "kshim.h" 0027 #include "kshimdata.h" 0028 0029 #include <algorithm> 0030 #include <iostream> 0031 #include <fstream> 0032 #include <sstream> 0033 #include <cstring> 0034 0035 #ifdef _WIN32 0036 #include <windows.h> 0037 #endif 0038 0039 bool KLog::s_loggingEnabled = !KShimLib::getenv(KSTRING("KSHIM_LOG")).empty(); 0040 bool KLog::s_stdLoggingEnabled = !KShimLib::getenv(KSTRING("KSHIM_LOG_STD")).empty(); 0041 0042 KLog::KLog(KLog::Type t) : m_type(t), m_stream(new KShimLib::stringstream) {} 0043 0044 KLog::KLog(const KLog &other) : m_type(other.m_type), m_stream(other.m_stream) {} 0045 0046 KLog::~KLog() 0047 { 0048 if (m_stream.use_count() == 1) { 0049 *this << "\n"; 0050 const auto line = m_stream->str(); 0051 if (s_stdLoggingEnabled) { 0052 #ifdef _WIN32 0053 std::wcerr << line; 0054 #else 0055 std::cerr << line; 0056 #endif 0057 } else { 0058 switch (m_type) { 0059 case KLog::Type::Error: 0060 case KLog::Type::Fatal: 0061 #ifdef _WIN32 0062 std::wcerr << line << std::endl;; 0063 #else 0064 std::cerr << line << std::endl; 0065 #endif 0066 [[fallthrough]]; 0067 case KLog::Type::Debug: { 0068 if (doLog()) { 0069 static auto _log = [] { 0070 auto home = KShimLib::getenv(KSTRING("HOME")); 0071 if (home.empty()) { 0072 home = KShimLib::getenv(KSTRING("USERPROFILE")); 0073 } 0074 const auto logPath = std::filesystem::path(home) / KSTRING(".kshim.log"); 0075 #ifdef _WIN32 0076 #if !defined(__MINGW32__) 0077 const auto &_name = logPath; 0078 #else 0079 const auto _name = logPath.string(); 0080 #endif 0081 auto out = std::wofstream(_name, std::ios::app); 0082 #else 0083 auto out = std::ofstream(logPath, std::ios::app); 0084 #endif 0085 if (!out.is_open()) { 0086 std::cerr << "KShim: Failed to open log \"" << logPath.string() << "\" " 0087 << strerror(errno) << std::endl; 0088 } 0089 out << "----------------------------\n"; 0090 return out; 0091 }(); 0092 #ifdef _WIN32 0093 OutputDebugStringW(line.data()); 0094 #endif 0095 _log << line; 0096 _log.flush(); 0097 } 0098 } 0099 } 0100 } 0101 } 0102 if (m_type == Type::Fatal) { 0103 exit(-1); 0104 } 0105 } 0106 0107 KLog &KLog::log() 0108 { 0109 *this << "KShimgen " << KShimLib::version << ": "; 0110 return *this; 0111 } 0112 0113 KLog::Type KLog::type() const 0114 { 0115 return m_type; 0116 } 0117 0118 bool KLog::doLog() const 0119 { 0120 return loggingEnabled() || m_type != KLog::Type::Debug; 0121 } 0122 0123 bool KLog::getStdLoggingEnabled() 0124 { 0125 return s_stdLoggingEnabled; 0126 } 0127 0128 void KLog::setStdLoggingEnabled(bool value) 0129 { 0130 s_stdLoggingEnabled = value; 0131 } 0132 0133 bool KLog::loggingEnabled() 0134 { 0135 return s_loggingEnabled; 0136 } 0137 0138 void KLog::setLoggingEnabled(bool loggingEnabled) 0139 { 0140 s_loggingEnabled = loggingEnabled; 0141 } 0142 0143 KLog &operator<<(KLog &log, const std::filesystem::path &t) 0144 { 0145 return log << t.native(); 0146 } 0147 0148 KLog &operator<<(KLog &log, const std::string &t) 0149 { 0150 log << t.data(); 0151 return log; 0152 } 0153 0154 KShimLib::string KShimLib::quoteArgs(const std::vector<KShimLib::string_view> &args) 0155 { 0156 KShimLib::stringstream command; 0157 for (const auto &arg : args) { 0158 command << " " << quote(arg); 0159 } 0160 return command.str(); 0161 } 0162 0163 KShimLib::string KShimLib::quote(const KShimLib::string_view &arg) 0164 { 0165 // based on https://github.com/python/cpython/blob/master/Lib/subprocess.py#L493 0166 if (arg.empty()) { 0167 return KSTRING("\"\""); 0168 } 0169 bool needsQuote = false; 0170 for (const auto c : arg) { 0171 needsQuote = c == ' ' || c == '\t'; 0172 if (needsQuote) { 0173 break; 0174 } 0175 } 0176 KShimLib::stringstream out; 0177 KShimLib::stringstream backslash; 0178 if (needsQuote) { 0179 out << '"'; 0180 } 0181 for (const auto c : arg) { 0182 if (c == '\\') { 0183 backslash << c; 0184 } else if (c == '"') { 0185 const auto bs = backslash.str(); 0186 out << bs << bs << "\\\""; 0187 backslash.str(KShimLib::string()); 0188 } else { 0189 const auto bs = backslash.str(); 0190 if (!bs.empty()) { 0191 out << bs; 0192 backslash.str(KShimLib::string()); 0193 } 0194 out << c; 0195 } 0196 } 0197 const auto bs = backslash.str(); 0198 if (!bs.empty()) { 0199 out << bs; 0200 } 0201 if (needsQuote) { 0202 out << bs; 0203 out << '"'; 0204 } 0205 return out.str(); 0206 }