Allow having semi-colons in quoted arguments in the cmd part of mimeview defs
This commit is contained in:
parent
4ebffd1a31
commit
7ef02a3b09
@ -905,11 +905,17 @@ bool RclConfig::getGuiFilter(const string& catfiltername, string& frag) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RclConfig::valueSplitAttributes(const string& whole, string& value,
|
bool RclConfig::valueSplitAttributes(const string& whole, string& value, ConfSimple& attrs)
|
||||||
ConfSimple& attrs)
|
|
||||||
{
|
{
|
||||||
/* There is currently no way to escape a semi-colon */
|
bool inquote{false};
|
||||||
string::size_type semicol0 = whole.find_first_of(";");
|
string::size_type semicol0;
|
||||||
|
for (semicol0 = 0; semicol0 < whole.size(); semicol0++) {
|
||||||
|
if (whole[semicol0] == '"') {
|
||||||
|
inquote = !inquote;
|
||||||
|
} else if (whole[semicol0] == ';' && !inquote) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
value = whole.substr(0, semicol0);
|
value = whole.substr(0, semicol0);
|
||||||
trimstring(value);
|
trimstring(value);
|
||||||
string attrstr;
|
string attrstr;
|
||||||
|
|||||||
@ -259,12 +259,18 @@ public:
|
|||||||
string getMimeHandlerDef(const string &mimetype, bool filtertypes=false,
|
string getMimeHandlerDef(const string &mimetype, bool filtertypes=false,
|
||||||
const std::string& fn = std::string());
|
const std::string& fn = std::string());
|
||||||
|
|
||||||
/** For lines like: "name = some value; attr1 = value1; attr2 = val2"
|
/** For lines like: [name = some value; attr1 = value1; attr2 = val2]
|
||||||
* Separate the value and store the attributes in a ConfSimple
|
* Separate the value and store the attributes in a ConfSimple
|
||||||
* @param whole the raw value. No way to escape a semi-colon in there.
|
*
|
||||||
|
* In the value part, semi-colons inside double quotes are ignored, and double quotes are
|
||||||
|
* conserved. In the common case where the string is then processed by stringToStrings() to
|
||||||
|
* build a command line, this allows having semi-colons inside arguments. However, no backslash
|
||||||
|
* escaping is possible, so that, for example "bla\"1;2\"" would not work (the value part
|
||||||
|
* would stop at the semi-colon).
|
||||||
|
*
|
||||||
|
* @param whole the raw value.
|
||||||
*/
|
*/
|
||||||
static bool valueSplitAttributes(const string& whole, string& value,
|
static bool valueSplitAttributes(const string& whole, string& value, ConfSimple& attrs) ;
|
||||||
ConfSimple& attrs) ;
|
|
||||||
|
|
||||||
/** Compute difference between 'base' and 'changed', as elements to be
|
/** Compute difference between 'base' and 'changed', as elements to be
|
||||||
* added and substracted from base. Input and output strings are in
|
* added and substracted from base. Input and output strings are in
|
||||||
|
|||||||
@ -32,19 +32,111 @@ using namespace std;
|
|||||||
#include "rclconfig.h"
|
#include "rclconfig.h"
|
||||||
#include "cstr.h"
|
#include "cstr.h"
|
||||||
|
|
||||||
|
void showFields(RclConfig *config)
|
||||||
|
{
|
||||||
|
set<string> stored = config->getStoredFields();
|
||||||
|
set<string> indexed = config->getIndexedFields();
|
||||||
|
cout << "Stored fields: ";
|
||||||
|
for (const auto& field: stored) {
|
||||||
|
cout << "[" << field << "] ";
|
||||||
|
}
|
||||||
|
cout << "\n";
|
||||||
|
cout << "Indexed fields: ";
|
||||||
|
for (const auto& field : indexed) {
|
||||||
|
const FieldTraits *ftp;
|
||||||
|
config->getFieldTraits(field, &ftp);
|
||||||
|
if (ftp)
|
||||||
|
cout << "[" << field << "]" << " -> [" << ftp->pfx << "] ";
|
||||||
|
else
|
||||||
|
cout << "[" << field << "]" << " -> [" << "(none)" << "] ";
|
||||||
|
|
||||||
|
}
|
||||||
|
cout << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkMtypesConsistency(RclConfig *config)
|
||||||
|
{
|
||||||
|
// Checking the configuration consistency
|
||||||
|
|
||||||
|
// Find and display category names
|
||||||
|
vector<string> catnames;
|
||||||
|
config->getMimeCategories(catnames);
|
||||||
|
cout << "Categories: ";
|
||||||
|
for (const auto& catg : catnames) {
|
||||||
|
cout << catg << " ";
|
||||||
|
}
|
||||||
|
cout << "\n";
|
||||||
|
|
||||||
|
// Compute union of all types from each category. Check that there
|
||||||
|
// are no duplicates while we are at it.
|
||||||
|
set<string> allmtsfromcats;
|
||||||
|
for (const auto& catg : catnames) {
|
||||||
|
vector<string> cts;
|
||||||
|
config->getMimeCatTypes(catg, cts);
|
||||||
|
for (const auto& cattype : cts) {
|
||||||
|
// Already in map -> duplicate
|
||||||
|
if (allmtsfromcats.find(cattype) != allmtsfromcats.end()) {
|
||||||
|
cout << "Duplicate: [" << cattype << "]" << "\n";
|
||||||
|
}
|
||||||
|
allmtsfromcats.insert(cattype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve complete list of mime types
|
||||||
|
vector<string> mtypes = config->getAllMimeTypes();
|
||||||
|
|
||||||
|
// And check that each mime type is found in exactly one category
|
||||||
|
// And have an icon
|
||||||
|
for (const auto& mtype: mtypes) {
|
||||||
|
if (allmtsfromcats.find(mtype) == allmtsfromcats.end()) {
|
||||||
|
cout << "Not found in catgs: [" << mtype << "]" << "\n";
|
||||||
|
}
|
||||||
|
// We'd like to check for types with no icons, but
|
||||||
|
// getMimeIconPath() returns the valid 'document' by
|
||||||
|
// default, we'd have to go look into the confsimple
|
||||||
|
// directly.
|
||||||
|
// string path = config->getMimeIconPath(mtype, string());
|
||||||
|
// cout << mtype << " -> " << path << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// List mime types not in mimeview
|
||||||
|
for (const auto & mtype : mtypes) {
|
||||||
|
if (config->getMimeViewerDef(mtype, "", false).empty()) {
|
||||||
|
cout << "No viewer: [" << mtype << "]" << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that each mime type has an indexer
|
||||||
|
for (const auto & mtype : mtypes) {
|
||||||
|
if (config->getMimeHandlerDef(mtype, false).empty()) {
|
||||||
|
cout << "No filter: [" << mtype << "]" << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that each mime type has a defined icon
|
||||||
|
for (const auto & mtype : mtypes) {
|
||||||
|
if (config->getMimeIconPath(mtype, "") == "document") {
|
||||||
|
cout << "No or generic icon: [" << mtype << "]" << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static char *thisprog;
|
static char *thisprog;
|
||||||
|
|
||||||
static char usage [] = "\n"
|
static char usage [] = "\n"
|
||||||
|
" -h : print help\n"
|
||||||
"-c: check a few things in the configuration files\n"
|
"-c: check a few things in the configuration files\n"
|
||||||
"[-s subkey] -q param : query parameter value\n"
|
"[-s subkey] -q param : query parameter value\n"
|
||||||
"-f : print some field data\n"
|
"-f : print some field data\n"
|
||||||
" : default: print parameters\n"
|
"-l : list recoll.conf parameters\n"
|
||||||
|
" : default: nothing\n"
|
||||||
;
|
;
|
||||||
static void
|
static void
|
||||||
Usage(void)
|
Usage(FILE *fp = stderr)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: usage: %s\n", thisprog, usage);
|
fprintf(fp, "%s: usage: %s\n", thisprog, usage);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +146,8 @@ static int op_flags;
|
|||||||
#define OPT_q 0x4
|
#define OPT_q 0x4
|
||||||
#define OPT_c 0x8
|
#define OPT_c 0x8
|
||||||
#define OPT_f 0x10
|
#define OPT_f 0x10
|
||||||
|
#define OPT_l 0x20
|
||||||
|
#define OPT_h 0x40
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -71,6 +165,10 @@ int main(int argc, char **argv)
|
|||||||
switch (*(*argv)++) {
|
switch (*(*argv)++) {
|
||||||
case 'c': op_flags |= OPT_c; break;
|
case 'c': op_flags |= OPT_c; break;
|
||||||
case 'f': op_flags |= OPT_f; break;
|
case 'f': op_flags |= OPT_f; break;
|
||||||
|
case 'h': op_flags |= OPT_h;
|
||||||
|
Usage(stdout);
|
||||||
|
break;
|
||||||
|
case 'l': op_flags |= OPT_l; break;
|
||||||
case 's': op_flags |= OPT_s; if (argc < 2) Usage();
|
case 's': op_flags |= OPT_s; if (argc < 2) Usage();
|
||||||
skey = *(++argv);
|
skey = *(++argv);
|
||||||
argc--;
|
argc--;
|
||||||
@ -90,7 +188,7 @@ int main(int argc, char **argv)
|
|||||||
string reason;
|
string reason;
|
||||||
RclConfig *config = recollinit(0, 0, 0, reason);
|
RclConfig *config = recollinit(0, 0, 0, reason);
|
||||||
if (config == 0 || !config->ok()) {
|
if (config == 0 || !config->ok()) {
|
||||||
cerr << "Configuration problem: " << reason << endl;
|
cerr << "Configuration problem: " << reason << "\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (op_flags & OPT_s)
|
if (op_flags & OPT_s)
|
||||||
@ -103,106 +201,49 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
printf("[%s] -> [%s]\n", pname.c_str(), value.c_str());
|
printf("[%s] -> [%s]\n", pname.c_str(), value.c_str());
|
||||||
} else if (op_flags & OPT_f) {
|
} else if (op_flags & OPT_f) {
|
||||||
set<string> stored = config->getStoredFields();
|
showFields(config);
|
||||||
set<string> indexed = config->getIndexedFields();
|
|
||||||
cout << "Stored fields: ";
|
|
||||||
for (set<string>::const_iterator it = stored.begin();
|
|
||||||
it != stored.end(); it++) {
|
|
||||||
cout << "[" << *it << "] ";
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
cout << "Indexed fields: ";
|
|
||||||
for (set<string>::const_iterator it = indexed.begin();
|
|
||||||
it != indexed.end(); it++) {
|
|
||||||
const FieldTraits *ftp;
|
|
||||||
config->getFieldTraits(*it, &ftp);
|
|
||||||
if (ftp)
|
|
||||||
cout << "[" << *it << "]" << " -> [" << ftp->pfx << "] ";
|
|
||||||
else
|
|
||||||
cout << "[" << *it << "]" << " -> [" << "(none)" << "] ";
|
|
||||||
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
} else if (op_flags & OPT_c) {
|
} else if (op_flags & OPT_c) {
|
||||||
// Checking the configuration consistency
|
checkMtypesConsistency(config);
|
||||||
|
} else if (op_flags & OPT_l) {
|
||||||
// Find and display category names
|
|
||||||
vector<string> catnames;
|
|
||||||
config->getMimeCategories(catnames);
|
|
||||||
cout << "Categories: ";
|
|
||||||
for (vector<string>::const_iterator it = catnames.begin();
|
|
||||||
it != catnames.end(); it++) {
|
|
||||||
cout << *it << " ";
|
|
||||||
}
|
|
||||||
cout << endl;
|
|
||||||
|
|
||||||
// Compute union of all types from each category. Check that there
|
|
||||||
// are no duplicates while we are at it.
|
|
||||||
set<string> allmtsfromcats;
|
|
||||||
for (vector<string>::const_iterator it = catnames.begin();
|
|
||||||
it != catnames.end(); it++) {
|
|
||||||
vector<string> cts;
|
|
||||||
config->getMimeCatTypes(*it, cts);
|
|
||||||
for (vector<string>::const_iterator it1 = cts.begin();
|
|
||||||
it1 != cts.end(); it1++) {
|
|
||||||
// Already in map -> duplicate
|
|
||||||
if (allmtsfromcats.find(*it1) != allmtsfromcats.end()) {
|
|
||||||
cout << "Duplicate: [" << *it1 << "]" << endl;
|
|
||||||
}
|
|
||||||
allmtsfromcats.insert(*it1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve complete list of mime types
|
|
||||||
vector<string> mtypes = config->getAllMimeTypes();
|
|
||||||
|
|
||||||
// And check that each mime type is found in exactly one category
|
|
||||||
// And have an icon
|
|
||||||
for (const auto& mtype: mtypes) {
|
|
||||||
if (allmtsfromcats.find(mtype) == allmtsfromcats.end()) {
|
|
||||||
cout << "Not found in catgs: [" << mtype << "]" << endl;
|
|
||||||
}
|
|
||||||
// We'd like to check for types with no icons, but
|
|
||||||
// getMimeIconPath() returns the valid 'document' by
|
|
||||||
// default, we'd have to go look into the confsimple
|
|
||||||
// directly.
|
|
||||||
// string path = config->getMimeIconPath(mtype, string());
|
|
||||||
// cout << mtype << " -> " << path << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// List mime types not in mimeview
|
|
||||||
for (vector<string>::const_iterator it = mtypes.begin();
|
|
||||||
it != mtypes.end(); it++) {
|
|
||||||
if (config->getMimeViewerDef(*it, "", false).empty()) {
|
|
||||||
cout << "No viewer: [" << *it << "]" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that each mime type has an indexer
|
|
||||||
for (vector<string>::const_iterator it = mtypes.begin();
|
|
||||||
it != mtypes.end(); it++) {
|
|
||||||
if (config->getMimeHandlerDef(*it, false).empty()) {
|
|
||||||
cout << "No filter: [" << *it << "]" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that each mime type has a defined icon
|
|
||||||
for (vector<string>::const_iterator it = mtypes.begin();
|
|
||||||
it != mtypes.end(); it++) {
|
|
||||||
if (config->getMimeIconPath(*it, "") == "document") {
|
|
||||||
cout << "No or generic icon: [" << *it << "]" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
config->setKeyDir(cstr_null);
|
config->setKeyDir(cstr_null);
|
||||||
vector<string> names = config->getConfNames();
|
vector<string> names = config->getConfNames();
|
||||||
for (vector<string>::iterator it = names.begin();
|
for (const auto& name : names) {
|
||||||
it != names.end();it++) {
|
|
||||||
string value;
|
string value;
|
||||||
config->getConfParam(*it, value);
|
config->getConfParam(name, value);
|
||||||
cout << *it << " -> [" << value << "]" << endl;
|
cout << name << " -> [" << value << "]" << "\n";
|
||||||
|
}
|
||||||
|
} else if (1) {
|
||||||
|
|
||||||
|
std::vector<std::string> samples {
|
||||||
|
"ebook-viewer %F;ignoreipath=1",
|
||||||
|
"rclshowinfo %F %(title);ignoreipath=1",
|
||||||
|
"xterm -u8 -e \"groff -T ascii -man %f | more\"",
|
||||||
|
"xterm -e \"info -f %f\"",
|
||||||
|
|
||||||
|
"\"C:/Program Files/Tracker Software/PDF Editor/PDFXEdit.exe\" /A "
|
||||||
|
"\"page=%p;search=%s\" \"%f\"",
|
||||||
|
|
||||||
|
"\"C:/Program Files/Tracker Software/PDF Editor/PDFXEdit.exe\" /A "
|
||||||
|
"\"page=%p;search=\\\"%s\\\"\" \"%f\"",
|
||||||
|
|
||||||
|
"\"C:/Program Files/Tracker Software/PDF Editor/PDFXEdit.exe\" /A "
|
||||||
|
"\"page=%p;search=%s\" \"%f\"; someattr = somevalue;quotedattr = \"hello world\"",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& sample: samples) {
|
||||||
|
string value;
|
||||||
|
ConfSimple attrs;
|
||||||
|
config->valueSplitAttributes(sample, value, attrs);
|
||||||
|
std::cout << "Input: ["<< sample << "]\n";
|
||||||
|
std::cout << "Value: [" << value << "]\n";
|
||||||
|
std::cout << "Attrs: ";
|
||||||
|
for (const auto& nm : attrs.getNames("")) {
|
||||||
|
std::string attr;
|
||||||
|
attrs.get(nm, attr);
|
||||||
|
std::cout << "{[" << nm << "] -> [" << attr << "]} ";
|
||||||
|
}
|
||||||
|
std::cout << "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user