Loading...
Searching...
No Matches
Bundling.cpp
Go to the documentation of this file.
1/*
2** This file is part of eOn.
3**
4** SPDX-License-Identifier: BSD-3-Clause
5**
6** Copyright (c) 2010--present, eOn Development Team
7** All rights reserved.
8**
9** Repo:
10** https://github.com/TheochemUI/eOn
11*/
12
13#include "eon/Bundling.h"
14#include "eon/EonLogger.h"
15
16#include <cctype>
17#include <cstdio>
18#include <cstdlib>
19#include <cstring>
20#include <filesystem>
21#include <system_error>
22#include <utility>
23
24namespace fs = std::filesystem;
25
26namespace eonc {
27
29 int num_bundle = -1;
30
31 for (const auto &entry : fs::directory_iterator(".")) {
32 std::string name = entry.path().filename().string();
33
34 if (name[0] == '.') {
35 continue;
36 }
37
38 // If "config" is not in the filename
39 // then skip.
40 if (name.find("config") == std::string::npos &&
41 name.find("ini") == std::string::npos) {
42 continue;
43 }
44
45 // Find the last underscore
46 auto upos = name.rfind('_');
47 if (upos == std::string::npos) {
48 continue;
49 }
50
51 // Find the last period
52 auto dpos = name.rfind('.');
53 if (dpos == std::string::npos || dpos <= upos) {
54 continue;
55 }
56
57 std::string numstr = name.substr(upos + 1, dpos - upos - 1);
58 if (!numstr.empty() &&
59 std::isdigit(static_cast<unsigned char>(numstr[0]))) {
60 int i = std::atoi(numstr.c_str()) + 1;
61 if (i > num_bundle) {
62 num_bundle = i;
63 }
64 }
65 }
66
67 return num_bundle;
68}
69
70int strchrcount(const char *haystack, char needle) {
71 int count = 0;
72 for (const char *ch = haystack; *ch != '\0'; ch++) {
73 if (*ch == needle) {
74 count++;
75 }
76 }
77 return count;
78}
79
80std::vector<std::string> unbundle(int number) {
81 std::vector<std::string> filenames;
82
83 for (const auto &entry : fs::directory_iterator(".")) {
84 std::string originalFilename = entry.path().filename().string();
85
86 if (originalFilename[0] == '.') {
87 continue;
88 }
89
90 int numUnderscores = strchrcount(originalFilename.c_str(), '_');
91 if (numUnderscores < 1) {
92 continue;
93 }
94
95 // Find the last underscore
96 auto upos = originalFilename.rfind('_');
97 if (upos == std::string::npos) {
98 continue;
99 }
100
101 // Find the last period
102 auto dpos = originalFilename.rfind('.');
103 if (dpos == std::string::npos || dpos <= upos) {
104 continue;
105 }
106
107 std::string numstr = originalFilename.substr(upos + 1, dpos - upos - 1);
108 if (!numstr.empty() &&
109 std::isdigit(static_cast<unsigned char>(numstr[0]))) {
110 int bundleNumber = std::atoi(numstr.c_str());
111 if (bundleNumber != number) {
112 continue;
113 }
114 }
115
116 std::string baseName = originalFilename.substr(0, upos);
117 // Drop the "_<n>" token and keep everything after it, so a compound
118 // extension (".con.gz", ".con.zst") survives whichever side of the
119 // underscore it sits on.
120 size_t extStart =
121 originalFilename.find_first_not_of("0123456789", upos + 1);
122 if (extStart == std::string::npos) {
123 extStart = originalFilename.size();
124 }
125 std::string newFilename = baseName + originalFilename.substr(extStart);
126
127 try {
128 fs::copy_file(originalFilename, newFilename,
129 fs::copy_options::overwrite_existing);
130 filenames.push_back(newFilename);
131 } catch (const fs::filesystem_error &e) {
132 EONC_LOG_ERROR("unbundle: problem copying {} to {}: {}", originalFilename,
133 newFilename, e.what());
134 }
135 }
136
137 return filenames;
138}
139
140void deleteUnbundledFiles(const std::vector<std::string> &unbundledFilenames) {
141 for (const auto &filename : unbundledFilenames) {
142 std::error_code ec;
143 fs::remove(filename, ec);
144 if (ec) {
145 EONC_LOG_ERROR("deleteUnbundledFiles: cannot remove {}: {}", filename,
146 ec.message());
147 }
148 }
149}
150
151namespace {
152
157std::pair<std::string, std::string>
158splitBundleExtension(const std::string &name) {
159 const size_t pos = name.find_last_of('.');
160 if (pos == std::string::npos) {
161 return {name, ""};
162 }
163 const std::string tail = name.substr(pos);
164 if (pos > 0 && (tail == ".gz" || tail == ".zst")) {
165 const size_t inner = name.find_last_of('.', pos - 1);
166 if (inner != std::string::npos) {
167 return {name.substr(0, inner), name.substr(inner)};
168 }
169 }
170 return {name.substr(0, pos), tail};
171}
172
173} // namespace
174
175void bundle(int number, const std::vector<std::string> &filenames,
176 std::vector<std::string> *bundledFilenames) {
177 for (const auto &filename : filenames) {
178 const auto [baseName, ext] = splitBundleExtension(filename);
179 const std::string newFilename =
180 baseName + "_" + std::to_string(number) + ext;
181
182 try {
183 fs::rename(filename, newFilename);
184 bundledFilenames->push_back(newFilename);
185 } catch (const fs::filesystem_error &e) {
186 EONC_LOG_ERROR("bundle: cannot rename {} to {}: {}", filename,
187 newFilename, e.what());
188 }
189 }
190}
191
192} // namespace eonc
#define EONC_LOG_ERROR(...)
Definition EonLogger.h:262
RAII resource manager for the ARTn C library with global synchronization.
void bundle(int number, const std::vector< std::string > &filenames, std::vector< std::string > *bundledFilenames)
Definition Bundling.cpp:175
void deleteUnbundledFiles(const std::vector< std::string > &unbundledFilenames)
Definition Bundling.cpp:140
std::vector< std::string > unbundle(int number)
Definition Bundling.cpp:80
int getBundleSize()
Definition Bundling.cpp:28
int strchrcount(const char *haystack, char needle)
Definition Bundling.cpp:70