properties.append(&shortOpt, 1).append("\1", 1);
properties.append(longOpt, strlen(longOpt)).append("\1", 1);
properties.append((char*) &dataType, 1).append("\1", 1);
- properties.append(defaultValue, -1).append("\1", 1);
+ properties.append(defaultValue == NULL ? "" : defaultValue,
+ lengthValue).append("\1", 1);
m_properties.put(name, properties.str());
// Mark current value as default:
properties.set("!", 1);
// Copy default value as current value:
- properties.append(defaultValue, -1);
+ properties.append(defaultValue == NULL ? "" : defaultValue, lengthValue);
m_values.put(name, properties.str());
}
static const int IxDescr = 0;
char shortOpt, const char* longOpt, bool mayBeEmpty, const char* defaultVal){
addProperties(name, description, shortOpt, longOpt,
mayBeEmpty ? DT_STRING_EMPTY : DT_STRING,
- defaultVal, strlen(defaultVal));
+ defaultVal, defaultVal == NULL ? 0 : strlen(defaultVal));
}
/** @brief Returns the value of a boolean option.
#include "base/rebase.hpp"
#include "os/reos.hpp"
+static const char* s_empty[] = { NULL };
+
class TestReTraverser : public ReTestUnit {
public:
TestReTraverser() : ReTestUnit("ReTraverser", __FILE__){
}
void run(){
initTree();
+ testDirOptions();
+ checkSetFilterFromProgramArgs();
testDirStatistic();
testBasic();
}
+ void checkRelDate(time_t absTime, int relTime){
+ int diff = int(time(NULL) - relTime - absTime);
+ if (diff < 0)
+ diff = - diff;
+ checkT(diff < 2);
+ }
+
+ void testDirOptions(){
+ class MyOptions : public ReDirOptions{
+ public:
+ MyOptions() : ReDirOptions(s_empty, s_empty) {}
+ public:
+ int count() { return m_countCompoundUsage; }
+ const char** usage() { return m_compoundUsage; }
+ };
+ static const char* usage1[] = { "line1", "line2", NULL };
+ static const char* usage2[] = { "x1", "x2", "x3", NULL };
+ MyOptions opts;
+ opts.initCompoundUsage(sizeof usage1 + sizeof usage2);
+ opts.addCompundUsage(usage1);
+ opts.addCompundUsage(usage2);
+ checkEqu(7, opts.count());
+ checkEqu("line1", opts.usage()[0]);
+ checkEqu("line2", opts.usage()[1]);
+ checkEqu("x1", opts.usage()[2]);
+ checkEqu("x2", opts.usage()[3]);
+ checkEqu("x3", opts.usage()[4]);
+
+ // local time: +3600
+ const int DIFF = 3600;
+ checkEqu(24*60*60 - DIFF, (int) opts.checkDate("1970.01.02"));
+ checkEqu(24*60*60+3600-DIFF, (int) opts.checkDate("1970.01.02/1"));
+ checkEqu(24*60*60 + 2*3600 + 33*60 - DIFF, (int) opts.checkDate("1970.01.02/02:33"));
+ checkRelDate(opts.checkDate("3m"), 3*60);
+ checkRelDate(opts.checkDate("7h"), 7*60*60);
+ checkRelDate(opts.checkDate("5d"), 5*24*60*60);
+
+ checkEqu(125ll, opts.checkSize("125"));
+ checkEqu(125ll, opts.checkSize("125b"));
+ checkEqu(3000ll, opts.checkSize("3k"));
+ checkEqu(3*1024ll, opts.checkSize("3K"));
+ checkEqu(4*1000*1000ll, opts.checkSize("4m"));
+ checkEqu(4*1024*1024ll, opts.checkSize("4M"));
+ checkEqu(5*1000*1000*1000ll, opts.checkSize("5g"));
+ checkEqu(5*1024*1024*1024ll, opts.checkSize("5G"));
+
+ }
+ void checkSetFilterFromProgramArgs(){
+ ReDirOptions opts(s_empty, s_empty);
+ opts.addStandardFilterOptions();
+ char* argv[] = { "x", "-y1970.01.02", "-o1970.01.03",
+ "-D5", "-d1", "-z1k", "-Z2M", "*"
+ };
+ DirEntryFilter_t filter;
+ opts.programArgs().init(sizeof argv / sizeof argv[0], argv);
+ opts.setFilterFromProgramArgs(filter);
+ // local time: +3600
+ const int DIFF = 3600;
+ checkEqu(1*24*3600 - DIFF, (int) filter.m_maxAge);
+ checkEqu(2*24*3600 - DIFF, (int) filter.m_minAge);
+ checkEqu(5, (int) filter.m_maxDepth);
+ checkEqu(1, (int) filter.m_minDepth);
+ checkEqu(1000ll, filter.m_minSize);
+ checkEqu(2*1024*1024ll, filter.m_maxSize);
+ checkNN(filter.m_nodePatterns);
+ checkEqu("*", filter.m_nodePatterns->patternString());
+ }
void checkOneFile(const char* node, const char* parent, const ReHashList& hash){
ReByteBuffer path, expected;
checkT(hash.get(ReByteBuffer(node), path));
*/
ReDirOptions::ReDirOptions(const char* usage[], const char* examples[]) :
m_programArgs(usage, examples),
+ m_patternList(),
m_compoundUsage(NULL),
m_countCompoundUsage(0)
{
while(m_compoundUsage[start] != NULL)
assert(++start < m_countCompoundUsage);
for (int ix = 0; usage[ix] != NULL; ix++){
- assert(start + ix >= m_countCompoundUsage);
+ assert(start + ix < m_countCompoundUsage);
m_compoundUsage[start + ix] = usage[ix];
}
}
throw ReOptionException(&m_programArgs,
i18n("date < 1970.01.01: "), value);
struct tm time;
+ memset(&time, 0, sizeof time);
time.tm_year = year - 1900;
time.tm_mon = month - 1;
time.tm_mday = day;
return rc;
}
+/**
+ * Sets the standard filter options given by the program arguments.
+ *
+ * @param filter OUT: the filter to set
+ */
+void ReDirOptions::setFilterFromProgramArgs(DirEntryFilter_t& filter){
+ ReByteBuffer buffer;
+ if (m_programArgs.getString("younger", buffer) != NULL)
+ filter.m_maxAge = checkDate(m_programArgs.getString("younger", buffer));
+ if (m_programArgs.getString("older", buffer) != NULL)
+ filter.m_minAge = checkDate(m_programArgs.getString("older", buffer));
+ if (m_programArgs.getString("maxsize", buffer) != NULL)
+ filter.m_maxSize = checkSize(m_programArgs.getString("maxsize", buffer));
+ if (m_programArgs.getString("minsize", buffer) != NULL)
+ filter.m_minSize = checkSize(m_programArgs.getString("minsize", buffer));
+ filter.m_minDepth = m_programArgs.getInt("mindepth");
+ filter.m_maxDepth = m_programArgs.getInt("maxdepth");
+ if (m_programArgs.getArgCount() > 0)
+ {
+ m_patternList.set(m_programArgs.getArg(0));
+ filter.m_nodePatterns = &m_patternList;
+ }
+}
/**
* Checks the correctness of the standard filter options.
*
printf("%s\n", lines[ix]);
}
}
+
/**
* Prints an message how to use the statistic module and exits.
*/
printField(statisticExamples);
}
+/**
+ * Gets the arguments for the "statistic" command and execute this.
+ *
+ * @param argc the number of arguments
+ * @param argav the argument vector
+ */
+void ReDirTools::list(int argc, char* argv[]){
+}
+
/**
* Gets the arguments for the "statistic" command and execute this.
* @param argc the number of arguments
* @param argav the argument vector
*/
-void ReDirTools::dirStatistic(int argc, char* argv[]){
+void ReDirTools::statistic(int argc, char* argv[]){
time_t start = time(NULL);
ReProgramArgs args(statisticCall, statisticExamples);
args.addBool("quiet", "no additional information", 'q', "quiet", false);
if (argc < 2)
tools.usage("missing arguments");
if (isArg("list", argv[1]))
- tools.dirList(argc - 1, argv + 1);
+ tools.list(argc - 1, argv + 1);
else if (isArg("help", argv[1]))
printField(helpSummary);
else if (isArg("statistic", argv[1]))
- tools.dirStatistic(argc - 1, argv + 1);
+ tools.statistic(argc - 1, argv + 1);
else if (isArg("test", argv[1])){
void testAll();
testAll();
void checkStandardFilterOptions();
void initCompoundUsage(size_t size);
void addCompundUsage(const char** usage);
-protected:
+ const char** compoundUsage() const
+ { return m_compoundUsage; }
+ ReProgramArgs& programArgs()
+ { return m_programArgs; }
time_t checkDate(const char* value);
int64_t checkSize(const char* value);
+ void setFilterFromProgramArgs(DirEntryFilter_t& filter);
protected:
ReProgramArgs m_programArgs;
+ RePatternList m_patternList;
const char** m_compoundUsage;
int m_countCompoundUsage;
};
public:
virtual void usage(const char* msg, const char* msg2 = NULL);
void dirListUsage();
- void dirList(int argc, char* argv[]);
+ void list(int argc, char* argv[]);
void statisticUsage();
- void dirStatistic(int argc, char* argv[]);
+ void statistic(int argc, char* argv[]);
public:
static int main(int argc, char* argv[]);
public:
const char* const ReTraverser::m_separatorStr = "\\";\r
#endif\r
\r
-#ifdef __linux__\r
-//#define isUndefHandle(handle) ((handle) == NULL)\r
-//#define findNextEntry(handle,data) (((data) = readdir(handle)) != NULL)\r
-#define closeDir(handle) closedir(handle)\r
-//#define setHandleUndef(h) ((h) = NULL)\r
-#else\r
-#define isUndefHandle(handle) ((handle) == INVALID_HANDLE_VALUE)\r
-#define setHandleUndef(h) ((h) = INVALID_HANDLE_VALUE)\r
-#define findNextEntry(handle, data) (FindNextFileA(handle, data) != 0)\r
-#define initEntryBuffer(entry) ((entry)->m_data = &(entry)->m_data)\r
-#endif\r
-\r
+/**\r
+ * Constructor.\r
+*/\r
ReDirStatus_t::ReDirStatus_t() :\r
#ifdef __linux__\r
m_handle(NULL),\r
m_pathPatterns(),\r
m_minSize(0),\r
m_maxSize(-1),\r
- m_minAge(),\r
- m_maxAge()\r
+ m_minAge(0),\r
+ m_maxAge(0),\r
+ m_minDepth(0),\r
+ m_maxDepth(512)\r
{\r
}\r
+\r
+/**\r
+ * Destructor.\r
+ */\r
+DirEntryFilter_t::~DirEntryFilter_t(){\r
+}\r
/**\r
*\r
*/\r
FileSize_t m_maxSize;
time_t m_minAge;
time_t m_maxAge;
+ int m_minDepth;
+ int m_maxDepth;
};
#define MAX_ENTRY_STACK_DEPTH 256
class ReTraverser {
* Constructor.
*/
RePatternList::RePatternList() :
+ m_patternString(),
m_patterns(NULL),
m_count(0)
{
const char* separator, const char* notPrefix){
char buffer[2];
destroy();
+ m_patternString = patterns;
if (separator == NULL){
buffer[0] = patterns[0];
buffer[1] = '\0';
bool match(const char* pattern);
void set(const char* patterns, bool ignoreCase = false,
const char* separator = NULL, const char* notPrefix = "^");
+ /** Returns the original pattern string.
+ * @return the string describing the patterns.
+ */
+ const char* patternString() const
+ { return m_patternString.str(); }
private:
int setOne(int index, const char* pattern, size_t patternLength,
bool ignoreCase, const ReByteBuffer& notPrefix);
private:
+ ReByteBuffer m_patternString;
// store of all patterns: the not patterns are at the bottom
ReSimpleMatcher** m_patterns;
// count of all patterns (including not patterns: