guts
Loading...
Searching...
No Matches
gutilities.cc
Go to the documentation of this file.
1// gutilities
2#include "gutilities.h"
3#include "gutsConventions.h"
4
5// Numbers / strings with units / io interface to CLHEP units
6#include "CLHEP/Units/PhysicalConstants.h"
7
8// geant4
9#include "G4UImanager.hh"
10
11// C and POSIX
12#include <dirent.h>
13#include <locale.h>
14#include <sys/stat.h>
15
16// c++
17// algorithm for 'transform'
18#include <algorithm>
19#include <sstream>
20#include <unordered_map>
21#include <iostream>
22#include <fstream>
23#include <vector>
24#include <charconv>
25#include <filesystem>
26
27namespace gutilities {
28/*
29 * Trim leading/trailing spaces and tabs from an owning std::string.
30 *
31 * Notes:
32 * - Whitespace considered here is strictly ' ' and '\t' (tab).
33 * - If the input is all whitespace (or empty), returns an empty string.
34 *
35 * See the API documentation in gutilities.h for full Doxygen docs.
36 */
37string removeLeadingAndTrailingSpacesFromString(const std::string& input) {
38 size_t startPos = input.find_first_not_of(" \t"); // Find the first non-whitespace character
39 size_t endPos = input.find_last_not_of(" \t"); // Find the last non-whitespace character
40
41 // If all spaces or empty, return an empty string
42 if (startPos == std::string::npos || endPos == std::string::npos) { return ""; }
43
44 // Return the substring between startPos and endPos
45 return input.substr(startPos, endPos - startPos + 1);
46}
47
48/*
49 * Fast trim for std::string_view.
50 *
51 * Notes:
52 * - No allocations: adjusts the view by removing prefix/suffix.
53 * - Uses std::isspace (locale-sensitive) to classify whitespace.
54 *
55 * See the API documentation in gutilities.h for full Doxygen docs.
56 */
57std::string_view removeLeadingAndTrailingSpacesFromString(std::string_view s) {
58 while (!s.empty() && std::isspace(static_cast<unsigned char>(s.front()))) s.remove_prefix(1);
59 while (!s.empty() && std::isspace(static_cast<unsigned char>(s.back()))) s.remove_suffix(1);
60 return s;
61}
62
63/*
64 * Remove all literal spaces ' ' from a string.
65 *
66 * See the API documentation in gutilities.h for full Doxygen docs.
67 */
68string removeAllSpacesFromString(const std::string& str) {
69 string result = str;
70 result.erase(std::remove(result.begin(), result.end(), ' '), result.end());
71 return result;
72}
73
74/*
75 * Extract the filename component from a POSIX-style path (splitting on '/').
76 *
77 * See the API documentation in gutilities.h for full Doxygen docs.
78 */
79string getFileFromPath(const std::string& path) {
80 std::size_t lastSlashPos = path.find_last_of('/');
81 if (lastSlashPos == std::string::npos) {
82 // No slashes found, return the entire path
83 return path;
84 }
85 return path.substr(lastSlashPos + 1);
86}
87
88/*
89 * Extract the directory component from a POSIX-style path (splitting on '/').
90 *
91 * See the API documentation in gutilities.h for full Doxygen docs.
92 */
93string getDirFromPath(const std::string& path) {
94 auto lastSlash = path.find_last_of('/');
95 if (lastSlash == std::string::npos) return ".";
96 return path.substr(0, lastSlash);
97}
98
99namespace fs = std::filesystem;
100
101
102/*
103 * Tokenize a string on whitespace into a vector.
104 *
105 * See the API documentation in gutilities.h for full Doxygen docs.
106 */
107vector<std::string> getStringVectorFromString(const std::string& input) {
108 std::vector<std::string> pvalues;
109 std::stringstream plist(input);
110 string tmp;
111 while (plist >> tmp) {
112 string trimmed = removeLeadingAndTrailingSpacesFromString(tmp);
113 if (!trimmed.empty()) { pvalues.push_back(trimmed); }
114 }
115 return pvalues;
116}
117
118/*
119 * Replace any character found in 'toReplace' with the string 'replacement'.
120 *
121 * See the API documentation in gutilities.h for full Doxygen docs.
122 */
123string replaceCharInStringWithChars(const std::string& input, const std::string& toReplace,
124 const std::string& replacement) {
125 string output;
126 for (const char& ch : input) {
127 if (toReplace.find(ch) != std::string::npos) { output.append(replacement); }
128 else { output.push_back(ch); }
129 }
130 return output;
131}
132
133/*
134 * Replace all occurrences of substring 'from' with substring 'to'.
135 *
136 * See the API documentation in gutilities.h for full Doxygen docs.
137 */
138string replaceAllStringsWithString(const string& source, const string& from, const string& to) {
139 if (from.empty()) return source; // Avoid infinite loop
140
141 string newString;
142 size_t lastPos = 0;
143 size_t findPos = source.find(from, lastPos);
144
145 while (findPos != string::npos) {
146 // Append part before the match and the replacement string
147 newString.append(source, lastPos, findPos - lastPos);
148 newString += to;
149 lastPos = findPos + from.length();
150 findPos = source.find(from, lastPos);
151 }
152
153 // Append the remaining part of the string after the last occurrence
154 newString += source.substr(lastPos);
155
156 return newString;
157}
158
159
160/*
161 * Left-pad a string using the first character of 'c' until length reaches ndigits.
162 *
163 * See the API documentation in gutilities.h for full Doxygen docs.
164 */
165string fillDigits(const string& word, const string& c, int ndigits) {
166 if (c.empty() || ndigits <= static_cast<int>(word.size())) return word; // Return original if no padding needed
167
168 string filled;
169
170 int toFill = ndigits - static_cast<int>(word.size());
171 filled.reserve(ndigits);
172
173 filled.append(toFill, c[0]); // Use the first character of the string 'c'
174 filled += word;
175
176 return filled;
177}
178
196static bool parse_double_clocale(std::string_view sv, double& out) {
197 std::string tmp(sv); // strtod_l needs a 0-terminated buffer
198#if defined(_WIN32)
199 _locale_t loc = _create_locale(LC_NUMERIC, "C");
200 char* end = nullptr;
201 out = _strtod_l(tmp.c_str(), &end, loc);
202 _free_locale(loc);
203 return end == tmp.c_str() + tmp.size();
204#else
205 locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
206 char* end = nullptr;
207 out = strtod_l(tmp.c_str(), &end, loc);
208 freelocale(loc);
209 return end == tmp.c_str() + tmp.size();
210#endif
211}
212
213
214// --- strict, locale-independent getG4Number: only accepts '*' as unit sep ---
215double getG4Number(const string& v, bool warnIfNotUnit) {
217 if (value.empty()) {
218 std::cerr << FATALERRORL << "empty numeric string.\n";
219 exit(EC__G4NUMBERERROR);
220 }
221
222 // Normalize a single decimal comma to dot when no dot is present
223 if (value.find('.') == string::npos) {
224 size_t firstComma = value.find(',');
225 if (firstComma != string::npos && value.find(',', firstComma + 1) == string::npos) {
226 value = replaceAllStringsWithString(value, ",", ".");
227 }
228 }
229
230 const size_t starCount = static_cast<size_t>(std::count(value.begin(), value.end(), '*'));
231
232 // --- Case 1: no '*' → pure number (strictly no trailing garbage) ---
233 if (value.find('*') == string::npos) {
234 double out = 0.0;
235 // normalize a single decimal comma to dot if needed
236 if (value.find('.') == string::npos) {
237 auto firstComma = value.find(',');
238 if (firstComma != string::npos && value.find(',', firstComma + 1) == string::npos)
239 value = replaceAllStringsWithString(value, ",", ".");
240 }
241 if (!parse_double_clocale(value, out)) {
242 std::cerr << FATALERRORL << "missing '*' before unit or invalid number in <" << v << ">.\n";
243 exit(EC__G4NUMBERERROR);
244 }
245 if (warnIfNotUnit && out != 0.0) {
246 std::cerr << " ! Warning: value " << v << " does not contain units." << std::endl;
247 }
248 return out;
249 }
250
251
252 // --- Case 2: must be exactly one '*' ---
253 if (starCount > 1) {
254 std::cerr << FATALERRORL << "multiple '*' separators are not allowed in <" << v << ">.\n";
255 exit(EC__G4NUMBERERROR);
256 }
257
258 // --- Exactly one '*' → split "<number>*<unit>" ---
259 const size_t pos = value.find('*');
260 string left = removeLeadingAndTrailingSpacesFromString(value.substr(0, pos));
261 string right = removeLeadingAndTrailingSpacesFromString(value.substr(pos + 1));
262 if (left.empty() || right.empty()) {
263 std::cerr << FATALERRORL << "expected '<number>*<unit>', got <" << v << ">.\n";
264 exit(EC__G4NUMBERERROR);
265 }
266
267 // normalize a single decimal comma in the numeric part
268 if (left.find('.') == string::npos) {
269 auto c = left.find(',');
270 if (c != string::npos && left.find(',', c + 1) == string::npos)
271 left = replaceAllStringsWithString(left, ",", ".");
272 }
273
274 double numeric = 0.0;
275 if (!parse_double_clocale(left, numeric)) {
276 std::cerr << FATALERRORL << "invalid numeric part before '*' in <" << v << ">.\n";
277 exit(EC__G4NUMBERERROR);
278 }
279
280 // sanitize unit and proceed with your existing unit table logic...
281 right = replaceAllStringsWithString(right, "µ", "u");
282 string unit = convertToLowercase(right);
283
284 // (keep your unitConversion map and SI prefix handling as-is)
285
286
287 // Unit table (lowercase keys)
288 static const std::unordered_map<string, double> unitConversion = {
289 // length
290 {"m", CLHEP::m}, {"cm", CLHEP::cm}, {"mm", CLHEP::mm},
291 {"um", 1E-6 * CLHEP::m}, {"fm", 1E-15 * CLHEP::m},
292 {"inch", 2.54 * CLHEP::cm}, {"inches", 2.54 * CLHEP::cm},
293 // angle
294 {"deg", CLHEP::deg}, {"degrees", CLHEP::deg}, {"arcmin", CLHEP::deg / 60.0},
295 {"rad", CLHEP::rad}, {"mrad", CLHEP::mrad},
296 // energy
297 {"ev", CLHEP::eV}, {"kev", 1e3 * CLHEP::eV}, {"mev", CLHEP::MeV}, {"gev", CLHEP::GeV},
298 // magnetic field
299 {"t", CLHEP::tesla}, {"tesla", CLHEP::tesla}, {"t/m", CLHEP::tesla / CLHEP::m},
300 {"gauss", CLHEP::gauss}, {"kilogauss", 1000.0 * CLHEP::gauss},
301 // time
302 {"s", CLHEP::s}, {"ns", CLHEP::ns}, {"ms", CLHEP::ms}, {"us", CLHEP::us},
303 // dimensionless
304 {"counts", 1.0}
305 };
306
307 // Exact unit match
308 if (auto it = unitConversion.find(unit); it != unitConversion.end()) {
309 return numeric * it->second;
310 }
311
312 // SI prefix handling: mT, uT, mm, um, etc.
313 auto si_prefix_factor = [](char p) -> double {
314 switch (p) {
315 case 'Y': return 1e24;
316 case 'Z': return 1e21;
317 case 'E': return 1e18;
318 case 'P': return 1e15;
319 case 'T': return 1e12;
320 case 'G': return 1e9;
321 case 'M': return 1e6;
322 case 'k': return 1e3;
323 case 'h': return 1e2;
324 case 'd': return 1e-1;
325 case 'c': return 1e-2;
326 case 'm': return 1e-3;
327 case 'u': return 1e-6;
328 case 'n': return 1e-9;
329 case 'p': return 1e-12;
330 case 'f': return 1e-15;
331 case 'a': return 1e-18;
332 case 'z': return 1e-21;
333 case 'y': return 1e-24;
334 default: return 0.0;
335 }
336 };
337
338 if (unit.size() >= 2) {
339 const double pf = si_prefix_factor(unit.front());
340 if (pf != 0.0) {
341 const string base = unit.substr(1);
342 if (auto it2 = unitConversion.find(base); it2 != unitConversion.end()) {
343 return numeric * pf * it2->second;
344 }
345 }
346 }
347
348 // Unknown unit: warn & return numeric part (keep your legacy behavior)
349 std::cerr << GWARNING << ">" << right << "<: unit not recognized for string <" << v << ">" << std::endl;
350 return numeric;
351}
352
353
354double getG4Number(double input, const string& unit) {
355 string gnumber = std::to_string(input) + "*" + unit;
356 return getG4Number(gnumber, true);
357}
358
359vector<double> getG4NumbersFromStringVector(const vector<string>& vstring, bool warnIfNotUnit) {
360 vector<double> output;
361 output.reserve(vstring.size());
362
363 for (const auto& s : vstring) { output.push_back(getG4Number(s, warnIfNotUnit)); }
364
365 return output;
366}
367
368vector<double> getG4NumbersFromString(const string& vstring, bool warnIfNotUnit) {
369 return getG4NumbersFromStringVector(getStringVectorFromStringWithDelimiter(vstring, ","), warnIfNotUnit);
370}
371
372
373string parseFileAndRemoveComments(const string& filename, const string& commentChars, int verbosity) {
374 // Reading file
375 std::ifstream in(filename);
376 if (!in) {
377 std::cerr << FATALERRORL << "can't open input file " << filename << ". Check your spelling. " << std::endl;
378 exit(EC__FILENOTFOUND);
379 }
380
381 std::stringstream strStream;
382 if (verbosity > 0) {
383 std::cout << std::endl << CIRCLEITEM << " Loading string from " << filename << std::endl;
384 }
385 strStream << in.rdbuf(); // Read the file
386 in.close();
387
388 string parsedString = strStream.str();
389
390 // Removing all occurrences of commentChars
391 size_t nFPos;
392 while ((nFPos = parsedString.find(commentChars)) != string::npos) {
393 size_t firstNL = parsedString.rfind('\n', nFPos);
394 size_t secondNL = parsedString.find('\n', nFPos);
395 size_t eraseStart = (firstNL == string::npos) ? 0 : firstNL;
396 size_t eraseLen = (secondNL == string::npos)
397 ? string::npos
398 : secondNL - eraseStart;
399 parsedString.erase(eraseStart, eraseLen);
400 }
401
402 return parsedString;
403}
404
405string retrieveStringBetweenChars(const string& input, const string& firstDelimiter,
406 const string& secondDelimiter) {
407 size_t firstpos = input.find(firstDelimiter);
408 size_t secondpos = input.find(secondDelimiter);
409
410 if (firstpos == string::npos || secondpos == string::npos) { return ""; }
411 return input.substr(firstpos + firstDelimiter.length(), secondpos - firstpos - firstDelimiter.length());
412}
413
414vector<string> getStringVectorFromStringWithDelimiter(const string& input, const string& x) {
415 vector<string> pvalues;
416 string tmp;
417
418 for (char ch : input) {
419 if (ch != x[0]) { tmp += ch; }
420 else {
421 if (!tmp.empty()) {
422 pvalues.push_back(removeLeadingAndTrailingSpacesFromString(tmp));
423 tmp.clear();
424 }
425 }
426 }
427
428 if (!tmp.empty()) { pvalues.push_back(removeLeadingAndTrailingSpacesFromString(tmp)); }
429
430 return pvalues;
431}
432
433
434// string search for a path with <name> from a possible list of absolute paths
435// returns UNINITIALIZEDSTRINGQUANTITY if not found
436// the filesystem solution does not work on linux systems.
437// TODO: periodically try this?
438//#include <filesystem>
439//
440// string searchForDirInLocations(string dirName, vector <string> possibleLocations) {
441//
442// for (auto trialLocation: possibleLocations) {
443// string possibleDir = trialLocation + "/" + dirName;
444// if (std::filesystem::exists(possibleDir)) {
445// return possibleDir;
446// }
447// }
448// return UNINITIALIZEDSTRINGQUANTITY;
449// }
450//
451// vector <string> getListOfFilesInDirectory(string dirName, vector <string> extensions) {
452//
453// vector <string> fileList;
454//
455// for (const auto &entry: std::filesystem::directory_iterator(dirName)) {
456// for (auto &extension: extensions) {
457// if (entry.path().extension() == extension) {
458// fileList.push_back(entry.path().filename());
459// }
460// }
461// }
462//
463// return fileList;
464// }
465// end of TODO
466
467bool directoryExists(const std::string& path) {
468 struct stat info{};
469 if (stat(path.c_str(), &info) != 0) {
470 return false; // Path does not exist
471 }
472 return (info.st_mode & S_IFDIR) != 0; // Check if it's a directory
473}
474
475string searchForDirInLocations(const string& dirName, const vector<string>& possibleLocations) {
476 for (const auto& trialLocation : possibleLocations) {
477 string possibleDir = trialLocation + "/" + dirName;
478 if (directoryExists(possibleDir)) { return possibleDir; }
479 }
480 return "UNINITIALIZEDSTRINGQUANTITY";
481}
482
483
484bool hasExtension(const std::string& filename, const std::vector<std::string>& extensions) {
485 for (const auto& ext : extensions) {
486 if (filename.size() >= ext.size() &&
487 filename.compare(filename.size() - ext.size(), ext.size(), ext) == 0) { return true; }
488 }
489 return false;
490}
491
492vector<string> getListOfFilesInDirectory(const string& dirName, const vector<string>& extensions) {
493 vector<string> fileList;
494
495 DIR* dir = opendir(dirName.c_str());
496 if (dir) {
497 struct dirent* entry;
498 while ((entry = readdir(dir)) != nullptr) {
499 struct stat info{};
500 string filepath = dirName + "/" + entry->d_name;
501 if (stat(filepath.c_str(), &info) == 0 && S_ISREG(info.st_mode)) {
502 string filename = entry->d_name;
503 if (hasExtension(filename, extensions)) { fileList.push_back(filename); }
504 }
505 }
506 closedir(dir);
507 }
508
509 return fileList;
510}
511
512string convertToLowercase(const string& str) {
513 string lower = str;
514 transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
515 return lower;
516}
517
518
519template <class KEY, class VALUE>
520vector<KEY> getKeys(const map<KEY, VALUE>& map) {
521 vector<KEY> keys;
522 keys.reserve(map.size()); // Reserve space for efficiency
523
524 for (const auto& it : map) { keys.push_back(it.first); }
525
526 return keys;
527}
528
529randomModel stringToRandomModel(const std::string& str) {
530 static const std::unordered_map<std::string, randomModel> strToEnum = {
531 {"uniform", uniform},
532 {"gaussian", gaussian},
533 {"cosine", cosine},
534 {"sphere", sphere}
535 };
536
537 auto it = strToEnum.find(str);
538 if (it != strToEnum.end()) { return it->second; }
539 else { throw std::invalid_argument("Invalid string for randomModel: " + str); }
540}
541
542
543G4Colour makeG4Colour(std::string_view code, double opacity) {
544 if (code.empty()) throw std::invalid_argument("empty colour string");
545 if (code.front() == '#') code.remove_prefix(1);
546 if (code.size() != 6)
547 throw std::invalid_argument("colour must have 6 or 7 hex digits");
548
549 auto hexNibble = [](char c) -> unsigned {
550 if ('0' <= c && c <= '9') return c - '0';
551 c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
552 if ('A' <= c && c <= 'F') return c - 'A' + 10;
553 throw std::invalid_argument("invalid hex digit");
554 };
555
556 // ---- parse RRGGBB ----
557 unsigned rgb = 0;
558 for (int i = 0; i < 6; ++i)
559 rgb = (rgb << 4) | hexNibble(code[i]);
560
561 auto byteToDouble = [](unsigned byte) { return byte / 255.0; };
562 double r = byteToDouble((rgb >> 16) & 0xFF);
563 double g = byteToDouble((rgb >> 8) & 0xFF);
564 double b = byteToDouble(rgb & 0xFF);
565
566 return {r, g, b, opacity}; // G4Colour
567}
568
569std::optional<std::string> searchForFileInLocations(
570 const std::vector<std::string>& locations,
571 std::string_view filename) {
572 namespace fs = std::filesystem;
573
574 for (const auto& loc : locations) {
575 if (loc.empty()) continue;
576
577 fs::path p(loc);
578 fs::path candidate = (!filename.empty() && fs::is_directory(p))
579 ? (p / filename)
580 : p;
581
582 std::error_code ec;
583 const bool ok = fs::exists(candidate, ec) && fs::is_regular_file(candidate, ec);
584 if (ok) return candidate.string();
585 }
586 return std::nullopt;
587}
588
589bool is_unset(std::string_view s) {
591 if (s.empty()) return true;
592 // match your sentinel and YAML nully spellings
593 auto eq = [](std::string_view a, std::string_view b) {
594 if (a.size() != b.size()) return false;
595 for (size_t i = 0; i < a.size(); ++i)
596 if (std::tolower(static_cast<unsigned char>(a[i])) != std::tolower(static_cast<unsigned char>(b[i])))
597 return false;
598 return true;
599 };
600 return eq(s, UNINITIALIZEDSTRINGQUANTITY) || eq(s, "null") || eq(s, "~");
601}
602
603void apply_uimanager_commands(const std::string& command) {
604 G4UImanager* g4uim = G4UImanager::GetUIpointer();
605 if (g4uim == nullptr) { return; }
606 g4uim->ApplyCommand(command);
607}
608}
Public API for the gutilities namespace.
Common constants and console-formatting macros used across gutilities and related code.
#define GWARNING
Standardized warning label prefix (bold yellow).
#define EC__FILENOTFOUND
Process exit code used when an expected file cannot be opened or found.
#define CIRCLEITEM
Hollow bullet glyph used for list formatting in console logs.
#define EC__G4NUMBERERROR
Process exit code used when parsing a Geant4-style numeric string fails.
#define UNINITIALIZEDSTRINGQUANTITY
Sentinel string representing an uninitialized string quantity.
#define FATALERRORL
Standardized fatal error label prefix (bold red).
string replaceAllStringsWithString(const string &source, const string &from, const string &to)
Replaces all occurrences of a substring with another string.
double getG4Number(const string &v, bool warnIfNotUnit)
Converts a string representation of a number with optional units to a double.
vector< double > getG4NumbersFromString(const string &vstring, bool warnIfNotUnit)
Converts a comma-separated string of numbers with units to a vector of doubles.
string removeAllSpacesFromString(const std::string &str)
Removes all spaces from a string.
Definition gutilities.cc:68
vector< string > getStringVectorFromStringWithDelimiter(const string &input, const string &x)
Splits a string into a vector of substrings using a specified delimiter.
G4Colour makeG4Colour(std::string_view code, double opacity)
Convert a hex colour string to G4Colour.
randomModel stringToRandomModel(const std::string &str)
Converts a string to a corresponding randomModel enum value.
vector< string > getListOfFilesInDirectory(const string &dirName, const vector< string > &extensions)
Retrieves a list of files with specific extensions from a directory.
vector< double > getG4NumbersFromStringVector(const vector< string > &vstring, bool warnIfNotUnit)
Converts a vector of strings representing numbers with units to a vector of doubles.
string retrieveStringBetweenChars(const string &input, const string &firstDelimiter, const string &secondDelimiter)
Retrieves a substring between two specified delimiters in a string.
string replaceCharInStringWithChars(const std::string &input, const std::string &toReplace, const std::string &replacement)
Replaces all occurrences of specified characters in a string with another string.
string fillDigits(const string &word, const string &c, int ndigits)
Pads a string with a specified character until it reaches a desired length.
bool is_unset(std::string_view s)
Determine whether a string should be treated as "unset".
randomModel
Enumeration of random models.
Definition gutilities.h:413
@ gaussian
Gaussian distribution.
Definition gutilities.h:415
@ uniform
Uniform distribution.
Definition gutilities.h:414
@ sphere
Sphere distribution.
Definition gutilities.h:417
@ cosine
Cosine distribution.
Definition gutilities.h:416
string getDirFromPath(const std::string &path)
Extracts the directory path from a given file path.
Definition gutilities.cc:93
string convertToLowercase(const string &str)
Converts a string to lowercase.
bool directoryExists(const std::string &path)
Checks if a directory exists at the given path.
vector< KEY > getKeys(const map< KEY, VALUE > &map)
Retrieves all keys from a map.
string removeLeadingAndTrailingSpacesFromString(const std::string &input)
Removes leading and trailing spaces and tabs from a string.
Definition gutilities.cc:37
std::optional< std::string > searchForFileInLocations(const std::vector< std::string > &locations, std::string_view filename)
Search for a regular file across candidate locations.
void apply_uimanager_commands(const std::string &command)
Apply a single Geant4 UI command if a UI manager is available.
string searchForDirInLocations(const string &dirName, const vector< string > &possibleLocations)
Searches for a directory within a list of possible locations.
string parseFileAndRemoveComments(const string &filename, const string &commentChars, int verbosity)
Parses a file and removes all lines containing specified comment characters.
bool hasExtension(const std::string &filename, const std::vector< std::string > &extensions)
string getFileFromPath(const std::string &path)
Extracts the filename from a given file path.
Definition gutilities.cc:79
vector< std::string > getStringVectorFromString(const std::string &input)
Splits a string into a vector of strings using whitespace as delimiters.