From: kawi Date: Sat, 3 Jan 2015 09:15:23 +0000 (+0100) Subject: dirtools: universal option handling X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=0809b045d66401ea5acc8d0d854a2feb503bdb93;p=crepublib dirtools: universal option handling --- diff --git a/os/ReDirTools.cpp b/os/ReDirTools.cpp index e746646..502185b 100644 --- a/os/ReDirTools.cpp +++ b/os/ReDirTools.cpp @@ -8,7 +8,245 @@ #include "base/rebase.hpp" #include "os/reos.hpp" -const char* ReDirTools::m_version = "2015.01.02"; +const char* ReDirTools::m_version = "2015.01.03"; + +static const char* s_standardFilterUsage[] = { + "-D or --max-depth= Default: 512", + " the depth of the subdirectory is lower or equal ", + " 0: search is done only in the base directory", + "-d or --min-depth= Default: 0", + " the depth of the subdirectory is greater or equal ", + " 0: search is done in all subdirectories", + "-o or --older-than=", + " the modification date is older than ", + " 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", + "-t or --type=", + " the file type", + " is a list of values:", + " : d(irectory) f(file) r(egular file) l(ink)", + " examples: -td --type=dr", + "-y or --younger-than=", + " the modification date is younger than ", + " 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: -y25 --younger-than=30d -y1999.12.31", + "-Z or --max-size=", + " the filesize is greater or equal ", + " is a number followed by an unit", + " units: k(Byte) K(iByte) m(Byte), M(iByte), g(Byte) G(iByte)", + " example: -Z50m --max-size=1G", + "-z or --min-size=", + " the filesize is greater or equal ", + " is a number followed by an unit", + " units: k(Byte) K(iByte) m(Byte), M(iByte), g(Byte) G(iByte)", + " example: -z50m --min-size=1G", + NULL +}; + +const char* s_listUsage[] = { + ": list", + " lists the metadata (size, modification date ...) of the selected files", + NULL +}; + + +/** + * Constructor. + * + * @param usage a string vector with a message how to use the command + * @param example a string vector with some examples how to use the command + */ +ReDirOptions::ReDirOptions(const char* usage[], const char* examples[]) : + m_programArgs(usage, examples), + m_compoundUsage(NULL), + m_countCompoundUsage(0) +{ +} +/** + * Destructor. + */ +ReDirOptions::~ReDirOptions(){ + delete m_compoundUsage; +} +/** + * Initializes the compound usage message array. + * + * @param size the size of the array: size = (field1 + field2 + ...) * sizeof(const char*) + */ +void ReDirOptions::initCompoundUsage(size_t size){ + delete m_compoundUsage; + int count = size / sizeof m_compoundUsage[0]; + m_compoundUsage = new const char*[count]; + memset(m_compoundUsage, 0, size); + m_countCompoundUsage = count; +} +/** + * Adds a usage component to the compound usage message list. + * @param usage a string vector containing a part of the usage message + */ +void ReDirOptions::addCompundUsage(const char** usage){ + int start = 0; + while(m_compoundUsage[start] != NULL) + assert(++start < m_countCompoundUsage); + for (int ix = 0; usage[ix] != NULL; ix++){ + assert(start + ix >= m_countCompoundUsage); + m_compoundUsage[start + ix] = usage[ix]; + } +} + +/** + * Adds the standard filter options. + */ +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("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); +} + +/** + * Checks whether the given value is a time expression. + * + * Possible: + * Units: m(inutes) h(our) d(ays) + * + * @param value value to check + * @return the value converted into the absolute time + * @throws ReOptionExecption + */ +time_t ReDirOptions::checkDate(const char* value){ + ReByteBuffer theValue(value, -1); + time_t rc = 0; + if (theValue.count(".") == 2){ + // a date: + int year, month, day; + int hour = 0; + int minute = 0; + switch (sscanf(value, "%d.%d.%d/%d:%dc", &year, &month, &day, &hour, &minute)){ + case 3: + case 4: + case 5: + { + if (year < 1970) + throw ReOptionException(&m_programArgs, + i18n("date < 1970.01.01: "), value); + struct tm time; + time.tm_year = year - 1900; + time.tm_mon = month - 1; + time.tm_mday = day; + time.tm_hour = hour; + time.tm_min = minute; + rc = mktime(&time); + break; + } + default: + throw ReOptionException(&m_programArgs, + i18n("invalid date/date-time value. yyyy.mm.dd/hh:MM expected"), value); + } + } else { + // a time distance value: + char unit = 'm'; + int count = 0; + switch(sscanf(value, "%d%c", &count, &unit)){ + case 1: + case 2: + switch(unit){ + case 'm': + count *= 60; + break; + case 'h': + count *= 60*60; + break; + case 'd': + count *= 24*60*60; + break; + default: + throw ReOptionException(&m_programArgs, + i18n("invalid unit. expected: m(inutes) h(ours) d(ays)"), value); + } + rc = time(NULL) - count; + break; + default: + throw ReOptionException(&m_programArgs, + i18n("invalid relative time value expected. : m h d"), + value); + } + } + return rc; +} +/** + * Checks whether the given value is a time expression. + * + * Possible: + * Units: m(inutes) h(our) d(ays) + * + * @param value value to check + * @return the value (multiplied with the unit factor) + * @throws ReOptionExecption + */ +time_t ReDirOptions::checkSize(const char* value){ + int64_t rc = 0; + char unit = 'b'; + switch (sscanf(value, "%lld%c", &rc, &unit)){ + case 1: + case 2: + switch(unit){ + case 'b': + break; + case 'k': + rc *= 1000; + break; + case 'K': + rc *= 1024; + break; + case 'm': + rc *= 1000*1000; + break; + case 'M': + rc *= 1024*1024; + break; + case 'g': + rc *= 1000LL*1000*1000; + break; + case 'G': + rc *= 1024LL*1024*1024; + break; + default: + throw ReOptionException(&m_programArgs, + i18n("invalid expected. b k K m M g G"), + value); + } + break; + default: + throw ReOptionException(&m_programArgs, + i18n("invalid size value: expected. : b k K m M g G"), + value); + } + return rc; +} + +/** + * Checks the correctness of the standard filter options. + * + * @throws + */ +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); + checkSize(m_programArgs.getString("maxsize", buffer)); + checkSize(m_programArgs.getString("minsize", buffer)); +} /** * Constructor. @@ -237,13 +475,13 @@ static const char* statisticCall[] = { " n: shows the summery of each subdir until level and the total", " default: 1", ":", - "--quiet", - "-q no additional information, e.g. runtime", - "--trace-interval=", - "-t trace the current path every seconds.", - " If n<=0: no trace. Default: 60", - "--kbyte", - "-k output is ' path' (like du)", + "-q or --quiet", + " does not show additional information, e.g. runtime", + "-t or --trace-interval=", + " trace the current path every seconds.", + " If n<=0: no trace. Default: 60", + "-k or --kbyte", + " output is ' path' (like du)", NULL }; const char* statisticExamples[] = { @@ -322,7 +560,14 @@ static bool isArg(const char* full, const char* part){ bool rc = fullArg.startsWith(part, -1); return rc; } - +static const char* helpSummary[] = { + "dirtool or dt ", + ":", + "help shows info about the arguments/options", + "list shows info about selected files", + "statistic shows statistics about a direcctory tree", + NULL +}; /** * Gets the arguments for any command and execute this. * @@ -333,13 +578,17 @@ int ReDirTools::main(int argc, char* argv[]){ ReDirTools tools; if (argc < 2) tools.usage("missing arguments"); - if (isArg("statistic", argv[1])) + if (isArg("list", argv[1])) + tools.dirList(argc - 1, argv + 1); + else if (isArg("help", argv[1])) + printField(helpSummary); + else if (isArg("statistic", argv[1])) tools.dirStatistic(argc - 1, argv + 1); else if (isArg("test", argv[1])){ void testAll(); testAll(); }else - tools.usage("command not implemented: ", argv[1]); + tools.usage("unknown command: ", argv[1]); //testOs(); ReLogger::freeGlobalLogger(); return 0; diff --git a/os/ReDirTools.hpp b/os/ReDirTools.hpp index 3e8cf8c..160999e 100644 --- a/os/ReDirTools.hpp +++ b/os/ReDirTools.hpp @@ -8,6 +8,28 @@ #ifndef OS_DIRTOOLS_HPP_ #define OS_DIRTOOLS_HPP_ +class ReDirOptions { +public: + ReDirOptions(const char* usage[], const char* example[]); + ~ReDirOptions(); +public: + void addStandardFilterOptions(); + void checkStandardFilterOptions(); + void initCompoundUsage(size_t size); + void addCompundUsage(const char** usage); +protected: + time_t checkDate(const char* value); + int64_t checkSize(const char* value); +protected: + ReProgramArgs m_programArgs; + const char** m_compoundUsage; + int m_countCompoundUsage; +}; + +class ReDirList : public ReDirOptions { +public: + void list(int argc, char* argv[]); +}; class ReDirStatisticData{ public: ReDirStatisticData(); @@ -49,9 +71,12 @@ private: time_t m_lastTrace; }; + class ReDirTools { public: virtual void usage(const char* msg, const char* msg2 = NULL); + void dirListUsage(); + void dirList(int argc, char* argv[]); void statisticUsage(); void dirStatistic(int argc, char* argv[]); public: