- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll - stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close - utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP), add deferred drain in both Phase J and L - stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39, exchange ed25519_pubkey in both handshake directions - etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb - chat_sync.c: fix lk->conn NULL dereference for TCP links - test_stcp.c: update stcp_server_create/stcp_client_connect callsites - tools/chat_tcp_test: change transport udp→tcp
88 lines
2.8 KiB
C++
88 lines
2.8 KiB
C++
// 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;
|
|
}
|