use conftree conversions
This commit is contained in:
parent
a7058476a7
commit
414222c003
@ -970,15 +970,10 @@ bool RclConfig::readFieldsConfig(const string& cnferrloc)
|
||||
"]: [" << val << "]\n");
|
||||
return 0;
|
||||
}
|
||||
string tval;
|
||||
if (attrs.get("wdfinc", tval))
|
||||
ft.wdfinc = atoi(tval.c_str());
|
||||
if (attrs.get("boost", tval))
|
||||
ft.boost = atof(tval.c_str());
|
||||
if (attrs.get("pfxonly", tval))
|
||||
ft.pfxonly = stringToBool(tval);
|
||||
if (attrs.get("noterms", tval))
|
||||
ft.noterms = stringToBool(tval);
|
||||
ft.wdfinc = attrs.getInt("wdfinc", 1);
|
||||
ft.boost = attrs.getFloat("boost", 1.0);
|
||||
ft.pfxonly = attrs.getBool("pfxonly", false);
|
||||
ft.noterms = attrs.getBool("noterms", false);
|
||||
m_fldtotraits[stringtolower(fieldname)] = ft;
|
||||
LOGDEB2("readFieldsConfig: [" << fieldname << "] -> [" << ft.pfx <<
|
||||
"] " << ft.wdfinc << " " << ft.boost << "\n");
|
||||
@ -1018,11 +1013,7 @@ bool RclConfig::readFieldsConfig(const string& cnferrloc)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
int valuelen{0};
|
||||
if (attrs.get("len", tval)) {
|
||||
valuelen = atoi(tval.c_str());
|
||||
}
|
||||
|
||||
int valuelen = attrs.getInt("len", 0);
|
||||
// Find or insert traits entry
|
||||
const auto pit =
|
||||
m_fldtotraits.insert(
|
||||
|
||||
@ -24,16 +24,12 @@
|
||||
void readIdxStatus(RclConfig *config, DbIxStatus &status)
|
||||
{
|
||||
ConfSimple cs(config->getIdxStatusFile().c_str(), 1);
|
||||
string val;
|
||||
cs.get("phase", val);
|
||||
status.phase = DbIxStatus::Phase(atoi(val.c_str()));
|
||||
status.phase = DbIxStatus::Phase(cs.getInt("phase", 0));
|
||||
cs.get("fn", status.fn);
|
||||
cs.get("docsdone", &status.docsdone);
|
||||
cs.get("filesdone", &status.filesdone);
|
||||
cs.get("fileerrors", &status.fileerrors);
|
||||
cs.get("dbtotdocs", &status.dbtotdocs);
|
||||
cs.get("totfiles", &status.totfiles);
|
||||
string shm("0");
|
||||
cs.get("hasmonitor", shm);
|
||||
status.hasmonitor = stringToBool(shm);
|
||||
status.docsdone = cs.getInt("docsdone", 0);
|
||||
status.filesdone = cs.getInt("filesdone", 0);
|
||||
status.fileerrors = cs.getInt("fileerrors", 0);
|
||||
status.dbtotdocs = cs.getInt("dbtotdocs", 0);
|
||||
status.totfiles = cs.getInt("totfiles", 0);
|
||||
status.hasmonitor = cs.getBool("hasmonitor", false);
|
||||
}
|
||||
|
||||
@ -289,14 +289,8 @@ void SpellW::showStats()
|
||||
if (!theconfig)
|
||||
return;
|
||||
|
||||
ConfSimple cs(theconfig->getIdxStatusFile().c_str(), 1);
|
||||
DbIxStatus st;
|
||||
cs.get("fn", st.fn);
|
||||
cs.get("docsdone", &st.docsdone);
|
||||
cs.get("filesdone", &st.filesdone);
|
||||
cs.get("fileerrors", &st.fileerrors);
|
||||
cs.get("dbtotdocs", &st.dbtotdocs);
|
||||
cs.get("totfiles", &st.totfiles);
|
||||
readIdxStatus(theconfig, st);
|
||||
|
||||
resTW->setRowCount(row+1);
|
||||
resTW->setItem(row, 0,
|
||||
|
||||
@ -32,7 +32,6 @@
|
||||
#include "rcldb_p.h"
|
||||
#include "rclquery.h"
|
||||
#include "rclquery_p.h"
|
||||
#include "conftree.h"
|
||||
#include "smallut.h"
|
||||
#include "chrono.h"
|
||||
#include "searchdata.h"
|
||||
|
||||
@ -37,7 +37,8 @@ AM_CPPFLAGS = -Wall -Wno-unused -std=c++11 \
|
||||
-D_GNU_SOURCE \
|
||||
$(DEFS)
|
||||
|
||||
noinst_PROGRAMS = textsplit utf8iter fstreewalk rclconfig hldata unac mbox
|
||||
noinst_PROGRAMS = textsplit utf8iter fstreewalk rclconfig hldata unac mbox \
|
||||
circache
|
||||
|
||||
textsplit_SOURCES = trtextsplit.cpp
|
||||
textsplit_LDADD = ../librecoll.la
|
||||
@ -59,3 +60,6 @@ unac_LDADD = ../librecoll.la
|
||||
|
||||
mbox_SOURCES = trmbox.cpp
|
||||
mbox_LDADD = ../librecoll.la
|
||||
|
||||
circache_SOURCES = trcircache.cpp
|
||||
circache_LDADD = ../librecoll.la
|
||||
|
||||
245
src/testmains/trcircache.cpp
Normal file
245
src/testmains/trcircache.cpp
Normal file
@ -0,0 +1,245 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "circache.h"
|
||||
#include "fileudi.h"
|
||||
#include "conftree.h"
|
||||
#include "readfile.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "smallut.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static char *thisprog;
|
||||
|
||||
static char usage [] =
|
||||
" -c [-u] <dirname> <sizekbs>: create\n"
|
||||
" -p <dirname> <apath> [apath ...] : put files\n"
|
||||
" -d <dirname> : dump\n"
|
||||
" -g [-i instance] [-D] <dirname> <udi>: get\n"
|
||||
" -D: also dump data\n"
|
||||
" -e <dirname> <udi> : erase\n"
|
||||
" -a <targetdir> <dir> [<dir> ...]: append old content to target\n"
|
||||
" The target should be first resized to hold all the data, else only\n"
|
||||
" as many entries as capacity permit will be retained\n"
|
||||
;
|
||||
|
||||
static void
|
||||
Usage(FILE *fp = stderr)
|
||||
{
|
||||
fprintf(fp, "%s: usage:\n%s", thisprog, usage);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int op_flags;
|
||||
#define OPT_MOINS 0x1
|
||||
#define OPT_c 0x2
|
||||
#define OPT_p 0x8
|
||||
#define OPT_g 0x10
|
||||
#define OPT_d 0x20
|
||||
#define OPT_i 0x40
|
||||
#define OPT_D 0x80
|
||||
#define OPT_u 0x100
|
||||
#define OPT_e 0x200
|
||||
#define OPT_a 0x800
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int instance = -1;
|
||||
|
||||
thisprog = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
while (argc > 0 && **argv == '-') {
|
||||
(*argv)++;
|
||||
if (!(**argv))
|
||||
/* Cas du "adb - core" */
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
while (**argv)
|
||||
switch (*(*argv)++) {
|
||||
case 'a':
|
||||
op_flags |= OPT_a;
|
||||
break;
|
||||
case 'c':
|
||||
op_flags |= OPT_c;
|
||||
break;
|
||||
case 'D':
|
||||
op_flags |= OPT_D;
|
||||
break;
|
||||
case 'd':
|
||||
op_flags |= OPT_d;
|
||||
break;
|
||||
case 'e':
|
||||
op_flags |= OPT_e;
|
||||
break;
|
||||
case 'g':
|
||||
op_flags |= OPT_g;
|
||||
break;
|
||||
case 'i':
|
||||
op_flags |= OPT_i;
|
||||
if (argc < 2) {
|
||||
Usage();
|
||||
}
|
||||
if ((sscanf(*(++argv), "%d", &instance)) != 1) {
|
||||
Usage();
|
||||
}
|
||||
argc--;
|
||||
goto b1;
|
||||
case 'p':
|
||||
op_flags |= OPT_p;
|
||||
break;
|
||||
case 'u':
|
||||
op_flags |= OPT_u;
|
||||
break;
|
||||
default:
|
||||
Usage();
|
||||
break;
|
||||
}
|
||||
b1:
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
Logger::getTheLog("")->setLogLevel(Logger::LLDEB1);
|
||||
|
||||
if (argc < 1) {
|
||||
Usage();
|
||||
}
|
||||
string dir = *argv++;
|
||||
argc--;
|
||||
|
||||
CirCache cc(dir);
|
||||
|
||||
if (op_flags & OPT_c) {
|
||||
if (argc != 1) {
|
||||
Usage();
|
||||
}
|
||||
int64_t sizekb = atoi(*argv++);
|
||||
argc--;
|
||||
int flags = 0;
|
||||
if (op_flags & OPT_u) {
|
||||
flags |= CirCache::CC_CRUNIQUE;
|
||||
}
|
||||
if (!cc.create(sizekb * 1024, flags)) {
|
||||
cerr << "Create failed:" << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
} else if (op_flags & OPT_a) {
|
||||
if (argc < 1) {
|
||||
Usage();
|
||||
}
|
||||
while (argc) {
|
||||
string reason;
|
||||
if (CirCache::append(dir, *argv++, &reason) < 0) {
|
||||
cerr << reason << endl;
|
||||
return 1;
|
||||
}
|
||||
argc--;
|
||||
}
|
||||
} else if (op_flags & OPT_p) {
|
||||
if (argc < 1) {
|
||||
Usage();
|
||||
}
|
||||
if (!cc.open(CirCache::CC_OPWRITE)) {
|
||||
cerr << "Open failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
while (argc) {
|
||||
string fn = *argv++;
|
||||
argc--;
|
||||
char dic[1000];
|
||||
string data, reason;
|
||||
if (!file_to_string(fn, data, &reason)) {
|
||||
cerr << "File_to_string: " << reason << endl;
|
||||
exit(1);
|
||||
}
|
||||
string udi;
|
||||
make_udi(fn, "", udi);
|
||||
string cmd("xdg-mime query filetype ");
|
||||
// Should do more quoting here...
|
||||
cmd += "'" + fn + "'";
|
||||
FILE *fp = popen(cmd.c_str(), "r");
|
||||
char* buf=0;
|
||||
size_t sz = 0;
|
||||
if (::getline(&buf, &sz, fp) -1) {
|
||||
cerr << "Could not read from xdg-mime output\n";
|
||||
exit(1);
|
||||
}
|
||||
pclose(fp);
|
||||
string mimetype(buf);
|
||||
free(buf);
|
||||
trimstring(mimetype, "\n\r");
|
||||
cout << "Got [" << mimetype << "]\n";
|
||||
|
||||
string s;
|
||||
ConfSimple conf(s);
|
||||
conf.set("udi", udi);
|
||||
conf.set("mimetype", mimetype);
|
||||
//ostringstream str; conf.write(str); cout << str.str() << endl;
|
||||
|
||||
if (!cc.put(udi, &conf, data, 0)) {
|
||||
cerr << "Put failed: " << cc.getReason() << endl;
|
||||
cerr << "conf: [";
|
||||
conf.write(cerr);
|
||||
cerr << "]" << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
cc.open(CirCache::CC_OPREAD);
|
||||
} else if (op_flags & OPT_g) {
|
||||
if (!cc.open(CirCache::CC_OPREAD)) {
|
||||
cerr << "Open failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
while (argc) {
|
||||
string udi = *argv++;
|
||||
argc--;
|
||||
string dic, data;
|
||||
if (!cc.get(udi, dic, &data, instance)) {
|
||||
cerr << "Get failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
cout << "Dict: [" << dic << "]" << endl;
|
||||
if (op_flags & OPT_D) {
|
||||
cout << "Data: [" << data << "]" << endl;
|
||||
}
|
||||
}
|
||||
} else if (op_flags & OPT_e) {
|
||||
if (!cc.open(CirCache::CC_OPWRITE)) {
|
||||
cerr << "Open failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
while (argc) {
|
||||
string udi = *argv++;
|
||||
argc--;
|
||||
string dic, data;
|
||||
if (!cc.erase(udi)) {
|
||||
cerr << "Erase failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else if (op_flags & OPT_d) {
|
||||
if (!cc.open(CirCache::CC_OPREAD)) {
|
||||
cerr << "Open failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
cc.dump();
|
||||
} else {
|
||||
Usage();
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@ -15,7 +15,6 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef TEST_CIRCACHE
|
||||
#include "autoconfig.h"
|
||||
|
||||
#include "circache.h"
|
||||
@ -235,13 +234,15 @@ public:
|
||||
bool khEnter(const string& udi, int64_t ofs) {
|
||||
UdiH h(udi);
|
||||
|
||||
LOGDEB2("Circache::khEnter: h " << h.asHexString() << " offs " << ofs << " udi [" << udi << "]\n");
|
||||
LOGDEB2("Circache::khEnter: h " << h.asHexString() << " offs " <<
|
||||
ofs << " udi [" << udi << "]\n");
|
||||
|
||||
pair<kh_type::iterator, kh_type::iterator> p = m_ofskh.equal_range(h);
|
||||
|
||||
if (p.first != m_ofskh.end() && p.first->first == h) {
|
||||
for (kh_type::iterator it = p.first; it != p.second; it++) {
|
||||
LOGDEB2("Circache::khEnter: col h " << it->first.asHexString() << ", ofs " << it->second << "\n");
|
||||
LOGDEB2("Circache::khEnter: col h " << it->first.asHexString() <<
|
||||
", ofs " << it->second << "\n");
|
||||
if (it->second == ofs) {
|
||||
// (h,offs) already there. Happens
|
||||
LOGDEB2("Circache::khEnter: already there\n");
|
||||
@ -255,8 +256,9 @@ public:
|
||||
}
|
||||
void khDump() {
|
||||
for (kh_type::const_iterator it = m_ofskh.begin();
|
||||
it != m_ofskh.end(); it++) {
|
||||
LOGDEB("Circache::KHDUMP: " << it->first.asHexString() << " " << it->second << "\n");
|
||||
it != m_ofskh.end(); it++) {
|
||||
LOGDEB("Circache::KHDUMP: " << it->first.asHexString() << " " <<
|
||||
it->second << "\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,7 +270,8 @@ public:
|
||||
|
||||
UdiH h(udi);
|
||||
|
||||
LOGDEB2("Circache::khFind: h " << h.asHexString() << " udi [" << udi << "]\n");
|
||||
LOGDEB2("Circache::khFind: h " << h.asHexString() << " udi [" << udi <<
|
||||
"]\n");
|
||||
|
||||
pair<kh_type::iterator, kh_type::iterator> p = m_ofskh.equal_range(h);
|
||||
|
||||
@ -280,7 +283,8 @@ public:
|
||||
LOGDEB("KHFIND: SECOND END()\n");
|
||||
}
|
||||
if (!(p.first->first == h))
|
||||
LOGDEB("KHFIND: NOKEY: " << p.first->first.asHexString() << " " << p.second->first.asHexString() << "\n");
|
||||
LOGDEB("KHFIND: NOKEY: " << p.first->first.asHexString() << " " <<
|
||||
p.second->first.asHexString() << "\n");
|
||||
#endif
|
||||
|
||||
if (p.first == m_ofskh.end() || !(p.first->first == h)) {
|
||||
@ -309,7 +313,7 @@ public:
|
||||
// Clear entries for vector of udi/offs
|
||||
bool khClear(const vector<pair<string, int64_t> >& udis) {
|
||||
for (vector<pair<string, int64_t> >::const_iterator it = udis.begin();
|
||||
it != udis.end(); it++) {
|
||||
it != udis.end(); it++) {
|
||||
khClear(*it);
|
||||
}
|
||||
return true;
|
||||
@ -367,15 +371,15 @@ public:
|
||||
|
||||
ostringstream s;
|
||||
s <<
|
||||
"maxsize = " << m_maxsize << "\n" <<
|
||||
"oheadoffs = " << m_oheadoffs << "\n" <<
|
||||
"nheadoffs = " << m_nheadoffs << "\n" <<
|
||||
"npadsize = " << m_npadsize << "\n" <<
|
||||
"unient = " << m_uniquentries << "\n" <<
|
||||
" " <<
|
||||
" " <<
|
||||
" " <<
|
||||
"\0";
|
||||
"maxsize = " << m_maxsize << "\n" <<
|
||||
"oheadoffs = " << m_oheadoffs << "\n" <<
|
||||
"nheadoffs = " << m_nheadoffs << "\n" <<
|
||||
"npadsize = " << m_npadsize << "\n" <<
|
||||
"unient = " << m_uniquentries << "\n" <<
|
||||
" " <<
|
||||
" " <<
|
||||
" " <<
|
||||
"\0";
|
||||
|
||||
int sz = int(s.str().size());
|
||||
assert(sz < CIRCACHE_FIRSTBLOCK_SIZE);
|
||||
@ -397,38 +401,33 @@ public:
|
||||
|
||||
lseek(m_fd, 0, 0);
|
||||
if (read(m_fd, bf, CIRCACHE_FIRSTBLOCK_SIZE) !=
|
||||
CIRCACHE_FIRSTBLOCK_SIZE) {
|
||||
CIRCACHE_FIRSTBLOCK_SIZE) {
|
||||
m_reason << "readfirstblock: read() failed: errno " << errno;
|
||||
return false;
|
||||
}
|
||||
string s(bf, CIRCACHE_FIRSTBLOCK_SIZE);
|
||||
ConfSimple conf(s, 1);
|
||||
string value;
|
||||
if (!conf.get("maxsize", value, cstr_null)) {
|
||||
m_maxsize = conf.getInt("maxsize", -1);
|
||||
if (m_maxsize == -1) {
|
||||
m_reason << "readfirstblock: conf get maxsize failed";
|
||||
return false;
|
||||
}
|
||||
m_maxsize = atoll(value.c_str());
|
||||
if (!conf.get("oheadoffs", value, cstr_null)) {
|
||||
m_oheadoffs = conf.getInt("oheadoffs", -1);
|
||||
if (m_oheadoffs == -1) {
|
||||
m_reason << "readfirstblock: conf get oheadoffs failed";
|
||||
return false;
|
||||
}
|
||||
m_oheadoffs = atoll(value.c_str());
|
||||
if (!conf.get("nheadoffs", value, cstr_null)) {
|
||||
m_nheadoffs = conf.getInt("nheadoffs", -1);
|
||||
if (m_nheadoffs == -1) {
|
||||
m_reason << "readfirstblock: conf get nheadoffs failed";
|
||||
return false;
|
||||
}
|
||||
m_nheadoffs = atoll(value.c_str());
|
||||
if (!conf.get("npadsize", value, cstr_null)) {
|
||||
m_npadsize = conf.getInt("npadsize", -1);
|
||||
if (m_npadsize == -1) {
|
||||
m_reason << "readfirstblock: conf get npadsize failed";
|
||||
return false;
|
||||
}
|
||||
m_npadsize = atoll(value.c_str());
|
||||
if (!conf.get("unient", value, cstr_null)) {
|
||||
m_uniquentries = false;
|
||||
} else {
|
||||
m_uniquentries = stringToBool(value);
|
||||
}
|
||||
m_uniquentries = conf.getBool("unient", false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -444,7 +443,7 @@ public:
|
||||
headerformat, d.dicsize, d.datasize, d.padsize, d.flags);
|
||||
if (lseek(m_fd, offset, 0) != offset) {
|
||||
m_reason << "CirCache::weh: lseek(" << offset <<
|
||||
") failed: errno " << errno;
|
||||
") failed: errno " << errno;
|
||||
return false;
|
||||
}
|
||||
if (write(m_fd, bf, CIRCACHE_HEADER_SIZE) != CIRCACHE_HEADER_SIZE) {
|
||||
@ -473,7 +472,7 @@ public:
|
||||
|
||||
if (lseek(m_fd, offset, 0) != offset) {
|
||||
m_reason << "readEntryHeader: lseek(" << offset <<
|
||||
") failed: errno " << errno;
|
||||
") failed: errno " << errno;
|
||||
return CCScanHook::Error;
|
||||
}
|
||||
char bf[CIRCACHE_HEADER_SIZE];
|
||||
@ -491,11 +490,11 @@ public:
|
||||
if (sscanf(bf, headerformat, &d.dicsize, &d.datasize,
|
||||
&d.padsize, &d.flags) != 4) {
|
||||
m_reason << " readEntryHeader: bad header at " <<
|
||||
offset << " [" << bf << "]";
|
||||
offset << " [" << bf << "]";
|
||||
return CCScanHook::Error;
|
||||
}
|
||||
LOGDEB2("Circache:readEntryHeader: dcsz " << d.dicsize << " dtsz " << d.datasize << " pdsz " << d.padsize <<
|
||||
" flgs " << d.flags << "\n");
|
||||
LOGDEB2("Circache:readEntryHeader: dcsz " << d.dicsize << " dtsz " <<
|
||||
d.datasize << " pdsz " << d.padsize << " flgs " <<d.flags<<"\n");
|
||||
return CCScanHook::Continue;
|
||||
}
|
||||
|
||||
@ -526,7 +525,7 @@ public:
|
||||
startoffset = CIRCACHE_FIRSTBLOCK_SIZE;
|
||||
continue;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
return st;
|
||||
}
|
||||
@ -564,7 +563,7 @@ public:
|
||||
}
|
||||
|
||||
startoffset += CIRCACHE_HEADER_SIZE + d.dicsize +
|
||||
d.datasize + d.padsize;
|
||||
d.datasize + d.padsize;
|
||||
}
|
||||
}
|
||||
|
||||
@ -597,7 +596,7 @@ public:
|
||||
// at the right position
|
||||
if (lseek(m_fd, offs, 0) != offs) {
|
||||
m_reason << "CirCache::get: lseek(" << offs << ") failed: " <<
|
||||
errno;
|
||||
errno;
|
||||
return false;
|
||||
}
|
||||
char *bf = 0;
|
||||
@ -680,7 +679,8 @@ public:
|
||||
const EntryHeaderData& d) {
|
||||
headoffs = offs;
|
||||
padsize = d.padsize;
|
||||
LOGDEB2("CCScanHookRecord::takeone: offs " << headoffs << " padsize " << padsize << "\n");
|
||||
LOGDEB2("CCScanHookRecord::takeone: offs " << headoffs << " padsize " <<
|
||||
padsize << "\n");
|
||||
return Continue;
|
||||
}
|
||||
};
|
||||
@ -692,7 +692,8 @@ string CirCache::getpath()
|
||||
|
||||
bool CirCache::create(int64_t maxsize, int flags)
|
||||
{
|
||||
LOGDEB("CirCache::create: [" << m_dir << "] maxsz " << maxsize << " flags 0x" << std::hex << flags <<std::dec<<"\n");
|
||||
LOGDEB("CirCache::create: [" << m_dir << "] maxsz " << maxsize <<
|
||||
" flags 0x" << std::hex << flags <<std::dec<<"\n");
|
||||
if (m_d == 0) {
|
||||
LOGERR("CirCache::create: null data\n");
|
||||
return false;
|
||||
@ -703,19 +704,19 @@ bool CirCache::create(int64_t maxsize, int flags)
|
||||
// Directory does not exist, create it
|
||||
if (mkdir(m_dir.c_str(), 0777) < 0) {
|
||||
m_d->m_reason << "CirCache::create: mkdir(" << m_dir <<
|
||||
") failed" << " errno " << errno;
|
||||
") failed" << " errno " << errno;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// If the file exists too, and truncate is not set, switch
|
||||
// to open-mode. Still may need to update header params.
|
||||
if (access(m_d->datafn(m_dir).c_str(), 0) >= 0 &&
|
||||
!(flags & CC_CRTRUNCATE)) {
|
||||
!(flags & CC_CRTRUNCATE)) {
|
||||
if (!open(CC_OPWRITE)) {
|
||||
return false;
|
||||
}
|
||||
if (maxsize == m_d->m_maxsize &&
|
||||
((flags & CC_CRUNIQUE) != 0) == m_d->m_uniquentries) {
|
||||
((flags & CC_CRUNIQUE) != 0) == m_d->m_uniquentries) {
|
||||
LOGDEB("Header unchanged, no rewrite\n");
|
||||
return true;
|
||||
}
|
||||
@ -733,9 +734,10 @@ bool CirCache::create(int64_t maxsize, int flags)
|
||||
}
|
||||
m_d->m_maxsize = maxsize;
|
||||
m_d->m_uniquentries = ((flags & CC_CRUNIQUE) != 0);
|
||||
LOGDEB2("CirCache::create: rewriting header with maxsize " << m_d->m_maxsize << " oheadoffs " <<
|
||||
m_d->m_oheadoffs << " nheadoffs " << m_d->m_nheadoffs << " npadsize " << m_d->m_npadsize <<
|
||||
" unient " << m_d->m_uniquentries << "\n");
|
||||
LOGDEB2("CirCache::create: rewriting header with maxsize " <<
|
||||
m_d->m_maxsize << " oheadoffs " << m_d->m_oheadoffs <<
|
||||
" nheadoffs " << m_d->m_nheadoffs << " npadsize " <<
|
||||
m_d->m_npadsize << " unient " << m_d->m_uniquentries <<"\n");
|
||||
return m_d->writefirstblock();
|
||||
}
|
||||
// Else fallthrough to create file
|
||||
@ -744,7 +746,7 @@ bool CirCache::create(int64_t maxsize, int flags)
|
||||
if ((m_d->m_fd = ::open(m_d->datafn(m_dir).c_str(),
|
||||
O_CREAT | O_RDWR | O_TRUNC | O_BINARY, 0666)) < 0) {
|
||||
m_d->m_reason << "CirCache::create: open/creat(" <<
|
||||
m_d->datafn(m_dir) << ") failed " << "errno " << errno;
|
||||
m_d->datafn(m_dir) << ") failed " << "errno " << errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -755,9 +757,9 @@ bool CirCache::create(int64_t maxsize, int flags)
|
||||
char buf[CIRCACHE_FIRSTBLOCK_SIZE];
|
||||
memset(buf, 0, CIRCACHE_FIRSTBLOCK_SIZE);
|
||||
if (::write(m_d->m_fd, buf, CIRCACHE_FIRSTBLOCK_SIZE) !=
|
||||
CIRCACHE_FIRSTBLOCK_SIZE) {
|
||||
CIRCACHE_FIRSTBLOCK_SIZE) {
|
||||
m_d->m_reason << "CirCache::create: write header failed, errno "
|
||||
<< errno;
|
||||
<< errno;
|
||||
return false;
|
||||
}
|
||||
return m_d->writefirstblock();
|
||||
@ -778,7 +780,7 @@ bool CirCache::open(OpMode mode)
|
||||
mode == CC_OPREAD ?
|
||||
O_RDONLY | O_BINARY : O_RDWR | O_BINARY)) < 0) {
|
||||
m_d->m_reason << "CirCache::open: open(" << m_d->datafn(m_dir) <<
|
||||
") failed " << "errno " << errno;
|
||||
") failed " << "errno " << errno;
|
||||
return false;
|
||||
}
|
||||
return m_d->readfirstblock();
|
||||
@ -789,9 +791,9 @@ public:
|
||||
virtual status takeone(int64_t offs, const string& udi,
|
||||
const EntryHeaderData& d) {
|
||||
cout << "Scan: offs " << offs << " dicsize " << d.dicsize
|
||||
<< " datasize " << d.datasize << " padsize " << d.padsize <<
|
||||
" flags " << d.flags <<
|
||||
" udi [" << udi << "]" << endl;
|
||||
<< " datasize " << d.datasize << " padsize " << d.padsize <<
|
||||
" flags " << d.flags <<
|
||||
" udi [" << udi << "]" << endl;
|
||||
return Continue;
|
||||
}
|
||||
};
|
||||
@ -810,7 +812,7 @@ bool CirCache::dump()
|
||||
return false;
|
||||
case CCScanHook::Continue:
|
||||
cout << "Scan returns Continue ?? " << CCScanHook::Continue << " " <<
|
||||
getReason() << endl;
|
||||
getReason() << endl;
|
||||
return false;
|
||||
case CCScanHook::Error:
|
||||
cout << "Scan returns Error: " << getReason() << endl;
|
||||
@ -837,7 +839,8 @@ public:
|
||||
|
||||
virtual status takeone(int64_t offs, const string& udi,
|
||||
const EntryHeaderData& d) {
|
||||
LOGDEB2("Circache:Scan: off " << offs << " udi [" << udi << "] dcsz " << d.dicsize << " dtsz " << d.datasize <<
|
||||
LOGDEB2("Circache:Scan: off " << offs << " udi [" << udi << "] dcsz " <<
|
||||
d.dicsize << " dtsz " << d.datasize <<
|
||||
" pdsz " << d.padsize << " flgs " << d.flags << "\n");
|
||||
if (!m_udi.compare(udi)) {
|
||||
m_instance++;
|
||||
@ -873,7 +876,7 @@ bool CirCache::get(const string& udi, string& dic, string *data, int instance)
|
||||
EntryHeaderData d_good;
|
||||
int64_t o_good = 0;
|
||||
for (vector<int64_t>::iterator it = ofss.begin();
|
||||
it != ofss.end(); it++) {
|
||||
it != ofss.end(); it++) {
|
||||
LOGDEB1("Circache::get: trying offs " << *it << "\n");
|
||||
EntryHeaderData d;
|
||||
string fudi;
|
||||
@ -989,7 +992,8 @@ public:
|
||||
|
||||
virtual status takeone(int64_t offs, const string& udi,
|
||||
const EntryHeaderData& d) {
|
||||
LOGDEB2("Circache:ScanSpacer:off " << offs << " dcsz " << d.dicsize << " dtsz " << d.datasize <<
|
||||
LOGDEB2("Circache:ScanSpacer:off " << offs << " dcsz " << d.dicsize <<
|
||||
" dtsz " << d.datasize <<
|
||||
" pdsz " << d.padsize << " udi[" << udi << "]\n");
|
||||
sizeseen += CIRCACHE_HEADER_SIZE + d.dicsize + d.datasize + d.padsize;
|
||||
squashed_udis.push_back(make_pair(udi, offs));
|
||||
@ -1016,7 +1020,8 @@ bool CirCache::put(const string& udi, const ConfSimple *iconf,
|
||||
string dic;
|
||||
if (!iconf || !iconf->get("udi", dic) || dic.empty() || dic.compare(udi)) {
|
||||
m_d->m_reason << "No/bad 'udi' entry in input dic";
|
||||
LOGERR("Circache::put: no/bad udi: DIC:[" << dic << "] UDI [" << udi << "]\n");
|
||||
LOGERR("Circache::put: no/bad udi: DIC:[" << dic << "] UDI [" << udi <<
|
||||
"]\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1060,12 +1065,13 @@ bool CirCache::put(const string& udi, const ConfSimple *iconf,
|
||||
int64_t npadsize = 0;
|
||||
bool extending = false;
|
||||
|
||||
LOGDEB("CirCache::put: nsz " << nsize << " oheadoffs " << m_d->m_oheadoffs << "\n");
|
||||
LOGDEB("CirCache::put: nsz " << nsize << " oheadoffs " <<
|
||||
m_d->m_oheadoffs << "\n");
|
||||
|
||||
// Check if we can recover some pad space from the (physically) previous
|
||||
// entry.
|
||||
int64_t recovpadsize = m_d->m_oheadoffs == CIRCACHE_FIRSTBLOCK_SIZE ?
|
||||
0 : m_d->m_npadsize;
|
||||
0 : m_d->m_npadsize;
|
||||
if (recovpadsize != 0) {
|
||||
// Need to read the latest entry's header, to rewrite it with a
|
||||
// zero pad size
|
||||
@ -1095,7 +1101,7 @@ bool CirCache::put(const string& udi, const ConfSimple *iconf,
|
||||
if (nsize <= recovpadsize) {
|
||||
// If the new entry fits entirely in the pad area from the
|
||||
// latest one, no need to recycle stuff
|
||||
LOGDEB("CirCache::put: new fits in old padsize " << recovpadsize << "\n");
|
||||
LOGDEB("CirCache::put: new fits in old padsize " << recovpadsize <<"\n");
|
||||
npadsize = recovpadsize - nsize;
|
||||
} else if (st.st_size < m_d->m_maxsize) {
|
||||
// Still growing the file.
|
||||
@ -1105,11 +1111,12 @@ bool CirCache::put(const string& udi, const ConfSimple *iconf,
|
||||
// Scan the file until we have enough space for the new entry,
|
||||
// and determine the pad size up to the 1st preserved entry
|
||||
int64_t scansize = nsize - recovpadsize;
|
||||
LOGDEB("CirCache::put: scanning for size " << scansize << " from offs " << m_d->m_oheadoffs << "\n");
|
||||
LOGDEB("CirCache::put: scanning for size " << scansize <<
|
||||
" from offs " << m_d->m_oheadoffs << "\n");
|
||||
CCScanHookSpacer spacer(scansize);
|
||||
switch (m_d->scan(m_d->m_oheadoffs, &spacer)) {
|
||||
case CCScanHook::Stop:
|
||||
LOGDEB("CirCache::put: Scan ok, sizeseen " << spacer.sizeseen << "\n");
|
||||
LOGDEB("CirCache::put: Scan ok, sizeseen " << spacer.sizeseen<<"\n");
|
||||
npadsize = spacer.sizeseen - scansize;
|
||||
break;
|
||||
case CCScanHook::Eof:
|
||||
@ -1124,7 +1131,8 @@ bool CirCache::put(const string& udi, const ConfSimple *iconf,
|
||||
m_d->khClear(spacer.squashed_udis);
|
||||
}
|
||||
|
||||
LOGDEB("CirCache::put: writing " << nsize << " at " << nwriteoffs << " padsize " << npadsize << "\n");
|
||||
LOGDEB("CirCache::put: writing " << nsize << " at " << nwriteoffs <<
|
||||
" padsize " << npadsize << "\n");
|
||||
|
||||
if (lseek(m_d->m_fd, nwriteoffs, 0) != nwriteoffs) {
|
||||
m_d->m_reason << "CirCache::put: lseek failed: " << errno;
|
||||
@ -1211,7 +1219,7 @@ bool CirCache::next(bool& eof)
|
||||
|
||||
// Skip to next header, using values stored from previous one
|
||||
m_d->m_itoffs += CIRCACHE_HEADER_SIZE + m_d->m_ithd.dicsize +
|
||||
m_d->m_ithd.datasize + m_d->m_ithd.padsize;
|
||||
m_d->m_ithd.datasize + m_d->m_ithd.padsize;
|
||||
|
||||
// Looped back ?
|
||||
if (m_d->m_itoffs == m_d->m_oheadoffs) {
|
||||
@ -1268,7 +1276,7 @@ bool CirCache::getCurrent(string& udi, string& dic, string *data)
|
||||
// Copy all entries from occ to ncc. Both are already open.
|
||||
static bool copyall(std::shared_ptr<CirCache> occ,
|
||||
std::shared_ptr<CirCache> ncc, int& nentries,
|
||||
ostringstream& msg)
|
||||
ostringstream& msg)
|
||||
{
|
||||
bool eof = false;
|
||||
if (!occ->rewind(eof)) {
|
||||
@ -1298,7 +1306,7 @@ static bool copyall(std::shared_ptr<CirCache> occ,
|
||||
//cerr << "UDI: " << udi << endl;
|
||||
if (!ncc->put(udi, &dic, data)) {
|
||||
msg << "put failed: " << ncc->getReason() << " sdic [" << sdic <<
|
||||
"]" << endl;
|
||||
"]" << endl;
|
||||
return false;
|
||||
}
|
||||
nentries++;
|
||||
@ -1342,253 +1350,3 @@ int CirCache::append(const string ddir, const string& sdir, string *reason)
|
||||
|
||||
return nentries;
|
||||
}
|
||||
|
||||
|
||||
#else // TEST ->
|
||||
#include "autoconfig.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "circache.h"
|
||||
#include "fileudi.h"
|
||||
#include "conftree.h"
|
||||
#include "readfile.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "smallut.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static char *thisprog;
|
||||
|
||||
static char usage [] =
|
||||
" -c [-u] <dirname> <sizekbs>: create\n"
|
||||
" -p <dirname> <apath> [apath ...] : put files\n"
|
||||
" -d <dirname> : dump\n"
|
||||
" -g [-i instance] [-D] <dirname> <udi>: get\n"
|
||||
" -D: also dump data\n"
|
||||
" -e <dirname> <udi> : erase\n"
|
||||
" -a <targetdir> <dir> [<dir> ...]: append old content to target\n"
|
||||
" The target should be first resized to hold all the data, else only\n"
|
||||
" as many entries as capacity permit will be retained\n"
|
||||
;
|
||||
|
||||
static void
|
||||
Usage(FILE *fp = stderr)
|
||||
{
|
||||
fprintf(fp, "%s: usage:\n%s", thisprog, usage);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int op_flags;
|
||||
#define OPT_MOINS 0x1
|
||||
#define OPT_c 0x2
|
||||
#define OPT_p 0x8
|
||||
#define OPT_g 0x10
|
||||
#define OPT_d 0x20
|
||||
#define OPT_i 0x40
|
||||
#define OPT_D 0x80
|
||||
#define OPT_u 0x100
|
||||
#define OPT_e 0x200
|
||||
#define OPT_a 0x800
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int instance = -1;
|
||||
|
||||
thisprog = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
while (argc > 0 && **argv == '-') {
|
||||
(*argv)++;
|
||||
if (!(**argv))
|
||||
/* Cas du "adb - core" */
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
while (**argv)
|
||||
switch (*(*argv)++) {
|
||||
case 'a':
|
||||
op_flags |= OPT_a;
|
||||
break;
|
||||
case 'c':
|
||||
op_flags |= OPT_c;
|
||||
break;
|
||||
case 'D':
|
||||
op_flags |= OPT_D;
|
||||
break;
|
||||
case 'd':
|
||||
op_flags |= OPT_d;
|
||||
break;
|
||||
case 'e':
|
||||
op_flags |= OPT_e;
|
||||
break;
|
||||
case 'g':
|
||||
op_flags |= OPT_g;
|
||||
break;
|
||||
case 'i':
|
||||
op_flags |= OPT_i;
|
||||
if (argc < 2) {
|
||||
Usage();
|
||||
}
|
||||
if ((sscanf(*(++argv), "%d", &instance)) != 1) {
|
||||
Usage();
|
||||
}
|
||||
argc--;
|
||||
goto b1;
|
||||
case 'p':
|
||||
op_flags |= OPT_p;
|
||||
break;
|
||||
case 'u':
|
||||
op_flags |= OPT_u;
|
||||
break;
|
||||
default:
|
||||
Usage();
|
||||
break;
|
||||
}
|
||||
b1:
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
Logger::getTheLog("")->setLogLevel(Logger::LLDEB1);
|
||||
|
||||
if (argc < 1) {
|
||||
Usage();
|
||||
}
|
||||
string dir = *argv++;
|
||||
argc--;
|
||||
|
||||
CirCache cc(dir);
|
||||
|
||||
if (op_flags & OPT_c) {
|
||||
if (argc != 1) {
|
||||
Usage();
|
||||
}
|
||||
int64_t sizekb = atoi(*argv++);
|
||||
argc--;
|
||||
int flags = 0;
|
||||
if (op_flags & OPT_u) {
|
||||
flags |= CirCache::CC_CRUNIQUE;
|
||||
}
|
||||
if (!cc.create(sizekb * 1024, flags)) {
|
||||
cerr << "Create failed:" << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
} else if (op_flags & OPT_a) {
|
||||
if (argc < 1) {
|
||||
Usage();
|
||||
}
|
||||
while (argc) {
|
||||
string reason;
|
||||
if (CirCache::append(dir, *argv++, &reason) < 0) {
|
||||
cerr << reason << endl;
|
||||
return 1;
|
||||
}
|
||||
argc--;
|
||||
}
|
||||
} else if (op_flags & OPT_p) {
|
||||
if (argc < 1) {
|
||||
Usage();
|
||||
}
|
||||
if (!cc.open(CirCache::CC_OPWRITE)) {
|
||||
cerr << "Open failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
while (argc) {
|
||||
string fn = *argv++;
|
||||
argc--;
|
||||
char dic[1000];
|
||||
string data, reason;
|
||||
if (!file_to_string(fn, data, &reason)) {
|
||||
cerr << "File_to_string: " << reason << endl;
|
||||
exit(1);
|
||||
}
|
||||
string udi;
|
||||
make_udi(fn, "", udi);
|
||||
string cmd("xdg-mime query filetype ");
|
||||
// Should do more quoting here...
|
||||
cmd += "'" + fn + "'";
|
||||
FILE *fp = popen(cmd.c_str(), "r");
|
||||
char* buf=0;
|
||||
size_t sz = 0;
|
||||
::getline(&buf, &sz, fp);
|
||||
pclose(fp);
|
||||
string mimetype(buf);
|
||||
free(buf);
|
||||
trimstring(mimetype, "\n\r");
|
||||
cout << "Got [" << mimetype << "]\n";
|
||||
|
||||
string s;
|
||||
ConfSimple conf(s);
|
||||
conf.set("udi", udi);
|
||||
conf.set("mimetype", mimetype);
|
||||
//ostringstream str; conf.write(str); cout << str.str() << endl;
|
||||
|
||||
if (!cc.put(udi, &conf, data, 0)) {
|
||||
cerr << "Put failed: " << cc.getReason() << endl;
|
||||
cerr << "conf: [";
|
||||
conf.write(cerr);
|
||||
cerr << "]" << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
cc.open(CirCache::CC_OPREAD);
|
||||
} else if (op_flags & OPT_g) {
|
||||
if (!cc.open(CirCache::CC_OPREAD)) {
|
||||
cerr << "Open failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
while (argc) {
|
||||
string udi = *argv++;
|
||||
argc--;
|
||||
string dic, data;
|
||||
if (!cc.get(udi, dic, &data, instance)) {
|
||||
cerr << "Get failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
cout << "Dict: [" << dic << "]" << endl;
|
||||
if (op_flags & OPT_D) {
|
||||
cout << "Data: [" << data << "]" << endl;
|
||||
}
|
||||
}
|
||||
} else if (op_flags & OPT_e) {
|
||||
if (!cc.open(CirCache::CC_OPWRITE)) {
|
||||
cerr << "Open failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
while (argc) {
|
||||
string udi = *argv++;
|
||||
argc--;
|
||||
string dic, data;
|
||||
if (!cc.erase(udi)) {
|
||||
cerr << "Erase failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else if (op_flags & OPT_d) {
|
||||
if (!cc.open(CirCache::CC_OPREAD)) {
|
||||
cerr << "Open failed: " << cc.getReason() << endl;
|
||||
exit(1);
|
||||
}
|
||||
cc.dump();
|
||||
} else {
|
||||
Usage();
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -57,6 +57,47 @@ using namespace std;
|
||||
#define CONFDEB LOGDEB2
|
||||
#endif
|
||||
|
||||
|
||||
long long ConfNull::getInt(const std::string& name, long long dflt,
|
||||
const std::string& sk)
|
||||
{
|
||||
string val;
|
||||
if (!get(name, val, sk)) {
|
||||
return dflt;
|
||||
}
|
||||
char *endptr;
|
||||
long long ret = strtoll(val.c_str(), &endptr, 0);
|
||||
if (endptr == val.c_str()) {
|
||||
return dflt;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
double ConfNull::getFloat(const std::string& name, double dflt,
|
||||
const std::string& sk)
|
||||
{
|
||||
string val;
|
||||
if (!get(name, val, sk)) {
|
||||
return dflt;
|
||||
}
|
||||
char *endptr;
|
||||
double ret = strtod(val.c_str(), &endptr);
|
||||
if (endptr == val.c_str()) {
|
||||
return dflt;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ConfNull::getBool(const std::string& name, bool dflt,
|
||||
const std::string& sk)
|
||||
{
|
||||
string val;
|
||||
if (!get(name, val, sk)) {
|
||||
return dflt;
|
||||
}
|
||||
return stringToBool(val);
|
||||
}
|
||||
|
||||
static const SimpleRegexp varcomment_rx("[ \t]*#[ \t]*([a-zA-Z0-9]+)[ \t]*=",
|
||||
0, 1);
|
||||
|
||||
@ -275,30 +316,20 @@ int ConfSimple::get(const string& nm, string& value, const string& sk) const
|
||||
}
|
||||
|
||||
// Find submap
|
||||
map<string, map<string, string> >::const_iterator ss;
|
||||
if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
|
||||
const auto ss = m_submaps.find(sk);
|
||||
if (ss == m_submaps.end()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Find named value
|
||||
map<string, string>::const_iterator s;
|
||||
if ((s = ss->second.find(nm)) == ss->second.end()) {
|
||||
const auto s = ss->second.find(nm);
|
||||
if (s == ss->second.end()) {
|
||||
return 0;
|
||||
}
|
||||
value = s->second;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ConfSimple::get(const string& nm, int *value, const string& sk) const
|
||||
{
|
||||
string sval;
|
||||
if (!get(nm, sval, sk)) {
|
||||
return 0;
|
||||
}
|
||||
*value = atoi(sval.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Appropriately output a subkey (nm=="") or variable line.
|
||||
// We can't make any assumption about the data except that it does not
|
||||
// contain line breaks.
|
||||
@ -314,7 +345,7 @@ int ConfSimple::get(const string& nm, int *value, const string& sk) const
|
||||
// the file data (when read back by conftree), only its ease of
|
||||
// editing with a normal editor.
|
||||
static ConfSimple::WalkerCode varprinter(void *f, const string& nm,
|
||||
const string& value)
|
||||
const string& value)
|
||||
{
|
||||
ostream& output = *((ostream *)f);
|
||||
if (nm.empty()) {
|
||||
@ -332,7 +363,7 @@ static ConfSimple::WalkerCode varprinter(void *f, const string& nm,
|
||||
// Break at whitespace if line too long and "a lot" of
|
||||
// remaining data
|
||||
if (ll > 50 && (value.length() - pos) > 10 &&
|
||||
(c == ' ' || c == '\t')) {
|
||||
(c == ' ' || c == '\t')) {
|
||||
ll = 0;
|
||||
output << "\\\n";
|
||||
}
|
||||
@ -356,13 +387,13 @@ int ConfSimple::set(const std::string& nm, const std::string& value,
|
||||
}
|
||||
return write();
|
||||
}
|
||||
|
||||
int ConfSimple::set(const string& nm, long long val,
|
||||
const string& sk)
|
||||
{
|
||||
return this->set(nm, lltodecstr(val), sk);
|
||||
}
|
||||
|
||||
|
||||
// Internal set variable: no rw checking or file rewriting. If init is
|
||||
// set, we're doing initial parsing, else we are changing a parsed
|
||||
// tree (changes the way we update the order data)
|
||||
@ -377,9 +408,9 @@ int ConfSimple::i_set(const std::string& nm, const std::string& value,
|
||||
return 0;
|
||||
}
|
||||
bool existing = false;
|
||||
map<string, map<string, string> >::iterator ss;
|
||||
auto ss = m_submaps.find(sk);
|
||||
// Test if submap already exists, else create it, and insert variable:
|
||||
if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
|
||||
if (ss == m_submaps.end()) {
|
||||
CONFDEB("ConfSimple::i_set: new submap\n");
|
||||
map<string, string> submap;
|
||||
submap[nm] = value;
|
||||
@ -397,8 +428,7 @@ int ConfSimple::i_set(const std::string& nm, const std::string& value,
|
||||
}
|
||||
} else {
|
||||
// Insert or update variable in existing map.
|
||||
map<string, string>::iterator it;
|
||||
it = ss->second.find(nm);
|
||||
auto it = ss->second.find(nm);
|
||||
if (it == ss->second.end()) {
|
||||
ss->second.insert(pair<string, string>(nm, value));
|
||||
} else {
|
||||
@ -438,7 +468,7 @@ int ConfSimple::i_set(const std::string& nm, const std::string& value,
|
||||
// This is not logically possible. The subkey must
|
||||
// exist. We're doomed
|
||||
std::cerr << "Logical failure during configuration variable "
|
||||
"insertion" << endl;
|
||||
"insertion" << endl;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
@ -486,8 +516,8 @@ int ConfSimple::erase(const string& nm, const string& sk)
|
||||
return 0;
|
||||
}
|
||||
|
||||
map<string, map<string, string> >::iterator ss;
|
||||
if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
|
||||
auto ss = m_submaps.find(sk);
|
||||
if (ss == m_submaps.end()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -501,8 +531,8 @@ int ConfSimple::erase(const string& nm, const string& sk)
|
||||
int ConfSimple::eraseKey(const string& sk)
|
||||
{
|
||||
vector<string> nms = getNames(sk);
|
||||
for (vector<string>::iterator it = nms.begin(); it != nms.end(); it++) {
|
||||
erase(*it, sk);
|
||||
for (const auto& nm : nms) {
|
||||
erase(nm, sk);
|
||||
}
|
||||
return write();
|
||||
}
|
||||
@ -523,21 +553,16 @@ ConfSimple::sortwalk(WalkerCode(*walker)(void *, const string&, const string&),
|
||||
return WALK_STOP;
|
||||
}
|
||||
// For all submaps:
|
||||
for (map<string, map<string, string> >::const_iterator sit =
|
||||
m_submaps.begin();
|
||||
sit != m_submaps.end(); sit++) {
|
||||
|
||||
for (const auto& submap : m_submaps) {
|
||||
// Possibly emit submap name:
|
||||
if (!sit->first.empty() && walker(clidata, string(), sit->first.c_str())
|
||||
== WALK_STOP) {
|
||||
if (!submap.first.empty() &&
|
||||
walker(clidata, string(), submap.first.c_str()) == WALK_STOP) {
|
||||
return WALK_STOP;
|
||||
}
|
||||
|
||||
// Walk submap
|
||||
const map<string, string>& sm = sit->second;
|
||||
for (map<string, string>::const_iterator it = sm.begin(); it != sm.end();
|
||||
it++) {
|
||||
if (walker(clidata, it->first, it->second) == WALK_STOP) {
|
||||
for (const auto& item : submap.second) {
|
||||
if (walker(clidata, item.first, item.second) == WALK_STOP) {
|
||||
return WALK_STOP;
|
||||
}
|
||||
}
|
||||
@ -579,30 +604,29 @@ bool ConfSimple::write(ostream& out) const
|
||||
return false;
|
||||
}
|
||||
string sk;
|
||||
for (vector<ConfLine>::const_iterator it = m_order.begin();
|
||||
it != m_order.end(); it++) {
|
||||
switch (it->m_kind) {
|
||||
for (const auto& confline : m_order) {
|
||||
switch (confline.m_kind) {
|
||||
case ConfLine::CFL_COMMENT:
|
||||
case ConfLine::CFL_VARCOMMENT:
|
||||
out << it->m_data << endl;
|
||||
out << confline.m_data << endl;
|
||||
if (!out.good()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case ConfLine::CFL_SK:
|
||||
sk = it->m_data;
|
||||
sk = confline.m_data;
|
||||
CONFDEB("ConfSimple::write: SK [" << sk << "]\n");
|
||||
// Check that the submap still exists, and only output it if it
|
||||
// does
|
||||
if (m_submaps.find(sk) != m_submaps.end()) {
|
||||
out << "[" << it->m_data << "]" << endl;
|
||||
out << "[" << confline.m_data << "]" << endl;
|
||||
if (!out.good()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ConfLine::CFL_VAR:
|
||||
string nm = it->m_data;
|
||||
string nm = confline.m_data;
|
||||
CONFDEB("ConfSimple::write: VAR [" << nm << "], sk [" <<sk<< "]\n");
|
||||
// As erase() doesnt update m_order we can find unexisting
|
||||
// variables, and must not output anything for them. Have
|
||||
@ -617,7 +641,7 @@ bool ConfSimple::write(ostream& out) const
|
||||
}
|
||||
break;
|
||||
}
|
||||
CONFDEB("ConfSimple::write: no value: nm["<<nm<<"] sk["<<sk<< "]\n");
|
||||
CONFDEB("ConfSimple::write: no value: nm["<<nm<<"] sk["<<sk<<"]\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -638,17 +662,16 @@ vector<string> ConfSimple::getNames(const string& sk, const char *pattern) const
|
||||
if (!ok()) {
|
||||
return mylist;
|
||||
}
|
||||
map<string, map<string, string> >::const_iterator ss;
|
||||
if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
|
||||
const auto ss = m_submaps.find(sk);
|
||||
if (ss == m_submaps.end()) {
|
||||
return mylist;
|
||||
}
|
||||
mylist.reserve(ss->second.size());
|
||||
map<string, string>::const_iterator it;
|
||||
for (it = ss->second.begin(); it != ss->second.end(); it++) {
|
||||
if (pattern && 0 != fnmatch(pattern, it->first.c_str(), 0)) {
|
||||
for (const auto& item : ss->second) {
|
||||
if (pattern && 0 != fnmatch(pattern, item.first.c_str(), 0)) {
|
||||
continue;
|
||||
}
|
||||
mylist.push_back(it->first);
|
||||
mylist.push_back(item.first);
|
||||
}
|
||||
return mylist;
|
||||
}
|
||||
@ -660,9 +683,8 @@ vector<string> ConfSimple::getSubKeys() const
|
||||
return mylist;
|
||||
}
|
||||
mylist.reserve(m_submaps.size());
|
||||
map<string, map<string, string> >::const_iterator ss;
|
||||
for (ss = m_submaps.begin(); ss != m_submaps.end(); ss++) {
|
||||
mylist.push_back(ss->first);
|
||||
for (const auto& submap : m_submaps) {
|
||||
mylist.push_back(submap.first);
|
||||
}
|
||||
return mylist;
|
||||
}
|
||||
@ -670,10 +692,9 @@ vector<string> ConfSimple::getSubKeys() const
|
||||
bool ConfSimple::hasNameAnywhere(const string& nm) const
|
||||
{
|
||||
vector<string>keys = getSubKeys();
|
||||
for (vector<string>::const_iterator it = keys.begin();
|
||||
it != keys.end(); it++) {
|
||||
for (const auto& key : keys) {
|
||||
string val;
|
||||
if (get(nm, val, *it)) {
|
||||
if (get(nm, val, key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -687,24 +708,23 @@ bool ConfSimple::commentsAsXML(ostream& out)
|
||||
out << "<confcomments>\n";
|
||||
|
||||
string sk;
|
||||
for (vector<ConfLine>::const_iterator it = lines.begin();
|
||||
it != lines.end(); it++) {
|
||||
switch (it->m_kind) {
|
||||
for (const auto& line : lines) {
|
||||
switch (line.m_kind) {
|
||||
case ConfLine::CFL_COMMENT:
|
||||
case ConfLine::CFL_VARCOMMENT:
|
||||
{
|
||||
string::size_type pos = it->m_data.find_first_not_of("# ");
|
||||
string::size_type pos = line.m_data.find_first_not_of("# ");
|
||||
if (pos != string::npos) {
|
||||
out << it->m_data.substr(pos) << endl;
|
||||
out << line.m_data.substr(pos) << endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ConfLine::CFL_SK:
|
||||
out << "<subkey>" << it->m_data << "</subkey>" << endl;
|
||||
out << "<subkey>" << line.m_data << "</subkey>" << endl;
|
||||
break;
|
||||
case ConfLine::CFL_VAR:
|
||||
out << "<varsetting>" << it->m_data << " = " <<
|
||||
it->m_value << "</varsetting>" << endl;
|
||||
out << "<varsetting>" << line.m_data << " = " <<
|
||||
line.m_value << "</varsetting>" << endl;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -721,7 +741,7 @@ bool ConfSimple::commentsAsXML(ostream& out)
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ConfTree::get(const std::string& name, string& value, const string& sk)
|
||||
const
|
||||
const
|
||||
{
|
||||
if (sk.empty() || !path_isabsolute(sk)) {
|
||||
LOGDEB2("ConfTree::get: looking in global space for [" <<
|
||||
@ -757,4 +777,3 @@ const
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2006 J.F.Dockes
|
||||
/* Copyright (C) 2006-2019 J.F.Dockes
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
@ -24,21 +24,21 @@
|
||||
*
|
||||
* Lines like '[subkey]' in the file define subsections, with independant
|
||||
* configuration namespaces. Only subsections holding at least one variable are
|
||||
* significant (empty subsections may be deleted during an update, or not)
|
||||
* significant (empty subsections may be deleted during an update, or not).
|
||||
*
|
||||
* Whitespace around name and value is insignificant.
|
||||
* Whitespace around name and value is ignored.
|
||||
*
|
||||
* The names are case-sensitive but don't depend on it, this might change
|
||||
* The names are case-sensitive but don't depend on it, this might change.
|
||||
*
|
||||
* Values can be queried for, or set.
|
||||
*
|
||||
* Any line without a '=' is a comment (a line like #var = value
|
||||
* actually assigns a variable named '#var', which is not a big issue)
|
||||
* Any line without a '=', or beginning with '[ \t]*#' is a comment.
|
||||
*
|
||||
* A configuration object can be created empty or by reading from a file or
|
||||
* a string.
|
||||
* All 'set' calls cause an immediate rewrite of the backing object if any
|
||||
* (file or string)
|
||||
*
|
||||
* All 'set' calls normally cause an immediate rewrite of the backing
|
||||
* object if any (file or string). This can be prevented with holdWrites().
|
||||
*
|
||||
* The ConfTree derived class interprets the subkeys as file paths and
|
||||
* lets subdir keys hierarchically inherit the properties from
|
||||
@ -46,7 +46,7 @@
|
||||
*
|
||||
* The ConfStack class stacks several Con(Simple/Tree) objects so that
|
||||
* parameters from the top of the stack override the values from lower
|
||||
* (useful to have central/personal config files)
|
||||
* (useful to have central/personal config files).
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
@ -62,7 +62,6 @@
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#endif
|
||||
#include <iostream>
|
||||
|
||||
#include "pathut.h"
|
||||
|
||||
@ -83,7 +82,7 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Virtual base class used to define an interface mostly useful for testing
|
||||
* Virtual base class used to define the interface, and a few helper methods.
|
||||
*/
|
||||
class ConfNull {
|
||||
public:
|
||||
@ -93,9 +92,15 @@ public:
|
||||
const std::string& sk = std::string()) const = 0;
|
||||
virtual int set(const std::string& nm, const std::string& val,
|
||||
const std::string& sk = std::string()) = 0;
|
||||
virtual long long getInt(const std::string& name, long long dflt,
|
||||
const std::string& sk = std::string());
|
||||
virtual double getFloat(const std::string& name, double dflt,
|
||||
const std::string& sk = std::string());
|
||||
virtual bool getBool(const std::string& name, bool dflt,
|
||||
const std::string& sk = std::string());
|
||||
virtual bool ok() const = 0;
|
||||
virtual std::vector<std::string> getNames(const std::string& sk,
|
||||
const char* = 0)const = 0;
|
||||
const char* = 0) const = 0;
|
||||
virtual bool hasNameAnywhere(const std::string& nm) const = 0;
|
||||
virtual int erase(const std::string&, const std::string&) = 0;
|
||||
virtual int eraseKey(const std::string&) = 0;
|
||||
@ -167,15 +172,6 @@ public:
|
||||
virtual int get(const std::string& name, std::string& value,
|
||||
const std::string& sk = std::string()) const override;
|
||||
|
||||
/**
|
||||
* Get integer value for named parameter, from specified subsection (looks
|
||||
* in global space if sk is empty).
|
||||
* @return 0 if name not found, 1 else
|
||||
*/
|
||||
virtual int get(const std::string& name, int* value,
|
||||
const std::string& sk = std::string()) const;
|
||||
|
||||
|
||||
/**
|
||||
* Set value for named string parameter in specified subsection (or global)
|
||||
* @return 0 for error, 1 else
|
||||
@ -302,8 +298,8 @@ protected:
|
||||
StatusCode status;
|
||||
private:
|
||||
// Set if we're working with a file
|
||||
std::string m_filename;
|
||||
time_t m_fmtime;
|
||||
std::string m_filename;
|
||||
time_t m_fmtime;
|
||||
// Configuration data submaps (one per subkey, the main data has a
|
||||
// null subkey)
|
||||
std::map<std::string, std::map<std::string, std::string> > m_submaps;
|
||||
@ -311,9 +307,9 @@ private:
|
||||
// Presentation data. We keep the comments, empty lines and
|
||||
// variable and subkey ordering information in there (for
|
||||
// rewriting the file while keeping hand-edited information)
|
||||
std::vector<ConfLine> m_order;
|
||||
std::vector<ConfLine> m_order;
|
||||
// Control if we're writing to the backing store
|
||||
bool m_holdWrites;
|
||||
bool m_holdWrites;
|
||||
|
||||
void parseinput(std::istream& input);
|
||||
bool write();
|
||||
@ -369,15 +365,16 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Use several config files, trying to get values from each in order. Used to
|
||||
* have a central config, with possible overrides from more specific
|
||||
* (ie personal) ones.
|
||||
* Use several config files, trying to get values from each in order.
|
||||
*
|
||||
* Enables having a central/default config, with possible overrides
|
||||
* from more specific (e.g. personal) ones.
|
||||
*
|
||||
* Notes: it's ok for some of the files not to exist, but the last
|
||||
* one must or we generate an error. We open all trees readonly, except the
|
||||
* topmost one if requested. All writes go to the topmost file. Note that
|
||||
* erase() won't work except for parameters only defined in the topmost
|
||||
* file (it erases only from there).
|
||||
* (bottom) one must or we generate an error. We open all trees
|
||||
* readonly, except the topmost one if requested. All writes go to the
|
||||
* topmost file. Note that erase() won't work except for parameters
|
||||
* only defined in the topmost file (it erases only from there).
|
||||
*/
|
||||
template <class T> class ConfStack : public ConfNull {
|
||||
public:
|
||||
@ -418,7 +415,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual bool sourceChanged() const override {
|
||||
virtual bool sourceChanged() const override {
|
||||
for (const auto& conf : m_confs) {
|
||||
if (conf->sourceChanged()) {
|
||||
return true;
|
||||
@ -500,7 +497,7 @@ public:
|
||||
return getNames1(sk, pattern, false);
|
||||
}
|
||||
virtual std::vector<std::string> getNamesShallow(const std::string& sk,
|
||||
const char *patt = 0) const {
|
||||
const char *patt = 0) const {
|
||||
return getNames1(sk, patt, true);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user