hmbackgui [<home_dir>]
+<home_dir>:
+ the base directory for the configuration directory ".reappl"
+ Default: the home directory of the user
+
+
Example:
+
hmbackgui /home/hugo
+
+
+
Installation
+
Linux
+
+
Copy rebackgui to /usr/local/bin
+
Copy rebackgui.*.qm to the configuration directory, e.g. /home/hm/.reappl
+
+
cd /usr/local/bin
+chown root.root rebackgui
+chmod u+s rebackgui
+
+
+
+
Configuration
+
The configuration is stored in <home_dir>/.rebackgui/rebackgui.conf
+
+
+
Program Documentation
+
+
Programming Features
+
+
This is a example for a complete QT application with the following features:
+
+
multithreaded
+
pattern matching
+
multithreaded GUI building
+
+
+
+
(Un)License: Public Domain
+
+
You can use and modify this file without any restriction.
+Do what you want.
+No warranties and disclaimer of any damages.
+More info: http://unlicense.org
+The latest sources: https://github.com/republib.
+
+
+
+
diff --git a/appl/rebackgui/rebackgui.pro b/appl/rebackgui/rebackgui.pro
index 4b10c3d..ba86e1c 100644
--- a/appl/rebackgui/rebackgui.pro
+++ b/appl/rebackgui/rebackgui.pro
@@ -53,7 +53,8 @@ FORMS += mainwindow.ui \
DISTFILES += \
ReBackGui.html \
- osconnect.pl
+ osconnect.pl \
+ rebackgui.html
TRANSLATIONS = rebackgui.de.ts
CODECFORTR = UTF-8
diff --git a/appl/recommand/recommand.pro b/appl/recommand/recommand.pro
index 8efbe4f..318b324 100644
--- a/appl/recommand/recommand.pro
+++ b/appl/recommand/recommand.pro
@@ -29,7 +29,8 @@ SOURCES += main.cpp\
../../gui/ReGuiQueue.cpp \
../../gui/ReGuiUtils.cpp \
mainwindow.cpp \
- CommandProcessor.cpp
+ CommandProcessor.cpp \
+ ../../base/ReProcess.cpp
HEADERS += mainwindow.hpp \
CommandProcessor.hpp \
diff --git a/base/ReConfig.hpp b/base/ReConfig.hpp
index 617e566..b2bdb44 100644
--- a/base/ReConfig.hpp
+++ b/base/ReConfig.hpp
@@ -11,7 +11,7 @@
#ifndef RECONFIG_HPP
#define RECONFIG_HPP
-class ReConfig: public ReConfigurator, protected QHash {
+class ReConfig: public ReConfigurator, public QHash {
public:
ReConfig(const char* file = NULL, bool readOnly = true, ReLogger* logger =
NULL);
diff --git a/base/ReContainer.cpp b/base/ReContainer.cpp
index 62d7683..9f50f2d 100644
--- a/base/ReContainer.cpp
+++ b/base/ReContainer.cpp
@@ -67,12 +67,12 @@ const char* ReContainer::MAGIC_1 = "Rpl&1";
* @param sizeHint Probable length of the container
*/
ReContainer::ReContainer(size_t sizeHint) :
- m_data(""),
- m_countBags(0),
- m_typeList(""),
- m_ixItem(0),
- m_ixBag(0),
- m_readPosition(NULL) {
+ m_data(""),
+ m_countBags(0),
+ m_typeList(""),
+ m_ixItem(0),
+ m_ixBag(0),
+ m_readPosition(NULL) {
if (sizeHint > 0)
m_data.reserve(sizeHint);
}
@@ -188,10 +188,10 @@ const QByteArray& ReContainer::getData() {
char buffer[128];
// RPL&1 0a b5[2]cis: !12
qsnprintf(buffer, sizeof buffer, "%x[%d]%s:",
- (unsigned int) m_data.length(), m_countBags, m_typeList.data());
+ (unsigned int) m_data.length(), m_countBags, m_typeList.data());
char header[128 + 8];
qsnprintf(header, sizeof header, "%s%02x%s", MAGIC_1,
- (unsigned int) strlen(buffer), buffer);
+ (unsigned int) strlen(buffer), buffer);
m_data.insert(0, header);
}
return m_data;
@@ -207,25 +207,25 @@ void ReContainer::fill(const QByteArray& data) {
const char* ptr = m_data.data();
if (strncmp(ptr, MAGIC_1, strlen(MAGIC_1)) != 0)
throw RplInvalidDataException(LOG_ERROR, LOC_FILL_1,
- "container has no magic", data.data(), data.length());
+ "container has no magic", data.data(), data.length());
ptr += strlen(MAGIC_1);
unsigned int headerSize = 0;
if (sscanf(ptr, "%02x", &headerSize) != 1)
throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
- "container has no header size", ptr, 2);
+ "container has no header size", ptr, 2);
ptr += 2;
unsigned int dataSize = 0;
unsigned int countBags = 0;
if (sscanf(ptr, "%x[%x]", &dataSize, &countBags) != 2)
throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
- "container has no data_size[bag_count]", ptr, 16);
+ "container has no data_size[bag_count]", ptr, 16);
m_countBags = countBags;
ptr = strchr(ptr, ']') + 1;
const char* end = ptr + strspn(ptr, "cisdDX!");
if (end == ptr || *end != ':') {
throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
- "container has no valid typelist", ptr, 16);
+ "container has no valid typelist", ptr, 16);
}
m_typeList.clear();
m_typeList.append(ptr, end - ptr);
@@ -247,13 +247,13 @@ int ReContainer::getCountBags() const {
void ReContainer::nextBag() {
if (m_ixItem < m_typeList.length() && m_ixItem != -1)
throw ReException(LOG_ERROR, LOC_NEXT_BAG_1, NULL,
- "end of bag not reached: remaining items: %s",
- m_typeList.data() + m_ixItem);
+ "end of bag not reached: remaining items: %s",
+ m_typeList.data() + m_ixItem);
m_ixItem = 0;
m_ixBag++;
if (m_ixBag >= m_countBags)
throw ReException(LOG_ERROR, LOC_NEXT_BAG_2, NULL, "no more bags: %d",
- m_ixBag);
+ m_ixBag);
}
/**
* @brief Sets the next item.
@@ -267,20 +267,20 @@ void ReContainer::nextItem(type_tag_t expected) {
}
if (m_ixItem >= m_typeList.length())
throw ReException(LOG_ERROR, LOC_NEXT_ITEM_1, ReLogger::globalLogger(),
- "no more items in the bag");
+ "no more items in the bag");
type_tag_t current = (type_tag_t) m_typeList.at(m_ixItem);
// Unify all data types:
if (current == TAG_DATA4G || current == TAG_DATA64K)
current = TAG_DATA255;
if (current != expected)
throw ReException(LOG_ERROR, LOC_NEXT_ITEM_2, NULL,
- "current item is a %c, not a %c", (char) m_typeList.at(m_ixItem),
- (char) expected);
+ "current item is a %c, not a %c", (char) m_typeList.at(m_ixItem),
+ (char) expected);
m_ixItem++;
if (m_readPosition > (uint8_t*) (m_data.data() + m_data.length()))
throw ReException(LOG_ERROR, LOC_NEXT_ITEM_3, NULL,
- "container size too small. Bag: %d of %d Item: %d of %d",
- 1 + m_ixBag, m_countBags, 1 + m_ixItem, m_typeList.length());
+ "container size too small. Bag: %d of %d Item: %d of %d",
+ 1 + m_ixBag, m_countBags, 1 + m_ixItem, m_typeList.length());
}
/**
@@ -307,7 +307,7 @@ int ReContainer::nextInt() {
unsigned int value = 0;
if (sscanf((const char*) m_readPosition, "%x ", &value) != 1)
throw RplInvalidDataException(LOG_ERROR, LOC_NEXT_INT_1,
- "not a hex_number", m_readPosition, 16);
+ "not a hex_number", m_readPosition, 16);
m_readPosition = (uint8_t*) strchr((const char*) m_readPosition, ' ') + 1;
if (isNegativ)
value = -value;
@@ -323,10 +323,10 @@ int64_t ReContainer::nextInt64() {
bool isNegativ = *m_readPosition == '-';
if (isNegativ)
m_readPosition++;
- uint64_t value = 0;
+ quint64 value = 0;
if (sscanf((const char*) m_readPosition, "%llx ", &value) != 1)
throw RplInvalidDataException(LOG_ERROR, LOC_NEXT_INT_1,
- "not a hex_number", m_readPosition, 16);
+ "not a hex_number", m_readPosition, 16);
m_readPosition = (uint8_t*) strchr((const char*) m_readPosition, ' ') + 1;
if (isNegativ)
value = -value;
@@ -392,7 +392,7 @@ size_t ReContainer::nextData(QByteArray& data, bool append) {
* @return a human readable string describing the container
*/
QByteArray ReContainer::dump(const char* title, int maxBags,
- int maxStringLength, int maxBlobLength, char separatorItems) {
+ int maxStringLength, int maxBlobLength, char separatorItems) {
QByteArray rc;
rc.reserve(64000);
rc.append("=== ").append(title).append('\n');
@@ -409,7 +409,7 @@ QByteArray ReContainer::dump(const char* title, int maxBags,
maxBags = m_countBags;
for (int ixBag = 0; ixBag < maxBags; ixBag++) {
rc.append("--- bag ").append(ReStringUtils::toNumber(ixBag)).append(
- ":\n");
+ ":\n");
nextBag();
QByteArray item;
int maxLength;
@@ -422,9 +422,9 @@ QByteArray ReContainer::dump(const char* title, int maxBags,
case TAG_INT:
iValue = nextInt();
rc.append(" i: ").append(ReStringUtils::toNumber(iValue)).append(
- " / ");
+ " / ");
rc.append(ReStringUtils::toNumber(iValue, "%x")).append(
- separatorItems);
+ separatorItems);
break;
case TAG_STRING:
sValue = nextString();
@@ -439,10 +439,10 @@ QByteArray ReContainer::dump(const char* title, int maxBags,
rc.append(' ').append((char) currentType).append(": [");
rc.append(ReStringUtils::toNumber(item.length())).append("] ");
maxLength =
- item.length() < maxBlobLength ?
- item.length() : maxBlobLength;
+ item.length() < maxBlobLength ?
+ item.length() : maxBlobLength;
rc.append(ReStringUtils::hexDump(item.data(), maxLength, 16))
- .append(separatorItems);
+ .append(separatorItems);
break;
default:
break;
diff --git a/base/ReFileUtils.cpp b/base/ReFileUtils.cpp
index 0897aa8..6f9b56f 100644
--- a/base/ReFileUtils.cpp
+++ b/base/ReFileUtils.cpp
@@ -21,6 +21,7 @@ enum {
LOC_MAKE_DIR_2, // 12506
LOC_SET_TIMES_2, // 12507
};
+int ReFileUtils::m_maxCharSet = 128;
QDateTime ReFileUtils::m_undefinedTime;
@@ -161,11 +162,13 @@ QString ReFileUtils::cleanPath(const QString& path) {
* @param source full path of the source file
* @param target full path of the target name
* @param sourceInfo NULL or the info about the surce
- * @param buffer IN/OUT: used as
+ * @param buffer IN/OUT: used for buffering the file content
+ *
* @return
*/
QString ReFileUtils::copy(const QString& source, const QString& target,
- const QFileInfo* sourceInfo, QByteArray& buffer){
+ const QFileInfo* sourceInfo, QByteArray& buffer,
+ bool setUser){
QString rc;
#if defined _WIN32
const ushort* src = source.utf16();
@@ -182,9 +185,23 @@ QString ReFileUtils::copy(const QString& source, const QString& target,
sourceInfo2.setFile(source);
sourceInfo = &sourceInfo2;
}
- if (! sourceInfo->exists())
+ if (! sourceInfo->exists()){
rc = QObject::tr("not found: %1").arg(source);
- else {
+ } else if (sourceInfo->isSymLink()){
+ // sourceInfo->symLink() returns the absolute path for relative links too.
+ // Though we use readlink():
+ size_t size = buffer.capacity();
+ if (size < 4096){
+ buffer.resize(4096);
+ size = buffer.capacity();
+ }
+ int length = readlink(source2.constData(), buffer.data(), size);
+ buffer.resize(length);
+ QString link = I18N::s2b(buffer);
+ QFile::link(link, target);
+ } else if (! sourceInfo->isFile()){
+ rc = QObject::tr("not a regular file: %1").arg(source);
+ } else {
FILE* fpSource = fopen(source2.constData(), "rb");
if (fpSource == NULL){
rc = QObject::tr("cannot open (%1): %2").arg(errno).arg(source);
@@ -228,6 +245,15 @@ QString ReFileUtils::copy(const QString& source, const QString& target,
}
}
fclose(fpSource);
+#ifdef __linux__
+ if (setUser){
+ if (chown(target2.constData(), sourceInfo->ownerId(),
+ sourceInfo->groupId()) != 0 && rc.isEmpty()){
+ rc = QObject::tr("cannot set user/gid (%1): %2")
+ .arg(errno).arg(target);
+ }
+ }
+#endif
}
}
#endif
@@ -372,6 +398,73 @@ QStringList ReFileUtils::findRootDirs()
return rc;
}
+/**
+ * Modify a filename until the file does not exist.
+ *
+ * @param filename filename to modify
+ * @return "": no unused filename found
+ * otherwise: a modification of filename which does not exist
+ */
+QString ReFileUtils::modifyToNonExisting(const QString& path){
+ static const char* charSet = "$_-+=!^#%~01234567890abcdefghijklmnopqrstuvwxyz";
+ static int charSetLength = 0;
+ static char indexOf[128] = { 0 };
+ if (charSetLength == 0){
+ charSetLength = min(m_maxCharSet, strlen(charSet));
+ memset(indexOf, charSetLength, sizeof indexOf);
+ for (int ix = 0; ix < charSetLength; ix++){
+ indexOf[(int) charSet[ix]] = ix;
+ }
+ }
+ QString rc = path;
+ int ix;
+ // begin is the first index of the filename (without path)
+ int begin = 0;
+ // last is the last index of the filename (without extension)
+ int last = -1;
+ for (ix = rc.length() - 1; ix >= 0; ix--){
+ if (rc.at(ix) == OS_SEPARATOR || rc.at(ix) == OS_2nd_SEPARATOR){
+ begin = ix - 1;
+ if (last < 0)
+ last = rc.length() - 1;
+ break;
+ } else if (last < 0 && rc.at(ix) == '.')
+ last = ix + 1;
+ }
+ if (last <= 0)
+ last = rc.length() - 1;
+ // first is the index of the first modified character in the filename
+ int first = last + 1;
+ while (first <= begin && QFile(rc).exists()){
+ if (first < last){
+ first++;
+ rc[last] = charSet[0];
+ } else if ( (ix = indexOf[rc.at(last).unicode()]) < charSetLength - 1){
+ rc[last] = charSet[ix + 1];
+ } else {
+ int pos = last;
+ rc[last] = charSet[0];
+ while(true){
+ if (--pos < begin){
+ first = begin + 1;
+ rc = "";
+ break;
+ }
+ if (pos > first){
+ first++;
+ rc[first] = charSet[0];
+ break;
+ } else if ( (ix = indexOf[rc.at(pos).unicode()]) < charSetLength - 1){
+ rc[pos] = charSet[ix + 1];
+ break;
+ } else {
+ rc[pos] = charSet[0];
+ }
+ }
+ }
+ }
+ return rc;
+}
/**
* Returns whether a path is an absolute path.
*
@@ -413,14 +506,15 @@ bool ReFileUtils::isAbsolutPath(const char* path) {
*
* @param path full name of the directory to inspect
* @param isFile OUT: true: this is a file (and not a directory)
- * @return true: path is a directory
+ * @return true: path is a directory (and not a symbolic
+ * link)
*/
bool ReFileUtils::isDirectory(const QString& path, bool* isFile)
{
QFileInfo info(path);
bool rc = info.exists();
if (rc){
- if (! info.isDir())
+ if (info.isSymLink() || ! info.isDir())
rc = false;
if (isFile != NULL)
*isFile = ! rc;
@@ -776,72 +870,6 @@ QByteArray ReFileUtils::replaceExtension(const char* path, const char* ext) {
return rc;
}
-/**
- * Splits an URL into its parts.
- *
- * Examples:
- *