You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

159 lines
5.4 KiB

// config_updater.cpp — Universal INI config file updater (like insert_or_replace_option in utun)
#include "config_updater.h"
#include <QFile>
#include <QTextStream>
static std::pair<int,int> find_section_bounds(const QStringList& lines, const QString& section) {
QString tag = "[" + section + "]";
for (int i = 0; i < lines.size(); i++) {
if (lines[i].trimmed() == tag) {
int se = lines.size();
for (int j = i + 1; j < lines.size(); j++) {
QString t = lines[j].trimmed();
if (t.startsWith('[') && t.endsWith(']')) { se = j; break; }
}
return {i, se};
}
}
return {-1, -1};
}
bool config_update_in_lines(QStringList& lines, const QString& section,
const QString& key, const QString& value, bool replace) {
auto bounds = find_section_bounds(lines, section);
if (bounds.first < 0) {
if (!lines.isEmpty() && !lines.last().trimmed().isEmpty())
lines.append("");
lines.append("[" + section + "]");
lines.append(key + "=" + value);
return true;
}
int si = bounds.first, se = bounds.second;
int ki = -1;
for (int i = si + 1; i < se; i++) {
int eq = lines[i].indexOf('=');
if (eq > 0 && lines[i].left(eq).trimmed() == key) { ki = i; break; }
}
QString newLine = key + "=" + value;
if (replace) {
if (ki >= 0)
lines[ki] = newLine;
else
lines.insert(si + 1, newLine);
} else {
if (ki >= 0) {
int lastKi = ki;
for (int i = ki + 1; i < se; i++) {
int eq = lines[i].indexOf('=');
if (eq > 0 && lines[i].left(eq).trimmed() == key) lastKi = i;
}
lines.insert(lastKi + 1, newLine);
} else {
lines.insert(si + 1, newLine);
}
}
return true;
}
bool config_update_option(const QString& filePath, const QString& section,
const QString& param, const QString& value, int flags) {
QFile f(filePath);
QStringList lines;
if (f.exists()) {
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) return false;
QTextStream in(&f);
while (!in.atEnd()) {
QString line = in.readLine(0);
if (line.endsWith('\r')) line.chop(1);
lines.append(line);
}
f.close();
}
bool replace = (flags != CONFIG_UPDATE_APPEND);
if (!config_update_in_lines(lines, section, param, value, replace))
return false;
if (!f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) return false;
QTextStream out(&f);
for (int i = 0; i < lines.size(); i++)
out << lines[i] << '\n';
f.close();
return true;
}
static bool is_section_header(const QString& line) {
QString t = line.trimmed();
return t.startsWith('[') && t.endsWith(']');
}
bool config_rewrite_servers(const QString& filePath, const QList<ConfigServer>& servers) {
QFile f(filePath);
QStringList lines;
if (f.exists()) {
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) return false;
QTextStream in(&f);
while (!in.atEnd()) {
QString line = in.readLine(0);
if (line.endsWith('\r')) line.chop(1);
lines.append(line);
}
f.close();
}
/* 1. Удалить все [server:*] секции (заголовок + ключи + хвостовую пустую строку-разделитель) */
QStringList filtered;
filtered.reserve(lines.size());
for (int i = 0; i < lines.size(); i++) {
QString t = lines[i].trimmed();
if (t.startsWith("[server:") && t.endsWith(']')) {
int j = i + 1;
while (j < lines.size() && !is_section_header(lines[j])) j++;
i = j - 1; /* for-loop сделает i++ → j: заголовок+ключи+пустая строка пропущены */
continue;
}
filtered << lines[i];
}
lines = filtered;
/* 2. Собрать блок секций [server:*] */
QStringList block;
for (const ConfigServer& s : servers) {
block << ("[server:" + s.name + "]");
block << ("addr=" + s.addr);
block << ("transport=" + (s.transport.isEmpty() ? QString("udp") : s.transport));
block << ("type=" + (s.type.isEmpty() ? QString("public") : s.type));
if (!s.netif.isEmpty()) block << ("netif=" + s.netif);
block << ""; /* разделитель: одна пустая строка между секциями */
}
/* 3. Точка вставки: после секции [global] (перед следующей секцией) */
int insertPos = lines.size();
for (int i = 0; i < lines.size(); i++) {
if (lines[i].trimmed() == "[global]") {
int j = i + 1;
while (j < lines.size() && !is_section_header(lines[j])) j++;
insertPos = j;
break;
}
}
/* 4. Вставить блок (если непустой) */
if (!block.isEmpty()) {
for (int i = block.size() - 1; i >= 0; i--)
lines.insert(insertPos, block[i]);
}
/* 5. Записать */
if (!f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) return false;
QTextStream out(&f);
for (const QString& l : lines)
out << l << '\n';
f.close();
return true;
}