--------------------------------------------------------------------------- cty.dat parser Format: Entity Name: CQ: ITU: Continent: lat: lon: tz: PrimaryPrefix: alias1,alias2,=EXACT1,=EXACT2; Alias tokens may have zone overrides in () or [] which we strip. Tokens starting with '=' are exact callsign matches. ---------------------------------------------------------------------------
| 63 | // Tokens starting with '=' are exact callsign matches. |
| 64 | // --------------------------------------------------------------------------- |
| 65 | void CtyDatParser::parse(const QStringList& lines) |
| 66 | { |
| 67 | m_exactMatch.clear(); |
| 68 | m_prefixTable.clear(); |
| 69 | m_entityByPrefix.clear(); |
| 70 | m_maxPrefixLen = 0; |
| 71 | |
| 72 | // We accumulate alias lines until we hit a new entity header. |
| 73 | DxccEntity current; |
| 74 | bool inEntity = false; |
| 75 | QString aliasBuffer; |
| 76 | |
| 77 | auto commitEntity = [&]() { |
| 78 | if (!inEntity || current.primaryPrefix.isEmpty()) |
| 79 | return; |
| 80 | |
| 81 | m_entityByPrefix.insert(current.primaryPrefix, current); |
| 82 | |
| 83 | // Register primary prefix itself |
| 84 | m_prefixTable.insert(current.primaryPrefix, current.primaryPrefix); |
| 85 | m_maxPrefixLen = std::max(m_maxPrefixLen, (int)current.primaryPrefix.length()); |
| 86 | |
| 87 | // Parse accumulated alias buffer |
| 88 | QString buf = aliasBuffer; |
| 89 | buf.remove('\n'); |
| 90 | buf.remove('\r'); |
| 91 | // Remove trailing semicolon |
| 92 | buf = buf.trimmed(); |
| 93 | if (buf.endsWith(';')) buf.chop(1); |
| 94 | |
| 95 | const QStringList tokens = buf.split(',', Qt::SkipEmptyParts); |
| 96 | for (const QString& raw : tokens) { |
| 97 | const QString tok = raw.trimmed(); |
| 98 | if (tok.isEmpty()) continue; |
| 99 | |
| 100 | if (tok.startsWith('=')) { |
| 101 | // Exact match |
| 102 | const QString exact = cleanPrefix(tok.mid(1)).toUpper(); |
| 103 | if (!exact.isEmpty()) |
| 104 | m_exactMatch.insert(exact, current.primaryPrefix); |
| 105 | } else { |
| 106 | // Prefix |
| 107 | const QString pfx = cleanPrefix(tok).toUpper(); |
| 108 | if (!pfx.isEmpty()) { |
| 109 | m_prefixTable.insert(pfx, current.primaryPrefix); |
| 110 | m_maxPrefixLen = std::max(m_maxPrefixLen, (int)pfx.length()); |
| 111 | } |
| 112 | } |
| 113 | } |
| 114 | }; |
| 115 | |
| 116 | // Regex for header line: "Entity Name: CQ: ITU: Cont: lat: lon: tz: Prefix:" |
| 117 | // Fields are colon-separated on the first line. |
| 118 | static const QRegularExpression headerRe( |
| 119 | R"(^([^:]+):\s*(\d+):\s*(\d+):\s*(\w+):\s*[\d\.\-]+:\s*[\d\.\-]+:\s*[\d\.\-]+:\s*([^:]+):)"); |
| 120 | |
| 121 | for (const QString& line : lines) { |
| 122 | // Header line — doesn't start with whitespace |
nothing calls this directly
no test coverage detected