From: kawi Date: Sun, 4 Jan 2015 23:30:18 +0000 (+0100) Subject: testing dirtools with many options X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=46957931b92e7c74c46943b09c3c624251b5613c;p=crepublib testing dirtools with many options --- diff --git a/base/ReProgramArgs.cpp b/base/ReProgramArgs.cpp index f8dcdb4..038c838 100644 --- a/base/ReProgramArgs.cpp +++ b/base/ReProgramArgs.cpp @@ -276,7 +276,8 @@ const char* ReProgramArgs::getString(const char* name, ReByteBuffer& buffer) { properties.strOf(IxType)); m_values.get(name, -1, buffer); - const char* rc = buffer.buffer() + 1; + buffer.remove(0, 1); + const char* rc = buffer.buffer(); return rc; } diff --git a/os/ReDirTools.cpp b/os/ReDirTools.cpp index e236801..304b9aa 100644 --- a/os/ReDirTools.cpp +++ b/os/ReDirTools.cpp @@ -8,31 +8,48 @@ #include "base/rebase.hpp" #include "os/reos.hpp" -const char* ReDirTools::m_version = "2015.01.03"; +const char* ReDirTools::m_version = "2015.01.04"; static const char* s_empty[] = { NULL }; -const char* s_listUsage[] = { - ": list", - " lists the metadata (size, modification date ...) of the selected files", - NULL -}; -const char* s_listExamples[] = { - "dirtool list --min-size=10M e:\\data", - "dirtool list --type=f -y7d --size=10M -p*.cpp;*.hpp;Makefile*;^*~ /home/data" , - NULL -}; static const char* s_helpSummary[] = { "dirtool or dt ", - " Useful commands around a directry tree", - " Type 'dirtool help ' for more help", + " Useful commands around directory trees.", + " Type 'dirtool help ' for more help.", ":", + "batch produce output to handle the found files with a script", "help shows info about the arguments/options", "list shows the meta data of the selected files", "statistic shows statistics about a direcctory tree", NULL }; +const char* s_batchUsage[] = { + ": batch", + " produces output usable for a batch file (script)", + " all found files can be processed with a given script", + " each line starts (usually) with a script name (see -c)", + " then it follows the full filename of the found file", + " use --arguments or --script to configure the output line", + NULL +}; +const char* s_batchExamples[] = { + "dirtool batch -cbackup.bat --basename-pattern=;*.txt;*.doc e:\\data", + "dirtool batch --type=r '--arguments=backup.sh !basename! !path!' usr etc", + NULL +}; + +const char* s_listUsage[] = { + ": list", + " lists the metadata (size, modification date ...) of the selected files", + NULL +}; +const char* s_listExamples[] = { + "dirtool list --min-size=10M e:\\data", + "dirtool list --type=f -y7d --size=10M -p;*.cpp;*.hpp;Makefile*;^*~ /home/data" , + NULL +}; + static const char* s_statisticUsage[] = { ":" "st(atistic) [] []", @@ -118,12 +135,13 @@ void ReDirOptions::addStandardFilterOptions(){ "examples: -o25 --older-than=30d -o24h -o2009.3.2/12:00 -o1999.01.01"), 'o', "older-than", false, NULL); m_programArgs.addString("pathpattern", - i18n("a list of patterns for the path (without basename) separated by ';'\n" + i18n("a list of patterns for the path (without basename)\n" + "the separator is the first character of the list\n" "Each pattern can contain '*' as wildcard\n" "If the first character is '^' the pattern is a 'not pattern':\n" "A directory will be entered if at least one of the positive patterns\n" "and none of the 'not patterns' matches\n" - "examples: '*;^*/.git/' '*/cache/;*/temp/"), + "examples: ';*;^*/.git/' ',*/cache/,*/temp/"), 'P', "path-pattern", false, NULL); m_programArgs.addString("nodepattern", i18n("a list of patterns for the basename (name without path) separated by ';'\n" @@ -288,6 +306,22 @@ time_t ReDirOptions::checkSize(const char* value){ } return rc; } +/** + * Checks whether the given value is a valid pattern list. + * + * The first character must be a separator (not '*', '.' and not a letter) + * + * @param value value to check + * @return the value (for chaining) + * @throws ReOptionExecption + */ +const char* ReDirOptions::checkPatternList(const char* value){ + if (isalpha(*value) || *value == '*' || *value == '.') + throw ReOptionException(&m_programArgs, + i18n("invalid separator (first character): $1 use ';' instead"), + value); + return value; +} /** * Checks whether the given value is a valid filetype list. * @@ -366,13 +400,15 @@ void ReDirOptions::setFilterFromProgramArgs(ReDirEntryFilter_t& filter){ filter.m_types = checkType(buffer.str()); filter.m_minDepth = m_programArgs.getInt("mindepth"); filter.m_maxDepth = m_programArgs.getInt("maxdepth"); - if (m_programArgs.getString("nodepattern", buffer) != NULL){ + if (m_programArgs.getString("nodepattern", buffer)[0] != '\0'){ + checkPatternList(buffer.str()); m_nodePatterns.set(buffer.str()); filter.m_nodePatterns = &m_nodePatterns; } - if (m_programArgs.getString("pathpattern", buffer) != NULL){ + if (m_programArgs.getString("pathpattern", buffer)[0] != '\0'){ + checkPatternList(buffer.str()); m_pathPatterns.set(buffer.str()); - filter.m_pathPatterns = &m_nodePatterns; + filter.m_pathPatterns = &m_pathPatterns; } filter.m_traceInterval = m_programArgs.getInt("trace"); } @@ -404,6 +440,8 @@ void ReDirOptions::checkStandardFilterOptions(){ checkType(m_programArgs.getString("types", buffer)); checkSize(m_programArgs.getString("maxsize", buffer)); checkSize(m_programArgs.getString("minsize", buffer)); + checkPatternList(m_programArgs.getString("nodepattern", buffer)); + checkPatternList(m_programArgs.getString("pathpattern", buffer)); } /** @@ -758,6 +796,160 @@ void ReDirList::list(int argc, char* argv[]){ } } +/** + * Constructor. + */ +ReDirBatch::ReDirBatch() : + ReDirOptions(s_batchUsage, s_batchExamples) +{ + m_programArgs.addString("first", + i18n("defines the first line of the output"), + '1', "first-line", true, +#if defined __linux__ + "#! /bin/sh" +#elif defined __WIN32__ + "rem this batch is created by dirtool" +#endif + ); + m_programArgs.addString("arguments", + i18n("template for the output line.\n" + "Possible placeholders: (e.g. e:\\data\\sample.txt)\n" + " !full!: e:\\data\\sample.txt\n" + " !path!: e:\\data\\\n" + " !basename!: sample.txt\n" + " !name!: sample\n" + " !ext!: .txt\n" + "example: --arguments='echo !basename! in !path! found'"), + 'a', "arguments", false, NULL); + m_programArgs.addString("script", + i18n("name of the script (starts each output line)"), + 'c', "script", false, NULL); +#if defined __WIN32__ + m_programArgs.addBool("isexe", + i18n("supresses the starting 'call' of each output line" + "neccessary if a *.exe will be called (instead of a *.bat)"), + 'x', "is-exe", false); +#endif + addStandardFilterOptions(); +} + +static void replaceMakros(const char* arguments, ReDirStatus_t* entry, const char* delim, ReByteBuffer& line){ + line.set(arguments, -1); + // we prepare the removal of unwanted delimiters in constructed placeholders: + // example: !path!!name!: without correction: "e:\\data\\""xxx" + // We want: "e:\\data\\xxx" + line.replaceAll("!!", 2, "!\x01!", 3); + ReByteBuffer replacement; + if (strstr(arguments, "!full!") != NULL){ + replacement.set(delim, -1).append(entry->m_path); + replacement.append(entry->node(), -1).append(delim, -1); + line.replaceAll("!full!", 6, replacement.str(), replacement.length()); + } + if (strstr(arguments, "!path!") != NULL){ + replacement.set(delim, -1).append(entry->m_path).append(delim, -1); + line.replaceAll("!path!", 6, replacement.str(), replacement.length()); + } + if (strstr(arguments, "!basename!") != NULL){ + replacement.set(delim, -1).append(entry->node(), -1).append(delim, -1); + line.replaceAll("!basename!", 10, replacement.str(), replacement.length()); + } + if (strstr(arguments, "!name!") != NULL){ + replacement.set(delim, -1).append(entry->node(), -1); + int ix = replacement.rindexOf(".", 1); + if (ix > 1) + replacement.setLength(ix); + replacement.append(delim, -1); + line.replaceAll("!name!", 6, replacement.str(), replacement.length()); + } + if (strstr(arguments, "!ext!") != NULL){ + replacement.set(delim, -1).append(entry->node(), -1); + int ix = replacement.rindexOf(".", 1); + if (ix > 1) + replacement.remove(1, ix - 1); + else + replacement.setLength(1); + replacement.append(delim, -1); + line.replaceAll("!ext!", 5, replacement.str(), replacement.length()); + } + // We remove the unwanted delimiters (see above): + ReByteBuffer buffer; + buffer.set(delim, -1).append("\x01", 1).append(delim, -1); + line.replaceAll(buffer.str(), buffer.length(), "", 0); +} +/** + * Gets the arguments for the "list" command and execute this. + * + * @param argc the number of arguments + * @param argav the argument vector + */ +void ReDirBatch::createBatch(int argc, char* argv[]){ + ReDirEntryFilter_t filter; + try { + time_t start = time(NULL); + m_programArgs.init(argc, argv); + ReByteBuffer buffer; + ReByteBuffer arguments(m_programArgs.getString("arguments", buffer), -1); + ReByteBuffer script(m_programArgs.getString("script", buffer), -1); + if (arguments.length() + script.length() == 0) + help(i18n("one of the option must be set: -a (--arguments) or -c (--script)")); + bool verbose = ! m_programArgs.getBool("quiet"); + bool isExe = ! m_programArgs.getBool("isexe"); + setFilterFromProgramArgs(filter); + if (m_programArgs.getArgCount() == 0) + help(i18n("no arguments given (missing path)")); + if (m_programArgs.getString("first", buffer)[0] != '\0') + printf("%s\n", buffer.str()); + int64_t sumSizes = 0; + int files = 0; + int dirs = 0; +#if defined __linux__ + const char* delim = "'"; +#elif defined __WIN32__ + const char* delim = "\""; +#endif + for (int ix = 0; ix < m_programArgs.getArgCount(); ix++){ + ReTraverser traverser(m_programArgs.getArg(ix)); + traverser.setMinLevel(filter.m_maxDepth); + traverser.setMaxLevel(filter.m_maxDepth); + int level; + ReDirStatus_t* entry; + ReByteBuffer line; + while( (entry = traverser.nextFile(level, &filter)) != NULL){ + if (entry->isDirectory()) + dirs++; + else{ + files++; + sumSizes += entry->fileSize(); + } + if (script.length() > 0){ + line.setLength(0); + if (! isExe) + line.append("call "); + line.append(script).append(" ").append(delim, -1); + line.append(entry->m_path).append(entry->node(), -1); + line.append(delim, -1); + } else { + replaceMakros(arguments.str(), entry, delim, line); + } + printf("%s\n", line.str()); + } + } + if (verbose){ + int duration = int(time(NULL) - start); +#if defined __linux__ + const char* prefix = "#"; +#elif defined __WIN32__ + const char* prefix = "rem"; +#endif + printf ("%s %d dir(s) and %d file(s) with %.6f MByte in %02d:%02d sec\n", + prefix, dirs, files, sumSizes / 1E6, duration / 60, duration % 60); + } + } catch(ReOptionException& exc){ + help(exc.getMessage()); + } +} + + /** * Gets the arguments for the "statistic" command and execute this. * @@ -769,6 +961,17 @@ void ReDirTools::list(int argc, char* argv[]){ lister.list(argc, argv); } +/** + * Gets the arguments for the "batch" command and execute this. + * + * @param argc the number of arguments + * @param argav the argument vector + */ +void ReDirTools::batch(int argc, char* argv[]){ + ReDirBatch batch; + batch.createBatch(argc, argv); +} + /** * Tests whether a abrevation of an argument is given. * @param full the full name @@ -788,13 +991,16 @@ static bool isArg(const char* full, const char* part){ * @param argav the argument vector */ void ReDirTools::help(int argc, char* argv[]){ - if (argc < 1) + if (argc <= 1) printField(s_helpSummary); else { argc--; argv++; const char* arg0 = argv[0]; - if (isArg("list", arg0)){ + if (isArg("batch", arg0)){ + ReDirBatch batch; + batch.help(NULL); + } else if (isArg("list", arg0)){ ReDirList list; list.help(NULL); } else if (isArg("help", arg0)) @@ -817,6 +1023,8 @@ void ReDirTools::help(int argc, char* argv[]){ * @param argav the argument vector */ void ReDirTools::statistic(int argc, char* argv[]){ + ReDirStatistic statistic; + statistic.run(argc, argv); } /** @@ -828,11 +1036,13 @@ void ReDirTools::statistic(int argc, char* argv[]){ int ReDirTools::main(int argc, char* argv[]){ ReDirTools tools; if (argc < 2) - tools.usage("missing arguments"); + tools.help(0, argv); argc--; argv++; const char* arg0 = argv[0]; - if (isArg("list", arg0)) + if (isArg("batch", arg0)) + tools.batch(argc, argv); + else if (isArg("list", arg0)) tools.list(argc, argv); else if (isArg("help", arg0)) tools.help(argc, argv); diff --git a/os/ReDirTools.hpp b/os/ReDirTools.hpp index 37c0351..301b000 100644 --- a/os/ReDirTools.hpp +++ b/os/ReDirTools.hpp @@ -24,6 +24,7 @@ public: time_t checkDate(const char* value); int64_t checkSize(const char* value); ReDirStatus_t::Type_t checkType(const char* value); + const char* checkPatternList(const char* value); void setFilterFromProgramArgs(ReDirEntryFilter_t& filter); void help(const char* errorMessage, const char* message2 = NULL); protected: @@ -42,6 +43,16 @@ public: virtual bool printOneFile(ReDirStatus_t* entry) { return false; } }; + +class ReDirBatch : public ReDirOptions { +public: + ReDirBatch(); +public: + void createBatch(int argc, char* argv[]); + virtual bool printOneFile(ReDirStatus_t* entry) + { return false; } +}; + class ReDirStatisticData{ public: ReDirStatisticData(); @@ -89,6 +100,7 @@ class ReDirTools { public: virtual void usage(const char* msg, const char* msg2 = NULL); void dirListUsage(); + void batch(int argc, char* argv[]); void help(int argc, char* argv[]); void list(int argc, char* argv[]); void statisticUsage(); diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp index 22f81b1..590585c 100644 --- a/os/ReTraverser.cpp +++ b/os/ReTraverser.cpp @@ -152,8 +152,8 @@ bool ReDirStatus_t::findNext(){ * Returns the type of the entry. * return the file type, e.g. TF_REGULAR */ -ReDirStatus_t::Type_t ReDirStatus_t::type(){ - Type_t rc = TF_UNDEF; +ReDirStatus_t::Type_t ReDirStatus_t::type(){ + Type_t rc = TF_UNDEF; #if defined __linux__ #elif defined __WIN32__ int flags = (m_data.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY @@ -178,8 +178,8 @@ ReDirStatus_t::Type_t ReDirStatus_t::type(){ else rc = TF_OTHER; #endif - return rc; -} + return rc; +} /** * Tests whether the instance is a directory. @@ -291,7 +291,7 @@ ReDirEntryFilter_t::ReDirEntryFilter_t() : m_maxAge(0), m_minDepth(0), m_maxDepth(512), - m_traceInterval(0), + m_traceInterval(0), m_lastTrace(0), m_traceCounter(0) { @@ -317,13 +317,16 @@ bool ReDirEntryFilter_t::match(ReDirStatus_t& entry){ } if (0 == (entry.type() & m_types)) break; - if (m_minSize > 0 && entry.fileSize() > m_minSize) + int64_t size = entry.fileSize(); + if (strstr(entry.node(), ".exe")) + ReByteBuffer breaker; + if (m_minSize > 0 && size < m_minSize) break; - if (m_maxSize >= 0 && entry.fileSize() < m_maxSize) + if (m_maxSize >= 0 && size > m_maxSize) break; - if (m_minAge != 0 && ReDirStatus_t::filetimeToTime(entry.modified()) < m_minAge) + if (m_minAge != 0 && ReDirStatus_t::filetimeToTime(entry.modified()) > m_minAge) break; - if (m_maxAge != 0 && ReDirStatus_t::filetimeToTime(entry.modified()) > m_maxAge) + if (m_maxAge != 0 && ReDirStatus_t::filetimeToTime(entry.modified()) < m_maxAge) break; if (m_nodePatterns != NULL && ! m_nodePatterns->match(entry.node())) break; diff --git a/os/ReTraverser.hpp b/os/ReTraverser.hpp index 6e76316..272ec2d 100644 --- a/os/ReTraverser.hpp +++ b/os/ReTraverser.hpp @@ -111,7 +111,7 @@ public: * @param value the value to set */ void setMaxLevel(int value) - { m_minLevel = value; } + { m_maxLevel = value; } protected: bool initEntry(const ReByteBuffer& parent, const char* node, int level); void freeEntry(int level);