Commit 7efddedf authored by Héctor Mesa Jiménez's avatar Héctor Mesa Jiménez Committed by Christoph Cullmann
Browse files

gdbplugin: fixed serialization format for targets (new version 5 based on JSON)

parent 006055c3
......@@ -14,6 +14,16 @@ static const QLatin1Char pathSeparator(':');
#endif
#include <QFileDialog>
#include <QJsonArray>
#include <QJsonObject>
const QString AdvancedGDBSettings::F_GDB = QStringLiteral("gdb");
const QString AdvancedGDBSettings::F_SRC_PATHS = QStringLiteral("srcPaths");
const static QString F_LOCAL_REMOTE = QStringLiteral("localRemote");
const static QString F_REMOTE_BAUD = QStringLiteral("remoteBaud");
const static QString F_SO_ABSOLUTE = QStringLiteral("soAbsolute");
const static QString F_SO_RELATIVE = QStringLiteral("soRelative");
const static QString F_CUSTOM_INIT = QStringLiteral("customInit");
AdvancedGDBSettings::AdvancedGDBSettings(QWidget *parent)
: QDialog(parent)
......@@ -45,30 +55,32 @@ AdvancedGDBSettings::~AdvancedGDBSettings()
{
}
const QStringList AdvancedGDBSettings::configs() const
const QJsonObject AdvancedGDBSettings::configs() const
{
QStringList tmp;
QJsonObject conf;
// gdb
conf[F_GDB] = u_gdbCmd->text();
tmp << u_gdbCmd->text();
// local/remote, baud
switch (u_localRemote->currentIndex()) {
case 1:
tmp << QStringLiteral("target remote %1:%2").arg(u_tcpHost->text(), u_tcpPort->text());
tmp << QString();
conf[F_LOCAL_REMOTE] = QStringLiteral("target remote %1:%2").arg(u_tcpHost->text(), u_tcpPort->text());
break;
case 2:
tmp << QStringLiteral("target remote %1").arg(u_ttyPort->text());
tmp << QStringLiteral("set remotebaud %1").arg(u_baudCombo->currentText());
conf[F_LOCAL_REMOTE] = QStringLiteral("target remote %1").arg(u_ttyPort->text());
conf[F_REMOTE_BAUD] = QStringLiteral("set remotebaud %1").arg(u_baudCombo->currentText());
break;
default:
tmp << QString();
tmp << QString();
break;
}
// solib absolute
if (!u_soAbsPrefix->text().isEmpty()) {
tmp << QStringLiteral("set solib-absolute-prefix %1").arg(u_soAbsPrefix->text());
} else {
tmp << QString();
conf[F_SO_ABSOLUTE] = QStringLiteral("set solib-absolute-prefix %1").arg(u_soAbsPrefix->text());
}
// solib search path
if (u_soSearchPaths->count() > 0) {
QString paths = QStringLiteral("set solib-search-path ");
for (int i = 0; i < u_soSearchPaths->count(); ++i) {
......@@ -77,29 +89,105 @@ const QStringList AdvancedGDBSettings::configs() const
}
paths += u_soSearchPaths->item(i)->text();
}
tmp << paths;
} else {
tmp << QString();
conf[F_SO_RELATIVE] = paths;
}
// source paths
if (u_srcPaths->count() > 0) {
QString paths = QStringLiteral("set directories ");
QJsonArray paths;
for (int i = 0; i < u_srcPaths->count(); ++i) {
if (i != 0) {
paths += pathSeparator;
const QString path = u_srcPaths->item(i)->text().trimmed();
if (!path.isEmpty()) {
paths << path;
}
paths += u_srcPaths->item(i)->text();
}
tmp << paths;
} else {
tmp << QString();
if (!paths.isEmpty()) {
conf[F_SRC_PATHS] = paths;
}
}
// custom init
const auto cinit = u_customInit->toPlainText().split(QLatin1Char('\n'), Qt::SkipEmptyParts);
if (!cinit.isEmpty()) {
conf[F_CUSTOM_INIT] = QJsonArray::fromStringList(cinit);
}
tmp << u_customInit->toPlainText().split(QLatin1Char('\n'));
return tmp;
return conf;
}
void AdvancedGDBSettings::setConfigs(const QStringList &cfgs)
QStringList AdvancedGDBSettings::commandList(const QJsonObject &config)
{
QStringList commands;
auto insertString = [&commands, config](const QString &field) {
const QString value = config[field].toString().trimmed();
if (!value.isEmpty()) {
commands << value;
}
};
insertString(F_LOCAL_REMOTE);
insertString(F_REMOTE_BAUD);
insertString(F_SO_ABSOLUTE);
insertString(F_SO_RELATIVE);
for (const auto &value : config[F_CUSTOM_INIT].toArray()) {
commands << value.toString();
}
return commands;
}
QJsonObject AdvancedGDBSettings::upgradeConfigV4_5(const QStringList &cfgs)
{
const int size = cfgs.count();
QJsonObject conf;
auto insert = [&conf, cfgs, size](CustomStringOrder index, const QString &field) {
if (index >= size)
return;
const QString value = cfgs[index].trimmed();
if (!value.isEmpty()) {
conf[field] = value;
}
};
// gdb
insert(GDBIndex, F_GDB);
// localremoteindex
insert(LocalRemoteIndex, F_LOCAL_REMOTE);
// remotebaudindex
insert(RemoteBaudIndex, F_REMOTE_BAUD);
// soabsoluteindex
insert(SoAbsoluteIndex, F_SO_ABSOLUTE);
// sorelativeindex
insert(SoRelativeIndex, F_SO_RELATIVE);
// srcpathsindex
if (SrcPathsIndex < size) {
QString allPaths = cfgs[SrcPathsIndex];
if (allPaths.startsWith(QStringLiteral("set directories "))) {
allPaths = allPaths.mid(16);
}
QStringList paths = allPaths.split(pathSeparator, Qt::SkipEmptyParts);
if (!paths.isEmpty()) {
conf[F_SRC_PATHS] = QJsonArray::fromStringList(paths);
}
}
// customstart
if (CustomStartIndex < size) {
QJsonArray parts;
for (int i = CustomStartIndex; i < size; i++) {
parts << cfgs[i];
}
conf[F_CUSTOM_INIT] = parts;
}
return conf;
}
void AdvancedGDBSettings::setConfigs(const QJsonObject &cfgs)
{
// clear all info
u_gdbCmd->setText(QStringLiteral("gdb"));
......@@ -114,63 +202,62 @@ void AdvancedGDBSettings::setConfigs(const QStringList &cfgs)
u_baudCombo->setCurrentIndex(0);
// GDB
if (cfgs.count() <= GDBIndex) {
return;
if (cfgs.contains(F_GDB)) {
u_gdbCmd->setText(cfgs[F_GDB].toString());
}
u_gdbCmd->setText(cfgs[GDBIndex]);
// Local / Remote
if (cfgs.count() <= LocalRemoteIndex) {
return;
}
const auto localRemote = cfgs[F_LOCAL_REMOTE].toString();
int start;
int end;
if (cfgs[LocalRemoteIndex].isEmpty()) {
if (localRemote.isEmpty()) {
u_localRemote->setCurrentIndex(0);
u_remoteStack->setCurrentIndex(0);
} else if (cfgs[LocalRemoteIndex].contains(pathSeparator)) {
} else if (localRemote.contains(pathSeparator)) {
u_localRemote->setCurrentIndex(1);
u_remoteStack->setCurrentIndex(1);
start = cfgs[LocalRemoteIndex].lastIndexOf(QLatin1Char(' '));
end = cfgs[LocalRemoteIndex].indexOf(pathSeparator);
u_tcpHost->setText(cfgs[LocalRemoteIndex].mid(start + 1, end - start - 1));
u_tcpPort->setText(cfgs[LocalRemoteIndex].mid(end + 1));
start = localRemote.lastIndexOf(QLatin1Char(' '));
end = localRemote.indexOf(pathSeparator);
u_tcpHost->setText(localRemote.mid(start + 1, end - start - 1));
u_tcpPort->setText(localRemote.mid(end + 1));
} else {
u_localRemote->setCurrentIndex(2);
u_remoteStack->setCurrentIndex(2);
start = cfgs[LocalRemoteIndex].lastIndexOf(QLatin1Char(' '));
u_ttyPort->setText(cfgs[LocalRemoteIndex].mid(start + 1));
start = localRemote.lastIndexOf(QLatin1Char(' '));
u_ttyPort->setText(localRemote.mid(start + 1));
start = cfgs[RemoteBaudIndex].lastIndexOf(QLatin1Char(' '));
setComboText(u_baudCombo, cfgs[RemoteBaudIndex].mid(start + 1));
const auto remoteBaud = cfgs[F_REMOTE_BAUD].toString();
start = remoteBaud.lastIndexOf(QLatin1Char(' '));
setComboText(u_baudCombo, remoteBaud.mid(start + 1));
}
// Solib absolute path
if (cfgs.count() <= SoAbsoluteIndex) {
return;
if (cfgs.contains(F_SO_ABSOLUTE)) {
start = 26; // "set solib-absolute-prefix "
u_soAbsPrefix->setText(cfgs[F_SO_ABSOLUTE].toString().mid(start));
}
start = 26; // "set solib-absolute-prefix "
u_soAbsPrefix->setText(cfgs[SoAbsoluteIndex].mid(start));
// Solib search path
if (cfgs.count() <= SoRelativeIndex) {
return;
if (cfgs.contains(F_SO_RELATIVE)) {
start = 22; // "set solib-search-path "
QString tmp = cfgs[F_SO_RELATIVE].toString().mid(start);
u_soSearchPaths->addItems(tmp.split(pathSeparator));
}
start = 22; // "set solib-search-path "
QString tmp = cfgs[SoRelativeIndex].mid(start);
u_soSearchPaths->addItems(tmp.split(pathSeparator));
if (cfgs.count() <= SrcPathsIndex) {
return;
if (cfgs.contains(F_SRC_PATHS)) {
QStringList paths;
for (const auto &value : cfgs[F_SRC_PATHS].toArray()) {
paths << value.toString();
}
u_srcPaths->addItems(paths);
}
start = 16; // "set directories "
tmp = cfgs[SrcPathsIndex].mid(start);
u_srcPaths->addItems(tmp.split(pathSeparator, Qt::SkipEmptyParts));
// Custom init
for (int i = CustomStartIndex; i < cfgs.count(); i++) {
u_customInit->appendPlainText(cfgs[i]);
if (cfgs.contains(F_CUSTOM_INIT)) {
for (const auto &line : cfgs[F_CUSTOM_INIT].toArray()) {
u_customInit->appendPlainText(line.toString());
}
}
slotLocalRemoteChanged();
......
......@@ -21,9 +21,14 @@ public:
AdvancedGDBSettings(QWidget *parent = nullptr);
~AdvancedGDBSettings() override;
const QStringList configs() const;
static QJsonObject upgradeConfigV4_5(const QStringList &cfgs);
static QStringList commandList(const QJsonObject &config);
const QJsonObject configs() const;
void setConfigs(const QStringList &cfgs);
void setConfigs(const QJsonObject &cfgs);
const static QString F_GDB;
const static QString F_SRC_PATHS;
private:
static void setComboText(QComboBox *combo, const QString &str);
......
......@@ -14,6 +14,7 @@
#include <QCompleter>
#include <QFileDialog>
#include <QFileSystemModel>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLayout>
......@@ -38,6 +39,15 @@ static const QLatin1Char pathSeparator(';');
static const QLatin1Char pathSeparator(':');
#endif
constexpr int CONFIG_VERSION = 5;
const static QString F_TARGET = QStringLiteral("target");
const static QString F_DEBUGGER = QStringLiteral("debuggerKey");
const static QString F_PROFILE = QStringLiteral("debuggerProfile");
const static QString F_FILE = QStringLiteral("file");
const static QString F_WORKDIR = QStringLiteral("workdir");
const static QString F_ARGS = QStringLiteral("args");
const static QString F_PID = QStringLiteral("pid");
void ConfigView::refreshUI()
{
// first false then true to make sure a layout is set
......@@ -225,65 +235,128 @@ void ConfigView::registerActions(KActionCollection *actionCollection)
connect(m_targetSelectAction, &KSelectAction::indexTriggered, this, &ConfigView::slotTargetSelected);
}
void ConfigView::readConfig(const KConfigGroup &group)
void upgradeConfigV1_3(QStringList &targetConfStrs)
{
m_targetCombo->clear();
if (targetConfStrs.count() == 3) {
// valid old style config, translate it now; note the
// reordering happening here!
QStringList temp;
temp << targetConfStrs[2];
temp << targetConfStrs[1];
targetConfStrs.swap(temp);
}
}
int version = group.readEntry(QStringLiteral("version"), 4);
int targetCount = group.readEntry(QStringLiteral("targetCount"), 1);
int lastTarget = group.readEntry(QStringLiteral("lastTarget"), 0);
QString targetKey(QStringLiteral("target_%1"));
void upgradeConfigV3_4(QStringList &targetConfStrs, const QStringList &args)
{
targetConfStrs.prepend(targetConfStrs[0].right(15));
QStringList targetConfStrs;
const QString targetName(QStringLiteral("%1<%2>"));
for (int i = 0; i < targetCount; i++) {
targetConfStrs = group.readEntry(targetKey.arg(i), QStringList());
if (targetConfStrs.count() == 0) {
continue;
for (int i = 0; i < args.size(); ++i) {
const QString &argStr = args.at(i);
if (i > 0) {
// copy the firsts and change the arguments
targetConfStrs[0] = targetName.arg(targetConfStrs[0]).arg(i + 1);
if (targetConfStrs.count() > 3) {
targetConfStrs[3] = argStr;
}
}
}
}
if ((version == 1) && (targetConfStrs.count() == 3)) {
// valid old style config, translate it now; note the
// reordering happening here!
QStringList temp;
temp << targetConfStrs[2];
temp << targetConfStrs[1];
targetConfStrs = temp;
}
void upgradeConfigV4_5(QStringList targetConfStrs, QJsonObject &conf)
{
typedef ConfigView::TargetStringOrder I;
if (version < 4) {
targetConfStrs.prepend(targetConfStrs[0].right(15));
}
while (targetConfStrs.count() < I::CustomStartIndex) {
targetConfStrs << QString();
}
if (targetConfStrs.count() > NameIndex) {
m_targetCombo->addItem(targetConfStrs[NameIndex], targetConfStrs);
auto insertField = [&conf, targetConfStrs](const QString &field, I index) {
const QString value = targetConfStrs[index].trimmed();
if (!value.isEmpty()) {
conf[field] = value;
}
};
// read fields
insertField(F_TARGET, I::NameIndex);
insertField(F_FILE, I::ExecIndex);
insertField(F_WORKDIR, I::WorkDirIndex);
insertField(F_ARGS, I::ArgsIndex);
// read advanced settings
for (int i = 0; i < I::GDBIndex; ++i) {
targetConfStrs.takeFirst();
}
const auto advanced = AdvancedGDBSettings::upgradeConfigV4_5(targetConfStrs);
if (!advanced.isEmpty()) {
conf[QStringLiteral("advanced")] = advanced;
}
}
QByteArray serialize(const QJsonObject obj)
{
const QJsonDocument doc(obj);
return doc.toJson(QJsonDocument::Compact);
}
QJsonObject unserialize(const QString map)
{
const auto doc = QJsonDocument::fromJson(map.toLatin1());
return doc.object();
}
void ConfigView::readConfig(const KConfigGroup &group)
{
m_targetCombo->clear();
const int version = group.readEntry(QStringLiteral("version"), CONFIG_VERSION);
const int targetCount = group.readEntry(QStringLiteral("targetCount"), 1);
int lastTarget = group.readEntry(QStringLiteral("lastTarget"), 0);
const QString targetKey(QStringLiteral("target_%1"));
QStringList args;
if (version < 4) {
// all targets now have only one argument string
int argListsCount = group.readEntry(QStringLiteral("argsCount"), 0);
QString argsKey(QStringLiteral("args_%1"));
QString targetName(QStringLiteral("%1<%2>"));
QString argStr;
int count = m_targetCombo->count();
for (int i = 0; i < argListsCount; i++) {
argStr = group.readEntry(argsKey.arg(i), QString());
for (int j = 0; j < count; j++) {
targetConfStrs = m_targetCombo->itemData(j).toStringList();
if (i > 0) {
// copy the firsts and change the arguments
targetConfStrs[0] = targetName.arg(targetConfStrs[0]).arg(i + 1);
if (targetConfStrs.count() > 3) {
targetConfStrs[3] = argStr;
}
m_targetCombo->addItem(targetConfStrs[0], targetConfStrs);
}
const int argsListsCount = group.readEntry(QStringLiteral("argsCount"), 0);
const QString argsKey(QStringLiteral("args_%1"));
const QString targetName(QStringLiteral("%1<%2>"));
for (int nArg = 0; nArg < argsListsCount; ++nArg) {
const QString argStr = group.readEntry(argsKey.arg(nArg), QString());
}
}
for (int i = 0; i < targetCount; i++) {
QJsonObject targetConf;
if (version < 5) {
QStringList targetConfStrs;
targetConfStrs = group.readEntry(targetKey.arg(i), QStringList());
if (targetConfStrs.count() == 0) {
continue;
}
if (version == 1) {
upgradeConfigV1_3(targetConfStrs);
}
if (version < 4) {
upgradeConfigV3_4(targetConfStrs, args);
}
if (version < 5) {
upgradeConfigV4_5(targetConfStrs, targetConf);
}
} else {
const QString data = group.readEntry(targetKey.arg(i), QString());
targetConf = unserialize(data);
}
if (!targetConf.isEmpty()) {
m_targetCombo->addItem(targetConf[QStringLiteral("target")].toString(), targetConf);
}
}
// make sure there is at least one item.
if (m_targetCombo->count() == 0) {
slotAddTarget();
......@@ -310,16 +383,15 @@ void ConfigView::writeConfig(KConfigGroup &group)
// make sure the data is up to date before writing
saveCurrentToIndex(m_currentTarget);
group.writeEntry("version", 4);
group.writeEntry("version", CONFIG_VERSION);
QString targetKey(QStringLiteral("target_%1"));
QStringList targetConfStrs;
group.writeEntry("targetCount", m_targetCombo->count());
group.writeEntry("lastTarget", m_targetCombo->currentIndex());
for (int i = 0; i < m_targetCombo->count(); i++) {
targetConfStrs = m_targetCombo->itemData(i).toStringList();
group.writeEntry(targetKey.arg(i), targetConfStrs);
QJsonObject targetConf = m_targetCombo->itemData(i).toJsonObject();
group.writeEntry(targetKey.arg(i), serialize(targetConf));
}
group.writeEntry("alwaysFocusOnInput", m_takeFocus->isChecked());
......@@ -333,34 +405,20 @@ const GDBTargetConf ConfigView::currentGDBTarget() const
cfg.executable = m_executable->text();
cfg.workDir = m_workingDirectory->text();
cfg.arguments = m_arguments->text();
cfg.customInit = m_advanced->configs();
// Note: AdvancedGDBSettings::GDBIndex == 0
if ((cfg.customInit.size() >= 0) && !cfg.customInit[0].isEmpty()) {
cfg.gdbCmd = cfg.customInit[0];
cfg.customInit.removeFirst();
} else {
cfg.gdbCmd = QStringLiteral("gdb");
}
// remove empty strings in the customInit
int i = cfg.customInit.size() - 1;
while (i >= 0) {
if (cfg.customInit[i].isEmpty()) {
cfg.customInit.removeAt(i);
} else if (cfg.customInit[i].startsWith(QLatin1String("set directories "))) {
QString paths = cfg.customInit[i];
paths.remove(QStringLiteral("set directories "));
cfg.srcPaths = paths.split(pathSeparator, Qt::SkipEmptyParts);
const auto advancedConfig = m_advanced->configs();
{
cfg.gdbCmd = advancedConfig[AdvancedGDBSettings::F_GDB].toString(QStringLiteral("gdb"));
cfg.srcPaths.clear();
for (const auto &value : advancedConfig[AdvancedGDBSettings::F_SRC_PATHS].toArray()) {
cfg.srcPaths << value.toString();
}
i--;
cfg.customInit = AdvancedGDBSettings::commandList(advancedConfig);
}
return cfg;
}
const static QString F_FILE = QStringLiteral("file");
const static QString F_WORKDIR = QStringLiteral("workdir");
const static QString F_ARGS = QStringLiteral("args");
const static QString F_PID = QStringLiteral("pid");
const DAPTargetConf ConfigView::currentDAPTarget(bool full) const
{
DAPTargetConf cfg;
......@@ -464,26 +522,23 @@ void ConfigView::slotTargetSelected(int index)
void ConfigView::slotAddTarget()
{
QStringList targetConfStrs;
QJsonObject targetConf;
targetConfStrs << i18n("Target %1", m_targetCombo->count() + 1);
targetConfStrs << QString();
targetConfStrs << QString();
targetConfStrs << QString();
targetConf[F_TARGET] = i18n("Target %1", m_targetCombo->count() + 1);
m_targetCombo->addItem(targetConfStrs[NameIndex], targetConfStrs);
m_targetCombo->addItem(targetConf[F_TARGET].toString(), targetConf);
m_targetCombo->setCurrentIndex(m_targetCombo->count() - 1);
}
void ConfigView::slotCopyTarget()
{
QStringList tmp = m_targetCombo->itemData(m_targetCombo->currentIndex()).toStringList();
if (tmp.empty()) {
QJsonObject tmp = m_targetCombo->itemData(m_targetCombo->currentIndex()).toJsonObject();
if (tmp.isEmpty()) {
slotAddTarget();
return;
}
tmp[NameIndex] = i18n("Target %1", m_targetCombo->count() + 1);
m_targetCombo->addItem(tmp[NameIndex], tmp);
tmp[F_TARGET] = i18n("Target %1", m_targetCombo->count() + 1);
m_targetCombo->addItem(tmp[F_TARGET].toString(), tmp);
m_targetCombo->setCurrentIndex(m_targetCombo->count() - 1);
}
......@@ -702,43 +757,28 @@ ConfigView::Field &ConfigView::getDapField(const QString &fieldName)
void ConfigView::setAdvancedOptions()
{
QStringList tmp = m_targetCombo->itemData(m_targetCombo->currentIndex()).toStringList();
// make sure we have enough strings;