]> gitweb.hamatoma.de Git - crepublib/commitdiff
dirtool list works
authorkawi <winfriedkappeler@atron.de>
Sun, 4 Jan 2015 13:56:04 +0000 (14:56 +0100)
committerkawi <winfriedkappeler@atron.de>
Sun, 4 Jan 2015 13:56:04 +0000 (14:56 +0100)
base/ReProgramArgs.cpp
os/ReDirTools.cpp
os/ReDirTools.hpp
os/ReTraverser.cpp
os/ReTraverser.hpp

index ce7d449b7454efc289ddf07036c9e038da8673e6..ba9d8d1ec30180317292ee707537ba3c2eb4b25e 100644 (file)
@@ -13,7 +13,9 @@
  * @param caller       The object which throw the exception.
  * @param message      The error message with one or two placeholders.
  * @param arg1         The first argument (for the first placeholder).
- * @param arg2         The 2nd argument (for the 2nd placeholder). If NULL only one placeholder exists.
+ * @param arg2         The 2nd argument (for the 2nd placeholder). 
+ *                  If NULL only one placeholder exists.
+ * @throws ReFormatException
 */
 ReOptionException::ReOptionException(ReProgramArgs* caller, const char* message,
                const char* arg1, const char* arg2)
@@ -21,10 +23,13 @@ ReOptionException::ReOptionException(ReProgramArgs* caller, const char* message,
        ReException()
 {
        ReVarArgs args(message);
+    if (strchr(message, '$') == NULL)
+        throw ReFormatException(i18n("Missing placeholder: "),
+                                       message); 
        args.arg(arg1);
        if (arg2 != NULL)
                args.arg(arg2);
-       setMessage(args.asCString());
+    setMessage(args.asCString());
        if (caller != NULL)
                caller->setLastError(args.asCString());
 }
index 28a707af5e4e8c9d450cf142cbd6ea81af6ac726..0989152fe6e33f9e3736181e6632080dc8691c56 100644 (file)
@@ -24,12 +24,14 @@ static const char* s_standardFilterUsage[] = {
     "   <v> is a date (e.g. 2015.02.17) or number followed by an unit",
     "   units: m(inutes) h(hours), d(days). Default: m(inutes)",
     "   examples: -o25 --older-than=30d -o24h -o2009.3.2/12:00 -o1999.01.01",
+    "-q or --quiet",
+    "   no additional information like runtime",
     "-P<p> or --pathname-pattern=<p>",
     "   a list of patterns for the path (without basename) separated by ';'",
     "   Each pattern can contain '*' as wildcard",
     "   If the first character is '^' the pattern is a 'not pattern':"
-    "   A directory will be entered if at least one of the positive patterns and none",
-    "   of the 'not patterns' matches",
+    "   A directory will be entered if at least one of the positive patterns",
+    "   and none of the 'not patterns' matches",
     "   examples: '*;^*/.git/' '*/cache/;*/temp/",
     "-p<p> or --basename-pattern=<p>",
     "   a list of patterns for the basename (filename without path) separated by ';'",
@@ -38,11 +40,16 @@ static const char* s_standardFilterUsage[] = {
     "   A file will be found if at least one of the positive patterns and none",
     "   of the 'not patterns' matches",
     "   examples: '*.cpp;*.hpp;Make*' '*;^*.bak;^*~",
+    "-t<n> or --trace-interval=<n> Default: 0",
+    "   all <n> seconds the current path will be traced",
+    "   0: no trace",
     "-t<l> or --type=<l>",
     "   the file type",
     "   <l> is a list of <v> values:",
-    "   <v>: d(irectory) f(file) r(egular file) l(ink)",
-    "   examples: -td --type=dr",
+    "   <v>: b(lock) c(har) d(irectory) (l)i(nkdir) l(ink) o(ther)",
+    "        p(ipe) s(ocket) r(egular)",
+    "   <v>-sets: S(pecial)=bcspo N(ondir)=Slr",
+    "   examples: -td --type=dr -tNi",
     "-y<v> or --younger-than=<v>",
     "   the modification date is younger than <v>",
     "   <v> is a date (e.g. 2015.02.17) or number followed by an unit",
@@ -164,12 +171,14 @@ void ReDirOptions::addStandardFilterOptions(){
     m_programArgs.addInt("maxdepth", "maximal subdir depth", 'D', "max-depth", 512);
     m_programArgs.addInt("mindepth", "minimal subdir depth", 'd', "min-depth", 512);
     m_programArgs.addString("older", "older than", 'o', "older-than", false, NULL);
-    m_programArgs.addString("type", "file type", 't', "type", false, "df");
+    m_programArgs.addString("nodepattern", "pattern list for the basename", 'p', "basename-pattern", false, NULL);
+    m_programArgs.addString("pathpattern", "pattern list for the path", 'P', "path-pattern", false, NULL);
+    m_programArgs.addBool("quiet", "suppress additional info", 'q', "quiet", false);
+    m_programArgs.addInt("trace", "trace interval", 'T', "trace-interval", 0);
+    m_programArgs.addString("type", "file type", 't', "type", false, NULL);
     m_programArgs.addString("younger", "younger than", 'y', "younger-than", false, NULL);
     m_programArgs.addString("maxsize", "maximal filesize", 'Z', "max-size", false, NULL);
     m_programArgs.addString("minsize", "minimal filesize", 'z', "min-size", false, NULL);
-    m_programArgs.addString("nodepattern", "pattern list for the basename", 'p', "basename-pattern", false, NULL);
-    m_programArgs.addString("pathpattern", "pattern list for the path", 'P', "path-pattern", false, NULL);
 }
 
 /**
@@ -282,17 +291,75 @@ time_t ReDirOptions::checkSize(const char* value){
             break;
         default:
              throw ReOptionException(&m_programArgs, 
-                i18n("invalid <unit> expected. b k K m M g G"), 
+                i18n("invalid <unit>. Expected: b k K m M g G"), 
                 value);
         }
         break;
     default:
         throw ReOptionException(&m_programArgs, 
-            i18n("invalid size value: <number><unit> expected. <unit>: b k K m M g G"), 
+            i18n("invalid size value: <number><unit> <unit>: b k K m M g G"), 
             value);
     }
     return rc;
 }
+/**
+ * Checks whether the given value is a valid filetype list.
+ *
+ * @param value     value to check
+ * @return          the bitmask
+ * @throws          ReOptionExecption
+ */
+ReDirStatus_t::Type_t ReDirOptions::checkType(const char* value){
+    int rc = ReDirStatus_t::TF_UNDEF;
+    while (*value != '\0'){
+        switch(*value){
+        case 'b':
+            rc |= ReDirStatus_t::TF_BLOCK;
+            break;
+        case 'c':
+            rc |= ReDirStatus_t::TF_CHAR;
+            break;
+        case 'd':
+            rc |= ReDirStatus_t::TF_SUBDIR;
+            break;
+        case 'i':
+            rc |= ReDirStatus_t::TF_LINK_DIR;
+            break;
+        case 'l':
+            rc |= ReDirStatus_t::TF_LINK;
+            break;
+        case 'o':
+            rc |= ReDirStatus_t::TF_OTHER;
+            break;
+        case 'p':
+            rc |= ReDirStatus_t::TF_PIPE;
+            break;
+        case 's':
+            rc |= ReDirStatus_t::TF_SOCKET;
+            break;
+        case 'r':
+            rc |= ReDirStatus_t::TF_REGULAR;
+            break;
+        case 'S':
+            rc |= ReDirStatus_t::TC_SPECIAL;
+            break;
+        case 'N':
+            rc |= ReDirStatus_t::TC_NON_DIR;
+            break;
+        case ' ':
+        case ',':
+            break;
+       default:
+           throw ReOptionException(&m_programArgs, 
+                i18n("invalid type: $1 Expected: b(lock) c(har) d(irectory)"
+                " (l)i(nkdir) l(ink) o(ther) p(ipe) s(ocket) r(egular)"
+                " S(pecial=bcspo) N(ondir=Slr)"), 
+                value);
+        }
+        value++;
+    }
+    return (ReDirStatus_t::Type_t) rc;
+}
 
 /**
  * Sets the standard filter options given by the program arguments.
@@ -309,6 +376,8 @@ void ReDirOptions::setFilterFromProgramArgs(ReDirEntryFilter_t& filter){
         filter.m_maxSize = checkSize(buffer.str());
     if (m_programArgs.getString("minsize", buffer)[0] != '\0')
         filter.m_minSize = checkSize(buffer.str());
+    if (m_programArgs.getString("type", buffer)[0] != '\0')
+        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){
@@ -319,6 +388,7 @@ void ReDirOptions::setFilterFromProgramArgs(ReDirEntryFilter_t& filter){
         m_pathPatterns.set(buffer.str());
         filter.m_pathPatterns = &m_nodePatterns;
     }
+    filter.m_traceInterval = m_programArgs.getInt("trace");
 }
 /**
  * Prints a help message, the error message and exits.
@@ -343,11 +413,7 @@ void ReDirOptions::checkStandardFilterOptions(){
     ReByteBuffer buffer;
     checkDate(m_programArgs.getString("older", buffer));
     checkDate(m_programArgs.getString("younger", buffer));
-    const char* value = m_programArgs.getString("type", buffer);
-    if (strspn (value, "dfrl") != strlen(value))
-        throw ReOptionException(&m_programArgs, 
-                i18n("unknown file type. Expected: d(irectory) f(file) r(egular file) l(ink)"), 
-                value);
+    checkType(m_programArgs.getString("types", buffer));
     checkSize(m_programArgs.getString("maxsize", buffer));
     checkSize(m_programArgs.getString("minsize", buffer));
 }
@@ -610,12 +676,17 @@ ReDirList::ReDirList() :
 void ReDirList::list(int argc, char* argv[]){
     ReDirEntryFilter_t filter;
     try {
+        time_t start = time(NULL);
         m_programArgs.init(argc, argv);
+        bool verbose = ! m_programArgs.getBool("quiet");
         setFilterFromProgramArgs(filter);
         if (m_programArgs.getArgCount() == 0)
             help(i18n("no arguments given (missing path)"));
         ReByteBuffer bufferRights;
         ReByteBuffer bufferTime;
+        int64_t sumSizes = 0;
+        int files = 0;
+        int dirs = 0;
         for (int ix = 0; ix < m_programArgs.getArgCount(); ix++){
             ReTraverser traverser(m_programArgs.getArg(ix));
             traverser.setMinLevel(filter.m_maxDepth);
@@ -623,13 +694,25 @@ void ReDirList::list(int argc, char* argv[]){
             int level;
             ReDirStatus_t* entry;
             while( (entry = traverser.nextFile(level, &filter)) != NULL){
+                if (entry->isDirectory())
+                    dirs++;
+                else{
+                    files++;
+                    sumSizes += entry->fileSize();
+                }
                 if (! printOneFile(entry))
-                    printf("%s %12lld %s %s%s\n",
-                    entry->rightsAsString(bufferRights), entry->fileSize(), 
+                    printf("%s %12.6f %s %02x %s%s\n",
+                    entry->rightsAsString(bufferRights), entry->fileSize() / 1E6
                     entry->filetimeAsString(bufferTime), 
+                    entry->type(),
                     entry->m_path.str(), entry->node());
             }
         }
+        if (verbose){
+            int duration = int(time(NULL) - start);
+            printf ("+++ %d dirs and %d file(s) with %.6f MByte in %02d:%02d sec\n",
+                dirs, files, sumSizes / 1E6, duration / 60, duration % 60);
+        }
     } catch(ReOptionException& exc){
         help(exc.getMessage());
     }
index 53d4e7d04bb6569c8dc5b1a33eb88ab58f63c515..7e1b2fd71979013ad7efa4449d86ff6fbc8e72d2 100644 (file)
@@ -23,6 +23,7 @@ public:
     { return m_programArgs; }
     time_t checkDate(const char* value);
     int64_t checkSize(const char* value);
+    ReDirStatus_t::Type_t checkType(const char* value);
     void setFilterFromProgramArgs(ReDirEntryFilter_t& filter);
     void help(const char* errorMessage, const char* message2 = NULL);
 protected:
index f2f9d14b7ee01afd582b8f870c81c9aa85e43c71..22f81b119095a14c1c18c586f91b0d222bfc51a3 100644 (file)
@@ -88,11 +88,13 @@ const char* ReDirStatus_t::rightsAsString(ReByteBuffer& buffer) {
  */\r
 const char* ReDirStatus_t::filetimeAsString(ReByteBuffer& buffer) {\r
     time_t time1 = filetimeToTime(modified());\r
-    struct tm* time2 = localtime(&time1);\r
-    buffer.setLength(4+2*1+2*2+1+3*2+2*1);\r
-    strftime(buffer.buffer(), buffer.length(), "%y.%m.%d %H:%M:%S", time2);\r
+    struct tm* time2 = gmtime(&time1);\r
+    buffer.setLength(4+2*2+2*2+1+3*2+2*1);\r
+    strftime(buffer.buffer(), buffer.length(), "%Y.%m.%d %H:%M:%S", time2);\r
     return buffer.str();\r
 }\r
+\r
+\r
 /**\r
  * Tests whether the instance contains data about "." or "..".\r
  *\r
@@ -145,6 +147,40 @@ bool ReDirStatus_t::findNext(){
 #endif\r
        return rc;\r
 }\r
+\r
+/**\r
+ * 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;
+#if defined __linux__\r
+#elif defined __WIN32__\r
+    int flags = (m_data.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY\r
+        | FILE_ATTRIBUTE_HIDDEN  \r
+        | FILE_ATTRIBUTE_SYSTEM  \r
+        | FILE_ATTRIBUTE_ARCHIVE  \r
+        | FILE_ATTRIBUTE_NORMAL\r
+        | FILE_ATTRIBUTE_TEMPORARY  \r
+        | FILE_ATTRIBUTE_SPARSE_FILE  \r
+        | FILE_ATTRIBUTE_COMPRESSED  \r
+        | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED  \r
+        | FILE_ATTRIBUTE_ENCRYPTED  \r
+        | FILE_ATTRIBUTE_HIDDEN));\r
+\r
+    if (0 == flags)\r
+        rc = TF_REGULAR;\r
+    else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){\r
+        rc = (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))\r
+            ? TF_LINK_DIR : TF_SUBDIR;\r
+    } else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))\r
+        rc = TF_LINK;\r
+    else\r
+        rc = TF_OTHER;\r
+#endif\r
+    return rc;
+}
+\r
 /**\r
  * Tests whether the instance is a directory.\r
  *\r
@@ -182,7 +218,7 @@ bool ReDirStatus_t::isRegular() {
 #ifdef __linux__\r
     return (m_data->d_type != DT_UNKNOWN && m_data->d_type == DT_REG) || S_ISREG(getStatus()->st_mode);\r
 #elif defined __WIN32__\r
-    return 0 != (m_data.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE));\r
+    return 0 == (m_data.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE));\r
 #endif\r
 }\r
 /**\r
@@ -246,9 +282,7 @@ void  ReDirStatus_t::timeToFiletime(time_t time, FileTime_t& filetime){
  * Constructor.\r
  */\r
 ReDirEntryFilter_t::ReDirEntryFilter_t() :\r
-       m_regulars(true),\r
-       m_specials(true),\r
-       m_directories(true),\r
+    m_types(ReDirStatus_t::TC_ALL),\r
        m_nodePatterns(),\r
        m_pathPatterns(),\r
        m_minSize(0),\r
@@ -256,7 +290,10 @@ ReDirEntryFilter_t::ReDirEntryFilter_t() :
        m_minAge(0),\r
        m_maxAge(0),\r
     m_minDepth(0),\r
-    m_maxDepth(512)\r
+    m_maxDepth(512),\r
+    m_traceInterval(0),
+    m_lastTrace(0),\r
+    m_traceCounter(0)\r
 {\r
 }\r
 \r
@@ -271,11 +308,14 @@ ReDirEntryFilter_t::~ReDirEntryFilter_t(){
 bool ReDirEntryFilter_t::match(ReDirStatus_t& entry){\r
        bool rc = false;\r
        do {\r
-               if (! m_directories && entry.isDirectory())\r
-                       break;\r
-        if (m_specials && (entry.isDirectory() || entry.isRegular()))\r
-                       break;\r
-               if (m_regulars && ! entry.isRegular())\r
+        if (m_traceCounter++ % 100 == 0 && m_traceInterval > 0){\r
+            time_t now = time(NULL);\r
+            if (int(now - m_lastTrace) > m_traceInterval){\r
+                m_lastTrace = now;\r
+                fprintf(stderr, "%s%s\n", entry.m_path.str(), entry.node());\r
+            }\r
+        }\r
+               if (0 == (entry.type() & m_types))\r
                        break;\r
         if (m_minSize > 0 && entry.fileSize() > m_minSize)\r
                        break;\r
index d817327658ca6857555afa74b52907a15ebdc93a..6e7631694e75a7aacccae965e52bbedd07be2651 100644 (file)
@@ -21,6 +21,25 @@ typedef int64_t FileSize_t;
 typedef FILETIME FileTime_t;
 #endif
 class ReDirStatus_t{
+public:
+    enum Type_t {
+        TF_UNDEF = 0,
+        // single property flags:
+        TF_SUBDIR   = 1 << 0,
+        TF_REGULAR  = 1 << 1,
+        TF_LINK     = 1 << 2,
+        TF_LINK_DIR = 1 << 3,
+        TF_BLOCK    = 1 << 4,
+        TF_PIPE     = 1 << 5,
+        TF_CHAR     = 1 << 6,
+        TF_SOCKET   = 1 << 7,
+        TF_OTHER    = 1 << 8,
+        // collections:
+        TC_SPECIAL  = (TF_BLOCK | TF_CHAR | TF_SOCKET | TF_PIPE | TF_OTHER),
+        TC_NON_DIR  = (TC_SPECIAL | TF_LINK | TF_REGULAR),
+        TC_ALL = (TF_SUBDIR | TC_NON_DIR | TF_LINK_DIR)
+    };
+
 public:
        ReDirStatus_t();
 public:
@@ -37,6 +56,7 @@ public:
     bool isDotDir() const;
     const char* rightsAsString(ReByteBuffer& buffer);
     const char* filetimeAsString(ReByteBuffer& buffer);
+    Type_t type(); 
 public:
        ReByteBuffer m_path;
        int m_passNo;
@@ -61,9 +81,7 @@ public:
 public:
        bool match(ReDirStatus_t& entry);
 public:
-       bool m_regulars;
-       bool m_specials;
-       bool m_directories;
+       ReDirStatus_t::Type_t m_types;
        RePatternList* m_nodePatterns;
        RePatternList* m_pathPatterns;
        FileSize_t m_minSize;
@@ -72,6 +90,9 @@ public:
        time_t m_maxAge;
     int m_minDepth;
     int m_maxDepth;
+    int m_traceInterval;
+    time_t m_lastTrace;
+    int m_traceCounter;
 };
 #define MAX_ENTRY_STACK_DEPTH 256
 class ReTraverser {