#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>]",
"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"
}
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.
*
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");
}
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));
}
/**
}
}
+/**
+ * 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.
*
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
* @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))
* @param argav the argument vector
*/
void ReDirTools::statistic(int argc, char* argv[]){
+ ReDirStatistic statistic;
+ statistic.run(argc, 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);