]> gitweb.hamatoma.de Git - crepublib/commitdiff
testing dirtools with many options
authorkawi <winfriedkappeler@atron.de>
Sun, 4 Jan 2015 23:30:18 +0000 (00:30 +0100)
committerkawi <winfriedkappeler@atron.de>
Sun, 4 Jan 2015 23:30:18 +0000 (00:30 +0100)
base/ReProgramArgs.cpp
os/ReDirTools.cpp
os/ReDirTools.hpp
os/ReTraverser.cpp
os/ReTraverser.hpp

index f8dcdb4dc1edd90212a3d14a32c2ed2c63d1f2e8..038c8380c637d77a8614db17151425a15bd15177 100644 (file)
@@ -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;
 }
 
index e236801877bb1f2351f9b1b4bc5ed35c0c244740..304b9aa320d46dfd7c33572a4308f5ddfc820037 100644 (file)
@@ -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[] = {
-    "<command>: 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 <command> <opts>",
-    "   Useful commands around a directry tree",
-    "   Type 'dirtool help <command>' for more help",
+    "   Useful commands around directory trees.",
+    "   Type 'dirtool help <command>' for more help.",
     "<command>:",
+    "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[] = {
+    "<command>: 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[] = {
+    "<command>: 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[] = {
     "<command>:"
     "st(atistic)  [<opts_stat>] <path> [<depth>]",
@@ -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 <cpde>value</code> (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);
index 37c0351266e227c9603dedc7cfa3ad5d4198dee7..301b000a6ffb090df5df455fc77c09f4ad23e351 100644 (file)
@@ -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();
index 22f81b119095a14c1c18c586f91b0d222bfc51a3..590585c4bcfc00ff508cc4f5729048984dc313a8 100644 (file)
@@ -152,8 +152,8 @@ bool ReDirStatus_t::findNext(){
  * Returns the type of the entry.\r
  * return       the file type, e.g. TF_REGULAR\r
  */\r
-ReDirStatus_t::Type_t ReDirStatus_t::type(){
-    Type_t rc = TF_UNDEF;
+ReDirStatus_t::Type_t ReDirStatus_t::type(){\r
+    Type_t rc = TF_UNDEF;\r
 #if defined __linux__\r
 #elif defined __WIN32__\r
     int flags = (m_data.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY\r
@@ -178,8 +178,8 @@ ReDirStatus_t::Type_t ReDirStatus_t::type(){
     else\r
         rc = TF_OTHER;\r
 #endif\r
-    return rc;
-}
+    return rc;\r
+}\r
 \r
 /**\r
  * Tests whether the instance is a directory.\r
@@ -291,7 +291,7 @@ ReDirEntryFilter_t::ReDirEntryFilter_t() :
        m_maxAge(0),\r
     m_minDepth(0),\r
     m_maxDepth(512),\r
-    m_traceInterval(0),
+    m_traceInterval(0),\r
     m_lastTrace(0),\r
     m_traceCounter(0)\r
 {\r
@@ -317,13 +317,16 @@ bool ReDirEntryFilter_t::match(ReDirStatus_t& entry){
         }\r
                if (0 == (entry.type() & m_types))\r
                        break;\r
-        if (m_minSize > 0 && entry.fileSize() > m_minSize)\r
+        int64_t size = entry.fileSize();\r
+        if (strstr(entry.node(), ".exe"))\r
+            ReByteBuffer breaker;\r
+        if (m_minSize > 0 && size < m_minSize)\r
                        break;\r
-               if (m_maxSize >= 0 && entry.fileSize() < m_maxSize)\r
+               if (m_maxSize >= 0 && size > m_maxSize)\r
                        break;\r
-               if (m_minAge != 0 && ReDirStatus_t::filetimeToTime(entry.modified()) < m_minAge)\r
+               if (m_minAge != 0 && ReDirStatus_t::filetimeToTime(entry.modified()) > m_minAge)\r
                        break;\r
-               if (m_maxAge != 0 && ReDirStatus_t::filetimeToTime(entry.modified()) > m_maxAge)\r
+               if (m_maxAge != 0 && ReDirStatus_t::filetimeToTime(entry.modified()) < m_maxAge)\r
                        break;\r
                if (m_nodePatterns != NULL && ! m_nodePatterns->match(entry.node()))\r
                        break;\r
index 6e7631694e75a7aacccae965e52bbedd07be2651..272ec2d6d7711b510592bb729aa36c62764a080a 100644 (file)
@@ -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);