#include #include #include #include #include #include static const std::regex number_regex_full(R"(\d+)"); static const std::regex number_regex_1to3(R"(\b\d{1,3}\b)"); // Find the first number in a line using the given regex bool find_first_number_in_line(const std::string& s, int& out, const std::regex& rx) { std::smatch m; if (std::regex_search(s, m, rx)) { out = std::stoi(m.str()); return true; } return false; } // Check if a line contains exactly 24 consecutive 'Ä' bool has_exactly_24_A(const std::string& s) { int count = 0; for (size_t i = 0; i <= s.size(); ++i) { if (i < s.size() && s[i] == (char)196) { count++; } else { if (count == 24) return true; // exact match found count = 0; // reset counter } } return false; } int main(int argc, char* argv[]) { if (argc < 3) { std::cerr << "Usage: " << argv[0] << " \n"; return 1; } // Read entire file into memory as lines std::ifstream infile(argv[1], std::ios::binary); if (!infile) { std::cerr << "Error opening input file.\n"; return 1; } std::ofstream outfile(argv[2], std::ios::binary); if (!outfile) { std::cerr << "Error opening output file.\n"; return 1; } std::vector lines; std::string line; while (std::getline(infile, line)) { if (!infile.eof()) line += '\n'; // preserve original line endings lines.push_back(line); } // Detect if document should be modified bool has_bbgyro = false; bool has_subs = false; for (const auto& l : lines) { if (!has_bbgyro && l.find("BBGYRS") != std::string::npos) has_bbgyro = true; if (!has_subs && l.find("SUBS") != std::string::npos) has_subs = true; if (has_bbgyro || has_subs) break; } // If neither BBGYRO nor SUBS appears, pass file through unmodified if (!has_bbgyro && !has_subs) { infile.clear(); infile.seekg(0, std::ios::beg); outfile << infile.rdbuf(); // exact byte-for-byte copy return 0; } const std::string marker = "F.L.C.M. %"; // === 1) Find marker index === bool marker_found = false; size_t marker_index = 0; for (size_t i = 0; i < lines.size(); ++i) { if (lines[i].find(marker) != std::string::npos) { marker_found = true; marker_index = i; break; } } if (!marker_found) { // Marker not found, write original file unchanged infile.clear(); infile.seekg(0, std::ios::beg); outfile << infile.rdbuf(); return 0; } // === 2) Extract gyros from "BBGYRO" line === int gyros = 0; bool gyros_found = false; size_t bbgyro_index = std::string::npos; const std::string bbgyro_token = "BBGYRO"; for (size_t i = 0; i < lines.size(); ++i) { size_t pos = lines[i].find(bbgyro_token); if (pos != std::string::npos) { bbgyro_index = i; std::string tail = lines[i].substr(pos + bbgyro_token.size()); if (find_first_number_in_line(tail, gyros, number_regex_full)) { gyros_found = true; } break; } } // === 3) Extract total_subs === int total_subs = 0; auto find_total_after_start_index = [&](size_t start_index) -> bool { for (size_t j = start_index; j < lines.size(); ++j) { if (has_exactly_24_A(lines[j])) { if (j + 1 < lines.size()) { if (find_first_number_in_line(lines[j + 1], total_subs, number_regex_1to3)) { return true; } } } } return false; }; if (gyros_found) { find_total_after_start_index(bbgyro_index + 1); } else { // Fallback: second "SUBS" int subs_count = 0; size_t subs_index = std::string::npos; for (size_t i = 0; i < lines.size(); ++i) { if (lines[i].find("SUBS") != std::string::npos) { subs_count++; if (subs_count == 2) { subs_index = i; break; } } } if (subs_index != std::string::npos) { find_total_after_start_index(subs_index + 1); } } // === 4) Truncate document after the marker === std::vector truncated(lines.begin(), lines.begin() + marker_index + 1); // === 5) Insert TOTAL SUBS --- diff before first form feed === int diff = total_subs - gyros; const std::string insert_line = "\n\n\r ROLLS USED --- " + std::to_string(diff); bool inserted = false; for (const auto& l : truncated) { size_t ff_pos = l.find('\f'); if (!inserted && ff_pos != std::string::npos) { std::string modified = l.substr(0, ff_pos) + insert_line + l.substr(ff_pos); outfile << modified; inserted = true; } else { outfile << l; } } if (inserted) { // === 6) Append a form feed to the very end of the truncated document === outfile << '\f'; } return 0; }