Commit fb16cb93fdeff4dc079622a9f5bd498ae4057730

Authored by Henry Fredrick Schreiner
1 parent b5ea5ce0

Added file validator functions, not used yet

include/CLI.hpp
@@ -14,6 +14,12 @@ @@ -14,6 +14,12 @@
14 #include <iomanip> 14 #include <iomanip>
15 #include <numeric> 15 #include <numeric>
16 16
  17 +// C standard library
  18 +// Only needed for existence checking
  19 +// Could be swapped for filesystem in C++17
  20 +#include <sys/types.h>
  21 +#include <sys/stat.h>
  22 +
17 //#define CLI_LOG 1 23 //#define CLI_LOG 1
18 24
19 namespace CLI { 25 namespace CLI {
@@ -61,6 +67,7 @@ struct Combiner { @@ -61,6 +67,7 @@ struct Combiner {
61 bool positional; 67 bool positional;
62 bool required; 68 bool required;
63 bool defaulted; 69 bool defaulted;
  70 + std::vector<std::function<bool(std::string)>> validators;
64 71
65 /// Can be or-ed together 72 /// Can be or-ed together
66 Combiner operator | (Combiner b) const { 73 Combiner operator | (Combiner b) const {
@@ -69,18 +76,49 @@ struct Combiner { @@ -69,18 +76,49 @@ struct Combiner {
69 self.positional = positional || b.positional; 76 self.positional = positional || b.positional;
70 self.required = required || b.required; 77 self.required = required || b.required;
71 self.defaulted = defaulted || b.defaulted; 78 self.defaulted = defaulted || b.defaulted;
  79 + self.validators.reserve(validators.size() + b.validators.size());
  80 + self.validators.insert(self.validators.end(), validators.begin(), validators.end());
  81 + self.validators.insert(self.validators.end(), b.validators.begin(), b.validators.end());
72 return self; 82 return self;
73 } 83 }
74 84
75 /// Call to give the number of arguments expected on cli 85 /// Call to give the number of arguments expected on cli
76 Combiner operator() (int n) const { 86 Combiner operator() (int n) const {
77 - return Combiner{n, positional, required, defaulted}; 87 + Combiner self = *this;
  88 + self.num = n;
  89 + return *this;
  90 + }
  91 + /// Call to give a validator
  92 + Combiner operator() (std::function<bool(std::string)> func) const {
  93 + Combiner self = *this;
  94 + self.validators.push_back(func);
  95 + return self;
78 } 96 }
79 Combiner operator, (Combiner b) const { 97 Combiner operator, (Combiner b) const {
80 return *this | b; 98 return *this | b;
81 } 99 }
82 }; 100 };
83 101
  102 +bool _ExistingFile(std::string filename) {
  103 +// std::fstream f(name.c_str());
  104 +// return f.good();
  105 +// Fastest way according to http://stackoverflow.com/questions/12774207/fastest-way-to-check-if-a-file-exist-using-standard-c-c11-c
  106 + struct stat buffer;
  107 + return (stat(filename.c_str(), &buffer) == 0);
  108 +}
  109 +
  110 +bool _ExistingDirectory(std::string filename) {
  111 + struct stat buffer;
  112 + if(stat(filename.c_str(), &buffer) == 0 && (buffer.st_mode & S_IFDIR) )
  113 + return true;
  114 + return false;
  115 +}
  116 +
  117 +bool _NonexistentPath(std::string filename) {
  118 + struct stat buffer;
  119 + return stat(filename.c_str(), &buffer) != 0;
  120 +}
  121 +
84 struct Error : public std::runtime_error { 122 struct Error : public std::runtime_error {
85 Error(std::string parent, std::string name) : runtime_error(parent + ": " + name) {} 123 Error(std::string parent, std::string name) : runtime_error(parent + ": " + name) {}
86 }; 124 };
@@ -137,12 +175,20 @@ std::tuple&lt;std::string, std::string&gt; split(std::string fullname) { @@ -137,12 +175,20 @@ std::tuple&lt;std::string, std::string&gt; split(std::string fullname) {
137 } else throw BadNameString(fullname); 175 } else throw BadNameString(fullname);
138 } 176 }
139 177
140 -const Combiner NOTHING {0, false,false,false};  
141 -const Combiner REQUIRED {1, false,true, false};  
142 -const Combiner DEFAULT {1, false,false,true};  
143 -const Combiner POSITIONAL{1, true, false,false};  
144 -const Combiner ARGS {1, false,false,false};  
145 -const Combiner UNLIMITED {-1,false,false,false}; 178 +const Combiner NOTHING {0, false,false,false, {}};
  179 +const Combiner REQUIRED {1, false,true, false, {}};
  180 +const Combiner DEFAULT {1, false,false,true, {}};
  181 +const Combiner POSITIONAL {1, true, false,false, {}};
  182 +const Combiner ARGS {1, false,false,false, {}};
  183 +const Combiner UNLIMITED {-1,false,false,false, {}};
  184 +const Combiner VALIDATORS {1, false, false, false, {}};
  185 +
  186 +// Warning about using these validators:
  187 +// The files could be added/deleted after the validation. This is not common,
  188 +// but if this is a possibility, check the file you open afterwards
  189 +const Combiner ExistingFile {1, false, false, false, {_ExistingFile}};
  190 +const Combiner ExistingDirectory {1, false, false, false, {_ExistingDirectory}};
  191 +const Combiner NonexistentPath {1, false, false, false, {_NonexistentPath}};
146 192
147 typedef std::vector<std::vector<std::string>> results_t; 193 typedef std::vector<std::vector<std::string>> results_t;
148 typedef std::function<bool(results_t)> callback_t; 194 typedef std::function<bool(results_t)> callback_t;
tests/SmallTest.cpp
1 #include "CLI.hpp" 1 #include "CLI.hpp"
2 #include "gtest/gtest.h" 2 #include "gtest/gtest.h"
  3 +#include <cstdio>
  4 +#include <fstream>
3 5
4 6
5 TEST(Split, GoodStrings) { 7 TEST(Split, GoodStrings) {
@@ -41,3 +43,25 @@ TEST(Split, BadStrings) { @@ -41,3 +43,25 @@ TEST(Split, BadStrings) {
41 43
42 44
43 } 45 }
  46 +
  47 +TEST(Validators, FileExists) {
  48 + std::string myfile{"TestFileNotUsed.txt"};
  49 + EXPECT_FALSE(CLI::_ExistingFile(myfile));
  50 + bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
  51 + EXPECT_TRUE(ok);
  52 + EXPECT_TRUE(CLI::_ExistingFile(myfile));
  53 +
  54 + std::remove(myfile.c_str());
  55 + EXPECT_FALSE(CLI::_ExistingFile(myfile));
  56 +}
  57 +
  58 +TEST(Validators, FileNotExists) {
  59 + std::string myfile{"TestFileNotUsed.txt"};
  60 + EXPECT_TRUE(CLI::_NonexistentPath(myfile));
  61 + bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
  62 + EXPECT_TRUE(ok);
  63 + EXPECT_FALSE(CLI::_NonexistentPath(myfile));
  64 +
  65 + std::remove(myfile.c_str());
  66 + EXPECT_TRUE(CLI::_NonexistentPath(myfile));
  67 +}