// config_updater.cpp — Universal INI config file updater (like insert_or_replace_option in utun) #include "config_updater.h" #include #include static std::pair 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; }