add methods useful for history. move stuff to smallut
This commit is contained in:
parent
b7d0a90d9d
commit
ccb27e07b4
@ -1,5 +1,5 @@
|
||||
#ifndef lint
|
||||
static char rcsid [] = "@(#$Id: conftree.cpp,v 1.2 2005-11-17 12:47:03 dockes Exp $ (C) 2003 J.F.Dockes";
|
||||
static char rcsid [] = "@(#$Id: conftree.cpp,v 1.3 2005-11-25 08:50:39 dockes Exp $ (C) 2003 J.F.Dockes";
|
||||
#endif
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
@ -25,6 +25,8 @@ using std::list;
|
||||
#define MIN(A,B) ((A)<(B) ? (A) : (B))
|
||||
#endif
|
||||
|
||||
/** Remove instances of characters belonging to set (default {space,
|
||||
tab}) at beginning and end of input string */
|
||||
static void trimstring(string &s, const char *ws = " \t")
|
||||
{
|
||||
string::size_type pos = s.find_first_not_of(ws);
|
||||
@ -71,7 +73,7 @@ void ConfSimple::parseinput(istream &input)
|
||||
line = cline;
|
||||
|
||||
// Note that we trim whitespace before checking for backslash-eol
|
||||
// This avoids invisible problems
|
||||
// This avoids invisible problems.
|
||||
trimstring(line);
|
||||
if (line.empty())
|
||||
continue;
|
||||
@ -183,7 +185,7 @@ ConfSimple::StatusCode ConfSimple::getStatus()
|
||||
|
||||
int ConfSimple::get(const string &nm, string &value, const string &sk)
|
||||
{
|
||||
if (status == STATUS_ERROR)
|
||||
if (!ok())
|
||||
return 0;
|
||||
|
||||
// Find submap
|
||||
@ -217,14 +219,28 @@ const char *ConfSimple::get(const char *nm, const char *sk)
|
||||
return (s->second).c_str();
|
||||
}
|
||||
|
||||
static ConfSimple::WalkerCode swalker(void *f, const char *nm,
|
||||
const char *value)
|
||||
static ConfSimple::WalkerCode swalker(void *f, const string &nm,
|
||||
const string &value)
|
||||
{
|
||||
ostream *output = (ostream *)f;
|
||||
if (!nm || !strcmp(nm, ""))
|
||||
if (nm.empty())
|
||||
*output << "\n[" << value << "]\n";
|
||||
else
|
||||
*output << nm << " = " << value << "\n";
|
||||
else {
|
||||
string value1;
|
||||
if (value.length() < 60) {
|
||||
value1 = value;
|
||||
} else {
|
||||
string::size_type pos = 0;
|
||||
while (pos < value.length()) {
|
||||
string::size_type len = MIN(60, value.length() - pos);
|
||||
value1 += value.substr(pos, len);
|
||||
pos += len;
|
||||
if (pos < value.length())
|
||||
value1 += "\\\n";
|
||||
}
|
||||
}
|
||||
*output << nm << " = " << value1 << "\n";
|
||||
}
|
||||
return ConfSimple::WALK_CONTINUE;
|
||||
}
|
||||
|
||||
@ -240,28 +256,14 @@ int ConfSimple::set(const std::string &nm, const std::string &value,
|
||||
return 0;
|
||||
}
|
||||
|
||||
string value1;
|
||||
string::size_type pos = 0;
|
||||
if (value.length() < 60) {
|
||||
value1 = value;
|
||||
} else {
|
||||
while (pos < value.length()) {
|
||||
string::size_type len = MIN(60, value.length() - pos);
|
||||
value1 += value.substr(pos, len);
|
||||
pos += len;
|
||||
if (pos < value.length())
|
||||
value1 += "\\\n";
|
||||
}
|
||||
}
|
||||
|
||||
map<string, map<string, string> >::iterator ss;
|
||||
if ((ss = submaps.find(sk)) == submaps.end()) {
|
||||
map<string, string> submap;
|
||||
submap[nm] = value1;
|
||||
submap[nm] = value;
|
||||
submaps[sk] = submap;
|
||||
|
||||
} else {
|
||||
ss->second[nm] = value1;
|
||||
ss->second[nm] = value;
|
||||
}
|
||||
|
||||
if (filename.length()) {
|
||||
@ -284,7 +286,39 @@ int ConfSimple::set(const std::string &nm, const std::string &value,
|
||||
}
|
||||
}
|
||||
|
||||
// Add parameter to file
|
||||
int ConfSimple::erase(const string &nm, const string &sk)
|
||||
{
|
||||
if (status != STATUS_RW)
|
||||
return 0;
|
||||
|
||||
map<string, map<string, string> >::iterator ss;
|
||||
if ((ss = submaps.find(sk)) == submaps.end()) {
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
ss->second.erase(nm);
|
||||
|
||||
if (filename.length()) {
|
||||
ofstream output(filename.c_str(), ios::out|ios::trunc);
|
||||
if (!output.is_open())
|
||||
return 0;
|
||||
if (sortwalk(swalker, &output) != WALK_CONTINUE) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else if (data) {
|
||||
ostringstream output(*data, ios::out | ios::trunc);
|
||||
if (sortwalk(swalker, &output) != WALK_CONTINUE) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
// ??
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ConfSimple::set(const char *nm, const char *value, const char *sk)
|
||||
{
|
||||
string ssk = (sk == 0) ? string("") : string(sk);
|
||||
@ -292,9 +326,11 @@ int ConfSimple::set(const char *nm, const char *value, const char *sk)
|
||||
}
|
||||
|
||||
ConfSimple::WalkerCode
|
||||
ConfSimple::sortwalk(WalkerCode (*walker)(void *,const char *,const char *),
|
||||
ConfSimple::sortwalk(WalkerCode (*walker)(void *,const string&,const string&),
|
||||
void *clidata)
|
||||
{
|
||||
if (!ok())
|
||||
return WALK_STOP;
|
||||
// For all submaps:
|
||||
for (map<string, map<string, string> >::iterator sit = submaps.begin();
|
||||
sit != submaps.end(); sit++) {
|
||||
@ -308,8 +344,7 @@ ConfSimple::sortwalk(WalkerCode (*walker)(void *,const char *,const char *),
|
||||
map<string, string> &sm = sit->second;
|
||||
for (map<string, string>::iterator it = sm.begin();it != sm.end();
|
||||
it++) {
|
||||
if (walker(clidata, it->first.c_str(), it->second.c_str())
|
||||
== WALK_STOP)
|
||||
if (walker(clidata, it->first, it->second) == WALK_STOP)
|
||||
return WALK_STOP;
|
||||
}
|
||||
}
|
||||
@ -319,24 +354,31 @@ ConfSimple::sortwalk(WalkerCode (*walker)(void *,const char *,const char *),
|
||||
#include <iostream>
|
||||
void ConfSimple::list()
|
||||
{
|
||||
if (!ok())
|
||||
return;
|
||||
sortwalk(swalker, &std::cout);
|
||||
}
|
||||
|
||||
static ConfSimple::WalkerCode lwalker(void *l, const char *nm, const char *)
|
||||
{
|
||||
list<string> *lst = (list<string> *)l;
|
||||
if (nm && *nm)
|
||||
lst->push_back(nm);
|
||||
return ConfSimple::WALK_CONTINUE;
|
||||
}
|
||||
|
||||
list<string> ConfSimple::getKeys()
|
||||
list<string> ConfSimple::getNames(const string &sk)
|
||||
{
|
||||
std::list<string> mylist;
|
||||
sortwalk(lwalker, &mylist);
|
||||
if (!ok())
|
||||
return mylist;
|
||||
map<string, map<string, string> >::iterator ss;
|
||||
if ((ss = submaps.find(sk)) == submaps.end()) {
|
||||
return mylist;
|
||||
}
|
||||
map<string, string>::const_iterator it;
|
||||
for (it = ss->second.begin();it != ss->second.end();it++) {
|
||||
mylist.push_back(it->first);
|
||||
}
|
||||
return mylist;
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
// ConfTree Methods: conftree interpret keys like a hierarchical file tree
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ConfTree::get(const std::string &name, string &value, const string &sk)
|
||||
{
|
||||
if (sk.empty() || sk[0] != '/') {
|
||||
@ -366,106 +408,6 @@ int ConfTree::get(const std::string &name, string &value, const string &sk)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ConfTree::stringToStrings(const string &s, std::list<string> &tokens)
|
||||
{
|
||||
string current;
|
||||
tokens.clear();
|
||||
enum states {SPACE, TOKEN, INQUOTE, ESCAPE};
|
||||
states state = SPACE;
|
||||
for (unsigned int i = 0; i < s.length(); i++) {
|
||||
switch (s[i]) {
|
||||
case '"':
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
state=INQUOTE; continue;
|
||||
case TOKEN:
|
||||
current += '"';
|
||||
continue;
|
||||
case INQUOTE:
|
||||
tokens.push_back(current);
|
||||
current = "";
|
||||
state = SPACE;
|
||||
continue;
|
||||
case ESCAPE:
|
||||
current += '"';
|
||||
state = INQUOTE;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
case TOKEN:
|
||||
current += '\\';
|
||||
state=TOKEN;
|
||||
continue;
|
||||
case INQUOTE:
|
||||
state = ESCAPE;
|
||||
continue;
|
||||
case ESCAPE:
|
||||
current += '\\';
|
||||
state = INQUOTE;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
continue;
|
||||
case TOKEN:
|
||||
tokens.push_back(current);
|
||||
current = "";
|
||||
state = SPACE;
|
||||
continue;
|
||||
case INQUOTE:
|
||||
case ESCAPE:
|
||||
current += s[i];
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch(state) {
|
||||
case ESCAPE:
|
||||
state = INQUOTE;
|
||||
break;
|
||||
case SPACE:
|
||||
state = TOKEN;
|
||||
break;
|
||||
case TOKEN:
|
||||
case INQUOTE:
|
||||
break;
|
||||
}
|
||||
current += s[i];
|
||||
}
|
||||
}
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
break;
|
||||
case TOKEN:
|
||||
tokens.push_back(current);
|
||||
break;
|
||||
case INQUOTE:
|
||||
case ESCAPE:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfTree::stringToBool(const string &s)
|
||||
{
|
||||
if (isdigit(s[0])) {
|
||||
int val = atoi(s.c_str());
|
||||
return val ? true : false;
|
||||
}
|
||||
if (strchr("yYoOtT", s[0]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#else // TEST_CONFTREE
|
||||
|
||||
#include <stdio.h>
|
||||
@ -476,17 +418,18 @@ bool ConfTree::stringToBool(const string &s)
|
||||
#include <list>
|
||||
|
||||
#include "conftree.h"
|
||||
#include "smallut.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static char *thisprog;
|
||||
|
||||
ConfSimple::WalkerCode mywalker(void *, const char *nm, const char *value)
|
||||
ConfSimple::WalkerCode mywalker(void *, const string &nm, const string &value)
|
||||
{
|
||||
if (!nm || nm[0] == 0)
|
||||
printf("\n[%s]\n", value);
|
||||
if (nm.empty())
|
||||
printf("\n[%s]\n", value.c_str());
|
||||
else
|
||||
printf("'%s' -> '%s'\n", nm, value);
|
||||
printf("'%s' -> '%s'\n", nm.c_str(), value.c_str());
|
||||
return ConfSimple::WALK_CONTINUE;
|
||||
}
|
||||
|
||||
@ -527,6 +470,7 @@ static char usage [] =
|
||||
"[-w] : read/write test.\n"
|
||||
"[-s] : string parsing test. Filename must hold parm 'strings'\n"
|
||||
"[-q] nm sect : subsection test: look for nm in 'sect' which can be ''\n"
|
||||
"[-d] nm sect : delete nm in 'sect' which can be ''\n"
|
||||
"[-S] : string io test. No filename in this case\n"
|
||||
;
|
||||
|
||||
@ -540,6 +484,7 @@ static int op_flags;
|
||||
#define OPT_q 0x4
|
||||
#define OPT_s 0x8
|
||||
#define OPT_S 0x10
|
||||
#define OPT_d 0x20
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@ -559,6 +504,13 @@ int main(int argc, char **argv)
|
||||
case 'w': op_flags |= OPT_w; break;
|
||||
case 's': op_flags |= OPT_s; break;
|
||||
case 'S': op_flags |= OPT_S; break;
|
||||
case 'd':
|
||||
op_flags |= OPT_d;
|
||||
if (argc < 3)
|
||||
Usage();
|
||||
nm = *(++argv);argc--;
|
||||
sub = *(++argv);argc--;
|
||||
goto b1;
|
||||
case 'q':
|
||||
op_flags |= OPT_q;
|
||||
if (argc < 3)
|
||||
@ -629,6 +581,18 @@ int main(int argc, char **argv)
|
||||
}
|
||||
printf("%s : '%s' = '%s'\n", sub, nm, value.c_str());
|
||||
exit(0);
|
||||
} else if (op_flags & OPT_d) {
|
||||
ConfTree parms(filename, 0);
|
||||
if (parms.getStatus() != ConfSimple::STATUS_RW) {
|
||||
fprintf(stderr, "Error opening or parsing file\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!parms.erase(nm, sub)) {
|
||||
fprintf(stderr, "delete name '%s' in '%s' failed\n", nm, sub);
|
||||
exit(1);
|
||||
}
|
||||
printf("OK\n");
|
||||
exit(0);
|
||||
} else if (op_flags & OPT_s) {
|
||||
ConfSimple parms(filename, 1);
|
||||
if (parms.getStatus() == ConfSimple::STATUS_ERROR) {
|
||||
@ -643,7 +607,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
cout << "source: [" << source << "]" << endl;
|
||||
list<string> strings;
|
||||
if (!ConfTree::stringToStrings(source, strings)) {
|
||||
if (!stringToStrings(source, strings)) {
|
||||
cerr << "parse failed" << endl;
|
||||
exit(1);
|
||||
}
|
||||
@ -659,12 +623,15 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, "Open failed\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("LIST\n");parms.list();
|
||||
printf("KEYS\n");
|
||||
list<string> keys = parms.getKeys();
|
||||
for (list<string>::iterator it = keys.begin();it!=keys.end();it++)
|
||||
printf("%s\n", (*it).c_str());
|
||||
printf("LIST\n");
|
||||
parms.list();
|
||||
//printf("WALK\n");parms.sortwalk(mywalker, 0);
|
||||
printf("\nNAMES in global space:\n");
|
||||
list<string> names = parms.getNames("");
|
||||
for (list<string>::iterator it = names.begin();it!=names.end();
|
||||
it++)
|
||||
printf("%s\n", (*it).c_str());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ class ConfSimple {
|
||||
virtual int get(const std::string &name, string &value) {
|
||||
return get(name, value, string(""));
|
||||
}
|
||||
/**
|
||||
/*
|
||||
* See comments for std::string variant
|
||||
* @return 0 if name not found, const C string else
|
||||
*/
|
||||
@ -75,10 +75,17 @@ class ConfSimple {
|
||||
* Set value for named parameter in specified subsection (or global)
|
||||
* @return 0 for error, 1 else
|
||||
*/
|
||||
int set(const std::string &nm, const std::string &val, const string &sk);
|
||||
int set(const char *name, const char *value, const char *sk = 0);
|
||||
virtual int set(const std::string &nm, const std::string &val,
|
||||
const std::string &sk);
|
||||
virtual int set(const char *name, const char *value, const char *sk = 0);
|
||||
|
||||
/**
|
||||
* Remove name and value from config
|
||||
*/
|
||||
virtual int erase(const std::string &name, const std::string &sk);
|
||||
|
||||
virtual StatusCode getStatus();
|
||||
virtual bool ok() {return getStatus() != STATUS_ERROR;}
|
||||
|
||||
/**
|
||||
* Walk the configuration values, calling function for each.
|
||||
@ -89,14 +96,17 @@ class ConfSimple {
|
||||
*/
|
||||
enum WalkerCode {WALK_STOP, WALK_CONTINUE};
|
||||
virtual WalkerCode sortwalk(WalkerCode
|
||||
(*wlkr)(void *cldata, const char *nm,
|
||||
const char *val),
|
||||
(*wlkr)(void *cldata, const std::string &nm,
|
||||
const std::string &val),
|
||||
void *clidata);
|
||||
void list();
|
||||
virtual void list();
|
||||
|
||||
/**
|
||||
* Return all key names:
|
||||
* Return all names in given submap
|
||||
*/
|
||||
std::list<string> getKeys();
|
||||
virtual std::list<string> getNames(const string &sk);
|
||||
|
||||
virtual std::string getFilename() {return filename;}
|
||||
|
||||
protected:
|
||||
bool dotildexpand;
|
||||
@ -145,14 +155,6 @@ class ConfTree : public ConfSimple {
|
||||
virtual int get(const char *name, string &value, const char *sk) {
|
||||
return get(string(name), value, sk ? string(sk) : string(""));
|
||||
}
|
||||
/**
|
||||
* Parse input stream into vector of strings.
|
||||
*
|
||||
* Token delimiter is " \t" except inside dquotes. dquote inside
|
||||
* dquotes can be escaped with \ etc...
|
||||
*/
|
||||
static bool stringToStrings(const string &s, std::list<string> &tokens);
|
||||
static bool stringToBool(const string &s);
|
||||
};
|
||||
|
||||
#endif /*_CONFTREE_H_ */
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef lint
|
||||
static char rcsid[] = "@(#$Id: smallut.cpp,v 1.8 2005-11-24 07:16:16 dockes Exp $ (C) 2004 J.F.Dockes";
|
||||
static char rcsid[] = "@(#$Id: smallut.cpp,v 1.9 2005-11-25 08:50:39 dockes Exp $ (C) 2004 J.F.Dockes";
|
||||
#endif
|
||||
#ifndef TEST_SMALLUT
|
||||
#include <string>
|
||||
@ -163,12 +163,12 @@ bool samecharset(const string &cs1, const string &cs2)
|
||||
{
|
||||
string mcs1, mcs2;
|
||||
// Remove all - and _, turn to lowecase
|
||||
for (int i = 0; i < cs1.length();i++) {
|
||||
for (unsigned int i = 0; i < cs1.length();i++) {
|
||||
if (cs1[i] != '_' && cs1[i] != '-') {
|
||||
mcs1 += ::tolower(cs1[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < cs2.length();i++) {
|
||||
for (unsigned int i = 0; i < cs2.length();i++) {
|
||||
if (cs2[i] != '_' && cs2[i] != '-') {
|
||||
mcs2 += ::tolower(cs2[i]);
|
||||
}
|
||||
@ -176,6 +176,108 @@ bool samecharset(const string &cs1, const string &cs2)
|
||||
return mcs1 == mcs2;
|
||||
}
|
||||
|
||||
|
||||
bool stringToStrings(const string &s, std::list<string> &tokens)
|
||||
{
|
||||
string current;
|
||||
tokens.clear();
|
||||
enum states {SPACE, TOKEN, INQUOTE, ESCAPE};
|
||||
states state = SPACE;
|
||||
for (unsigned int i = 0; i < s.length(); i++) {
|
||||
switch (s[i]) {
|
||||
case '"':
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
state=INQUOTE; continue;
|
||||
case TOKEN:
|
||||
current += '"';
|
||||
continue;
|
||||
case INQUOTE:
|
||||
tokens.push_back(current);
|
||||
current = "";
|
||||
state = SPACE;
|
||||
continue;
|
||||
case ESCAPE:
|
||||
current += '"';
|
||||
state = INQUOTE;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
case TOKEN:
|
||||
current += '\\';
|
||||
state=TOKEN;
|
||||
continue;
|
||||
case INQUOTE:
|
||||
state = ESCAPE;
|
||||
continue;
|
||||
case ESCAPE:
|
||||
current += '\\';
|
||||
state = INQUOTE;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
continue;
|
||||
case TOKEN:
|
||||
tokens.push_back(current);
|
||||
current = "";
|
||||
state = SPACE;
|
||||
continue;
|
||||
case INQUOTE:
|
||||
case ESCAPE:
|
||||
current += s[i];
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch(state) {
|
||||
case ESCAPE:
|
||||
state = INQUOTE;
|
||||
break;
|
||||
case SPACE:
|
||||
state = TOKEN;
|
||||
break;
|
||||
case TOKEN:
|
||||
case INQUOTE:
|
||||
break;
|
||||
}
|
||||
current += s[i];
|
||||
}
|
||||
}
|
||||
switch(state) {
|
||||
case SPACE:
|
||||
break;
|
||||
case TOKEN:
|
||||
tokens.push_back(current);
|
||||
break;
|
||||
case INQUOTE:
|
||||
case ESCAPE:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool stringToBool(const string &s)
|
||||
{
|
||||
if (s.empty())
|
||||
return false;
|
||||
if (isdigit(s[0])) {
|
||||
int val = atoi(s.c_str());
|
||||
return val ? true : false;
|
||||
}
|
||||
if (strchr("yYoOtT", s[0]))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#ifndef _SMALLUT_H_INCLUDED_
|
||||
#define _SMALLUT_H_INCLUDED_
|
||||
/* @(#$Id: smallut.h,v 1.8 2005-11-24 07:16:16 dockes Exp $ (C) 2004 J.F.Dockes */
|
||||
/* @(#$Id: smallut.h,v 1.9 2005-11-25 08:50:39 dockes Exp $ (C) 2004 J.F.Dockes */
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
@ -19,4 +19,14 @@ extern bool samecharset(const string &cs1, const string &cs2);
|
||||
extern bool maketmpdir(string& tdir);
|
||||
extern string stringlistdisp(const list<string>& strs);
|
||||
|
||||
/**
|
||||
* Parse input stream into list of strings.
|
||||
*
|
||||
* Token delimiter is " \t" except inside dquotes. dquote inside
|
||||
* dquotes can be escaped with \ etc...
|
||||
*/
|
||||
extern bool stringToStrings(const string &s, std::list<string> &tokens);
|
||||
|
||||
extern bool stringToBool(const string &s);
|
||||
|
||||
#endif /* _SMALLUT_H_INCLUDED_ */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user