/**************************************************************************** ** ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "algorithm.h" #include "namevaluedictionary.h" #include "qtcassert.h" #include namespace Utils { namespace { NameValueMap::iterator findKey(NameValueMap &input, Utils::OsType osType, const QString &key) { const Qt::CaseSensitivity casing = (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive : Qt::CaseSensitive; for (auto it = input.begin(); it != input.end(); ++it) { if (key.compare(it.key(), casing) == 0) return it; } return input.end(); } NameValueMap::const_iterator findKey(const NameValueMap &input, Utils::OsType osType, const QString &key) { const Qt::CaseSensitivity casing = (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive : Qt::CaseSensitive; for (auto it = input.constBegin(); it != input.constEnd(); ++it) { if (key.compare(it.key(), casing) == 0) return it; } return input.constEnd(); } } // namespace NameValueDictionary::NameValueDictionary(const QStringList &env, OsType osType) : m_osType(osType) { for (const QString &s : env) { int i = s.indexOf('=', 1); if (i >= 0) { const QString key = s.left(i); if (!key.contains('=')) { const QString value = s.mid(i + 1); set(key, value); } } } } NameValueDictionary::NameValueDictionary(const NameValuePairs &nameValues) { for (const auto &nameValue : nameValues) set(nameValue.first, nameValue.second); } QStringList NameValueDictionary::toStringList() const { QStringList result; for (auto it = m_values.constBegin(); it != m_values.constEnd(); ++it) { if (it.value().second) result.append(it.key() + '=' + it.value().first); } return result; } void NameValueDictionary::set(const QString &key, const QString &value, bool enabled) { QTC_ASSERT(!key.contains('='), return ); auto it = findKey(m_values, m_osType, key); const auto valuePair = qMakePair(value, enabled); if (it == m_values.end()) m_values.insert(key, valuePair); else it.value() = valuePair; } void NameValueDictionary::unset(const QString &key) { QTC_ASSERT(!key.contains('='), return ); auto it = findKey(m_values, m_osType, key); if (it != m_values.end()) m_values.erase(it); } void NameValueDictionary::clear() { m_values.clear(); } QString NameValueDictionary::value(const QString &key) const { const auto it = findKey(m_values, m_osType, key); return it != m_values.end() && it.value().second ? it.value().first : QString(); } NameValueDictionary::const_iterator NameValueDictionary::constFind(const QString &name) const { return findKey(m_values, m_osType, name); } int NameValueDictionary::size() const { return m_values.size(); } void NameValueDictionary::modify(const NameValueItems &items) { NameValueDictionary resultKeyValueDictionary = *this; for (const NameValueItem &item : items) item.apply(&resultKeyValueDictionary); *this = resultKeyValueDictionary; } enum : char { #ifdef Q_OS_WIN pathSepC = ';' #else pathSepC = ':' #endif }; NameValueItems NameValueDictionary::diff(const NameValueDictionary &other, bool checkAppendPrepend) const { NameValueMap::const_iterator thisIt = constBegin(); NameValueMap::const_iterator otherIt = other.constBegin(); NameValueItems result; while (thisIt != constEnd() || otherIt != other.constEnd()) { if (thisIt == constEnd() || thisIt.key() > otherIt.key()) { result.append({otherIt.key(), otherIt.value().first, otherIt.value().second ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); ++otherIt; } else if (otherIt == other.constEnd()) { result.append(NameValueItem(thisIt.key(), QString(), NameValueItem::Unset)); ++thisIt; } else if (thisIt.key() < otherIt.key()) { result.append(NameValueItem(thisIt.key(), QString(), NameValueItem::Unset)); ++thisIt; } else { const QString &oldValue = thisIt.value().first; const QString &newValue = otherIt.value().first; const bool oldEnabled = thisIt.value().second; const bool newEnabled = otherIt.value().second; if (oldValue != newValue) { if (checkAppendPrepend && newValue.startsWith(oldValue) && oldEnabled == newEnabled) { QString appended = newValue.right(newValue.size() - oldValue.size()); if (appended.startsWith(QLatin1Char(pathSepC))) appended.remove(0, 1); result.append(NameValueItem(otherIt.key(), appended, NameValueItem::Append)); } else if (checkAppendPrepend && newValue.endsWith(oldValue) && oldEnabled == newEnabled) { QString prepended = newValue.left(newValue.size() - oldValue.size()); if (prepended.endsWith(QLatin1Char(pathSepC))) prepended.chop(1); result.append(NameValueItem(otherIt.key(), prepended, NameValueItem::Prepend)); } else { result.append({otherIt.key(), newValue, newEnabled ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); } } ++otherIt; ++thisIt; } } return result; } bool NameValueDictionary::hasKey(const QString &key) const { return m_values.contains(key); } OsType NameValueDictionary::osType() const { return m_osType; } QString NameValueDictionary::userName() const { return value(QString::fromLatin1(m_osType == OsTypeWindows ? "USERNAME" : "USER")); } } // namespace Utils