#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<n> or --max-depth=<n> Default: 512",
+ " the depth of the subdirectory is lower or equal <n>",
+ " 0: search is done only in the base directory",
+ "-d<n> or --min-depth=<n> Default: 0",
+ " the depth of the subdirectory is greater or equal <n>",
+ " 0: search is done in all subdirectories",
+ "-o<v> or --older-than=<v>",
+ " the modification date is older than <v>",
+ " <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",
+ "-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",
+ "-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",
+ " units: m(inutes) h(hours), d(days). Default: m(inutes)",
+ " examples: -y25 --younger-than=30d -y1999.12.31",
+ "-Z<v> or --max-size=<v>",
+ " the filesize is greater or equal <v>",
+ " <v> 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<n> or --min-size=<n>",
+ " the filesize is greater or equal <n>",
+ " <v> 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[] = {
+ "<command>: 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: <date> <date_time> <n><unit>
+ * 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 <number><unit> expected. <unit>: m h d"),
+ value);
+ }
+ }
+ return rc;
+}
+/**
+ * Checks whether the given value is a time expression.
+ *
+ * Possible: <date> <date_time> <n><unit>
+ * 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 <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"),
+ 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.
" n: shows the summery of each subdir until level <n> and the total",
" default: 1",
"<opts_stat>:",
- "--quiet",
- "-q no additional information, e.g. runtime",
- "--trace-interval=<n>",
- "-t<n> trace the current path every <n> seconds.",
- " If n<=0: no trace. Default: 60",
- "--kbyte",
- "-k output is '<kbyte> path' (like du)",
+ "-q or --quiet",
+ " does not show additional information, e.g. runtime",
+ "-t<n> or --trace-interval=<n>",
+ " trace the current path every <n> seconds.",
+ " If n<=0: no trace. Default: 60",
+ "-k or --kbyte",
+ " output is '<kbyte> path' (like du)",
NULL
};
const char* statisticExamples[] = {
bool rc = fullArg.startsWith(part, -1);
return rc;
}
-
+static const char* helpSummary[] = {
+ "dirtool or dt <command> <opts>",
+ "<command>:",
+ "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.
*
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;