| 632 | // ── Base address validation (supports simple +/- equations) ── |
| 633 | |
| 634 | QString validateBaseAddress(const QString& text) { |
| 635 | QString s = text.trimmed(); |
| 636 | if (s.isEmpty()) return QStringLiteral("empty"); |
| 637 | |
| 638 | int pos = 0; |
| 639 | bool firstTerm = true; |
| 640 | |
| 641 | while (pos < s.size()) { |
| 642 | // Skip whitespace |
| 643 | while (pos < s.size() && s[pos].isSpace()) pos++; |
| 644 | if (pos >= s.size()) break; |
| 645 | |
| 646 | // Check for +/- operator (except first term) |
| 647 | if (!firstTerm) { |
| 648 | if (s[pos] == '+' || s[pos] == '-') pos++; |
| 649 | else return QStringLiteral("invalid '%1'").arg(s[pos]); |
| 650 | while (pos < s.size() && s[pos].isSpace()) pos++; |
| 651 | } |
| 652 | |
| 653 | // Skip 0x prefix if present |
| 654 | if (pos + 1 < s.size() && s[pos] == '0' && (s[pos+1] == 'x' || s[pos+1] == 'X')) |
| 655 | pos += 2; |
| 656 | |
| 657 | // Must have at least one hex digit |
| 658 | int numStart = pos; |
| 659 | while (pos < s.size() && (s[pos].isDigit() || |
| 660 | (s[pos] >= 'a' && s[pos] <= 'f') || |
| 661 | (s[pos] >= 'A' && s[pos] <= 'F'))) pos++; |
| 662 | |
| 663 | if (pos == numStart) return QStringLiteral("invalid"); |
| 664 | |
| 665 | firstTerm = false; |
| 666 | } |
| 667 | |
| 668 | return {}; |
| 669 | } |
| 670 | |
| 671 | } // namespace rcx::fmt |